diff --git a/web-app/.meteor/local/build/README b/web-app/.meteor/local/build/README deleted file mode 100644 index 5e02281..0000000 --- a/web-app/.meteor/local/build/README +++ /dev/null @@ -1,14 +0,0 @@ -This is a Meteor application bundle. It has only one external dependency: -Node.js 0.10.36 or newer. To run the application: - - $ (cd programs/server && npm install) - $ export MONGO_URL='mongodb://user:password@host:port/databasename' - $ export ROOT_URL='http://example.com' - $ export MAIL_URL='smtp://user:password@mailhost:port/' - $ node main.js - -Use the PORT environment variable to set the port where the -application will listen. The default is 80, but that will require -root on most systems. - -Find out more about Meteor at meteor.com. diff --git a/web-app/.meteor/local/build/main.js b/web-app/.meteor/local/build/main.js deleted file mode 100644 index 056d8a4..0000000 --- a/web-app/.meteor/local/build/main.js +++ /dev/null @@ -1,9 +0,0 @@ - -// The debugger pauses here when you run `meteor debug`, because this is -// the very first code to be executed by the server process. If you have -// not already added any `debugger` statements to your code, feel free to -// do so now, wait for the server to restart, then reload this page and -// click the |▶ button to continue. -process.argv.splice(2, 0, 'program.json'); -process.chdir(require('path').join(__dirname, 'programs', 'server')); -require('./programs/server/boot.js'); \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.browser.html b/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.browser.html deleted file mode 100644 index 3871c81..0000000 --- a/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.browser.html +++ /dev/null @@ -1,28 +0,0 @@ - - -{{#each css}} {{/each}} - -{{#if inlineScriptsAllowed}} - -{{else}} - -{{/if}} -{{#each js}} -{{/each}} -{{#each additionalStaticJs}} - {{#if ../inlineScriptsAllowed}} - - {{else}} - - {{/if}} -{{/each}} - -{{{head}}} - - -{{{body}}} - - diff --git a/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.cordova.html b/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.cordova.html deleted file mode 100644 index 7f82521..0000000 --- a/web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.cordova.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - -{{#each css}} {{/each}} - - - - -{{#each js}} -{{/each}} -{{#each additionalStaticJs}} - {{#if ../inlineScriptsAllowed}} - - {{else}} - - {{/if}} -{{/each}} - {{{head}}} - - - - {{{body}}} - - diff --git a/web-app/.meteor/local/build/programs/server/boot-utils.js b/web-app/.meteor/local/build/programs/server/boot-utils.js deleted file mode 100644 index 58e4024..0000000 --- a/web-app/.meteor/local/build/programs/server/boot-utils.js +++ /dev/null @@ -1,7 +0,0 @@ -// Separated from boot.js for testing. - -// Check that we have a pid that looks like an integer (non-decimal -// integer is okay). -exports.validPid = function (pid) { - return ! isNaN(+pid); -}; diff --git a/web-app/.meteor/local/build/programs/server/boot.js b/web-app/.meteor/local/build/programs/server/boot.js deleted file mode 100644 index bad9b3e..0000000 --- a/web-app/.meteor/local/build/programs/server/boot.js +++ /dev/null @@ -1,263 +0,0 @@ -var Fiber = require("fibers"); -var fs = require("fs"); -var path = require("path"); -var Future = require("fibers/future"); -var _ = require('underscore'); -var sourcemap_support = require('source-map-support'); - -var bootUtils = require('./boot-utils.js'); -var files = require('./mini-files.js'); - -// This code is duplicated in tools/main.js. -var MIN_NODE_VERSION = 'v0.10.36'; - -if (require('semver').lt(process.version, MIN_NODE_VERSION)) { - process.stderr.write( - 'Meteor requires Node ' + MIN_NODE_VERSION + ' or later.\n'); - process.exit(1); -} - -// read our control files -var serverJsonPath = path.resolve(process.argv[2]); -var serverDir = path.dirname(serverJsonPath); -var serverJson = JSON.parse(fs.readFileSync(serverJsonPath, 'utf8')); -var configJson = - JSON.parse(fs.readFileSync(path.resolve(serverDir, 'config.json'), 'utf8')); - -// Set up environment -__meteor_bootstrap__ = { - startupHooks: [], - serverDir: serverDir, - configJson: configJson }; -__meteor_runtime_config__ = { meteorRelease: configJson.meteorRelease }; - - -// connect (and some other NPM modules) use $NODE_ENV to make some decisions; -// eg, if $NODE_ENV is not production, they send stack traces on error. connect -// considers 'development' to be the default mode, but that's less safe than -// assuming 'production' to be the default. If you really want development mode, -// set it in your wrapper script (eg, run-app.js). -if (!process.env.NODE_ENV) - process.env.NODE_ENV = 'production'; - -// Map from load path to its source map. -var parsedSourceMaps = {}; - -// Read all the source maps into memory once. -_.each(serverJson.load, function (fileInfo) { - if (fileInfo.sourceMap) { - var rawSourceMap = fs.readFileSync( - path.resolve(serverDir, fileInfo.sourceMap), 'utf8'); - // Parse the source map only once, not each time it's needed. Also remove - // the anti-XSSI header if it's there. - var parsedSourceMap = JSON.parse(rawSourceMap.replace(/^\)\]\}'/, '')); - // source-map-support doesn't ever look at the sourcesContent field, so - // there's no point in keeping it in memory. - delete parsedSourceMap.sourcesContent; - var url; - if (fileInfo.sourceMapRoot) { - // Add the specified root to any root that may be in the file. - parsedSourceMap.sourceRoot = path.join( - fileInfo.sourceMapRoot, parsedSourceMap.sourceRoot || ''); - } - parsedSourceMaps[path.resolve(__dirname, fileInfo.path)] = parsedSourceMap; - } -}); - -var retrieveSourceMap = function (pathForSourceMap) { - if (_.has(parsedSourceMaps, pathForSourceMap)) - return { map: parsedSourceMaps[pathForSourceMap] }; - return null; -}; - -sourcemap_support.install({ - // Use the source maps specified in program.json instead of parsing source - // code for them. - retrieveSourceMap: retrieveSourceMap, - // For now, don't fix the source line in uncaught exceptions, because we - // haven't fixed handleUncaughtExceptions in source-map-support to properly - // locate the source files. - handleUncaughtExceptions: false -}); - -// Only enabled by default in development. -if (process.env.METEOR_SHELL_DIR) { - require('./shell-server.js').listen(process.env.METEOR_SHELL_DIR); -} - -// As a replacement to the old keepalives mechanism, check for a running -// parent every few seconds. Exit if the parent is not running. -// -// Two caveats to this strategy: -// * Doesn't catch the case where the parent is CPU-hogging (but maybe we -// don't want to catch that case anyway, since the bundler not yielding -// is what caused #2536). -// * Could be fooled by pid re-use, i.e. if another process comes up and -// takes the parent process's place before the child process dies. -var startCheckForLiveParent = function (parentPid) { - if (parentPid) { - if (! bootUtils.validPid(parentPid)) { - console.error("METEOR_PARENT_PID must be a valid process ID."); - process.exit(1); - } - - setInterval(function () { - try { - process.kill(parentPid, 0); - } catch (err) { - console.error("Parent process is dead! Exiting."); - process.exit(1); - } - }, 3000); - } -}; - - -Fiber(function () { - _.each(serverJson.load, function (fileInfo) { - var code = fs.readFileSync(path.resolve(serverDir, fileInfo.path)); - - var Npm = { - /** - * @summary Require a package that was specified using - * `Npm.depends()`. - * @param {String} name The name of the package to require. - * @locus Server - * @memberOf Npm - */ - require: function (name) { - if (! fileInfo.node_modules) { - return require(name); - } - - var nodeModuleBase = path.resolve(serverDir, - files.convertToOSPath(fileInfo.node_modules)); - var nodeModuleDir = path.resolve(nodeModuleBase, name); - - // If the user does `Npm.require('foo/bar')`, then we should resolve to - // the package's node modules if `foo` was one of the modules we - // installed. (`foo/bar` might be implemented as `foo/bar.js` so we - // can't just naively see if all of nodeModuleDir exists. - if (fs.existsSync(path.resolve(nodeModuleBase, name.split("/")[0]))) { - return require(nodeModuleDir); - } - - try { - return require(name); - } catch (e) { - // Try to guess the package name so we can print a nice - // error message - // fileInfo.path is a standard path, use files.pathSep - var filePathParts = fileInfo.path.split(files.pathSep); - var packageName = filePathParts[1].replace(/\.js$/, ''); - - // XXX better message - throw new Error( - "Can't find npm module '" + name + - "'. Did you forget to call 'Npm.depends' in package.js " + - "within the '" + packageName + "' package?"); - } - } - }; - var getAsset = function (assetPath, encoding, callback) { - var fut; - if (! callback) { - fut = new Future(); - callback = fut.resolver(); - } - // This assumes that we've already loaded the meteor package, so meteor - // itself (and weird special cases like js-analyze) can't call - // Assets.get*. (We could change this function so that it doesn't call - // bindEnvironment if you don't pass a callback if we need to.) - var _callback = Package.meteor.Meteor.bindEnvironment(function (err, result) { - if (result && ! encoding) - // Sadly, this copies in Node 0.10. - result = new Uint8Array(result); - callback(err, result); - }, function (e) { - console.log("Exception in callback of getAsset", e.stack); - }); - - // Convert a DOS-style path to Unix-style in case the application code was - // written on Windows. - assetPath = files.convertToStandardPath(assetPath); - - if (!fileInfo.assets || !_.has(fileInfo.assets, assetPath)) { - _callback(new Error("Unknown asset: " + assetPath)); - } else { - var filePath = path.join(serverDir, fileInfo.assets[assetPath]); - fs.readFile(files.convertToOSPath(filePath), encoding, _callback); - } - if (fut) - return fut.wait(); - }; - - var Assets = { - getText: function (assetPath, callback) { - return getAsset(assetPath, "utf8", callback); - }, - getBinary: function (assetPath, callback) { - return getAsset(assetPath, undefined, callback); - } - }; - - // \n is necessary in case final line is a //-comment - var wrapped = "(function(Npm, Assets){" + code + "\n})"; - - // It is safer to use the absolute path when source map is present as - // different tooling, such as node-inspector, can get confused on relative - // urls. - - // fileInfo.path is a standard path, convert it to OS path to join with - // __dirname - var fileInfoOSPath = files.convertToOSPath(fileInfo.path); - var absoluteFilePath = path.resolve(__dirname, fileInfoOSPath); - - var scriptPath = - parsedSourceMaps[absoluteFilePath] ? absoluteFilePath : fileInfoOSPath; - // The final 'true' is an undocumented argument to runIn[Foo]Context that - // causes it to print out a descriptive error message on parse error. It's - // what require() uses to generate its errors. - var func = require('vm').runInThisContext(wrapped, scriptPath, true); - func.call(global, Npm, Assets); // Coffeescript - }); - - // run the user startup hooks. other calls to startup() during this can still - // add hooks to the end. - while (__meteor_bootstrap__.startupHooks.length) { - var hook = __meteor_bootstrap__.startupHooks.shift(); - hook(); - } - // Setting this to null tells Meteor.startup to call hooks immediately. - __meteor_bootstrap__.startupHooks = null; - - // find and run main() - // XXX hack. we should know the package that contains main. - var mains = []; - var globalMain; - if ('main' in global) { - mains.push(main); - globalMain = main; - } - typeof Package !== 'undefined' && _.each(Package, function (p, n) { - if ('main' in p && p.main !== globalMain) { - mains.push(p.main); - } - }); - if (! mains.length) { - process.stderr.write("Program has no main() function.\n"); - process.exit(1); - } - if (mains.length > 1) { - process.stderr.write("Program has more than one main() function?\n"); - process.exit(1); - } - var exitCode = mains[0].call({}, process.argv.slice(3)); - // XXX hack, needs a better way to keep alive - if (exitCode !== 'DAEMON') - process.exit(exitCode); - - if (process.env.METEOR_PARENT_PID) { - startCheckForLiveParent(process.env.METEOR_PARENT_PID); - } -}).run(); diff --git a/web-app/.meteor/local/build/programs/server/config.json b/web-app/.meteor/local/build/programs/server/config.json deleted file mode 100644 index 94d6023..0000000 --- a/web-app/.meteor/local/build/programs/server/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "meteorRelease": "METEOR@1.1.0.2", - "clientPaths": { - "web.browser": "../web.browser/program.json" - } -} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/mini-files.js b/web-app/.meteor/local/build/programs/server/mini-files.js deleted file mode 100644 index 46aa74b..0000000 --- a/web-app/.meteor/local/build/programs/server/mini-files.js +++ /dev/null @@ -1,108 +0,0 @@ -var _ = require("underscore"); -var os = require("os"); -var path = require("path"); - -// All of these functions are attached to files.js for the tool; -// they live here because we need them in boot.js as well to avoid duplicating -// a lot of the code. -// -// Note that this file does NOT contain any of the "perform I/O maybe -// synchronously" functions from files.js; this is intentional, because we want -// to make it very hard to accidentally use fs.*Sync functions in the app server -// after bootup (since they block all concurrency!) -var files = module.exports; - -var toPosixPath = function (p, partialPath) { - // Sometimes, you can have a path like \Users\IEUser on windows, and this - // actually means you want C:\Users\IEUser - if (p[0] === "\\" && (! partialPath)) { - p = process.env.SystemDrive + p; - } - - p = p.replace(/\\/g, '/'); - if (p[1] === ':' && ! partialPath) { - // transform "C:/bla/bla" to "/c/bla/bla" - p = '/' + p[0] + p.slice(2); - } - - return p; -}; - -var toDosPath = function (p, partialPath) { - if (p[0] === '/' && ! partialPath) { - if (! /^\/[A-Za-z](\/|$)/.test(p)) - throw new Error("Surprising path: " + p); - // transform a previously windows path back - // "/C/something" to "c:/something" - p = p[1] + ":" + p.slice(2); - } - - p = p.replace(/\//g, '\\'); - return p; -}; - - -var convertToOSPath = function (standardPath, partialPath) { - if (process.platform === "win32") { - return toDosPath(standardPath, partialPath); - } - - return standardPath; -}; - -var convertToStandardPath = function (osPath, partialPath) { - if (process.platform === "win32") { - return toPosixPath(osPath, partialPath); - } - - return osPath; -} - -var convertToOSLineEndings = function (fileContents) { - return fileContents.replace(/\n/g, os.EOL); -}; - -var convertToStandardLineEndings = function (fileContents) { - // Convert all kinds of end-of-line chars to linuxy "\n". - return fileContents.replace(new RegExp("\r\n", "g"), "\n") - .replace(new RegExp("\r", "g"), "\n"); -}; - - -// wrappings for path functions that always run as they were on unix (using -// forward slashes) -var wrapPathFunction = function (name, partialPaths) { - var f = path[name]; - return function (/* args */) { - if (process.platform === 'win32') { - var args = _.toArray(arguments); - args = _.map(args, function (p, i) { - // if partialPaths is turned on (for path.join mostly) - // forget about conversion of absolute paths for Windows - return toDosPath(p, partialPaths); - }); - return toPosixPath(f.apply(path, args), partialPaths); - } else { - return f.apply(path, arguments); - } - }; -}; - -files.pathJoin = wrapPathFunction("join", true); -files.pathNormalize = wrapPathFunction("normalize"); -files.pathRelative = wrapPathFunction("relative"); -files.pathResolve = wrapPathFunction("resolve"); -files.pathDirname = wrapPathFunction("dirname"); -files.pathBasename = wrapPathFunction("basename"); -files.pathExtname = wrapPathFunction("extname"); -files.pathSep = '/'; -files.pathDelimiter = ':'; -files.pathOsDelimiter = path.delimiter; - -files.convertToStandardPath = convertToStandardPath; -files.convertToOSPath = convertToOSPath; -files.convertToWindowsPath = toDosPath; -files.convertToPosixPath = toPosixPath; - -files.convertToStandardLineEndings = convertToStandardLineEndings; -files.convertToOSLineEndings = convertToOSLineEndings; diff --git a/web-app/.meteor/local/build/programs/server/npm-shrinkwrap.json b/web-app/.meteor/local/build/programs/server/npm-shrinkwrap.json deleted file mode 100644 index 9136b92..0000000 --- a/web-app/.meteor/local/build/programs/server/npm-shrinkwrap.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "meteor-dev-bundle", - "version": "0.0.0", - "dependencies": { - "fibers": { - "version": "1.0.5", - "from": "fibers@1.0.5", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-1.0.5.tgz" - }, - "semver": { - "version": "4.1.0", - "from": "semver@4.1.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.1.0.tgz" - }, - "source-map-support": { - "version": "0.2.8", - "from": "source-map-support@0.2.8", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.8.tgz", - "dependencies": { - "source-map": { - "version": "0.1.32", - "from": "source-map@0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "dependencies": { - "amdefine": { - "version": "0.1.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.0.tgz" - } - } - } - } - }, - "underscore": { - "version": "1.5.2", - "from": "underscore@1.5.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.5.2.tgz" - } - } -} diff --git a/web-app/.meteor/local/build/programs/server/package.json b/web-app/.meteor/local/build/programs/server/package.json deleted file mode 100644 index ec572d0..0000000 --- a/web-app/.meteor/local/build/programs/server/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "meteor-dev-bundle", - "version": "0.0.0", - "dependencies": { - "fibers": "1.0.5", - "underscore": "1.5.2", - "source-map-support": "0.2.8", - "semver": "4.1.0" - }, - "devDependencies": { - "eachline": "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da", - "chalk": "0.5.1" - } -} diff --git a/web-app/.meteor/local/build/programs/server/packages/autopublish.js b/web-app/.meteor/local/build/programs/server/packages/autopublish.js deleted file mode 100644 index dce0285..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/autopublish.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.autopublish = {}; - -})(); - -//# sourceMappingURL=autopublish.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/autopublish.js.map b/web-app/.meteor/local/build/programs/server/packages/autopublish.js.map deleted file mode 100644 index abd020f..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/autopublish.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/autopublish.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/autoupdate.js b/web-app/.meteor/local/build/programs/server/packages/autoupdate.js deleted file mode 100644 index 565e37e..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/autoupdate.js +++ /dev/null @@ -1,237 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var WebApp = Package.webapp.WebApp; -var main = Package.webapp.main; -var WebAppInternals = Package.webapp.WebAppInternals; -var DDP = Package.ddp.DDP; -var DDPServer = Package.ddp.DDPServer; -var MongoInternals = Package.mongo.MongoInternals; -var Mongo = Package.mongo.Mongo; -var _ = Package.underscore._; - -/* Package-scope variables */ -var Autoupdate, ClientVersions; - -(function () { - -////////////////////////////////////////////////////////////////////////////////// -// // -// packages/autoupdate/autoupdate_server.js // -// // -////////////////////////////////////////////////////////////////////////////////// - // -// Publish the current client versions to the client. When a client // 1 -// sees the subscription change and that there is a new version of the // 2 -// client available on the server, it can reload. // 3 -// // 4 -// By default there are two current client versions. The refreshable client // 5 -// version is identified by a hash of the client resources seen by the browser // 6 -// that are refreshable, such as CSS, while the non refreshable client version // 7 -// is identified by a hash of the rest of the client assets // 8 -// (the HTML, code, and static files in the `public` directory). // 9 -// // 10 -// If the environment variable `AUTOUPDATE_VERSION` is set it will be // 11 -// used as the client id instead. You can use this to control when // 12 -// the client reloads. For example, if you want to only force a // 13 -// reload on major changes, you can use a custom AUTOUPDATE_VERSION // 14 -// which you only change when something worth pushing to clients // 15 -// immediately happens. // 16 -// // 17 -// The server publishes a `meteor_autoupdate_clientVersions` // 18 -// collection. There are two documents in this collection, a document // 19 -// with _id 'version' which represnets the non refreshable client assets, // 20 -// and a document with _id 'version-refreshable' which represents the // 21 -// refreshable client assets. Each document has a 'version' field // 22 -// which is equivalent to the hash of the relevant assets. The refreshable // 23 -// document also contains a list of the refreshable assets, so that the client // 24 -// can swap in the new assets without forcing a page refresh. Clients can // 25 -// observe changes on these documents to detect when there is a new // 26 -// version available. // 27 -// // 28 -// In this implementation only two documents are present in the collection // 29 -// the current refreshable client version and the current nonRefreshable client // 30 -// version. Developers can easily experiment with different versioning and // 31 -// updating models by forking this package. // 32 - // 33 -var Future = Npm.require("fibers/future"); // 34 - // 35 -Autoupdate = {}; // 36 - // 37 -// The collection of acceptable client versions. // 38 -ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions", // 39 - { connection: null }); // 40 - // 41 -// The client hash includes __meteor_runtime_config__, so wait until // 42 -// all packages have loaded and have had a chance to populate the // 43 -// runtime config before using the client hash as our default auto // 44 -// update version id. // 45 - // 46 -// Note: Tests allow people to override Autoupdate.autoupdateVersion before // 47 -// startup. // 48 -Autoupdate.autoupdateVersion = null; // 49 -Autoupdate.autoupdateVersionRefreshable = null; // 50 -Autoupdate.autoupdateVersionCordova = null; // 51 -Autoupdate.appId = __meteor_runtime_config__.appId = process.env.APP_ID; // 52 - // 53 -var syncQueue = new Meteor._SynchronousQueue(); // 54 - // 55 -// updateVersions can only be called after the server has fully loaded. // 56 -var updateVersions = function (shouldReloadClientProgram) { // 57 - // Step 1: load the current client program on the server and update the // 58 - // hash values in __meteor_runtime_config__. // 59 - if (shouldReloadClientProgram) { // 60 - WebAppInternals.reloadClientPrograms(); // 61 - } // 62 - // 63 - // If we just re-read the client program, or if we don't have an autoupdate // 64 - // version, calculate it. // 65 - if (shouldReloadClientProgram || Autoupdate.autoupdateVersion === null) { // 66 - Autoupdate.autoupdateVersion = // 67 - process.env.AUTOUPDATE_VERSION || // 68 - WebApp.calculateClientHashNonRefreshable(); // 69 - } // 70 - // If we just recalculated it OR if it was set by (eg) test-in-browser, // 71 - // ensure it ends up in __meteor_runtime_config__. // 72 - __meteor_runtime_config__.autoupdateVersion = // 73 - Autoupdate.autoupdateVersion; // 74 - // 75 - Autoupdate.autoupdateVersionRefreshable = // 76 - __meteor_runtime_config__.autoupdateVersionRefreshable = // 77 - process.env.AUTOUPDATE_VERSION || // 78 - WebApp.calculateClientHashRefreshable(); // 79 - // 80 - Autoupdate.autoupdateVersionCordova = // 81 - __meteor_runtime_config__.autoupdateVersionCordova = // 82 - process.env.AUTOUPDATE_VERSION || // 83 - WebApp.calculateClientHashCordova(); // 84 - // 85 - // Step 2: form the new client boilerplate which contains the updated // 86 - // assets and __meteor_runtime_config__. // 87 - if (shouldReloadClientProgram) { // 88 - WebAppInternals.generateBoilerplate(); // 89 - } // 90 - // 91 - // XXX COMPAT WITH 0.8.3 // 92 - if (! ClientVersions.findOne({current: true})) { // 93 - // To ensure apps with version of Meteor prior to 0.9.0 (in // 94 - // which the structure of documents in `ClientVersions` was // 95 - // different) also reload. // 96 - ClientVersions.insert({current: true}); // 97 - } // 98 - // 99 - if (! ClientVersions.findOne({_id: "version"})) { // 100 - ClientVersions.insert({ // 101 - _id: "version", // 102 - version: Autoupdate.autoupdateVersion // 103 - }); // 104 - } else { // 105 - ClientVersions.update("version", { $set: { // 106 - version: Autoupdate.autoupdateVersion // 107 - }}); // 108 - } // 109 - // 110 - if (! ClientVersions.findOne({_id: "version-cordova"})) { // 111 - ClientVersions.insert({ // 112 - _id: "version-cordova", // 113 - version: Autoupdate.autoupdateVersionCordova, // 114 - refreshable: false // 115 - }); // 116 - } else { // 117 - ClientVersions.update("version-cordova", { $set: { // 118 - version: Autoupdate.autoupdateVersionCordova // 119 - }}); // 120 - } // 121 - // 122 - // Use `onListening` here because we need to use // 123 - // `WebAppInternals.refreshableAssets`, which is only set after // 124 - // `WebApp.generateBoilerplate` is called by `main` in webapp. // 125 - WebApp.onListening(function () { // 126 - if (! ClientVersions.findOne({_id: "version-refreshable"})) { // 127 - ClientVersions.insert({ // 128 - _id: "version-refreshable", // 129 - version: Autoupdate.autoupdateVersionRefreshable, // 130 - assets: WebAppInternals.refreshableAssets // 131 - }); // 132 - } else { // 133 - ClientVersions.update("version-refreshable", { $set: { // 134 - version: Autoupdate.autoupdateVersionRefreshable, // 135 - assets: WebAppInternals.refreshableAssets // 136 - }}); // 137 - } // 138 - }); // 139 -}; // 140 - // 141 -Meteor.publish( // 142 - "meteor_autoupdate_clientVersions", // 143 - function (appId) { // 144 - // `null` happens when a client doesn't have an appId and passes // 145 - // `undefined` to `Meteor.subscribe`. `undefined` is translated to // 146 - // `null` as JSON doesn't have `undefined. // 147 - check(appId, Match.OneOf(String, undefined, null)); // 148 - // 149 - // Don't notify clients using wrong appId such as mobile apps built with a // 150 - // different server but pointing at the same local url // 151 - if (Autoupdate.appId && appId && Autoupdate.appId !== appId) // 152 - return []; // 153 - // 154 - return ClientVersions.find(); // 155 - }, // 156 - {is_auto: true} // 157 -); // 158 - // 159 -Meteor.startup(function () { // 160 - updateVersions(false); // 161 -}); // 162 - // 163 -var fut = new Future(); // 164 - // 165 -// We only want 'refresh' to trigger 'updateVersions' AFTER onListen, // 166 -// so we add a queued task that waits for onListen before 'refresh' can queue // 167 -// tasks. Note that the `onListening` callbacks do not fire until after // 168 -// Meteor.startup, so there is no concern that the 'updateVersions' calls from // 169 -// 'refresh' will overlap with the `updateVersions` call from Meteor.startup. // 170 - // 171 -syncQueue.queueTask(function () { // 172 - fut.wait(); // 173 -}); // 174 - // 175 -WebApp.onListening(function () { // 176 - fut.return(); // 177 -}); // 178 - // 179 -var enqueueVersionsRefresh = function () { // 180 - syncQueue.queueTask(function () { // 181 - updateVersions(true); // 182 - }); // 183 -}; // 184 - // 185 -// Listen for the special {refresh: 'client'} message, which signals that a // 186 -// client asset has changed. // 187 -process.on('message', Meteor.bindEnvironment(function (m) { // 188 - if (m && m.refresh === 'client') { // 189 - enqueueVersionsRefresh(); // 190 - } // 191 -})); // 192 - // 193 -// Another way to tell the process to refresh: send SIGHUP signal // 194 -process.on('SIGHUP', Meteor.bindEnvironment(function () { // 195 - enqueueVersionsRefresh(); // 196 -})); // 197 - // 198 - // 199 -////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.autoupdate = { - Autoupdate: Autoupdate -}; - -})(); - -//# sourceMappingURL=autoupdate.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/autoupdate.js.map b/web-app/.meteor/local/build/programs/server/packages/autoupdate.js.map deleted file mode 100644 index 3f372c8..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/autoupdate.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["autoupdate/autoupdate_server.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,oE;AACA,sE;AACA,iD;AACA,E;AACA,2E;AACA,8E;AACA,8E;AACA,2D;AACA,gE;AACA,E;AACA,qE;AACA,mE;AACA,gE;AACA,mE;AACA,gE;AACA,uB;AACA,E;AACA,4D;AACA,qE;AACA,yE;AACA,qE;AACA,iE;AACA,0E;AACA,8E;AACA,yE;AACA,mE;AACA,qB;AACA,E;AACA,0E;AACA,+E;AACA,2E;AACA,2C;;AAEA,0C;;AAEA,gB;;AAEA,gD;AACA,yE;AACA,wB;;AAEA,oE;AACA,iE;AACA,kE;AACA,qB;;AAEA,2E;AACA,W;AACA,oC;AACA,+C;AACA,2C;AACA,wE;;AAEA,+C;;AAEA,uE;AACA,2D;AACA,yE;AACA,8C;AACA,kC;AACA,2C;AACA,G;;AAEA,6E;AACA,2B;AACA,2E;AACA,kC;AACA,uC;AACA,iD;AACA,G;AACA,yE;AACA,oD;AACA,+C;AACA,iC;;AAEA,2C;AACA,4D;AACA,uC;AACA,8C;;AAEA,uC;AACA,wD;AACA,uC;AACA,0C;;AAEA,uE;AACA,0C;AACA,kC;AACA,0C;AACA,G;;AAEA,0B;AACA,kD;AACA,+D;AACA,+D;AACA,8B;AACA,2C;AACA,G;;AAEA,mD;AACA,2B;AACA,qB;AACA,2C;AACA,O;AACA,U;AACA,8C;AACA,2C;AACA,Q;AACA,G;;AAEA,2D;AACA,2B;AACA,6B;AACA,mD;AACA,wB;AACA,O;AACA,U;AACA,sD;AACA,kD;AACA,Q;AACA,G;;AAEA,kD;AACA,iE;AACA,gE;AACA,kC;AACA,iE;AACA,6B;AACA,mC;AACA,yD;AACA,iD;AACA,S;AACA,Y;AACA,4D;AACA,yD;AACA,iD;AACA,U;AACA,K;AACA,K;AACA,E;;AAEA,e;AACA,qC;AACA,oB;AACA,oE;AACA,sE;AACA,8C;AACA,uD;;AAEA,8E;AACA,0D;AACA,gE;AACA,gB;;AAEA,iC;AACA,I;AACA,iB;AACA,E;;AAEA,4B;AACA,wB;AACA,G;;AAEA,uB;;AAEA,qE;AACA,6E;AACA,uE;AACA,8E;AACA,6E;;AAEA,iC;AACA,a;AACA,G;;AAEA,gC;AACA,e;AACA,G;;AAEA,0C;AACA,mC;AACA,yB;AACA,K;AACA,E;;AAEA,2E;AACA,4B;AACA,2D;AACA,oC;AACA,6B;AACA,G;AACA,I;;AAEA,iE;AACA,yD;AACA,2B;AACA,I","file":"/packages/autoupdate.js","sourcesContent":["// Publish the current client versions to the client. When a client\n// sees the subscription change and that there is a new version of the\n// client available on the server, it can reload.\n//\n// By default there are two current client versions. The refreshable client\n// version is identified by a hash of the client resources seen by the browser\n// that are refreshable, such as CSS, while the non refreshable client version\n// is identified by a hash of the rest of the client assets\n// (the HTML, code, and static files in the `public` directory).\n//\n// If the environment variable `AUTOUPDATE_VERSION` is set it will be\n// used as the client id instead. You can use this to control when\n// the client reloads. For example, if you want to only force a\n// reload on major changes, you can use a custom AUTOUPDATE_VERSION\n// which you only change when something worth pushing to clients\n// immediately happens.\n//\n// The server publishes a `meteor_autoupdate_clientVersions`\n// collection. There are two documents in this collection, a document\n// with _id 'version' which represnets the non refreshable client assets,\n// and a document with _id 'version-refreshable' which represents the\n// refreshable client assets. Each document has a 'version' field\n// which is equivalent to the hash of the relevant assets. The refreshable\n// document also contains a list of the refreshable assets, so that the client\n// can swap in the new assets without forcing a page refresh. Clients can\n// observe changes on these documents to detect when there is a new\n// version available.\n//\n// In this implementation only two documents are present in the collection\n// the current refreshable client version and the current nonRefreshable client\n// version. Developers can easily experiment with different versioning and\n// updating models by forking this package.\n\nvar Future = Npm.require(\"fibers/future\");\n\nAutoupdate = {};\n\n// The collection of acceptable client versions.\nClientVersions = new Mongo.Collection(\"meteor_autoupdate_clientVersions\",\n { connection: null });\n\n// The client hash includes __meteor_runtime_config__, so wait until\n// all packages have loaded and have had a chance to populate the\n// runtime config before using the client hash as our default auto\n// update version id.\n\n// Note: Tests allow people to override Autoupdate.autoupdateVersion before\n// startup.\nAutoupdate.autoupdateVersion = null;\nAutoupdate.autoupdateVersionRefreshable = null;\nAutoupdate.autoupdateVersionCordova = null;\nAutoupdate.appId = __meteor_runtime_config__.appId = process.env.APP_ID;\n\nvar syncQueue = new Meteor._SynchronousQueue();\n\n// updateVersions can only be called after the server has fully loaded.\nvar updateVersions = function (shouldReloadClientProgram) {\n // Step 1: load the current client program on the server and update the\n // hash values in __meteor_runtime_config__.\n if (shouldReloadClientProgram) {\n WebAppInternals.reloadClientPrograms();\n }\n\n // If we just re-read the client program, or if we don't have an autoupdate\n // version, calculate it.\n if (shouldReloadClientProgram || Autoupdate.autoupdateVersion === null) {\n Autoupdate.autoupdateVersion =\n process.env.AUTOUPDATE_VERSION ||\n WebApp.calculateClientHashNonRefreshable();\n }\n // If we just recalculated it OR if it was set by (eg) test-in-browser,\n // ensure it ends up in __meteor_runtime_config__.\n __meteor_runtime_config__.autoupdateVersion =\n Autoupdate.autoupdateVersion;\n\n Autoupdate.autoupdateVersionRefreshable =\n __meteor_runtime_config__.autoupdateVersionRefreshable =\n process.env.AUTOUPDATE_VERSION ||\n WebApp.calculateClientHashRefreshable();\n\n Autoupdate.autoupdateVersionCordova =\n __meteor_runtime_config__.autoupdateVersionCordova =\n process.env.AUTOUPDATE_VERSION ||\n WebApp.calculateClientHashCordova();\n\n // Step 2: form the new client boilerplate which contains the updated\n // assets and __meteor_runtime_config__.\n if (shouldReloadClientProgram) {\n WebAppInternals.generateBoilerplate();\n }\n\n // XXX COMPAT WITH 0.8.3\n if (! ClientVersions.findOne({current: true})) {\n // To ensure apps with version of Meteor prior to 0.9.0 (in\n // which the structure of documents in `ClientVersions` was\n // different) also reload.\n ClientVersions.insert({current: true});\n }\n\n if (! ClientVersions.findOne({_id: \"version\"})) {\n ClientVersions.insert({\n _id: \"version\",\n version: Autoupdate.autoupdateVersion\n });\n } else {\n ClientVersions.update(\"version\", { $set: {\n version: Autoupdate.autoupdateVersion\n }});\n }\n\n if (! ClientVersions.findOne({_id: \"version-cordova\"})) {\n ClientVersions.insert({\n _id: \"version-cordova\",\n version: Autoupdate.autoupdateVersionCordova,\n refreshable: false\n });\n } else {\n ClientVersions.update(\"version-cordova\", { $set: {\n version: Autoupdate.autoupdateVersionCordova\n }});\n }\n\n // Use `onListening` here because we need to use\n // `WebAppInternals.refreshableAssets`, which is only set after\n // `WebApp.generateBoilerplate` is called by `main` in webapp.\n WebApp.onListening(function () {\n if (! ClientVersions.findOne({_id: \"version-refreshable\"})) {\n ClientVersions.insert({\n _id: \"version-refreshable\",\n version: Autoupdate.autoupdateVersionRefreshable,\n assets: WebAppInternals.refreshableAssets\n });\n } else {\n ClientVersions.update(\"version-refreshable\", { $set: {\n version: Autoupdate.autoupdateVersionRefreshable,\n assets: WebAppInternals.refreshableAssets\n }});\n }\n });\n};\n\nMeteor.publish(\n \"meteor_autoupdate_clientVersions\",\n function (appId) {\n // `null` happens when a client doesn't have an appId and passes\n // `undefined` to `Meteor.subscribe`. `undefined` is translated to\n // `null` as JSON doesn't have `undefined.\n check(appId, Match.OneOf(String, undefined, null));\n\n // Don't notify clients using wrong appId such as mobile apps built with a\n // different server but pointing at the same local url\n if (Autoupdate.appId && appId && Autoupdate.appId !== appId)\n return [];\n\n return ClientVersions.find();\n },\n {is_auto: true}\n);\n\nMeteor.startup(function () {\n updateVersions(false);\n});\n\nvar fut = new Future();\n\n// We only want 'refresh' to trigger 'updateVersions' AFTER onListen,\n// so we add a queued task that waits for onListen before 'refresh' can queue\n// tasks. Note that the `onListening` callbacks do not fire until after\n// Meteor.startup, so there is no concern that the 'updateVersions' calls from\n// 'refresh' will overlap with the `updateVersions` call from Meteor.startup.\n\nsyncQueue.queueTask(function () {\n fut.wait();\n});\n\nWebApp.onListening(function () {\n fut.return();\n});\n\nvar enqueueVersionsRefresh = function () {\n syncQueue.queueTask(function () {\n updateVersions(true);\n });\n};\n\n// Listen for the special {refresh: 'client'} message, which signals that a\n// client asset has changed.\nprocess.on('message', Meteor.bindEnvironment(function (m) {\n if (m && m.refresh === 'client') {\n enqueueVersionsRefresh();\n }\n}));\n\n// Another way to tell the process to refresh: send SIGHUP signal\nprocess.on('SIGHUP', Meteor.bindEnvironment(function () {\n enqueueVersionsRefresh();\n}));\n\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/base64.js b/web-app/.meteor/local/build/programs/server/packages/base64.js deleted file mode 100644 index 8fd732c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/base64.js +++ /dev/null @@ -1,175 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - -/* Package-scope variables */ -var Base64; - -(function () { - -////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/base64/base64.js // -// // -////////////////////////////////////////////////////////////////////////////////////////// - // -// Base 64 encoding // 1 - // 2 -var BASE_64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // 3 - // 4 -var BASE_64_VALS = {}; // 5 - // 6 -for (var i = 0; i < BASE_64_CHARS.length; i++) { // 7 - BASE_64_VALS[BASE_64_CHARS.charAt(i)] = i; // 8 -}; // 9 - // 10 -Base64 = {}; // 11 - // 12 -Base64.encode = function (array) { // 13 - // 14 - if (typeof array === "string") { // 15 - var str = array; // 16 - array = Base64.newBinary(str.length); // 17 - for (var i = 0; i < str.length; i++) { // 18 - var ch = str.charCodeAt(i); // 19 - if (ch > 0xFF) { // 20 - throw new Error( // 21 - "Not ascii. Base64.encode can only take ascii strings."); // 22 - } // 23 - array[i] = ch; // 24 - } // 25 - } // 26 - // 27 - var answer = []; // 28 - var a = null; // 29 - var b = null; // 30 - var c = null; // 31 - var d = null; // 32 - for (var i = 0; i < array.length; i++) { // 33 - switch (i % 3) { // 34 - case 0: // 35 - a = (array[i] >> 2) & 0x3F; // 36 - b = (array[i] & 0x03) << 4; // 37 - break; // 38 - case 1: // 39 - b = b | (array[i] >> 4) & 0xF; // 40 - c = (array[i] & 0xF) << 2; // 41 - break; // 42 - case 2: // 43 - c = c | (array[i] >> 6) & 0x03; // 44 - d = array[i] & 0x3F; // 45 - answer.push(getChar(a)); // 46 - answer.push(getChar(b)); // 47 - answer.push(getChar(c)); // 48 - answer.push(getChar(d)); // 49 - a = null; // 50 - b = null; // 51 - c = null; // 52 - d = null; // 53 - break; // 54 - } // 55 - } // 56 - if (a != null) { // 57 - answer.push(getChar(a)); // 58 - answer.push(getChar(b)); // 59 - if (c == null) // 60 - answer.push('='); // 61 - else // 62 - answer.push(getChar(c)); // 63 - if (d == null) // 64 - answer.push('='); // 65 - } // 66 - return answer.join(""); // 67 -}; // 68 - // 69 -var getChar = function (val) { // 70 - return BASE_64_CHARS.charAt(val); // 71 -}; // 72 - // 73 -var getVal = function (ch) { // 74 - if (ch === '=') { // 75 - return -1; // 76 - } // 77 - return BASE_64_VALS[ch]; // 78 -}; // 79 - // 80 -// XXX This is a weird place for this to live, but it's used both by // 81 -// this package and 'ejson', and we can't put it in 'ejson' without // 82 -// introducing a circular dependency. It should probably be in its own // 83 -// package or as a helper in a package that both 'base64' and 'ejson' // 84 -// use. // 85 -Base64.newBinary = function (len) { // 86 - if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined') { // 87 - var ret = []; // 88 - for (var i = 0; i < len; i++) { // 89 - ret.push(0); // 90 - } // 91 - ret.$Uint8ArrayPolyfill = true; // 92 - return ret; // 93 - } // 94 - return new Uint8Array(new ArrayBuffer(len)); // 95 -}; // 96 - // 97 -Base64.decode = function (str) { // 98 - var len = Math.floor((str.length*3)/4); // 99 - if (str.charAt(str.length - 1) == '=') { // 100 - len--; // 101 - if (str.charAt(str.length - 2) == '=') // 102 - len--; // 103 - } // 104 - var arr = Base64.newBinary(len); // 105 - // 106 - var one = null; // 107 - var two = null; // 108 - var three = null; // 109 - // 110 - var j = 0; // 111 - // 112 - for (var i = 0; i < str.length; i++) { // 113 - var c = str.charAt(i); // 114 - var v = getVal(c); // 115 - switch (i % 4) { // 116 - case 0: // 117 - if (v < 0) // 118 - throw new Error('invalid base64 string'); // 119 - one = v << 2; // 120 - break; // 121 - case 1: // 122 - if (v < 0) // 123 - throw new Error('invalid base64 string'); // 124 - one = one | (v >> 4); // 125 - arr[j++] = one; // 126 - two = (v & 0x0F) << 4; // 127 - break; // 128 - case 2: // 129 - if (v >= 0) { // 130 - two = two | (v >> 2); // 131 - arr[j++] = two; // 132 - three = (v & 0x03) << 6; // 133 - } // 134 - break; // 135 - case 3: // 136 - if (v >= 0) { // 137 - arr[j++] = three | v; // 138 - } // 139 - break; // 140 - } // 141 - } // 142 - return arr; // 143 -}; // 144 - // 145 -////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.base64 = { - Base64: Base64 -}; - -})(); - -//# sourceMappingURL=base64.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/base64.js.map b/web-app/.meteor/local/build/programs/server/packages/base64.js.map deleted file mode 100644 index 3dd2dd2..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/base64.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["base64/base64.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mB;;AAEA,uF;;AAEA,sB;;AAEA,gD;AACA,4C;AACA,E;;AAEA,Y;;AAEA,kC;;AAEA,kC;AACA,oB;AACA,yC;AACA,0C;AACA,iC;AACA,sB;AACA,wB;AACA,mE;AACA,O;AACA,oB;AACA,K;AACA,G;;AAEA,kB;AACA,e;AACA,e;AACA,e;AACA,e;AACA,0C;AACA,oB;AACA,W;AACA,iC;AACA,iC;AACA,Y;AACA,W;AACA,oC;AACA,gC;AACA,Y;AACA,W;AACA,qC;AACA,0B;AACA,8B;AACA,8B;AACA,8B;AACA,8B;AACA,e;AACA,e;AACA,e;AACA,e;AACA,Y;AACA,K;AACA,G;AACA,kB;AACA,4B;AACA,4B;AACA,kB;AACA,uB;AACA,Q;AACA,8B;AACA,kB;AACA,uB;AACA,G;AACA,yB;AACA,E;;AAEA,8B;AACA,mC;AACA,E;;AAEA,4B;AACA,mB;AACA,c;AACA,G;AACA,0B;AACA,E;;AAEA,oE;AACA,mE;AACA,sE;AACA,qE;AACA,O;AACA,mC;AACA,gF;AACA,iB;AACA,mC;AACA,kB;AACA,K;AACA,mC;AACA,e;AACA,G;AACA,8C;AACA,E;;AAEA,gC;AACA,yC;AACA,0C;AACA,U;AACA,0C;AACA,Y;AACA,G;AACA,kC;;AAEA,iB;AACA,iB;AACA,mB;;AAEA,Y;;AAEA,wC;AACA,0B;AACA,sB;AACA,oB;AACA,W;AACA,gB;AACA,iD;AACA,mB;AACA,Y;AACA,W;AACA,gB;AACA,iD;AACA,2B;AACA,qB;AACA,4B;AACA,Y;AACA,W;AACA,mB;AACA,6B;AACA,uB;AACA,gC;AACA,O;AACA,Y;AACA,W;AACA,mB;AACA,6B;AACA,O;AACA,Y;AACA,K;AACA,G;AACA,a;AACA,E","file":"/packages/base64.js","sourcesContent":["// Base 64 encoding\n\nvar BASE_64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nvar BASE_64_VALS = {};\n\nfor (var i = 0; i < BASE_64_CHARS.length; i++) {\n BASE_64_VALS[BASE_64_CHARS.charAt(i)] = i;\n};\n\nBase64 = {};\n\nBase64.encode = function (array) {\n\n if (typeof array === \"string\") {\n var str = array;\n array = Base64.newBinary(str.length);\n for (var i = 0; i < str.length; i++) {\n var ch = str.charCodeAt(i);\n if (ch > 0xFF) {\n throw new Error(\n \"Not ascii. Base64.encode can only take ascii strings.\");\n }\n array[i] = ch;\n }\n }\n\n var answer = [];\n var a = null;\n var b = null;\n var c = null;\n var d = null;\n for (var i = 0; i < array.length; i++) {\n switch (i % 3) {\n case 0:\n a = (array[i] >> 2) & 0x3F;\n b = (array[i] & 0x03) << 4;\n break;\n case 1:\n b = b | (array[i] >> 4) & 0xF;\n c = (array[i] & 0xF) << 2;\n break;\n case 2:\n c = c | (array[i] >> 6) & 0x03;\n d = array[i] & 0x3F;\n answer.push(getChar(a));\n answer.push(getChar(b));\n answer.push(getChar(c));\n answer.push(getChar(d));\n a = null;\n b = null;\n c = null;\n d = null;\n break;\n }\n }\n if (a != null) {\n answer.push(getChar(a));\n answer.push(getChar(b));\n if (c == null)\n answer.push('=');\n else\n answer.push(getChar(c));\n if (d == null)\n answer.push('=');\n }\n return answer.join(\"\");\n};\n\nvar getChar = function (val) {\n return BASE_64_CHARS.charAt(val);\n};\n\nvar getVal = function (ch) {\n if (ch === '=') {\n return -1;\n }\n return BASE_64_VALS[ch];\n};\n\n// XXX This is a weird place for this to live, but it's used both by\n// this package and 'ejson', and we can't put it in 'ejson' without\n// introducing a circular dependency. It should probably be in its own\n// package or as a helper in a package that both 'base64' and 'ejson'\n// use.\nBase64.newBinary = function (len) {\n if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined') {\n var ret = [];\n for (var i = 0; i < len; i++) {\n ret.push(0);\n }\n ret.$Uint8ArrayPolyfill = true;\n return ret;\n }\n return new Uint8Array(new ArrayBuffer(len));\n};\n\nBase64.decode = function (str) {\n var len = Math.floor((str.length*3)/4);\n if (str.charAt(str.length - 1) == '=') {\n len--;\n if (str.charAt(str.length - 2) == '=')\n len--;\n }\n var arr = Base64.newBinary(len);\n\n var one = null;\n var two = null;\n var three = null;\n\n var j = 0;\n\n for (var i = 0; i < str.length; i++) {\n var c = str.charAt(i);\n var v = getVal(c);\n switch (i % 4) {\n case 0:\n if (v < 0)\n throw new Error('invalid base64 string');\n one = v << 2;\n break;\n case 1:\n if (v < 0)\n throw new Error('invalid base64 string');\n one = one | (v >> 4);\n arr[j++] = one;\n two = (v & 0x0F) << 4;\n break;\n case 2:\n if (v >= 0) {\n two = two | (v >> 2);\n arr[j++] = two;\n three = (v & 0x03) << 6;\n }\n break;\n case 3:\n if (v >= 0) {\n arr[j++] = three | v;\n }\n break;\n }\n }\n return arr;\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/binary-heap.js b/web-app/.meteor/local/build/programs/server/packages/binary-heap.js deleted file mode 100644 index 0df1bdb..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/binary-heap.js +++ /dev/null @@ -1,369 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var IdMap = Package['id-map'].IdMap; - -/* Package-scope variables */ -var MaxHeap, MinHeap, MinMaxHeap; - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/binary-heap/max-heap.js // -// // -//////////////////////////////////////////////////////////////////////////////////////// - // -// Constructor of Heap // 1 -// - comparator - Function - given two items returns a number // 2 -// - options: // 3 -// - initData - Array - Optional - the initial data in a format: // 4 -// Object: // 5 -// - id - String - unique id of the item // 6 -// - value - Any - the data value // 7 -// each value is retained // 8 -// - IdMap - Constructor - Optional - custom IdMap class to store id->index // 9 -// mappings internally. Standard IdMap is used by default. // 10 -MaxHeap = function (comparator, options) { // 11 - if (! _.isFunction(comparator)) // 12 - throw new Error('Passed comparator is invalid, should be a comparison function'); // 13 - var self = this; // 14 - // 15 - // a C-style comparator that is given two values and returns a number, // 16 - // negative if the first value is less than the second, positive if the second // 17 - // value is greater than the first and zero if they are equal. // 18 - self._comparator = comparator; // 19 - // 20 - options = _.defaults(options || {}, { IdMap: IdMap }); // 21 - // 22 - // _heapIdx maps an id to an index in the Heap array the corresponding value // 23 - // is located on. // 24 - self._heapIdx = new options.IdMap; // 25 - // 26 - // The Heap data-structure implemented as a 0-based contiguous array where // 27 - // every item on index idx is a node in a complete binary tree. Every node can // 28 - // have children on indexes idx*2+1 and idx*2+2, except for the leaves. Every // 29 - // node has a parent on index (idx-1)/2; // 30 - self._heap = []; // 31 - // 32 - // If the initial array is passed, we can build the heap in linear time // 33 - // complexity (O(N)) compared to linearithmic time complexity (O(nlogn)) if // 34 - // we push elements one by one. // 35 - if (_.isArray(options.initData)) // 36 - self._initFromData(options.initData); // 37 -}; // 38 - // 39 -_.extend(MaxHeap.prototype, { // 40 - // Builds a new heap in-place in linear time based on passed data // 41 - _initFromData: function (data) { // 42 - var self = this; // 43 - // 44 - self._heap = _.map(data, function (o) { // 45 - return { id: o.id, value: o.value }; // 46 - }); // 47 - // 48 - _.each(data, function (o, i) { // 49 - self._heapIdx.set(o.id, i); // 50 - }); // 51 - // 52 - if (! data.length) // 53 - return; // 54 - // 55 - // start from the first non-leaf - the parent of the last leaf // 56 - for (var i = parentIdx(data.length - 1); i >= 0; i--) // 57 - self._downHeap(i); // 58 - }, // 59 - // 60 - _downHeap: function (idx) { // 61 - var self = this; // 62 - // 63 - while (leftChildIdx(idx) < self.size()) { // 64 - var left = leftChildIdx(idx); // 65 - var right = rightChildIdx(idx); // 66 - var largest = idx; // 67 - // 68 - if (left < self.size()) { // 69 - largest = self._maxIndex(largest, left); // 70 - } // 71 - if (right < self.size()) { // 72 - largest = self._maxIndex(largest, right); // 73 - } // 74 - // 75 - if (largest === idx) // 76 - break; // 77 - // 78 - self._swap(largest, idx); // 79 - idx = largest; // 80 - } // 81 - }, // 82 - // 83 - _upHeap: function (idx) { // 84 - var self = this; // 85 - // 86 - while (idx > 0) { // 87 - var parent = parentIdx(idx); // 88 - if (self._maxIndex(parent, idx) === idx) { // 89 - self._swap(parent, idx) // 90 - idx = parent; // 91 - } else { // 92 - break; // 93 - } // 94 - } // 95 - }, // 96 - // 97 - _maxIndex: function (idxA, idxB) { // 98 - var self = this; // 99 - var valueA = self._get(idxA); // 100 - var valueB = self._get(idxB); // 101 - return self._comparator(valueA, valueB) >= 0 ? idxA : idxB; // 102 - }, // 103 - // 104 - // Internal: gets raw data object placed on idxth place in heap // 105 - _get: function (idx) { // 106 - var self = this; // 107 - return self._heap[idx].value; // 108 - }, // 109 - // 110 - _swap: function (idxA, idxB) { // 111 - var self = this; // 112 - var recA = self._heap[idxA]; // 113 - var recB = self._heap[idxB]; // 114 - // 115 - self._heapIdx.set(recA.id, idxB); // 116 - self._heapIdx.set(recB.id, idxA); // 117 - // 118 - self._heap[idxA] = recB; // 119 - self._heap[idxB] = recA; // 120 - }, // 121 - // 122 - get: function (id) { // 123 - var self = this; // 124 - if (! self.has(id)) // 125 - return null; // 126 - return self._get(self._heapIdx.get(id)); // 127 - }, // 128 - set: function (id, value) { // 129 - var self = this; // 130 - // 131 - if (self.has(id)) { // 132 - if (self.get(id) === value) // 133 - return; // 134 - // 135 - var idx = self._heapIdx.get(id); // 136 - self._heap[idx].value = value; // 137 - // 138 - // Fix the new value's position // 139 - // Either bubble new value up if it is greater than its parent // 140 - self._upHeap(idx); // 141 - // or bubble it down if it is smaller than one of its children // 142 - self._downHeap(idx); // 143 - } else { // 144 - self._heapIdx.set(id, self._heap.length); // 145 - self._heap.push({ id: id, value: value }); // 146 - self._upHeap(self._heap.length - 1); // 147 - } // 148 - }, // 149 - remove: function (id) { // 150 - var self = this; // 151 - // 152 - if (self.has(id)) { // 153 - var last = self._heap.length - 1; // 154 - var idx = self._heapIdx.get(id); // 155 - // 156 - if (idx !== last) { // 157 - self._swap(idx, last); // 158 - self._heap.pop(); // 159 - self._heapIdx.remove(id); // 160 - // 161 - // Fix the swapped value's position // 162 - self._upHeap(idx); // 163 - self._downHeap(idx); // 164 - } else { // 165 - self._heap.pop(); // 166 - self._heapIdx.remove(id); // 167 - } // 168 - } // 169 - }, // 170 - has: function (id) { // 171 - var self = this; // 172 - return self._heapIdx.has(id); // 173 - }, // 174 - empty: function () { // 175 - var self = this; // 176 - return !self.size(); // 177 - }, // 178 - clear: function () { // 179 - var self = this; // 180 - self._heap = []; // 181 - self._heapIdx.clear(); // 182 - }, // 183 - // iterate over values in no particular order // 184 - forEach: function (iterator) { // 185 - var self = this; // 186 - _.each(self._heap, function (obj) { // 187 - return iterator(obj.value, obj.id); // 188 - }); // 189 - }, // 190 - size: function () { // 191 - var self = this; // 192 - return self._heap.length; // 193 - }, // 194 - setDefault: function (id, def) { // 195 - var self = this; // 196 - if (self.has(id)) // 197 - return self.get(id); // 198 - self.set(id, def); // 199 - return def; // 200 - }, // 201 - clone: function () { // 202 - var self = this; // 203 - var clone = new MaxHeap(self._comparator, self._heap); // 204 - return clone; // 205 - }, // 206 - // 207 - maxElementId: function () { // 208 - var self = this; // 209 - return self.size() ? self._heap[0].id : null; // 210 - }, // 211 - // 212 - _selfCheck: function () { // 213 - var self = this; // 214 - for (var i = 1; i < self._heap.length; i++) // 215 - if (self._maxIndex(parentIdx(i), i) !== parentIdx(i)) // 216 - throw new Error("An item with id " + self._heap[i].id + // 217 - " has a parent younger than it: " + // 218 - self._heap[parentIdx(i)].id); // 219 - } // 220 -}); // 221 - // 222 -function leftChildIdx (i) { return i * 2 + 1; } // 223 -function rightChildIdx (i) { return i * 2 + 2; } // 224 -function parentIdx (i) { return (i - 1) >> 1; } // 225 - // 226 - // 227 -//////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/binary-heap/min-heap.js // -// // -//////////////////////////////////////////////////////////////////////////////////////// - // -MinHeap = function (comparator, options) { // 1 - var self = this; // 2 - MaxHeap.call(self, function (a, b) { // 3 - return -comparator(a, b); // 4 - }, options); // 5 -}; // 6 - // 7 -Meteor._inherits(MinHeap, MaxHeap); // 8 - // 9 -_.extend(MinHeap.prototype, { // 10 - maxElementId: function () { // 11 - throw new Error("Cannot call maxElementId on MinHeap"); // 12 - }, // 13 - minElementId: function () { // 14 - var self = this; // 15 - return MaxHeap.prototype.maxElementId.call(self); // 16 - } // 17 -}); // 18 - // 19 - // 20 -//////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/binary-heap/min-max-heap.js // -// // -//////////////////////////////////////////////////////////////////////////////////////// - // -// This implementation of Min/Max-Heap is just a subclass of Max-Heap // 1 -// with a Min-Heap as an encapsulated property. // 2 -// // 3 -// Most of the operations are just proxy methods to call the same method on both // 4 -// heaps. // 5 -// // 6 -// This implementation takes 2*N memory but is fairly simple to write and // 7 -// understand. And the constant factor of a simple Heap is usually smaller // 8 -// compared to other two-way priority queues like Min/Max Heaps // 9 -// (http://www.cs.otago.ac.nz/staffpriv/mike/Papers/MinMaxHeaps/MinMaxHeaps.pdf) // 10 -// and Interval Heaps // 11 -// (http://www.cise.ufl.edu/~sahni/dsaac/enrich/c13/double.htm) // 12 -MinMaxHeap = function (comparator, options) { // 13 - var self = this; // 14 - // 15 - MaxHeap.call(self, comparator, options); // 16 - self._minHeap = new MinHeap(comparator, options); // 17 -}; // 18 - // 19 -Meteor._inherits(MinMaxHeap, MaxHeap); // 20 - // 21 -_.extend(MinMaxHeap.prototype, { // 22 - set: function (id, value) { // 23 - var self = this; // 24 - MaxHeap.prototype.set.apply(self, arguments); // 25 - self._minHeap.set(id, value); // 26 - }, // 27 - remove: function (id) { // 28 - var self = this; // 29 - MaxHeap.prototype.remove.apply(self, arguments); // 30 - self._minHeap.remove(id); // 31 - }, // 32 - clear: function () { // 33 - var self = this; // 34 - MaxHeap.prototype.clear.apply(self, arguments); // 35 - self._minHeap.clear(); // 36 - }, // 37 - setDefault: function (id, def) { // 38 - var self = this; // 39 - MaxHeap.prototype.setDefault.apply(self, arguments); // 40 - return self._minHeap.setDefault(id, def); // 41 - }, // 42 - clone: function () { // 43 - var self = this; // 44 - var clone = new MinMaxHeap(self._comparator, self._heap); // 45 - return clone; // 46 - }, // 47 - minElementId: function () { // 48 - var self = this; // 49 - return self._minHeap.minElementId(); // 50 - } // 51 -}); // 52 - // 53 - // 54 -//////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['binary-heap'] = { - MaxHeap: MaxHeap, - MinHeap: MinHeap, - MinMaxHeap: MinMaxHeap -}; - -})(); - -//# sourceMappingURL=binary-heap.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/binary-heap.js.map b/web-app/.meteor/local/build/programs/server/packages/binary-heap.js.map deleted file mode 100644 index d5b4a83..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/binary-heap.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["binary-heap/max-heap.js","binary-heap/min-heap.js","binary-heap/min-max-heap.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,sB;AACA,6D;AACA,a;AACA,kE;AACA,iB;AACA,iD;AACA,0C;AACA,8B;AACA,6E;AACA,gE;AACA,0C;AACA,iC;AACA,qF;AACA,kB;;AAEA,wE;AACA,gF;AACA,gE;AACA,gC;;AAEA,wD;;AAEA,8E;AACA,mB;AACA,oC;;AAEA,4E;AACA,gF;AACA,+E;AACA,0C;AACA,kB;;AAEA,yE;AACA,6E;AACA,iC;AACA,kC;AACA,yC;AACA,E;;AAEA,6B;AACA,mE;AACA,kC;AACA,oB;;AAEA,2C;AACA,0C;AACA,O;;AAEA,kC;AACA,iC;AACA,O;;AAEA,sB;AACA,a;;AAEA,kE;AACA,yD;AACA,wB;AACA,I;;AAEA,6B;AACA,oB;;AAEA,6C;AACA,mC;AACA,qC;AACA,wB;;AAEA,+B;AACA,gD;AACA,O;AACA,gC;AACA,iD;AACA,O;;AAEA,0B;AACA,c;;AAEA,+B;AACA,oB;AACA,K;AACA,I;;AAEA,2B;AACA,oB;;AAEA,qB;AACA,kC;AACA,gD;AACA,+B;AACA,qB;AACA,c;AACA,c;AACA,O;AACA,K;AACA,I;;AAEA,oC;AACA,oB;AACA,iC;AACA,iC;AACA,+D;AACA,I;;AAEA,iE;AACA,wB;AACA,oB;AACA,iC;AACA,I;;AAEA,gC;AACA,oB;AACA,gC;AACA,gC;;AAEA,qC;AACA,qC;;AAEA,4B;AACA,4B;AACA,I;;AAEA,sB;AACA,oB;AACA,uB;AACA,kB;AACA,4C;AACA,I;AACA,6B;AACA,oB;;AAEA,uB;AACA,iC;AACA,e;;AAEA,sC;AACA,oC;;AAEA,qC;AACA,oE;AACA,wB;AACA,oE;AACA,0B;AACA,Y;AACA,+C;AACA,gD;AACA,0C;AACA,K;AACA,I;AACA,yB;AACA,oB;;AAEA,uB;AACA,uC;AACA,sC;;AAEA,yB;AACA,8B;AACA,yB;AACA,iC;;AAEA,2C;AACA,0B;AACA,4B;AACA,c;AACA,yB;AACA,iC;AACA,O;AACA,K;AACA,I;AACA,sB;AACA,oB;AACA,iC;AACA,I;AACA,sB;AACA,oB;AACA,wB;AACA,I;AACA,sB;AACA,oB;AACA,oB;AACA,0B;AACA,I;AACA,+C;AACA,gC;AACA,oB;AACA,uC;AACA,yC;AACA,O;AACA,I;AACA,qB;AACA,oB;AACA,6B;AACA,I;AACA,kC;AACA,oB;AACA,qB;AACA,0B;AACA,sB;AACA,e;AACA,I;AACA,sB;AACA,oB;AACA,0D;AACA,iB;AACA,I;;AAEA,6B;AACA,oB;AACA,iD;AACA,I;;AAEA,2B;AACA,oB;AACA,+C;AACA,2D;AACA,iE;AACA,6D;AACA,uD;AACA,G;AACA,G;;AAEA,+C;AACA,gD;AACA,+C;;;;;;;;;;;;;;;;;;;;AChOA,0C;AACA,kB;AACA,sC;AACA,6B;AACA,c;AACA,E;;AAEA,mC;;AAEA,6B;AACA,6B;AACA,2D;AACA,I;AACA,6B;AACA,oB;AACA,qD;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;;ACjBA,qE;AACA,+C;AACA,E;AACA,gF;AACA,S;AACA,E;AACA,yE;AACA,0E;AACA,+D;AACA,gF;AACA,qB;AACA,+D;AACA,6C;AACA,kB;;AAEA,0C;AACA,mD;AACA,E;;AAEA,sC;;AAEA,gC;AACA,6B;AACA,oB;AACA,iD;AACA,iC;AACA,I;AACA,yB;AACA,oB;AACA,oD;AACA,6B;AACA,I;AACA,sB;AACA,oB;AACA,mD;AACA,0B;AACA,I;AACA,kC;AACA,oB;AACA,wD;AACA,6C;AACA,I;AACA,sB;AACA,oB;AACA,6D;AACA,iB;AACA,I;AACA,6B;AACA,oB;AACA,wC;AACA,G;AACA,G","file":"/packages/binary-heap.js","sourcesContent":["// Constructor of Heap\n// - comparator - Function - given two items returns a number\n// - options:\n// - initData - Array - Optional - the initial data in a format:\n// Object:\n// - id - String - unique id of the item\n// - value - Any - the data value\n// each value is retained\n// - IdMap - Constructor - Optional - custom IdMap class to store id->index\n// mappings internally. Standard IdMap is used by default.\nMaxHeap = function (comparator, options) {\n if (! _.isFunction(comparator))\n throw new Error('Passed comparator is invalid, should be a comparison function');\n var self = this;\n\n // a C-style comparator that is given two values and returns a number,\n // negative if the first value is less than the second, positive if the second\n // value is greater than the first and zero if they are equal.\n self._comparator = comparator;\n\n options = _.defaults(options || {}, { IdMap: IdMap });\n\n // _heapIdx maps an id to an index in the Heap array the corresponding value\n // is located on.\n self._heapIdx = new options.IdMap;\n\n // The Heap data-structure implemented as a 0-based contiguous array where\n // every item on index idx is a node in a complete binary tree. Every node can\n // have children on indexes idx*2+1 and idx*2+2, except for the leaves. Every\n // node has a parent on index (idx-1)/2;\n self._heap = [];\n\n // If the initial array is passed, we can build the heap in linear time\n // complexity (O(N)) compared to linearithmic time complexity (O(nlogn)) if\n // we push elements one by one.\n if (_.isArray(options.initData))\n self._initFromData(options.initData);\n};\n\n_.extend(MaxHeap.prototype, {\n // Builds a new heap in-place in linear time based on passed data\n _initFromData: function (data) {\n var self = this;\n\n self._heap = _.map(data, function (o) {\n return { id: o.id, value: o.value };\n });\n\n _.each(data, function (o, i) {\n self._heapIdx.set(o.id, i);\n });\n\n if (! data.length)\n return;\n\n // start from the first non-leaf - the parent of the last leaf\n for (var i = parentIdx(data.length - 1); i >= 0; i--)\n self._downHeap(i);\n },\n\n _downHeap: function (idx) {\n var self = this;\n\n while (leftChildIdx(idx) < self.size()) {\n var left = leftChildIdx(idx);\n var right = rightChildIdx(idx);\n var largest = idx;\n\n if (left < self.size()) {\n largest = self._maxIndex(largest, left);\n }\n if (right < self.size()) {\n largest = self._maxIndex(largest, right);\n }\n\n if (largest === idx)\n break;\n\n self._swap(largest, idx);\n idx = largest;\n }\n },\n\n _upHeap: function (idx) {\n var self = this;\n\n while (idx > 0) {\n var parent = parentIdx(idx);\n if (self._maxIndex(parent, idx) === idx) {\n self._swap(parent, idx)\n idx = parent;\n } else {\n break;\n }\n }\n },\n\n _maxIndex: function (idxA, idxB) {\n var self = this;\n var valueA = self._get(idxA);\n var valueB = self._get(idxB);\n return self._comparator(valueA, valueB) >= 0 ? idxA : idxB;\n },\n\n // Internal: gets raw data object placed on idxth place in heap\n _get: function (idx) {\n var self = this;\n return self._heap[idx].value;\n },\n\n _swap: function (idxA, idxB) {\n var self = this;\n var recA = self._heap[idxA];\n var recB = self._heap[idxB];\n\n self._heapIdx.set(recA.id, idxB);\n self._heapIdx.set(recB.id, idxA);\n\n self._heap[idxA] = recB;\n self._heap[idxB] = recA;\n },\n\n get: function (id) {\n var self = this;\n if (! self.has(id))\n return null;\n return self._get(self._heapIdx.get(id));\n },\n set: function (id, value) {\n var self = this;\n\n if (self.has(id)) {\n if (self.get(id) === value)\n return;\n\n var idx = self._heapIdx.get(id);\n self._heap[idx].value = value;\n\n // Fix the new value's position\n // Either bubble new value up if it is greater than its parent\n self._upHeap(idx);\n // or bubble it down if it is smaller than one of its children\n self._downHeap(idx);\n } else {\n self._heapIdx.set(id, self._heap.length);\n self._heap.push({ id: id, value: value });\n self._upHeap(self._heap.length - 1);\n }\n },\n remove: function (id) {\n var self = this;\n\n if (self.has(id)) {\n var last = self._heap.length - 1;\n var idx = self._heapIdx.get(id);\n\n if (idx !== last) {\n self._swap(idx, last);\n self._heap.pop();\n self._heapIdx.remove(id);\n\n // Fix the swapped value's position\n self._upHeap(idx);\n self._downHeap(idx);\n } else {\n self._heap.pop();\n self._heapIdx.remove(id);\n }\n }\n },\n has: function (id) {\n var self = this;\n return self._heapIdx.has(id);\n },\n empty: function () {\n var self = this;\n return !self.size();\n },\n clear: function () {\n var self = this;\n self._heap = [];\n self._heapIdx.clear();\n },\n // iterate over values in no particular order\n forEach: function (iterator) {\n var self = this;\n _.each(self._heap, function (obj) {\n return iterator(obj.value, obj.id);\n });\n },\n size: function () {\n var self = this;\n return self._heap.length;\n },\n setDefault: function (id, def) {\n var self = this;\n if (self.has(id))\n return self.get(id);\n self.set(id, def);\n return def;\n },\n clone: function () {\n var self = this;\n var clone = new MaxHeap(self._comparator, self._heap);\n return clone;\n },\n\n maxElementId: function () {\n var self = this;\n return self.size() ? self._heap[0].id : null;\n },\n\n _selfCheck: function () {\n var self = this;\n for (var i = 1; i < self._heap.length; i++)\n if (self._maxIndex(parentIdx(i), i) !== parentIdx(i))\n throw new Error(\"An item with id \" + self._heap[i].id +\n \" has a parent younger than it: \" +\n self._heap[parentIdx(i)].id);\n }\n});\n\nfunction leftChildIdx (i) { return i * 2 + 1; }\nfunction rightChildIdx (i) { return i * 2 + 2; }\nfunction parentIdx (i) { return (i - 1) >> 1; }\n\n","MinHeap = function (comparator, options) {\n var self = this;\n MaxHeap.call(self, function (a, b) {\n return -comparator(a, b);\n }, options);\n};\n\nMeteor._inherits(MinHeap, MaxHeap);\n\n_.extend(MinHeap.prototype, {\n maxElementId: function () {\n throw new Error(\"Cannot call maxElementId on MinHeap\");\n },\n minElementId: function () {\n var self = this;\n return MaxHeap.prototype.maxElementId.call(self);\n }\n});\n\n","// This implementation of Min/Max-Heap is just a subclass of Max-Heap\n// with a Min-Heap as an encapsulated property.\n//\n// Most of the operations are just proxy methods to call the same method on both\n// heaps.\n//\n// This implementation takes 2*N memory but is fairly simple to write and\n// understand. And the constant factor of a simple Heap is usually smaller\n// compared to other two-way priority queues like Min/Max Heaps\n// (http://www.cs.otago.ac.nz/staffpriv/mike/Papers/MinMaxHeaps/MinMaxHeaps.pdf)\n// and Interval Heaps\n// (http://www.cise.ufl.edu/~sahni/dsaac/enrich/c13/double.htm)\nMinMaxHeap = function (comparator, options) {\n var self = this;\n\n MaxHeap.call(self, comparator, options);\n self._minHeap = new MinHeap(comparator, options);\n};\n\nMeteor._inherits(MinMaxHeap, MaxHeap);\n\n_.extend(MinMaxHeap.prototype, {\n set: function (id, value) {\n var self = this;\n MaxHeap.prototype.set.apply(self, arguments);\n self._minHeap.set(id, value);\n },\n remove: function (id) {\n var self = this;\n MaxHeap.prototype.remove.apply(self, arguments);\n self._minHeap.remove(id);\n },\n clear: function () {\n var self = this;\n MaxHeap.prototype.clear.apply(self, arguments);\n self._minHeap.clear();\n },\n setDefault: function (id, def) {\n var self = this;\n MaxHeap.prototype.setDefault.apply(self, arguments);\n return self._minHeap.setDefault(id, def);\n },\n clone: function () {\n var self = this;\n var clone = new MinMaxHeap(self._comparator, self._heap);\n return clone;\n },\n minElementId: function () {\n var self = this;\n return self._minHeap.minElementId();\n }\n});\n\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js b/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js deleted file mode 100644 index a5cf3be..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js +++ /dev/null @@ -1,403 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var HTML = Package.htmljs.HTML; -var _ = Package.underscore._; - -/* Package-scope variables */ -var BlazeTools, toJSLiteral, toObjectLiteralKey, ToJSVisitor; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze-tools/preamble.js // -// // -/////////////////////////////////////////////////////////////////////////////////////// - // -BlazeTools = {}; // 1 - // 2 -/////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze-tools/tokens.js // -// // -/////////////////////////////////////////////////////////////////////////////////////// - // - // 1 -// Adapted from source code of http://xregexp.com/plugins/#unicode // 2 -var unicodeCategories = { // 3 - Ll: "0061-007A00B500DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F05210523052505270561-05871D00-1D2B1D6B-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7B2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2CF32D00-2D252D272D2DA641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA661A663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CA78EA791A793A7A1A7A3A7A5A7A7A7A9A7FAFB00-FB06FB13-FB17FF41-FF5A", - Lm: "02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D6A1D781D9B-1DBF2071207F2090-209C2C7C2C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A7F8A7F9A9CFAA70AADDAAF3AAF4FF70FF9EFF9F", - Lo: "00AA00BA01BB01C0-01C3029405D0-05EA05F0-05F20620-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150840-085808A008A2-08AC0904-0939093D09500958-09610972-09770979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10CF10CF20D05-0D0C0D0E-0D100D12-0D3A0D3D0D4E0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC-0EDF0F000F40-0F470F49-0F6C0F88-0F8C1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA10FD-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1BBA-1BE51C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF11CF51CF62135-21382D30-2D672D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCAAE0-AAEAAAF2AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC", - Lt: "01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC", // 7 - Lu: "0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E05200522052405260531-055610A0-10C510C710CD1E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CED2CF2A640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA660A662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BA78DA790A792A7A0A7A2A7A4A7A6A7A8A7AAFF21-FF3A", - Mc: "0903093B093E-09400949-094C094E094F0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1BAC1BAD1BE71BEA-1BEC1BEE1BF21BF31C24-1C2B1C341C351CE11CF21CF3302E302FA823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BAAEBAAEEAAEFAAF5ABE3ABE4ABE6ABE7ABE9ABEAABEC", - Mn: "0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065F067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0859-085B08E4-08FE0900-0902093A093C0941-0948094D0951-095709620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F8D-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135D-135F1712-17141732-1734175217531772177317B417B517B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91BAB1BE61BE81BE91BED1BEF-1BF11C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF20D0-20DC20E120E5-20F02CEF-2CF12D7F2DE0-2DFF302A-302D3099309AA66FA674-A67DA69FA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1AAECAAEDAAF6ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26", - Nd: "0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19D91A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19", - Nl: "16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF", // 12 - Pc: "005F203F20402054FE33FE34FE4D-FE4FFF3F" // 13 -}; // 14 - // 15 -var unicodeClass = function (abbrev) { // 16 - return '[' + // 17 - unicodeCategories[abbrev].replace(/[0-9A-F]{4}/ig, "\\u$&") + ']'; // 18 -}; // 19 - // 20 -// See ECMA-262 spec, 3rd edition, Section 7.6 // 21 -// Match one or more characters that can start an identifier. // 22 -// This is IdentifierStart+. // 23 -var rIdentifierPrefix = new RegExp( // 24 - "^([a-zA-Z$_]+|\\\\u[0-9a-fA-F]{4}|" + // 25 - [unicodeClass('Lu'), unicodeClass('Ll'), unicodeClass('Lt'), // 26 - unicodeClass('Lm'), unicodeClass('Lo'), unicodeClass('Nl')].join('|') + // 27 - ")+"); // 28 -// Match one or more characters that can continue an identifier. // 29 -// This is (IdentifierPart and not IdentifierStart)+. // 30 -// To match a full identifier, match rIdentifierPrefix, then // 31 -// match rIdentifierMiddle followed by rIdentifierPrefix until they both fail. // 32 -var rIdentifierMiddle = new RegExp( // 33 - "^([0-9]|" + [unicodeClass('Mn'), unicodeClass('Mc'), unicodeClass('Nd'), // 34 - unicodeClass('Pc')].join('|') + ")+"); // 35 - // 36 - // 37 -// See ECMA-262 spec, 3rd edition, Section 7.8.3 // 38 -var rHexLiteral = /^0[xX][0-9a-fA-F]+(?!\w)/; // 39 -var rDecLiteral = // 40 - /^(((0|[1-9][0-9]*)(\.[0-9]*)?)|\.[0-9]+)([Ee][+-]?[0-9]+)?(?!\w)/; // 41 - // 42 -// Section 7.8.4 // 43 -var rStringQuote = /^["']/; // 44 -// Match one or more characters besides quotes, backslashes, or line ends // 45 -var rStringMiddle = /^(?=.)[^"'\\]+?((?!.)|(?=["'\\]))/; // 46 -// Match one escape sequence, including the backslash. // 47 -var rEscapeSequence = // 48 - /^\\(['"\\bfnrtv]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|(?=.)[^ux0-9])/; // 49 -// Match one ES5 line continuation // 50 -var rLineContinuation = // 51 - /^\\(\r\n|[\u000A\u000D\u2028\u2029])/; // 52 - // 53 - // 54 -BlazeTools.parseNumber = function (scanner) { // 55 - var startPos = scanner.pos; // 56 - // 57 - var isNegative = false; // 58 - if (scanner.peek() === '-') { // 59 - scanner.pos++; // 60 - isNegative = true; // 61 - } // 62 - // Note that we allow `"-0xa"`, unlike `Number(...)`. // 63 - // 64 - var rest = scanner.rest(); // 65 - var match = rDecLiteral.exec(rest) || rHexLiteral.exec(rest); // 66 - if (! match) { // 67 - scanner.pos = startPos; // 68 - return null; // 69 - } // 70 - var matchText = match[0]; // 71 - scanner.pos += matchText.length; // 72 - // 73 - var text = (isNegative ? '-' : '') + matchText; // 74 - var value = Number(matchText); // 75 - value = (isNegative ? -value : value); // 76 - return { text: text, value: value }; // 77 -}; // 78 - // 79 -BlazeTools.parseIdentifierName = function (scanner) { // 80 - var startPos = scanner.pos; // 81 - var rest = scanner.rest(); // 82 - var match = rIdentifierPrefix.exec(rest); // 83 - if (! match) // 84 - return null; // 85 - scanner.pos += match[0].length; // 86 - rest = scanner.rest(); // 87 - var foundMore = true; // 88 - // 89 - while (foundMore) { // 90 - foundMore = false; // 91 - // 92 - match = rIdentifierMiddle.exec(rest); // 93 - if (match) { // 94 - foundMore = true; // 95 - scanner.pos += match[0].length; // 96 - rest = scanner.rest(); // 97 - } // 98 - // 99 - match = rIdentifierPrefix.exec(rest); // 100 - if (match) { // 101 - foundMore = true; // 102 - scanner.pos += match[0].length; // 103 - rest = scanner.rest(); // 104 - } // 105 - } // 106 - // 107 - return scanner.input.substring(startPos, scanner.pos); // 108 -}; // 109 - // 110 -BlazeTools.parseStringLiteral = function (scanner) { // 111 - var startPos = scanner.pos; // 112 - var rest = scanner.rest(); // 113 - var match = rStringQuote.exec(rest); // 114 - if (! match) // 115 - return null; // 116 - // 117 - var quote = match[0]; // 118 - scanner.pos++; // 119 - rest = scanner.rest(); // 120 - // 121 - var jsonLiteral = '"'; // 122 - // 123 - while (match) { // 124 - match = rStringMiddle.exec(rest); // 125 - if (match) { // 126 - jsonLiteral += match[0]; // 127 - } else { // 128 - match = rEscapeSequence.exec(rest); // 129 - if (match) { // 130 - var esc = match[0]; // 131 - // Convert all string escapes to JSON-compatible string escapes, so we // 132 - // can use JSON.parse for some of the work. JSON strings are not the // 133 - // same as JS strings. They don't support `\0`, `\v`, `\'`, or hex // 134 - // escapes. // 135 - if (esc === '\\0') // 136 - jsonLiteral += '\\u0000'; // 137 - else if (esc === '\\v') // 138 - // Note: IE 8 doesn't correctly parse '\v' in JavaScript. // 139 - jsonLiteral += '\\u000b'; // 140 - else if (esc.charAt(1) === 'x') // 141 - jsonLiteral += '\\u00' + esc.slice(2); // 142 - else if (esc === '\\\'') // 143 - jsonLiteral += "'"; // 144 - else // 145 - jsonLiteral += esc; // 146 - } else { // 147 - match = rLineContinuation.exec(rest); // 148 - if (! match) { // 149 - match = rStringQuote.exec(rest); // 150 - if (match) { // 151 - var c = match[0]; // 152 - if (c !== quote) { // 153 - if (c === '"') // 154 - jsonLiteral += '\\'; // 155 - jsonLiteral += c; // 156 - } // 157 - } // 158 - } // 159 - } // 160 - } // 161 - if (match) { // 162 - scanner.pos += match[0].length; // 163 - rest = scanner.rest(); // 164 - if (match[0] === quote) // 165 - break; // 166 - } // 167 - } // 168 - // 169 - if (match[0] !== quote) // 170 - scanner.fatal("Unterminated string literal"); // 171 - // 172 - jsonLiteral += '"'; // 173 - var text = scanner.input.substring(startPos, scanner.pos); // 174 - var value = JSON.parse(jsonLiteral); // 175 - return { text: text, value: value }; // 176 -}; // 177 - // 178 -/////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze-tools/tojs.js // -// // -/////////////////////////////////////////////////////////////////////////////////////// - // - // 1 -BlazeTools.EmitCode = function (value) { // 2 - if (! (this instanceof BlazeTools.EmitCode)) // 3 - // called without `new` // 4 - return new BlazeTools.EmitCode(value); // 5 - // 6 - if (typeof value !== 'string') // 7 - throw new Error('BlazeTools.EmitCode must be constructed with a string'); // 8 - // 9 - this.value = value; // 10 -}; // 11 -BlazeTools.EmitCode.prototype.toJS = function (visitor) { // 12 - return this.value; // 13 -}; // 14 - // 15 -// Turns any JSONable value into a JavaScript literal. // 16 -toJSLiteral = function (obj) { // 17 - // See for `\u2028\u2029`. // 18 - // Also escape Unicode surrogates. // 19 - return (JSON.stringify(obj) // 20 - .replace(/[\u2028\u2029\ud800-\udfff]/g, function (c) { // 21 - return '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4); // 22 - })); // 23 -}; // 24 -BlazeTools.toJSLiteral = toJSLiteral; // 25 - // 26 - // 27 - // 28 -var jsReservedWordSet = (function (set) { // 29 - _.each("abstract else instanceof super boolean enum int switch break export interface synchronized byte extends let this case false long throw catch final native throws char finally new transient class float null true const for package try continue function private typeof debugger goto protected var default if public void delete implements return volatile do import short while double in static with".split(' '), function (w) { - set[w] = 1; // 31 - }); // 32 - return set; // 33 -})({}); // 34 - // 35 -toObjectLiteralKey = function (k) { // 36 - if (/^[a-zA-Z$_][a-zA-Z$0-9_]*$/.test(k) && jsReservedWordSet[k] !== 1) // 37 - return k; // 38 - return toJSLiteral(k); // 39 -}; // 40 -BlazeTools.toObjectLiteralKey = toObjectLiteralKey; // 41 - // 42 -var hasToJS = function (x) { // 43 - return x.toJS && (typeof (x.toJS) === 'function'); // 44 -}; // 45 - // 46 -ToJSVisitor = HTML.Visitor.extend(); // 47 -ToJSVisitor.def({ // 48 - visitNull: function (nullOrUndefined) { // 49 - return 'null'; // 50 - }, // 51 - visitPrimitive: function (stringBooleanOrNumber) { // 52 - return toJSLiteral(stringBooleanOrNumber); // 53 - }, // 54 - visitArray: function (array) { // 55 - var parts = []; // 56 - for (var i = 0; i < array.length; i++) // 57 - parts.push(this.visit(array[i])); // 58 - return '[' + parts.join(', ') + ']'; // 59 - }, // 60 - visitTag: function (tag) { // 61 - return this.generateCall(tag.tagName, tag.attrs, tag.children); // 62 - }, // 63 - visitComment: function (comment) { // 64 - return this.generateCall('HTML.Comment', null, [comment.value]); // 65 - }, // 66 - visitCharRef: function (charRef) { // 67 - return this.generateCall('HTML.CharRef', // 68 - {html: charRef.html, str: charRef.str}); // 69 - }, // 70 - visitRaw: function (raw) { // 71 - return this.generateCall('HTML.Raw', null, [raw.value]); // 72 - }, // 73 - visitObject: function (x) { // 74 - if (hasToJS(x)) { // 75 - return x.toJS(this); // 76 - } // 77 - // 78 - throw new Error("Unexpected object in HTMLjs in toJS: " + x); // 79 - }, // 80 - generateCall: function (name, attrs, children) { // 81 - var tagSymbol; // 82 - if (name.indexOf('.') >= 0) { // 83 - tagSymbol = name; // 84 - } else if (HTML.isTagEnsured(name)) { // 85 - tagSymbol = 'HTML.' + HTML.getSymbolName(name); // 86 - } else { // 87 - tagSymbol = 'HTML.getTag(' + toJSLiteral(name) + ')'; // 88 - } // 89 - // 90 - var attrsArray = null; // 91 - if (attrs) { // 92 - attrsArray = []; // 93 - var needsHTMLAttrs = false; // 94 - if (HTML.isArray(attrs)) { // 95 - var attrsArray = []; // 96 - for (var i = 0; i < attrs.length; i++) { // 97 - var a = attrs[i]; // 98 - if (hasToJS(a)) { // 99 - attrsArray.push(a.toJS(this)); // 100 - needsHTMLAttrs = true; // 101 - } else { // 102 - var attrsObjStr = this.generateAttrsDictionary(attrs[i]); // 103 - if (attrsObjStr !== null) // 104 - attrsArray.push(attrsObjStr); // 105 - } // 106 - } // 107 - } else if (hasToJS(attrs)) { // 108 - attrsArray.push(attrs.toJS(this)); // 109 - needsHTMLAttrs = true; // 110 - } else { // 111 - attrsArray.push(this.generateAttrsDictionary(attrs)); // 112 - } // 113 - } // 114 - var attrsStr = null; // 115 - if (attrsArray && attrsArray.length) { // 116 - if (attrsArray.length === 1 && ! needsHTMLAttrs) { // 117 - attrsStr = attrsArray[0]; // 118 - } else { // 119 - attrsStr = 'HTML.Attrs(' + attrsArray.join(', ') + ')'; // 120 - } // 121 - } // 122 - // 123 - var argStrs = []; // 124 - if (attrsStr !== null) // 125 - argStrs.push(attrsStr); // 126 - // 127 - if (children) { // 128 - for (var i = 0; i < children.length; i++) // 129 - argStrs.push(this.visit(children[i])); // 130 - } // 131 - // 132 - return tagSymbol + '(' + argStrs.join(', ') + ')'; // 133 - }, // 134 - generateAttrsDictionary: function (attrsDict) { // 135 - if (attrsDict.toJS && (typeof (attrsDict.toJS) === 'function')) { // 136 - // not an attrs dictionary, but something else! Like a template tag. // 137 - return attrsDict.toJS(this); // 138 - } // 139 - // 140 - var kvStrs = []; // 141 - for (var k in attrsDict) { // 142 - if (! HTML.isNully(attrsDict[k])) // 143 - kvStrs.push(toObjectLiteralKey(k) + ': ' + // 144 - this.visit(attrsDict[k])); // 145 - } // 146 - if (kvStrs.length) // 147 - return '{' + kvStrs.join(', ') + '}'; // 148 - return null; // 149 - } // 150 -}); // 151 -BlazeTools.ToJSVisitor = ToJSVisitor; // 152 - // 153 -BlazeTools.toJS = function (content) { // 154 - return (new ToJSVisitor).visit(content); // 155 -}; // 156 - // 157 -/////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['blaze-tools'] = { - BlazeTools: BlazeTools -}; - -})(); - -//# sourceMappingURL=blaze-tools.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js.map b/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js.map deleted file mode 100644 index 45eac66..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/blaze-tools.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["blaze-tools/preamble.js","blaze-tools/tokens.js","blaze-tools/tojs.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,gB;;;;;;;;;;;;;;;;;;;;ACCA,kE;AACA,yB;AACA,6kF;AACA,wS;AACA,iuE;AACA,gE;AACA,kgF;AACA,gxB;AACA,2zC;AACA,oU;AACA,mE;AACA,6C;AACA,E;;AAEA,sC;AACA,c;AACA,sE;AACA,E;;AAEA,8C;AACA,6D;AACA,4B;AACA,mC;AACA,wC;AACA,gE;AACA,4E;AACA,U;AACA,gE;AACA,qD;AACA,4D;AACA,8E;AACA,mC;AACA,2E;AACA,sD;;;AAGA,gD;AACA,6C;AACA,iB;AACA,yE;;AAEA,gB;AACA,2B;AACA,yE;AACA,wD;AACA,sD;AACA,qB;AACA,mF;AACA,kC;AACA,uB;AACA,6C;;;AAGA,6C;AACA,6B;;AAEA,yB;AACA,+B;AACA,kB;AACA,sB;AACA,G;AACA,uD;;AAEA,4B;AACA,+D;AACA,gB;AACA,2B;AACA,gB;AACA,G;AACA,2B;AACA,kC;;AAEA,iD;AACA,gC;AACA,wC;AACA,sC;AACA,E;;AAEA,qD;AACA,6B;AACA,4B;AACA,2C;AACA,c;AACA,gB;AACA,iC;AACA,wB;AACA,uB;;AAEA,qB;AACA,sB;;AAEA,yC;AACA,gB;AACA,uB;AACA,qC;AACA,4B;AACA,K;;AAEA,yC;AACA,gB;AACA,uB;AACA,qC;AACA,4B;AACA,K;AACA,G;;AAEA,wD;AACA,E;;AAEA,oD;AACA,6B;AACA,4B;AACA,sC;AACA,c;AACA,gB;;AAEA,uB;AACA,gB;AACA,wB;;AAEA,wB;;AAEA,iB;AACA,qC;AACA,gB;AACA,8B;AACA,Y;AACA,yC;AACA,kB;AACA,2B;AACA,8E;AACA,6E;AACA,2E;AACA,mB;AACA,0B;AACA,mC;AACA,+B;AACA,mE;AACA,mC;AACA,uC;AACA,gD;AACA,gC;AACA,6B;AACA,Y;AACA,6B;AACA,c;AACA,6C;AACA,sB;AACA,0C;AACA,sB;AACA,6B;AACA,8B;AACA,4B;AACA,oC;AACA,+B;AACA,a;AACA,W;AACA,S;AACA,O;AACA,K;AACA,gB;AACA,qC;AACA,4B;AACA,6B;AACA,c;AACA,K;AACA,G;;AAEA,yB;AACA,iD;;AAEA,qB;AACA,4D;AACA,sC;AACA,sC;AACA,E;;;;;;;;;;;;;;;;;;;;AC/KA,wC;AACA,8C;AACA,2B;AACA,0C;;AAEA,gC;AACA,6E;;AAEA,qB;AACA,E;AACA,yD;AACA,oB;AACA,E;;AAEA,sD;AACA,8B;AACA,oF;AACA,oC;AACA,6B;AACA,iE;AACA,4E;AACA,c;AACA,E;AACA,qC;;;;AAIA,yC;AACA,+a;AACA,e;AACA,K;AACA,a;AACA,O;;AAEA,mC;AACA,yE;AACA,a;AACA,wB;AACA,E;AACA,mD;;AAEA,4B;AACA,oD;AACA,E;;AAEA,oC;AACA,iB;AACA,yC;AACA,kB;AACA,I;AACA,oD;AACA,8C;AACA,I;AACA,gC;AACA,mB;AACA,0C;AACA,uC;AACA,wC;AACA,I;AACA,4B;AACA,mE;AACA,I;AACA,oC;AACA,oE;AACA,I;AACA,oC;AACA,4C;AACA,qE;AACA,I;AACA,4B;AACA,4D;AACA,I;AACA,6B;AACA,qB;AACA,0B;AACA,K;;AAEA,iE;AACA,I;AACA,kD;AACA,kB;AACA,iC;AACA,uB;AACA,yC;AACA,qD;AACA,Y;AACA,2D;AACA,K;;AAEA,0B;AACA,gB;AACA,sB;AACA,iC;AACA,gC;AACA,4B;AACA,gD;AACA,2B;AACA,2B;AACA,0C;AACA,kC;AACA,kB;AACA,qE;AACA,qC;AACA,2C;AACA,W;AACA,S;AACA,kC;AACA,0C;AACA,8B;AACA,c;AACA,6D;AACA,O;AACA,K;AACA,wB;AACA,0C;AACA,wD;AACA,iC;AACA,c;AACA,+D;AACA,O;AACA,K;;AAEA,qB;AACA,0B;AACA,6B;;AAEA,mB;AACA,+C;AACA,8C;AACA,K;;AAEA,sD;AACA,I;AACA,iD;AACA,qE;AACA,2E;AACA,kC;AACA,K;;AAEA,oB;AACA,8B;AACA,uC;AACA,kD;AACA,8C;AACA,K;AACA,sB;AACA,2C;AACA,gB;AACA,G;AACA,G;AACA,qC;;AAEA,sC;AACA,0C;AACA,E","file":"/packages/blaze-tools.js","sourcesContent":["BlazeTools = {};\n","\n// Adapted from source code of http://xregexp.com/plugins/#unicode\nvar unicodeCategories = {\n Ll: \"0061-007A00B500DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F05210523052505270561-05871D00-1D2B1D6B-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7B2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2CF32D00-2D252D272D2DA641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA661A663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CA78EA791A793A7A1A7A3A7A5A7A7A7A9A7FAFB00-FB06FB13-FB17FF41-FF5A\",\n Lm: \"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D6A1D781D9B-1DBF2071207F2090-209C2C7C2C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A7F8A7F9A9CFAA70AADDAAF3AAF4FF70FF9EFF9F\",\n Lo: \"00AA00BA01BB01C0-01C3029405D0-05EA05F0-05F20620-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150840-085808A008A2-08AC0904-0939093D09500958-09610972-09770979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10CF10CF20D05-0D0C0D0E-0D100D12-0D3A0D3D0D4E0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC-0EDF0F000F40-0F470F49-0F6C0F88-0F8C1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA10FD-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1BBA-1BE51C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF11CF51CF62135-21382D30-2D672D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31BA31F0-31FF3400-4DB54E00-9FCCA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCAAE0-AAEAAAF2AB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2EABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC\",\n Lt: \"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC\",\n Lu: \"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E05200522052405260531-055610A0-10C510C710CD1E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CED2CF2A640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA660A662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BA78DA790A792A7A0A7A2A7A4A7A6A7A8A7AAFF21-FF3A\",\n Mc: \"0903093B093E-09400949-094C094E094F0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1BAC1BAD1BE71BEA-1BEC1BEE1BF21BF31C24-1C2B1C341C351CE11CF21CF3302E302FA823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BAAEBAAEEAAEFAAF5ABE3ABE4ABE6ABE7ABE9ABEAABEC\",\n Mn: \"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065F067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0859-085B08E4-08FE0900-0902093A093C0941-0948094D0951-095709620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F8D-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135D-135F1712-17141732-1734175217531772177317B417B517B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91BAB1BE61BE81BE91BED1BEF-1BF11C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF20D0-20DC20E120E5-20F02CEF-2CF12D7F2DE0-2DFF302A-302D3099309AA66FA674-A67DA69FA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1AAECAAEDAAF6ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26\",\n Nd: \"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19D91A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19\",\n Nl: \"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF\",\n Pc: \"005F203F20402054FE33FE34FE4D-FE4FFF3F\"\n};\n\nvar unicodeClass = function (abbrev) {\n return '[' +\n unicodeCategories[abbrev].replace(/[0-9A-F]{4}/ig, \"\\\\u$&\") + ']';\n};\n\n// See ECMA-262 spec, 3rd edition, Section 7.6\n// Match one or more characters that can start an identifier.\n// This is IdentifierStart+.\nvar rIdentifierPrefix = new RegExp(\n \"^([a-zA-Z$_]+|\\\\\\\\u[0-9a-fA-F]{4}|\" +\n [unicodeClass('Lu'), unicodeClass('Ll'), unicodeClass('Lt'),\n unicodeClass('Lm'), unicodeClass('Lo'), unicodeClass('Nl')].join('|') +\n \")+\");\n// Match one or more characters that can continue an identifier.\n// This is (IdentifierPart and not IdentifierStart)+.\n// To match a full identifier, match rIdentifierPrefix, then\n// match rIdentifierMiddle followed by rIdentifierPrefix until they both fail.\nvar rIdentifierMiddle = new RegExp(\n \"^([0-9]|\" + [unicodeClass('Mn'), unicodeClass('Mc'), unicodeClass('Nd'),\n unicodeClass('Pc')].join('|') + \")+\");\n\n\n// See ECMA-262 spec, 3rd edition, Section 7.8.3\nvar rHexLiteral = /^0[xX][0-9a-fA-F]+(?!\\w)/;\nvar rDecLiteral =\n /^(((0|[1-9][0-9]*)(\\.[0-9]*)?)|\\.[0-9]+)([Ee][+-]?[0-9]+)?(?!\\w)/;\n\n// Section 7.8.4\nvar rStringQuote = /^[\"']/;\n// Match one or more characters besides quotes, backslashes, or line ends\nvar rStringMiddle = /^(?=.)[^\"'\\\\]+?((?!.)|(?=[\"'\\\\]))/;\n// Match one escape sequence, including the backslash.\nvar rEscapeSequence =\n /^\\\\(['\"\\\\bfnrtv]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|(?=.)[^ux0-9])/;\n// Match one ES5 line continuation\nvar rLineContinuation =\n /^\\\\(\\r\\n|[\\u000A\\u000D\\u2028\\u2029])/;\n\n\nBlazeTools.parseNumber = function (scanner) {\n var startPos = scanner.pos;\n\n var isNegative = false;\n if (scanner.peek() === '-') {\n scanner.pos++;\n isNegative = true;\n }\n // Note that we allow `\"-0xa\"`, unlike `Number(...)`.\n\n var rest = scanner.rest();\n var match = rDecLiteral.exec(rest) || rHexLiteral.exec(rest);\n if (! match) {\n scanner.pos = startPos;\n return null;\n }\n var matchText = match[0];\n scanner.pos += matchText.length;\n\n var text = (isNegative ? '-' : '') + matchText;\n var value = Number(matchText);\n value = (isNegative ? -value : value);\n return { text: text, value: value };\n};\n\nBlazeTools.parseIdentifierName = function (scanner) {\n var startPos = scanner.pos;\n var rest = scanner.rest();\n var match = rIdentifierPrefix.exec(rest);\n if (! match)\n return null;\n scanner.pos += match[0].length;\n rest = scanner.rest();\n var foundMore = true;\n\n while (foundMore) {\n foundMore = false;\n\n match = rIdentifierMiddle.exec(rest);\n if (match) {\n foundMore = true;\n scanner.pos += match[0].length;\n rest = scanner.rest();\n }\n\n match = rIdentifierPrefix.exec(rest);\n if (match) {\n foundMore = true;\n scanner.pos += match[0].length;\n rest = scanner.rest();\n }\n }\n\n return scanner.input.substring(startPos, scanner.pos);\n};\n\nBlazeTools.parseStringLiteral = function (scanner) {\n var startPos = scanner.pos;\n var rest = scanner.rest();\n var match = rStringQuote.exec(rest);\n if (! match)\n return null;\n\n var quote = match[0];\n scanner.pos++;\n rest = scanner.rest();\n\n var jsonLiteral = '\"';\n\n while (match) {\n match = rStringMiddle.exec(rest);\n if (match) {\n jsonLiteral += match[0];\n } else {\n match = rEscapeSequence.exec(rest);\n if (match) {\n var esc = match[0];\n // Convert all string escapes to JSON-compatible string escapes, so we\n // can use JSON.parse for some of the work. JSON strings are not the\n // same as JS strings. They don't support `\\0`, `\\v`, `\\'`, or hex\n // escapes.\n if (esc === '\\\\0')\n jsonLiteral += '\\\\u0000';\n else if (esc === '\\\\v')\n // Note: IE 8 doesn't correctly parse '\\v' in JavaScript.\n jsonLiteral += '\\\\u000b';\n else if (esc.charAt(1) === 'x')\n jsonLiteral += '\\\\u00' + esc.slice(2);\n else if (esc === '\\\\\\'')\n jsonLiteral += \"'\";\n else\n jsonLiteral += esc;\n } else {\n match = rLineContinuation.exec(rest);\n if (! match) {\n match = rStringQuote.exec(rest);\n if (match) {\n var c = match[0];\n if (c !== quote) {\n if (c === '\"')\n jsonLiteral += '\\\\';\n jsonLiteral += c;\n }\n }\n }\n }\n }\n if (match) {\n scanner.pos += match[0].length;\n rest = scanner.rest();\n if (match[0] === quote)\n break;\n }\n }\n\n if (match[0] !== quote)\n scanner.fatal(\"Unterminated string literal\");\n\n jsonLiteral += '\"';\n var text = scanner.input.substring(startPos, scanner.pos);\n var value = JSON.parse(jsonLiteral);\n return { text: text, value: value };\n};\n","\nBlazeTools.EmitCode = function (value) {\n if (! (this instanceof BlazeTools.EmitCode))\n // called without `new`\n return new BlazeTools.EmitCode(value);\n\n if (typeof value !== 'string')\n throw new Error('BlazeTools.EmitCode must be constructed with a string');\n\n this.value = value;\n};\nBlazeTools.EmitCode.prototype.toJS = function (visitor) {\n return this.value;\n};\n\n// Turns any JSONable value into a JavaScript literal.\ntoJSLiteral = function (obj) {\n // See for `\\u2028\\u2029`.\n // Also escape Unicode surrogates.\n return (JSON.stringify(obj)\n .replace(/[\\u2028\\u2029\\ud800-\\udfff]/g, function (c) {\n return '\\\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4);\n }));\n};\nBlazeTools.toJSLiteral = toJSLiteral;\n\n\n\nvar jsReservedWordSet = (function (set) {\n _.each(\"abstract else instanceof super boolean enum int switch break export interface synchronized byte extends let this case false long throw catch final native throws char finally new transient class float null true const for package try continue function private typeof debugger goto protected var default if public void delete implements return volatile do import short while double in static with\".split(' '), function (w) {\n set[w] = 1;\n });\n return set;\n})({});\n\ntoObjectLiteralKey = function (k) {\n if (/^[a-zA-Z$_][a-zA-Z$0-9_]*$/.test(k) && jsReservedWordSet[k] !== 1)\n return k;\n return toJSLiteral(k);\n};\nBlazeTools.toObjectLiteralKey = toObjectLiteralKey;\n\nvar hasToJS = function (x) {\n return x.toJS && (typeof (x.toJS) === 'function');\n};\n\nToJSVisitor = HTML.Visitor.extend();\nToJSVisitor.def({\n visitNull: function (nullOrUndefined) {\n return 'null';\n },\n visitPrimitive: function (stringBooleanOrNumber) {\n return toJSLiteral(stringBooleanOrNumber);\n },\n visitArray: function (array) {\n var parts = [];\n for (var i = 0; i < array.length; i++)\n parts.push(this.visit(array[i]));\n return '[' + parts.join(', ') + ']';\n },\n visitTag: function (tag) {\n return this.generateCall(tag.tagName, tag.attrs, tag.children);\n },\n visitComment: function (comment) {\n return this.generateCall('HTML.Comment', null, [comment.value]);\n },\n visitCharRef: function (charRef) {\n return this.generateCall('HTML.CharRef',\n {html: charRef.html, str: charRef.str});\n },\n visitRaw: function (raw) {\n return this.generateCall('HTML.Raw', null, [raw.value]);\n },\n visitObject: function (x) {\n if (hasToJS(x)) {\n return x.toJS(this);\n }\n\n throw new Error(\"Unexpected object in HTMLjs in toJS: \" + x);\n },\n generateCall: function (name, attrs, children) {\n var tagSymbol;\n if (name.indexOf('.') >= 0) {\n tagSymbol = name;\n } else if (HTML.isTagEnsured(name)) {\n tagSymbol = 'HTML.' + HTML.getSymbolName(name);\n } else {\n tagSymbol = 'HTML.getTag(' + toJSLiteral(name) + ')';\n }\n\n var attrsArray = null;\n if (attrs) {\n attrsArray = [];\n var needsHTMLAttrs = false;\n if (HTML.isArray(attrs)) {\n var attrsArray = [];\n for (var i = 0; i < attrs.length; i++) {\n var a = attrs[i];\n if (hasToJS(a)) {\n attrsArray.push(a.toJS(this));\n needsHTMLAttrs = true;\n } else {\n var attrsObjStr = this.generateAttrsDictionary(attrs[i]);\n if (attrsObjStr !== null)\n attrsArray.push(attrsObjStr);\n }\n }\n } else if (hasToJS(attrs)) {\n attrsArray.push(attrs.toJS(this));\n needsHTMLAttrs = true;\n } else {\n attrsArray.push(this.generateAttrsDictionary(attrs));\n }\n }\n var attrsStr = null;\n if (attrsArray && attrsArray.length) {\n if (attrsArray.length === 1 && ! needsHTMLAttrs) {\n attrsStr = attrsArray[0];\n } else {\n attrsStr = 'HTML.Attrs(' + attrsArray.join(', ') + ')';\n }\n }\n\n var argStrs = [];\n if (attrsStr !== null)\n argStrs.push(attrsStr);\n\n if (children) {\n for (var i = 0; i < children.length; i++)\n argStrs.push(this.visit(children[i]));\n }\n\n return tagSymbol + '(' + argStrs.join(', ') + ')';\n },\n generateAttrsDictionary: function (attrsDict) {\n if (attrsDict.toJS && (typeof (attrsDict.toJS) === 'function')) {\n // not an attrs dictionary, but something else! Like a template tag.\n return attrsDict.toJS(this);\n }\n\n var kvStrs = [];\n for (var k in attrsDict) {\n if (! HTML.isNully(attrsDict[k]))\n kvStrs.push(toObjectLiteralKey(k) + ': ' +\n this.visit(attrsDict[k]));\n }\n if (kvStrs.length)\n return '{' + kvStrs.join(', ') + '}';\n return null;\n }\n});\nBlazeTools.ToJSVisitor = ToJSVisitor;\n\nBlazeTools.toJS = function (content) {\n return (new ToJSVisitor).visit(content);\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/blaze.js b/web-app/.meteor/local/build/programs/server/packages/blaze.js deleted file mode 100644 index f76533d..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/blaze.js +++ /dev/null @@ -1,2084 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; -var _ = Package.underscore._; -var HTML = Package.htmljs.HTML; -var ObserveSequence = Package['observe-sequence'].ObserveSequence; -var ReactiveVar = Package['reactive-var'].ReactiveVar; - -/* Package-scope variables */ -var Blaze, UI, Handlebars; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/preamble.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/** // 1 - * @namespace Blaze // 2 - * @summary The namespace for all Blaze-related methods and classes. // 3 - */ // 4 -Blaze = {}; // 5 - // 6 -// Utility to HTML-escape a string. Included for legacy reasons. // 7 -Blaze._escape = (function() { // 8 - var escape_map = { // 9 - "<": "<", // 10 - ">": ">", // 11 - '"': """, // 12 - "'": "'", // 13 - "`": "`", /* IE allows backtick-delimited attributes?? */ // 14 - "&": "&" // 15 - }; // 16 - var escape_one = function(c) { // 17 - return escape_map[c]; // 18 - }; // 19 - // 20 - return function (x) { // 21 - return x.replace(/[&<>"'`]/g, escape_one); // 22 - }; // 23 -})(); // 24 - // 25 -Blaze._warn = function (msg) { // 26 - msg = 'Warning: ' + msg; // 27 - // 28 - if ((typeof Log !== 'undefined') && Log && Log.warn) // 29 - Log.warn(msg); // use Meteor's "logging" package // 30 - else if ((typeof console !== 'undefined') && console.log) // 31 - console.log(msg); // 32 -}; // 33 - // 34 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/exceptions.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var debugFunc; // 1 - // 2 -// We call into user code in many places, and it's nice to catch exceptions // 3 -// propagated from user code immediately so that the whole system doesn't just // 4 -// break. Catching exceptions is easy; reporting them is hard. This helper // 5 -// reports exceptions. // 6 -// // 7 -// Usage: // 8 -// // 9 -// ``` // 10 -// try { // 11 -// // ... someStuff ... // 12 -// } catch (e) { // 13 -// reportUIException(e); // 14 -// } // 15 -// ``` // 16 -// // 17 -// An optional second argument overrides the default message. // 18 - // 19 -// Set this to `true` to cause `reportException` to throw // 20 -// the next exception rather than reporting it. This is // 21 -// useful in unit tests that test error messages. // 22 -Blaze._throwNextException = false; // 23 - // 24 -Blaze._reportException = function (e, msg) { // 25 - if (Blaze._throwNextException) { // 26 - Blaze._throwNextException = false; // 27 - throw e; // 28 - } // 29 - // 30 - if (! debugFunc) // 31 - // adapted from Tracker // 32 - debugFunc = function () { // 33 - return (typeof Meteor !== "undefined" ? Meteor._debug : // 34 - ((typeof console !== "undefined") && console.log ? console.log : // 35 - function () {})); // 36 - }; // 37 - // 38 - // In Chrome, `e.stack` is a multiline string that starts with the message // 39 - // and contains a stack trace. Furthermore, `console.log` makes it clickable. // 40 - // `console.log` supplies the space between the two arguments. // 41 - debugFunc()(msg || 'Exception caught in template:', e.stack || e.message); // 42 -}; // 43 - // 44 -Blaze._wrapCatchingExceptions = function (f, where) { // 45 - if (typeof f !== 'function') // 46 - return f; // 47 - // 48 - return function () { // 49 - try { // 50 - return f.apply(this, arguments); // 51 - } catch (e) { // 52 - Blaze._reportException(e, 'Exception in ' + where + ':'); // 53 - } // 54 - }; // 55 -}; // 56 - // 57 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/view.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/// [new] Blaze.View([name], renderMethod) // 1 -/// // 2 -/// Blaze.View is the building block of reactive DOM. Views have // 3 -/// the following features: // 4 -/// // 5 -/// * lifecycle callbacks - Views are created, rendered, and destroyed, // 6 -/// and callbacks can be registered to fire when these things happen. // 7 -/// // 8 -/// * parent pointer - A View points to its parentView, which is the // 9 -/// View that caused it to be rendered. These pointers form a // 10 -/// hierarchy or tree of Views. // 11 -/// // 12 -/// * render() method - A View's render() method specifies the DOM // 13 -/// (or HTML) content of the View. If the method establishes // 14 -/// reactive dependencies, it may be re-run. // 15 -/// // 16 -/// * a DOMRange - If a View is rendered to DOM, its position and // 17 -/// extent in the DOM are tracked using a DOMRange object. // 18 -/// // 19 -/// When a View is constructed by calling Blaze.View, the View is // 20 -/// not yet considered "created." It doesn't have a parentView yet, // 21 -/// and no logic has been run to initialize the View. All real // 22 -/// work is deferred until at least creation time, when the onViewCreated // 23 -/// callbacks are fired, which happens when the View is "used" in // 24 -/// some way that requires it to be rendered. // 25 -/// // 26 -/// ...more lifecycle stuff // 27 -/// // 28 -/// `name` is an optional string tag identifying the View. The only // 29 -/// time it's used is when looking in the View tree for a View of a // 30 -/// particular name; for example, data contexts are stored on Views // 31 -/// of name "with". Names are also useful when debugging, so in // 32 -/// general it's good for functions that create Views to set the name. // 33 -/// Views associated with templates have names of the form "Template.foo". // 34 - // 35 -/** // 36 - * @class // 37 - * @summary Constructor for a View, which represents a reactive region of DOM. // 38 - * @locus Client // 39 - * @param {String} [name] Optional. A name for this type of View. See [`view.name`](#view_name). // 40 - * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). In this function, `this` is bound to the View. - */ // 42 -Blaze.View = function (name, render) { // 43 - if (! (this instanceof Blaze.View)) // 44 - // called without `new` // 45 - return new Blaze.View(name, render); // 46 - // 47 - if (typeof name === 'function') { // 48 - // omitted "name" argument // 49 - render = name; // 50 - name = ''; // 51 - } // 52 - this.name = name; // 53 - this._render = render; // 54 - // 55 - this._callbacks = { // 56 - created: null, // 57 - rendered: null, // 58 - destroyed: null // 59 - }; // 60 - // 61 - // Setting all properties here is good for readability, // 62 - // and also may help Chrome optimize the code by keeping // 63 - // the View object from changing shape too much. // 64 - this.isCreated = false; // 65 - this._isCreatedForExpansion = false; // 66 - this.isRendered = false; // 67 - this._isAttached = false; // 68 - this.isDestroyed = false; // 69 - this._isInRender = false; // 70 - this.parentView = null; // 71 - this._domrange = null; // 72 - // This flag is normally set to false except for the cases when view's parent // 73 - // was generated as part of expanding some syntactic sugar expressions or // 74 - // methods. // 75 - // Ex.: Blaze.renderWithData is an equivalent to creating a view with regular // 76 - // Blaze.render and wrapping it into {{#with data}}{{/with}} view. Since the // 77 - // users don't know anything about these generated parent views, Blaze needs // 78 - // this information to be available on views to make smarter decisions. For // 79 - // example: removing the generated parent view with the view on Blaze.remove. // 80 - this._hasGeneratedParent = false; // 81 - // 82 - this.renderCount = 0; // 83 -}; // 84 - // 85 -Blaze.View.prototype._render = function () { return null; }; // 86 - // 87 -Blaze.View.prototype.onViewCreated = function (cb) { // 88 - this._callbacks.created = this._callbacks.created || []; // 89 - this._callbacks.created.push(cb); // 90 -}; // 91 - // 92 -Blaze.View.prototype._onViewRendered = function (cb) { // 93 - this._callbacks.rendered = this._callbacks.rendered || []; // 94 - this._callbacks.rendered.push(cb); // 95 -}; // 96 - // 97 -Blaze.View.prototype.onViewReady = function (cb) { // 98 - var self = this; // 99 - var fire = function () { // 100 - Tracker.afterFlush(function () { // 101 - if (! self.isDestroyed) { // 102 - Blaze._withCurrentView(self, function () { // 103 - cb.call(self); // 104 - }); // 105 - } // 106 - }); // 107 - }; // 108 - self._onViewRendered(function onViewRendered() { // 109 - if (self.isDestroyed) // 110 - return; // 111 - if (! self._domrange.attached) // 112 - self._domrange.onAttached(fire); // 113 - else // 114 - fire(); // 115 - }); // 116 -}; // 117 - // 118 -Blaze.View.prototype.onViewDestroyed = function (cb) { // 119 - this._callbacks.destroyed = this._callbacks.destroyed || []; // 120 - this._callbacks.destroyed.push(cb); // 121 -}; // 122 - // 123 -/// View#autorun(func) // 124 -/// // 125 -/// Sets up a Tracker autorun that is "scoped" to this View in two // 126 -/// important ways: 1) Blaze.currentView is automatically set // 127 -/// on every re-run, and 2) the autorun is stopped when the // 128 -/// View is destroyed. As with Tracker.autorun, the first run of // 129 -/// the function is immediate, and a Computation object that can // 130 -/// be used to stop the autorun is returned. // 131 -/// // 132 -/// View#autorun is meant to be called from View callbacks like // 133 -/// onViewCreated, or from outside the rendering process. It may not // 134 -/// be called before the onViewCreated callbacks are fired (too early), // 135 -/// or from a render() method (too confusing). // 136 -/// // 137 -/// Typically, autoruns that update the state // 138 -/// of the View (as in Blaze.With) should be started from an onViewCreated // 139 -/// callback. Autoruns that update the DOM should be started // 140 -/// from either onViewCreated (guarded against the absence of // 141 -/// view._domrange), or onViewReady. // 142 -Blaze.View.prototype.autorun = function (f, _inViewScope, displayName) { // 143 - var self = this; // 144 - // 145 - // The restrictions on when View#autorun can be called are in order // 146 - // to avoid bad patterns, like creating a Blaze.View and immediately // 147 - // calling autorun on it. A freshly created View is not ready to // 148 - // have logic run on it; it doesn't have a parentView, for example. // 149 - // It's when the View is materialized or expanded that the onViewCreated // 150 - // handlers are fired and the View starts up. // 151 - // // 152 - // Letting the render() method call `this.autorun()` is problematic // 153 - // because of re-render. The best we can do is to stop the old // 154 - // autorun and start a new one for each render, but that's a pattern // 155 - // we try to avoid internally because it leads to helpers being // 156 - // called extra times, in the case where the autorun causes the // 157 - // view to re-render (and thus the autorun to be torn down and a // 158 - // new one established). // 159 - // // 160 - // We could lift these restrictions in various ways. One interesting // 161 - // idea is to allow you to call `view.autorun` after instantiating // 162 - // `view`, and automatically wrap it in `view.onViewCreated`, deferring // 163 - // the autorun so that it starts at an appropriate time. However, // 164 - // then we can't return the Computation object to the caller, because // 165 - // it doesn't exist yet. // 166 - if (! self.isCreated) { // 167 - throw new Error("View#autorun must be called from the created callback at the earliest"); // 168 - } // 169 - if (this._isInRender) { // 170 - throw new Error("Can't call View#autorun from inside render(); try calling it from the created or rendered callback"); - } // 172 - if (Tracker.active) { // 173 - throw new Error("Can't call View#autorun from a Tracker Computation; try calling it from the created or rendered callback"); - } // 175 - // 176 - // Each local variable allocate additional space on each frame of the // 177 - // execution stack. When too many variables are allocated on stack, you can // 178 - // run out of memory on stack running a deep recursion (which is typical for // 179 - // Blaze functions) and get stackoverlow error. (The size of the stack varies // 180 - // between browsers). // 181 - // The trick we use here is to allocate only one variable on stack `locals` // 182 - // that keeps references to all the rest. Since locals is allocated on heap, // 183 - // we don't take up any space on the stack. // 184 - var locals = {}; // 185 - locals.templateInstanceFunc = Blaze.Template._currentTemplateInstanceFunc; // 186 - // 187 - locals.f = function viewAutorun(c) { // 188 - return Blaze._withCurrentView(_inViewScope || self, function () { // 189 - return Blaze.Template._withTemplateInstanceFunc(locals.templateInstanceFunc, function () { // 190 - return f.call(self, c); // 191 - }); // 192 - }); // 193 - }; // 194 - // 195 - // Give the autorun function a better name for debugging and profiling. // 196 - // The `displayName` property is not part of the spec but browsers like Chrome // 197 - // and Firefox prefer it in debuggers over the name function was declared by. // 198 - locals.f.displayName = // 199 - (self.name || 'anonymous') + ':' + (displayName || 'anonymous'); // 200 - locals.c = Tracker.autorun(locals.f); // 201 - // 202 - self.onViewDestroyed(function () { locals.c.stop(); }); // 203 - // 204 - return locals.c; // 205 -}; // 206 - // 207 -Blaze.View.prototype._errorIfShouldntCallSubscribe = function () { // 208 - var self = this; // 209 - // 210 - if (! self.isCreated) { // 211 - throw new Error("View#subscribe must be called from the created callback at the earliest"); // 212 - } // 213 - if (self._isInRender) { // 214 - throw new Error("Can't call View#subscribe from inside render(); try calling it from the created or rendered callback"); - } // 216 - if (self.isDestroyed) { // 217 - throw new Error("Can't call View#subscribe from inside the destroyed callback, try calling it inside created or rendered."); - } // 219 -}; // 220 - // 221 -/** // 222 - * Just like Blaze.View#autorun, but with Meteor.subscribe instead of // 223 - * Tracker.autorun. Stop the subscription when the view is destroyed. // 224 - * @return {SubscriptionHandle} A handle to the subscription so that you can // 225 - * see if it is ready, or stop it manually // 226 - */ // 227 -Blaze.View.prototype.subscribe = function (args, options) { // 228 - var self = this; // 229 - options = {} || options; // 230 - // 231 - self._errorIfShouldntCallSubscribe(); // 232 - // 233 - var subHandle; // 234 - if (options.connection) { // 235 - subHandle = options.connection.subscribe.apply(options.connection, args); // 236 - } else { // 237 - subHandle = Meteor.subscribe.apply(Meteor, args); // 238 - } // 239 - // 240 - self.onViewDestroyed(function () { // 241 - subHandle.stop(); // 242 - }); // 243 - // 244 - return subHandle; // 245 -}; // 246 - // 247 -Blaze.View.prototype.firstNode = function () { // 248 - if (! this._isAttached) // 249 - throw new Error("View must be attached before accessing its DOM"); // 250 - // 251 - return this._domrange.firstNode(); // 252 -}; // 253 - // 254 -Blaze.View.prototype.lastNode = function () { // 255 - if (! this._isAttached) // 256 - throw new Error("View must be attached before accessing its DOM"); // 257 - // 258 - return this._domrange.lastNode(); // 259 -}; // 260 - // 261 -Blaze._fireCallbacks = function (view, which) { // 262 - Blaze._withCurrentView(view, function () { // 263 - Tracker.nonreactive(function fireCallbacks() { // 264 - var cbs = view._callbacks[which]; // 265 - for (var i = 0, N = (cbs && cbs.length); i < N; i++) // 266 - cbs[i].call(view); // 267 - }); // 268 - }); // 269 -}; // 270 - // 271 -Blaze._createView = function (view, parentView, forExpansion) { // 272 - if (view.isCreated) // 273 - throw new Error("Can't render the same View twice"); // 274 - // 275 - view.parentView = (parentView || null); // 276 - view.isCreated = true; // 277 - if (forExpansion) // 278 - view._isCreatedForExpansion = true; // 279 - // 280 - Blaze._fireCallbacks(view, 'created'); // 281 -}; // 282 - // 283 -var doFirstRender = function (view, initialContent) { // 284 - var domrange = new Blaze._DOMRange(initialContent); // 285 - view._domrange = domrange; // 286 - domrange.view = view; // 287 - view.isRendered = true; // 288 - Blaze._fireCallbacks(view, 'rendered'); // 289 - // 290 - var teardownHook = null; // 291 - // 292 - domrange.onAttached(function attached(range, element) { // 293 - view._isAttached = true; // 294 - // 295 - teardownHook = Blaze._DOMBackend.Teardown.onElementTeardown( // 296 - element, function teardown() { // 297 - Blaze._destroyView(view, true /* _skipNodes */); // 298 - }); // 299 - }); // 300 - // 301 - // tear down the teardown hook // 302 - view.onViewDestroyed(function () { // 303 - teardownHook && teardownHook.stop(); // 304 - teardownHook = null; // 305 - }); // 306 - // 307 - return domrange; // 308 -}; // 309 - // 310 -// Take an uncreated View `view` and create and render it to DOM, // 311 -// setting up the autorun that updates the View. Returns a new // 312 -// DOMRange, which has been associated with the View. // 313 -// // 314 -// The private arguments `_workStack` and `_intoArray` are passed in // 315 -// by Blaze._materializeDOM. If provided, then we avoid the mutual // 316 -// recursion of calling back into Blaze._materializeDOM so that deep // 317 -// View hierarchies don't blow the stack. Instead, we push tasks onto // 318 -// workStack for the initial rendering and subsequent setup of the // 319 -// View, and they are done after we return. When there is a // 320 -// _workStack, we do not return the new DOMRange, but instead push it // 321 -// into _intoArray from a _workStack task. // 322 -Blaze._materializeView = function (view, parentView, _workStack, _intoArray) { // 323 - Blaze._createView(view, parentView); // 324 - // 325 - var domrange; // 326 - var lastHtmljs; // 327 - // We don't expect to be called in a Computation, but just in case, // 328 - // wrap in Tracker.nonreactive. // 329 - Tracker.nonreactive(function () { // 330 - view.autorun(function doRender(c) { // 331 - // `view.autorun` sets the current view. // 332 - view.renderCount++; // 333 - view._isInRender = true; // 334 - // Any dependencies that should invalidate this Computation come // 335 - // from this line: // 336 - var htmljs = view._render(); // 337 - view._isInRender = false; // 338 - // 339 - if (! c.firstRun) { // 340 - Tracker.nonreactive(function doMaterialize() { // 341 - // re-render // 342 - var rangesAndNodes = Blaze._materializeDOM(htmljs, [], view); // 343 - if (! Blaze._isContentEqual(lastHtmljs, htmljs)) { // 344 - domrange.setMembers(rangesAndNodes); // 345 - Blaze._fireCallbacks(view, 'rendered'); // 346 - } // 347 - }); // 348 - } // 349 - lastHtmljs = htmljs; // 350 - // 351 - // Causes any nested views to stop immediately, not when we call // 352 - // `setMembers` the next time around the autorun. Otherwise, // 353 - // helpers in the DOM tree to be replaced might be scheduled // 354 - // to re-run before we have a chance to stop them. // 355 - Tracker.onInvalidate(function () { // 356 - if (domrange) { // 357 - domrange.destroyMembers(); // 358 - } // 359 - }); // 360 - }, undefined, 'materialize'); // 361 - // 362 - // first render. lastHtmljs is the first htmljs. // 363 - var initialContents; // 364 - if (! _workStack) { // 365 - initialContents = Blaze._materializeDOM(lastHtmljs, [], view); // 366 - domrange = doFirstRender(view, initialContents); // 367 - initialContents = null; // help GC because we close over this scope a lot // 368 - } else { // 369 - // We're being called from Blaze._materializeDOM, so to avoid // 370 - // recursion and save stack space, provide a description of the // 371 - // work to be done instead of doing it. Tasks pushed onto // 372 - // _workStack will be done in LIFO order after we return. // 373 - // The work will still be done within a Tracker.nonreactive, // 374 - // because it will be done by some call to Blaze._materializeDOM // 375 - // (which is always called in a Tracker.nonreactive). // 376 - initialContents = []; // 377 - // push this function first so that it happens last // 378 - _workStack.push(function () { // 379 - domrange = doFirstRender(view, initialContents); // 380 - initialContents = null; // help GC because of all the closures here // 381 - _intoArray.push(domrange); // 382 - }); // 383 - // now push the task that calculates initialContents // 384 - _workStack.push([lastHtmljs, initialContents, view]); // 385 - } // 386 - }); // 387 - // 388 - if (! _workStack) { // 389 - return domrange; // 390 - } else { // 391 - return null; // 392 - } // 393 -}; // 394 - // 395 -// Expands a View to HTMLjs, calling `render` recursively on all // 396 -// Views and evaluating any dynamic attributes. Calls the `created` // 397 -// callback, but not the `materialized` or `rendered` callbacks. // 398 -// Destroys the view immediately, unless called in a Tracker Computation, // 399 -// in which case the view will be destroyed when the Computation is // 400 -// invalidated. If called in a Tracker Computation, the result is a // 401 -// reactive string; that is, the Computation will be invalidated // 402 -// if any changes are made to the view or subviews that might affect // 403 -// the HTML. // 404 -Blaze._expandView = function (view, parentView) { // 405 - Blaze._createView(view, parentView, true /*forExpansion*/); // 406 - // 407 - view._isInRender = true; // 408 - var htmljs = Blaze._withCurrentView(view, function () { // 409 - return view._render(); // 410 - }); // 411 - view._isInRender = false; // 412 - // 413 - var result = Blaze._expand(htmljs, view); // 414 - // 415 - if (Tracker.active) { // 416 - Tracker.onInvalidate(function () { // 417 - Blaze._destroyView(view); // 418 - }); // 419 - } else { // 420 - Blaze._destroyView(view); // 421 - } // 422 - // 423 - return result; // 424 -}; // 425 - // 426 -// Options: `parentView` // 427 -Blaze._HTMLJSExpander = HTML.TransformingVisitor.extend(); // 428 -Blaze._HTMLJSExpander.def({ // 429 - visitObject: function (x) { // 430 - if (x instanceof Blaze.Template) // 431 - x = x.constructView(); // 432 - if (x instanceof Blaze.View) // 433 - return Blaze._expandView(x, this.parentView); // 434 - // 435 - // this will throw an error; other objects are not allowed! // 436 - return HTML.TransformingVisitor.prototype.visitObject.call(this, x); // 437 - }, // 438 - visitAttributes: function (attrs) { // 439 - // expand dynamic attributes // 440 - if (typeof attrs === 'function') // 441 - attrs = Blaze._withCurrentView(this.parentView, attrs); // 442 - // 443 - // call super (e.g. for case where `attrs` is an array) // 444 - return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs); // 445 - }, // 446 - visitAttribute: function (name, value, tag) { // 447 - // expand attribute values that are functions. Any attribute value // 448 - // that contains Views must be wrapped in a function. // 449 - if (typeof value === 'function') // 450 - value = Blaze._withCurrentView(this.parentView, value); // 451 - // 452 - return HTML.TransformingVisitor.prototype.visitAttribute.call( // 453 - this, name, value, tag); // 454 - } // 455 -}); // 456 - // 457 -// Return Blaze.currentView, but only if it is being rendered // 458 -// (i.e. we are in its render() method). // 459 -var currentViewIfRendering = function () { // 460 - var view = Blaze.currentView; // 461 - return (view && view._isInRender) ? view : null; // 462 -}; // 463 - // 464 -Blaze._expand = function (htmljs, parentView) { // 465 - parentView = parentView || currentViewIfRendering(); // 466 - return (new Blaze._HTMLJSExpander( // 467 - {parentView: parentView})).visit(htmljs); // 468 -}; // 469 - // 470 -Blaze._expandAttributes = function (attrs, parentView) { // 471 - parentView = parentView || currentViewIfRendering(); // 472 - return (new Blaze._HTMLJSExpander( // 473 - {parentView: parentView})).visitAttributes(attrs); // 474 -}; // 475 - // 476 -Blaze._destroyView = function (view, _skipNodes) { // 477 - if (view.isDestroyed) // 478 - return; // 479 - view.isDestroyed = true; // 480 - // 481 - Blaze._fireCallbacks(view, 'destroyed'); // 482 - // 483 - // Destroy views and elements recursively. If _skipNodes, // 484 - // only recurse up to views, not elements, for the case where // 485 - // the backend (jQuery) is recursing over the elements already. // 486 - // 487 - if (view._domrange) // 488 - view._domrange.destroyMembers(_skipNodes); // 489 -}; // 490 - // 491 -Blaze._destroyNode = function (node) { // 492 - if (node.nodeType === 1) // 493 - Blaze._DOMBackend.Teardown.tearDownElement(node); // 494 -}; // 495 - // 496 -// Are the HTMLjs entities `a` and `b` the same? We could be // 497 -// more elaborate here but the point is to catch the most basic // 498 -// cases. // 499 -Blaze._isContentEqual = function (a, b) { // 500 - if (a instanceof HTML.Raw) { // 501 - return (b instanceof HTML.Raw) && (a.value === b.value); // 502 - } else if (a == null) { // 503 - return (b == null); // 504 - } else { // 505 - return (a === b) && // 506 - ((typeof a === 'number') || (typeof a === 'boolean') || // 507 - (typeof a === 'string')); // 508 - } // 509 -}; // 510 - // 511 -/** // 512 - * @summary The View corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`. - * @locus Client // 514 - * @type {Blaze.View} // 515 - */ // 516 -Blaze.currentView = null; // 517 - // 518 -Blaze._withCurrentView = function (view, func) { // 519 - var oldView = Blaze.currentView; // 520 - try { // 521 - Blaze.currentView = view; // 522 - return func(); // 523 - } finally { // 524 - Blaze.currentView = oldView; // 525 - } // 526 -}; // 527 - // 528 -// Blaze.render publicly takes a View or a Template. // 529 -// Privately, it takes any HTMLJS (extended with Views and Templates) // 530 -// except null or undefined, or a function that returns any extended // 531 -// HTMLJS. // 532 -var checkRenderContent = function (content) { // 533 - if (content === null) // 534 - throw new Error("Can't render null"); // 535 - if (typeof content === 'undefined') // 536 - throw new Error("Can't render undefined"); // 537 - // 538 - if ((content instanceof Blaze.View) || // 539 - (content instanceof Blaze.Template) || // 540 - (typeof content === 'function')) // 541 - return; // 542 - // 543 - try { // 544 - // Throw if content doesn't look like HTMLJS at the top level // 545 - // (i.e. verify that this is an HTML.Tag, or an array, // 546 - // or a primitive, etc.) // 547 - (new HTML.Visitor).visit(content); // 548 - } catch (e) { // 549 - // Make error message suitable for public API // 550 - throw new Error("Expected Template or View"); // 551 - } // 552 -}; // 553 - // 554 -// For Blaze.render and Blaze.toHTML, take content and // 555 -// wrap it in a View, unless it's a single View or // 556 -// Template already. // 557 -var contentAsView = function (content) { // 558 - checkRenderContent(content); // 559 - // 560 - if (content instanceof Blaze.Template) { // 561 - return content.constructView(); // 562 - } else if (content instanceof Blaze.View) { // 563 - return content; // 564 - } else { // 565 - var func = content; // 566 - if (typeof func !== 'function') { // 567 - func = function () { // 568 - return content; // 569 - }; // 570 - } // 571 - return Blaze.View('render', func); // 572 - } // 573 -}; // 574 - // 575 -// For Blaze.renderWithData and Blaze.toHTMLWithData, wrap content // 576 -// in a function, if necessary, so it can be a content arg to // 577 -// a Blaze.With. // 578 -var contentAsFunc = function (content) { // 579 - checkRenderContent(content); // 580 - // 581 - if (typeof content !== 'function') { // 582 - return function () { // 583 - return content; // 584 - }; // 585 - } else { // 586 - return content; // 587 - } // 588 -}; // 589 - // 590 -/** // 591 - * @summary Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered [View](#blaze_view) which can be passed to [`Blaze.remove`](#blaze_remove). - * @locus Client // 593 - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render. If a template, a View object is [constructed](#template_constructview). If a View, it must be an unrendered View, which becomes a rendered View and is returned. - * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node. // 595 - * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode. - * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview). - */ // 598 -Blaze.render = function (content, parentElement, nextNode, parentView) { // 599 - if (! parentElement) { // 600 - Blaze._warn("Blaze.render without a parent element is deprecated. " + // 601 - "You must specify where to insert the rendered content."); // 602 - } // 603 - // 604 - if (nextNode instanceof Blaze.View) { // 605 - // handle omitted nextNode // 606 - parentView = nextNode; // 607 - nextNode = null; // 608 - } // 609 - // 610 - // parentElement must be a DOM node. in particular, can't be the // 611 - // result of a call to `$`. Can't check if `parentElement instanceof // 612 - // Node` since 'Node' is undefined in IE8. // 613 - if (parentElement && typeof parentElement.nodeType !== 'number') // 614 - throw new Error("'parentElement' must be a DOM node"); // 615 - if (nextNode && typeof nextNode.nodeType !== 'number') // 'nextNode' is optional // 616 - throw new Error("'nextNode' must be a DOM node"); // 617 - // 618 - parentView = parentView || currentViewIfRendering(); // 619 - // 620 - var view = contentAsView(content); // 621 - Blaze._materializeView(view, parentView); // 622 - // 623 - if (parentElement) { // 624 - view._domrange.attach(parentElement, nextNode); // 625 - } // 626 - // 627 - return view; // 628 -}; // 629 - // 630 -Blaze.insert = function (view, parentElement, nextNode) { // 631 - Blaze._warn("Blaze.insert has been deprecated. Specify where to insert the " + // 632 - "rendered content in the call to Blaze.render."); // 633 - // 634 - if (! (view && (view._domrange instanceof Blaze._DOMRange))) // 635 - throw new Error("Expected template rendered with Blaze.render"); // 636 - // 637 - view._domrange.attach(parentElement, nextNode); // 638 -}; // 639 - // 640 -/** // 641 - * @summary Renders a template or View to DOM nodes with a data context. Otherwise identical to `Blaze.render`. // 642 - * @locus Client // 643 - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render. // 644 - * @param {Object|Function} data The data context to use, or a function returning a data context. If a function is provided, it will be reactively re-run. - * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node. // 646 - * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode. - * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview). - */ // 649 -Blaze.renderWithData = function (content, data, parentElement, nextNode, parentView) { // 650 - // We defer the handling of optional arguments to Blaze.render. At this point, // 651 - // `nextNode` may actually be `parentView`. // 652 - return Blaze.render(Blaze._TemplateWith(data, contentAsFunc(content)), // 653 - parentElement, nextNode, parentView); // 654 -}; // 655 - // 656 -/** // 657 - * @summary Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it. // 658 - * @locus Client // 659 - * @param {Blaze.View} renderedView The return value from `Blaze.render` or `Blaze.renderWithData`. // 660 - */ // 661 -Blaze.remove = function (view) { // 662 - if (! (view && (view._domrange instanceof Blaze._DOMRange))) // 663 - throw new Error("Expected template rendered with Blaze.render"); // 664 - // 665 - while (view) { // 666 - if (! view.isDestroyed) { // 667 - var range = view._domrange; // 668 - if (range.attached && ! range.parentRange) // 669 - range.detach(); // 670 - range.destroy(); // 671 - } // 672 - // 673 - view = view._hasGeneratedParent && view.parentView; // 674 - } // 675 -}; // 676 - // 677 -/** // 678 - * @summary Renders a template or View to a string of HTML. // 679 - * @locus Client // 680 - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML. - */ // 682 -Blaze.toHTML = function (content, parentView) { // 683 - parentView = parentView || currentViewIfRendering(); // 684 - // 685 - return HTML.toHTML(Blaze._expandView(contentAsView(content), parentView)); // 686 -}; // 687 - // 688 -/** // 689 - * @summary Renders a template or View to HTML with a data context. Otherwise identical to `Blaze.toHTML`. // 690 - * @locus Client // 691 - * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML. - * @param {Object|Function} data The data context to use, or a function returning a data context. // 693 - */ // 694 -Blaze.toHTMLWithData = function (content, data, parentView) { // 695 - parentView = parentView || currentViewIfRendering(); // 696 - // 697 - return HTML.toHTML(Blaze._expandView(Blaze._TemplateWith( // 698 - data, contentAsFunc(content)), parentView)); // 699 -}; // 700 - // 701 -Blaze._toText = function (htmljs, parentView, textMode) { // 702 - if (typeof htmljs === 'function') // 703 - throw new Error("Blaze._toText doesn't take a function, just HTMLjs"); // 704 - // 705 - if ((parentView != null) && ! (parentView instanceof Blaze.View)) { // 706 - // omitted parentView argument // 707 - textMode = parentView; // 708 - parentView = null; // 709 - } // 710 - parentView = parentView || currentViewIfRendering(); // 711 - // 712 - if (! textMode) // 713 - throw new Error("textMode required"); // 714 - if (! (textMode === HTML.TEXTMODE.STRING || // 715 - textMode === HTML.TEXTMODE.RCDATA || // 716 - textMode === HTML.TEXTMODE.ATTRIBUTE)) // 717 - throw new Error("Unknown textMode: " + textMode); // 718 - // 719 - return HTML.toText(Blaze._expand(htmljs, parentView), textMode); // 720 -}; // 721 - // 722 -/** // 723 - * @summary Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template. - * @locus Client // 725 - * @param {DOMElement|Blaze.View} [elementOrView] Optional. An element that was rendered by a Meteor, or a View. // 726 - */ // 727 -Blaze.getData = function (elementOrView) { // 728 - var theWith; // 729 - // 730 - if (! elementOrView) { // 731 - theWith = Blaze.getView('with'); // 732 - } else if (elementOrView instanceof Blaze.View) { // 733 - var view = elementOrView; // 734 - theWith = (view.name === 'with' ? view : // 735 - Blaze.getView(view, 'with')); // 736 - } else if (typeof elementOrView.nodeType === 'number') { // 737 - if (elementOrView.nodeType !== 1) // 738 - throw new Error("Expected DOM element"); // 739 - theWith = Blaze.getView(elementOrView, 'with'); // 740 - } else { // 741 - throw new Error("Expected DOM element or View"); // 742 - } // 743 - // 744 - return theWith ? theWith.dataVar.get() : null; // 745 -}; // 746 - // 747 -// For back-compat // 748 -Blaze.getElementData = function (element) { // 749 - Blaze._warn("Blaze.getElementData has been deprecated. Use " + // 750 - "Blaze.getData(element) instead."); // 751 - // 752 - if (element.nodeType !== 1) // 753 - throw new Error("Expected DOM element"); // 754 - // 755 - return Blaze.getData(element); // 756 -}; // 757 - // 758 -// Both arguments are optional. // 759 - // 760 -/** // 761 - * @summary Gets either the current View, or the View enclosing the given DOM element. // 762 - * @locus Client // 763 - * @param {DOMElement} [element] Optional. If specified, the View enclosing `element` is returned. // 764 - */ // 765 -Blaze.getView = function (elementOrView, _viewName) { // 766 - var viewName = _viewName; // 767 - // 768 - if ((typeof elementOrView) === 'string') { // 769 - // omitted elementOrView; viewName present // 770 - viewName = elementOrView; // 771 - elementOrView = null; // 772 - } // 773 - // 774 - // We could eventually shorten the code by folding the logic // 775 - // from the other methods into this method. // 776 - if (! elementOrView) { // 777 - return Blaze._getCurrentView(viewName); // 778 - } else if (elementOrView instanceof Blaze.View) { // 779 - return Blaze._getParentView(elementOrView, viewName); // 780 - } else if (typeof elementOrView.nodeType === 'number') { // 781 - return Blaze._getElementView(elementOrView, viewName); // 782 - } else { // 783 - throw new Error("Expected DOM element or View"); // 784 - } // 785 -}; // 786 - // 787 -// Gets the current view or its nearest ancestor of name // 788 -// `name`. // 789 -Blaze._getCurrentView = function (name) { // 790 - var view = Blaze.currentView; // 791 - // Better to fail in cases where it doesn't make sense // 792 - // to use Blaze._getCurrentView(). There will be a current // 793 - // view anywhere it does. You can check Blaze.currentView // 794 - // if you want to know whether there is one or not. // 795 - if (! view) // 796 - throw new Error("There is no current view"); // 797 - // 798 - if (name) { // 799 - while (view && view.name !== name) // 800 - view = view.parentView; // 801 - return view || null; // 802 - } else { // 803 - // Blaze._getCurrentView() with no arguments just returns // 804 - // Blaze.currentView. // 805 - return view; // 806 - } // 807 -}; // 808 - // 809 -Blaze._getParentView = function (view, name) { // 810 - var v = view.parentView; // 811 - // 812 - if (name) { // 813 - while (v && v.name !== name) // 814 - v = v.parentView; // 815 - } // 816 - // 817 - return v || null; // 818 -}; // 819 - // 820 -Blaze._getElementView = function (elem, name) { // 821 - var range = Blaze._DOMRange.forElement(elem); // 822 - var view = null; // 823 - while (range && ! view) { // 824 - view = (range.view || null); // 825 - if (! view) { // 826 - if (range.parentRange) // 827 - range = range.parentRange; // 828 - else // 829 - range = Blaze._DOMRange.forElement(range.parentElement); // 830 - } // 831 - } // 832 - // 833 - if (name) { // 834 - while (view && view.name !== name) // 835 - view = view.parentView; // 836 - return view || null; // 837 - } else { // 838 - return view; // 839 - } // 840 -}; // 841 - // 842 -Blaze._addEventMap = function (view, eventMap, thisInHandler) { // 843 - thisInHandler = (thisInHandler || null); // 844 - var handles = []; // 845 - // 846 - if (! view._domrange) // 847 - throw new Error("View must have a DOMRange"); // 848 - // 849 - view._domrange.onAttached(function attached_eventMaps(range, element) { // 850 - _.each(eventMap, function (handler, spec) { // 851 - var clauses = spec.split(/,\s+/); // 852 - // iterate over clauses of spec, e.g. ['click .foo', 'click .bar'] // 853 - _.each(clauses, function (clause) { // 854 - var parts = clause.split(/\s+/); // 855 - if (parts.length === 0) // 856 - return; // 857 - // 858 - var newEvents = parts.shift(); // 859 - var selector = parts.join(' '); // 860 - handles.push(Blaze._EventSupport.listen( // 861 - element, newEvents, selector, // 862 - function (evt) { // 863 - if (! range.containsElement(evt.currentTarget)) // 864 - return null; // 865 - var handlerThis = thisInHandler || this; // 866 - var handlerArgs = arguments; // 867 - return Blaze._withCurrentView(view, function () { // 868 - return handler.apply(handlerThis, handlerArgs); // 869 - }); // 870 - }, // 871 - range, function (r) { // 872 - return r.parentRange; // 873 - })); // 874 - }); // 875 - }); // 876 - }); // 877 - // 878 - view.onViewDestroyed(function () { // 879 - _.each(handles, function (h) { // 880 - h.stop(); // 881 - }); // 882 - handles.length = 0; // 883 - }); // 884 -}; // 885 - // 886 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/builtins.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -Blaze._calculateCondition = function (cond) { // 1 - if (cond instanceof Array && cond.length === 0) // 2 - cond = false; // 3 - return !! cond; // 4 -}; // 5 - // 6 -/** // 7 - * @summary Constructs a View that renders content with a data context. // 8 - * @locus Client // 9 - * @param {Object|Function} data An object to use as the data context, or a function returning such an object. If a function is provided, it will be reactively re-run. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). // 11 - */ // 12 -Blaze.With = function (data, contentFunc) { // 13 - var view = Blaze.View('with', contentFunc); // 14 - // 15 - view.dataVar = new ReactiveVar; // 16 - // 17 - view.onViewCreated(function () { // 18 - if (typeof data === 'function') { // 19 - // `data` is a reactive function // 20 - view.autorun(function () { // 21 - view.dataVar.set(data()); // 22 - }, view.parentView, 'setData'); // 23 - } else { // 24 - view.dataVar.set(data); // 25 - } // 26 - }); // 27 - // 28 - return view; // 29 -}; // 30 - // 31 -/** // 32 - * @summary Constructs a View that renders content conditionally. // 33 - * @locus Client // 34 - * @param {Function} conditionFunc A function to reactively re-run. Whether the result is truthy or falsy determines whether `contentFunc` or `elseFunc` is shown. An empty array is considered falsy. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). // 36 - * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the "else" case. - */ // 38 -Blaze.If = function (conditionFunc, contentFunc, elseFunc, _not) { // 39 - var conditionVar = new ReactiveVar; // 40 - // 41 - var view = Blaze.View(_not ? 'unless' : 'if', function () { // 42 - return conditionVar.get() ? contentFunc() : // 43 - (elseFunc ? elseFunc() : null); // 44 - }); // 45 - view.__conditionVar = conditionVar; // 46 - view.onViewCreated(function () { // 47 - this.autorun(function () { // 48 - var cond = Blaze._calculateCondition(conditionFunc()); // 49 - conditionVar.set(_not ? (! cond) : cond); // 50 - }, this.parentView, 'condition'); // 51 - }); // 52 - // 53 - return view; // 54 -}; // 55 - // 56 -/** // 57 - * @summary An inverted [`Blaze.If`](#blaze_if). // 58 - * @locus Client // 59 - * @param {Function} conditionFunc A function to reactively re-run. If the result is falsy, `contentFunc` is shown, otherwise `elseFunc` is shown. An empty array is considered falsy. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). // 61 - * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the "else" case. - */ // 63 -Blaze.Unless = function (conditionFunc, contentFunc, elseFunc) { // 64 - return Blaze.If(conditionFunc, contentFunc, elseFunc, true /*_not*/); // 65 -}; // 66 - // 67 -/** // 68 - * @summary Constructs a View that renders `contentFunc` for each item in a sequence. // 69 - * @locus Client // 70 - * @param {Function} argFunc A function to reactively re-run. The function may return a Cursor, an array, null, or undefined. - * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content). // 72 - * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content) to display in the case when there are no items to display. - */ // 74 -Blaze.Each = function (argFunc, contentFunc, elseFunc) { // 75 - var eachView = Blaze.View('each', function () { // 76 - var subviews = this.initialSubviews; // 77 - this.initialSubviews = null; // 78 - if (this._isCreatedForExpansion) { // 79 - this.expandedValueDep = new Tracker.Dependency; // 80 - this.expandedValueDep.depend(); // 81 - } // 82 - return subviews; // 83 - }); // 84 - eachView.initialSubviews = []; // 85 - eachView.numItems = 0; // 86 - eachView.inElseMode = false; // 87 - eachView.stopHandle = null; // 88 - eachView.contentFunc = contentFunc; // 89 - eachView.elseFunc = elseFunc; // 90 - eachView.argVar = new ReactiveVar; // 91 - // 92 - eachView.onViewCreated(function () { // 93 - // We evaluate argFunc in an autorun to make sure // 94 - // Blaze.currentView is always set when it runs (rather than // 95 - // passing argFunc straight to ObserveSequence). // 96 - eachView.autorun(function () { // 97 - eachView.argVar.set(argFunc()); // 98 - }, eachView.parentView, 'collection'); // 99 - // 100 - eachView.stopHandle = ObserveSequence.observe(function () { // 101 - return eachView.argVar.get(); // 102 - }, { // 103 - addedAt: function (id, item, index) { // 104 - Tracker.nonreactive(function () { // 105 - var newItemView = Blaze.With(item, eachView.contentFunc); // 106 - eachView.numItems++; // 107 - // 108 - if (eachView.expandedValueDep) { // 109 - eachView.expandedValueDep.changed(); // 110 - } else if (eachView._domrange) { // 111 - if (eachView.inElseMode) { // 112 - eachView._domrange.removeMember(0); // 113 - eachView.inElseMode = false; // 114 - } // 115 - // 116 - var range = Blaze._materializeView(newItemView, eachView); // 117 - eachView._domrange.addMember(range, index); // 118 - } else { // 119 - eachView.initialSubviews.splice(index, 0, newItemView); // 120 - } // 121 - }); // 122 - }, // 123 - removedAt: function (id, item, index) { // 124 - Tracker.nonreactive(function () { // 125 - eachView.numItems--; // 126 - if (eachView.expandedValueDep) { // 127 - eachView.expandedValueDep.changed(); // 128 - } else if (eachView._domrange) { // 129 - eachView._domrange.removeMember(index); // 130 - if (eachView.elseFunc && eachView.numItems === 0) { // 131 - eachView.inElseMode = true; // 132 - eachView._domrange.addMember( // 133 - Blaze._materializeView( // 134 - Blaze.View('each_else',eachView.elseFunc), // 135 - eachView), 0); // 136 - } // 137 - } else { // 138 - eachView.initialSubviews.splice(index, 1); // 139 - } // 140 - }); // 141 - }, // 142 - changedAt: function (id, newItem, oldItem, index) { // 143 - Tracker.nonreactive(function () { // 144 - if (eachView.expandedValueDep) { // 145 - eachView.expandedValueDep.changed(); // 146 - } else { // 147 - var itemView; // 148 - if (eachView._domrange) { // 149 - itemView = eachView._domrange.getMember(index).view; // 150 - } else { // 151 - itemView = eachView.initialSubviews[index]; // 152 - } // 153 - itemView.dataVar.set(newItem); // 154 - } // 155 - }); // 156 - }, // 157 - movedTo: function (id, item, fromIndex, toIndex) { // 158 - Tracker.nonreactive(function () { // 159 - if (eachView.expandedValueDep) { // 160 - eachView.expandedValueDep.changed(); // 161 - } else if (eachView._domrange) { // 162 - eachView._domrange.moveMember(fromIndex, toIndex); // 163 - } else { // 164 - var subviews = eachView.initialSubviews; // 165 - var itemView = subviews[fromIndex]; // 166 - subviews.splice(fromIndex, 1); // 167 - subviews.splice(toIndex, 0, itemView); // 168 - } // 169 - }); // 170 - } // 171 - }); // 172 - // 173 - if (eachView.elseFunc && eachView.numItems === 0) { // 174 - eachView.inElseMode = true; // 175 - eachView.initialSubviews[0] = // 176 - Blaze.View('each_else', eachView.elseFunc); // 177 - } // 178 - }); // 179 - // 180 - eachView.onViewDestroyed(function () { // 181 - if (eachView.stopHandle) // 182 - eachView.stopHandle.stop(); // 183 - }); // 184 - // 185 - return eachView; // 186 -}; // 187 - // 188 -Blaze._TemplateWith = function (arg, contentFunc) { // 189 - var w; // 190 - // 191 - var argFunc = arg; // 192 - if (typeof arg !== 'function') { // 193 - argFunc = function () { // 194 - return arg; // 195 - }; // 196 - } // 197 - // 198 - // This is a little messy. When we compile `{{> Template.contentBlock}}`, we // 199 - // wrap it in Blaze._InOuterTemplateScope in order to skip the intermediate // 200 - // parent Views in the current template. However, when there's an argument // 201 - // (`{{> Template.contentBlock arg}}`), the argument needs to be evaluated // 202 - // in the original scope. There's no good order to nest // 203 - // Blaze._InOuterTemplateScope and Spacebars.TemplateWith to achieve this, // 204 - // so we wrap argFunc to run it in the "original parentView" of the // 205 - // Blaze._InOuterTemplateScope. // 206 - // // 207 - // To make this better, reconsider _InOuterTemplateScope as a primitive. // 208 - // Longer term, evaluate expressions in the proper lexical scope. // 209 - var wrappedArgFunc = function () { // 210 - var viewToEvaluateArg = null; // 211 - if (w.parentView && w.parentView.name === 'InOuterTemplateScope') { // 212 - viewToEvaluateArg = w.parentView.originalParentView; // 213 - } // 214 - if (viewToEvaluateArg) { // 215 - return Blaze._withCurrentView(viewToEvaluateArg, argFunc); // 216 - } else { // 217 - return argFunc(); // 218 - } // 219 - }; // 220 - // 221 - var wrappedContentFunc = function () { // 222 - var content = contentFunc.call(this); // 223 - // 224 - // Since we are generating the Blaze._TemplateWith view for the // 225 - // user, set the flag on the child view. If `content` is a template, // 226 - // construct the View so that we can set the flag. // 227 - if (content instanceof Blaze.Template) { // 228 - content = content.constructView(); // 229 - } // 230 - if (content instanceof Blaze.View) { // 231 - content._hasGeneratedParent = true; // 232 - } // 233 - // 234 - return content; // 235 - }; // 236 - // 237 - w = Blaze.With(wrappedArgFunc, wrappedContentFunc); // 238 - w.__isTemplateWith = true; // 239 - return w; // 240 -}; // 241 - // 242 -Blaze._InOuterTemplateScope = function (templateView, contentFunc) { // 243 - var view = Blaze.View('InOuterTemplateScope', contentFunc); // 244 - var parentView = templateView.parentView; // 245 - // 246 - // Hack so that if you call `{{> foo bar}}` and it expands into // 247 - // `{{#with bar}}{{> foo}}{{/with}}`, and then `foo` is a template // 248 - // that inserts `{{> Template.contentBlock}}`, the data context for // 249 - // `Template.contentBlock` is not `bar` but the one enclosing that. // 250 - if (parentView.__isTemplateWith) // 251 - parentView = parentView.parentView; // 252 - // 253 - view.onViewCreated(function () { // 254 - this.originalParentView = this.parentView; // 255 - this.parentView = parentView; // 256 - }); // 257 - return view; // 258 -}; // 259 - // 260 -// XXX COMPAT WITH 0.9.0 // 261 -Blaze.InOuterTemplateScope = Blaze._InOuterTemplateScope; // 262 - // 263 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/lookup.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -Blaze._globalHelpers = {}; // 1 - // 2 -// Documented as Template.registerHelper. // 3 -// This definition also provides back-compat for `UI.registerHelper`. // 4 -Blaze.registerHelper = function (name, func) { // 5 - Blaze._globalHelpers[name] = func; // 6 -}; // 7 - // 8 -var bindIfIsFunction = function (x, target) { // 9 - if (typeof x !== 'function') // 10 - return x; // 11 - return _.bind(x, target); // 12 -}; // 13 - // 14 -// If `x` is a function, binds the value of `this` for that function // 15 -// to the current data context. // 16 -var bindDataContext = function (x) { // 17 - if (typeof x === 'function') { // 18 - return function () { // 19 - var data = Blaze.getData(); // 20 - if (data == null) // 21 - data = {}; // 22 - return x.apply(data, arguments); // 23 - }; // 24 - } // 25 - return x; // 26 -}; // 27 - // 28 -Blaze._OLDSTYLE_HELPER = {}; // 29 - // 30 -var getTemplateHelper = Blaze._getTemplateHelper = function (template, name) { // 31 - // XXX COMPAT WITH 0.9.3 // 32 - var isKnownOldStyleHelper = false; // 33 - // 34 - if (template.__helpers.has(name)) { // 35 - var helper = template.__helpers.get(name); // 36 - if (helper === Blaze._OLDSTYLE_HELPER) { // 37 - isKnownOldStyleHelper = true; // 38 - } else { // 39 - return helper; // 40 - } // 41 - } // 42 - // 43 - // old-style helper // 44 - if (name in template) { // 45 - // Only warn once per helper // 46 - if (! isKnownOldStyleHelper) { // 47 - template.__helpers.set(name, Blaze._OLDSTYLE_HELPER); // 48 - if (! template._NOWARN_OLDSTYLE_HELPERS) { // 49 - Blaze._warn('Assigning helper with `' + template.viewName + '.' + // 50 - name + ' = ...` is deprecated. Use `' + template.viewName + // 51 - '.helpers(...)` instead.'); // 52 - } // 53 - } // 54 - return template[name]; // 55 - } // 56 - // 57 - return null; // 58 -}; // 59 - // 60 -var wrapHelper = function (f, templateFunc) { // 61 - if (typeof f !== "function") { // 62 - return f; // 63 - } // 64 - // 65 - return function () { // 66 - var self = this; // 67 - var args = arguments; // 68 - // 69 - return Blaze.Template._withTemplateInstanceFunc(templateFunc, function () { // 70 - return Blaze._wrapCatchingExceptions(f, 'template helper').apply(self, args); // 71 - }); // 72 - }; // 73 -}; // 74 - // 75 -// Looks up a name, like "foo" or "..", as a helper of the // 76 -// current template; a global helper; the name of a template; // 77 -// or a property of the data context. Called on the View of // 78 -// a template (i.e. a View with a `.template` property, // 79 -// where the helpers are). Used for the first name in a // 80 -// "path" in a template tag, like "foo" in `{{foo.bar}}` or // 81 -// ".." in `{{frobulate ../blah}}`. // 82 -// // 83 -// Returns a function, a non-function value, or null. If // 84 -// a function is found, it is bound appropriately. // 85 -// // 86 -// NOTE: This function must not establish any reactive // 87 -// dependencies itself. If there is any reactivity in the // 88 -// value, lookup should return a function. // 89 -Blaze.View.prototype.lookup = function (name, _options) { // 90 - var template = this.template; // 91 - var lookupTemplate = _options && _options.template; // 92 - var helper; // 93 - var boundTmplInstance; // 94 - // 95 - if (this.templateInstance) { // 96 - boundTmplInstance = _.bind(this.templateInstance, this); // 97 - } // 98 - // 99 - if (/^\./.test(name)) { // 100 - // starts with a dot. must be a series of dots which maps to an // 101 - // ancestor of the appropriate height. // 102 - if (!/^(\.)+$/.test(name)) // 103 - throw new Error("id starting with dot must be a series of dots"); // 104 - // 105 - return Blaze._parentData(name.length - 1, true /*_functionWrapped*/); // 106 - // 107 - } else if (template && // 108 - ((helper = getTemplateHelper(template, name)) != null)) { // 109 - return wrapHelper(bindDataContext(helper), boundTmplInstance); // 110 - } else if (lookupTemplate && (name in Blaze.Template) && // 111 - (Blaze.Template[name] instanceof Blaze.Template)) { // 112 - return Blaze.Template[name]; // 113 - } else if (Blaze._globalHelpers[name] != null) { // 114 - return wrapHelper(bindDataContext(Blaze._globalHelpers[name]), // 115 - boundTmplInstance); // 116 - } else { // 117 - return function () { // 118 - var isCalledAsFunction = (arguments.length > 0); // 119 - var data = Blaze.getData(); // 120 - if (lookupTemplate && ! (data && data[name])) { // 121 - throw new Error("No such template: " + name); // 122 - } // 123 - if (isCalledAsFunction && ! (data && data[name])) { // 124 - throw new Error("No such function: " + name); // 125 - } // 126 - if (! data) // 127 - return null; // 128 - var x = data[name]; // 129 - if (typeof x !== 'function') { // 130 - if (isCalledAsFunction) { // 131 - throw new Error("Can't call non-function: " + x); // 132 - } // 133 - return x; // 134 - } // 135 - return x.apply(data, arguments); // 136 - }; // 137 - } // 138 - return null; // 139 -}; // 140 - // 141 -// Implement Spacebars' {{../..}}. // 142 -// @param height {Number} The number of '..'s // 143 -Blaze._parentData = function (height, _functionWrapped) { // 144 - // If height is null or undefined, we default to 1, the first parent. // 145 - if (height == null) { // 146 - height = 1; // 147 - } // 148 - var theWith = Blaze.getView('with'); // 149 - for (var i = 0; (i < height) && theWith; i++) { // 150 - theWith = Blaze.getView(theWith, 'with'); // 151 - } // 152 - // 153 - if (! theWith) // 154 - return null; // 155 - if (_functionWrapped) // 156 - return function () { return theWith.dataVar.get(); }; // 157 - return theWith.dataVar.get(); // 158 -}; // 159 - // 160 - // 161 -Blaze.View.prototype.lookupTemplate = function (name) { // 162 - return this.lookup(name, {template:true}); // 163 -}; // 164 - // 165 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/template.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// [new] Blaze.Template([viewName], renderFunction) // 1 -// // 2 -// `Blaze.Template` is the class of templates, like `Template.foo` in // 3 -// Meteor, which is `instanceof Template`. // 4 -// // 5 -// `viewKind` is a string that looks like "Template.foo" for templates // 6 -// defined by the compiler. // 7 - // 8 -/** // 9 - * @class // 10 - * @summary Constructor for a Template, which is used to construct Views with particular name and content. // 11 - * @locus Client // 12 - * @param {String} [viewName] Optional. A name for Views constructed by this Template. See [`view.name`](#view_name). - * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). This function is used as the `renderFunction` for Views constructed by this Template. - */ // 15 -Blaze.Template = function (viewName, renderFunction) { // 16 - if (! (this instanceof Blaze.Template)) // 17 - // called without `new` // 18 - return new Blaze.Template(viewName, renderFunction); // 19 - // 20 - if (typeof viewName === 'function') { // 21 - // omitted "viewName" argument // 22 - renderFunction = viewName; // 23 - viewName = ''; // 24 - } // 25 - if (typeof viewName !== 'string') // 26 - throw new Error("viewName must be a String (or omitted)"); // 27 - if (typeof renderFunction !== 'function') // 28 - throw new Error("renderFunction must be a function"); // 29 - // 30 - this.viewName = viewName; // 31 - this.renderFunction = renderFunction; // 32 - // 33 - this.__helpers = new HelperMap; // 34 - this.__eventMaps = []; // 35 - // 36 - this._callbacks = { // 37 - created: [], // 38 - rendered: [], // 39 - destroyed: [] // 40 - }; // 41 -}; // 42 -var Template = Blaze.Template; // 43 - // 44 -var HelperMap = function () {}; // 45 -HelperMap.prototype.get = function (name) { // 46 - return this[' '+name]; // 47 -}; // 48 -HelperMap.prototype.set = function (name, helper) { // 49 - this[' '+name] = helper; // 50 -}; // 51 -HelperMap.prototype.has = function (name) { // 52 - return (' '+name) in this; // 53 -}; // 54 - // 55 -/** // 56 - * @summary Returns true if `value` is a template object like `Template.myTemplate`. // 57 - * @locus Client // 58 - * @param {Any} value The value to test. // 59 - */ // 60 -Blaze.isTemplate = function (t) { // 61 - return (t instanceof Blaze.Template); // 62 -}; // 63 - // 64 -/** // 65 - * @name onCreated // 66 - * @instance // 67 - * @memberOf Template // 68 - * @summary Register a function to be called when an instance of this template is created. // 69 - * @param {Function} callback A function to be added as a callback. // 70 - * @locus Client // 71 - */ // 72 -Template.prototype.onCreated = function (cb) { // 73 - this._callbacks.created.push(cb); // 74 -}; // 75 - // 76 -/** // 77 - * @name onRendered // 78 - * @instance // 79 - * @memberOf Template // 80 - * @summary Register a function to be called when an instance of this template is inserted into the DOM. // 81 - * @param {Function} callback A function to be added as a callback. // 82 - * @locus Client // 83 - */ // 84 -Template.prototype.onRendered = function (cb) { // 85 - this._callbacks.rendered.push(cb); // 86 -}; // 87 - // 88 -/** // 89 - * @name onDestroyed // 90 - * @instance // 91 - * @memberOf Template // 92 - * @summary Register a function to be called when an instance of this template is removed from the DOM and destroyed. // 93 - * @param {Function} callback A function to be added as a callback. // 94 - * @locus Client // 95 - */ // 96 -Template.prototype.onDestroyed = function (cb) { // 97 - this._callbacks.destroyed.push(cb); // 98 -}; // 99 - // 100 -Template.prototype._getCallbacks = function (which) { // 101 - var self = this; // 102 - var callbacks = self[which] ? [self[which]] : []; // 103 - // Fire all callbacks added with the new API (Template.onRendered()) // 104 - // as well as the old-style callback (e.g. Template.rendered) for // 105 - // backwards-compatibility. // 106 - callbacks = callbacks.concat(self._callbacks[which]); // 107 - return callbacks; // 108 -}; // 109 - // 110 -var fireCallbacks = function (callbacks, template) { // 111 - Template._withTemplateInstanceFunc( // 112 - function () { return template; }, // 113 - function () { // 114 - for (var i = 0, N = callbacks.length; i < N; i++) { // 115 - callbacks[i].call(template); // 116 - } // 117 - }); // 118 -}; // 119 - // 120 -Template.prototype.constructView = function (contentFunc, elseFunc) { // 121 - var self = this; // 122 - var view = Blaze.View(self.viewName, self.renderFunction); // 123 - view.template = self; // 124 - // 125 - view.templateContentBlock = ( // 126 - contentFunc ? new Template('(contentBlock)', contentFunc) : null); // 127 - view.templateElseBlock = ( // 128 - elseFunc ? new Template('(elseBlock)', elseFunc) : null); // 129 - // 130 - if (self.__eventMaps || typeof self.events === 'object') { // 131 - view._onViewRendered(function () { // 132 - if (view.renderCount !== 1) // 133 - return; // 134 - // 135 - if (! self.__eventMaps.length && typeof self.events === "object") { // 136 - // Provide limited back-compat support for `.events = {...}` // 137 - // syntax. Pass `template.events` to the original `.events(...)` // 138 - // function. This code must run only once per template, in // 139 - // order to not bind the handlers more than once, which is // 140 - // ensured by the fact that we only do this when `__eventMaps` // 141 - // is falsy, and we cause it to be set now. // 142 - Template.prototype.events.call(self, self.events); // 143 - } // 144 - // 145 - _.each(self.__eventMaps, function (m) { // 146 - Blaze._addEventMap(view, m, view); // 147 - }); // 148 - }); // 149 - } // 150 - // 151 - view._templateInstance = new Blaze.TemplateInstance(view); // 152 - view.templateInstance = function () { // 153 - // Update data, firstNode, and lastNode, and return the TemplateInstance // 154 - // object. // 155 - var inst = view._templateInstance; // 156 - // 157 - /** // 158 - * @instance // 159 - * @memberOf Blaze.TemplateInstance // 160 - * @name data // 161 - * @summary The data context of this instance's latest invocation. // 162 - * @locus Client // 163 - */ // 164 - inst.data = Blaze.getData(view); // 165 - // 166 - if (view._domrange && !view.isDestroyed) { // 167 - inst.firstNode = view._domrange.firstNode(); // 168 - inst.lastNode = view._domrange.lastNode(); // 169 - } else { // 170 - // on 'created' or 'destroyed' callbacks we don't have a DomRange // 171 - inst.firstNode = null; // 172 - inst.lastNode = null; // 173 - } // 174 - // 175 - return inst; // 176 - }; // 177 - // 178 - /** // 179 - * @name created // 180 - * @instance // 181 - * @memberOf Template // 182 - * @summary Provide a callback when an instance of a template is created. // 183 - * @locus Client // 184 - * @deprecated in 1.1 // 185 - */ // 186 - // To avoid situations when new callbacks are added in between view // 187 - // instantiation and event being fired, decide on all callbacks to fire // 188 - // immediately and then fire them on the event. // 189 - var createdCallbacks = self._getCallbacks('created'); // 190 - view.onViewCreated(function () { // 191 - fireCallbacks(createdCallbacks, view.templateInstance()); // 192 - }); // 193 - // 194 - /** // 195 - * @name rendered // 196 - * @instance // 197 - * @memberOf Template // 198 - * @summary Provide a callback when an instance of a template is rendered. // 199 - * @locus Client // 200 - * @deprecated in 1.1 // 201 - */ // 202 - var renderedCallbacks = self._getCallbacks('rendered'); // 203 - view.onViewReady(function () { // 204 - fireCallbacks(renderedCallbacks, view.templateInstance()); // 205 - }); // 206 - // 207 - /** // 208 - * @name destroyed // 209 - * @instance // 210 - * @memberOf Template // 211 - * @summary Provide a callback when an instance of a template is destroyed. // 212 - * @locus Client // 213 - * @deprecated in 1.1 // 214 - */ // 215 - var destroyedCallbacks = self._getCallbacks('destroyed'); // 216 - view.onViewDestroyed(function () { // 217 - fireCallbacks(destroyedCallbacks, view.templateInstance()); // 218 - }); // 219 - // 220 - return view; // 221 -}; // 222 - // 223 -/** // 224 - * @class // 225 - * @summary The class for template instances // 226 - * @param {Blaze.View} view // 227 - * @instanceName template // 228 - */ // 229 -Blaze.TemplateInstance = function (view) { // 230 - if (! (this instanceof Blaze.TemplateInstance)) // 231 - // called without `new` // 232 - return new Blaze.TemplateInstance(view); // 233 - // 234 - if (! (view instanceof Blaze.View)) // 235 - throw new Error("View required"); // 236 - // 237 - view._templateInstance = this; // 238 - // 239 - /** // 240 - * @name view // 241 - * @memberOf Blaze.TemplateInstance // 242 - * @instance // 243 - * @summary The [View](#blaze_view) object for this invocation of the template. // 244 - * @locus Client // 245 - * @type {Blaze.View} // 246 - */ // 247 - this.view = view; // 248 - this.data = null; // 249 - // 250 - /** // 251 - * @name firstNode // 252 - * @memberOf Blaze.TemplateInstance // 253 - * @instance // 254 - * @summary The first top-level DOM node in this template instance. // 255 - * @locus Client // 256 - * @type {DOMNode} // 257 - */ // 258 - this.firstNode = null; // 259 - // 260 - /** // 261 - * @name lastNode // 262 - * @memberOf Blaze.TemplateInstance // 263 - * @instance // 264 - * @summary The last top-level DOM node in this template instance. // 265 - * @locus Client // 266 - * @type {DOMNode} // 267 - */ // 268 - this.lastNode = null; // 269 - // 270 - // This dependency is used to identify state transitions in // 271 - // _subscriptionHandles which could cause the result of // 272 - // TemplateInstance#subscriptionsReady to change. Basically this is triggered // 273 - // whenever a new subscription handle is added or when a subscription handle // 274 - // is removed and they are not ready. // 275 - this._allSubsReadyDep = new Tracker.Dependency(); // 276 - this._allSubsReady = false; // 277 - // 278 - this._subscriptionHandles = {}; // 279 -}; // 280 - // 281 -/** // 282 - * @summary Find all elements matching `selector` in this template instance, and return them as a JQuery object. // 283 - * @locus Client // 284 - * @param {String} selector The CSS selector to match, scoped to the template contents. // 285 - * @returns {DOMNode[]} // 286 - */ // 287 -Blaze.TemplateInstance.prototype.$ = function (selector) { // 288 - var view = this.view; // 289 - if (! view._domrange) // 290 - throw new Error("Can't use $ on template instance with no DOM"); // 291 - return view._domrange.$(selector); // 292 -}; // 293 - // 294 -/** // 295 - * @summary Find all elements matching `selector` in this template instance. // 296 - * @locus Client // 297 - * @param {String} selector The CSS selector to match, scoped to the template contents. // 298 - * @returns {DOMElement[]} // 299 - */ // 300 -Blaze.TemplateInstance.prototype.findAll = function (selector) { // 301 - return Array.prototype.slice.call(this.$(selector)); // 302 -}; // 303 - // 304 -/** // 305 - * @summary Find one element matching `selector` in this template instance. // 306 - * @locus Client // 307 - * @param {String} selector The CSS selector to match, scoped to the template contents. // 308 - * @returns {DOMElement} // 309 - */ // 310 -Blaze.TemplateInstance.prototype.find = function (selector) { // 311 - var result = this.$(selector); // 312 - return result[0] || null; // 313 -}; // 314 - // 315 -/** // 316 - * @summary A version of [Tracker.autorun](#tracker_autorun) that is stopped when the template is destroyed. // 317 - * @locus Client // 318 - * @param {Function} runFunc The function to run. It receives one argument: a Tracker.Computation object. // 319 - */ // 320 -Blaze.TemplateInstance.prototype.autorun = function (f) { // 321 - return this.view.autorun(f); // 322 -}; // 323 - // 324 -/** // 325 - * @summary A version of [Meteor.subscribe](#meteor_subscribe) that is stopped // 326 - * when the template is destroyed. // 327 - * @return {SubscriptionHandle} The subscription handle to the newly made // 328 - * subscription. Call `handle.stop()` to manually stop the subscription, or // 329 - * `handle.ready()` to find out if this particular subscription has loaded all // 330 - * of its inital data. // 331 - * @locus Client // 332 - * @param {String} name Name of the subscription. Matches the name of the // 333 - * server's `publish()` call. // 334 - * @param {Any} [arg1,arg2...] Optional arguments passed to publisher function // 335 - * on server. // 336 - * @param {Function|Object} [callbacks] Optional. May include `onStop` and // 337 - * `onReady` callbacks. If a function is passed instead of an object, it is // 338 - * interpreted as an `onReady` callback. // 339 - */ // 340 -Blaze.TemplateInstance.prototype.subscribe = function (/* arguments */) { // 341 - var self = this; // 342 - // 343 - var subHandles = self._subscriptionHandles; // 344 - var args = _.toArray(arguments); // 345 - // 346 - // Duplicate logic from Meteor.subscribe // 347 - var callbacks = {}; // 348 - if (args.length) { // 349 - var lastParam = _.last(args); // 350 - if (_.isFunction(lastParam)) { // 351 - callbacks.onReady = args.pop(); // 352 - } else if (lastParam && // 353 - // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use // 354 - // onStop with an error callback instead. // 355 - _.any([lastParam.onReady, lastParam.onError, lastParam.onStop], // 356 - _.isFunction)) { // 357 - callbacks = args.pop(); // 358 - } // 359 - } // 360 - // 361 - var subHandle; // 362 - var oldStopped = callbacks.onStop; // 363 - callbacks.onStop = function (error) { // 364 - // When the subscription is stopped, remove it from the set of tracked // 365 - // subscriptions to avoid this list growing without bound // 366 - delete subHandles[subHandle.subscriptionId]; // 367 - // 368 - // Removing a subscription can only change the result of subscriptionsReady // 369 - // if we are not ready (that subscription could be the one blocking us being // 370 - // ready). // 371 - if (! self._allSubsReady) { // 372 - self._allSubsReadyDep.changed(); // 373 - } // 374 - // 375 - if (oldStopped) { // 376 - oldStopped(error); // 377 - } // 378 - }; // 379 - args.push(callbacks); // 380 - // 381 - subHandle = self.view.subscribe.call(self.view, args); // 382 - // 383 - if (! _.has(subHandles, subHandle.subscriptionId)) { // 384 - subHandles[subHandle.subscriptionId] = subHandle; // 385 - // 386 - // Adding a new subscription will always cause us to transition from ready // 387 - // to not ready, but if we are already not ready then this can't make us // 388 - // ready. // 389 - if (self._allSubsReady) { // 390 - self._allSubsReadyDep.changed(); // 391 - } // 392 - } // 393 - // 394 - return subHandle; // 395 -}; // 396 - // 397 -/** // 398 - * @summary A reactive function that returns true when all of the subscriptions // 399 - * called with [this.subscribe](#TemplateInstance-subscribe) are ready. // 400 - * @return {Boolean} True if all subscriptions on this template instance are // 401 - * ready. // 402 - */ // 403 -Blaze.TemplateInstance.prototype.subscriptionsReady = function () { // 404 - this._allSubsReadyDep.depend(); // 405 - // 406 - this._allSubsReady = _.all(this._subscriptionHandles, function (handle) { // 407 - return handle.ready(); // 408 - }); // 409 - // 410 - return this._allSubsReady; // 411 -}; // 412 - // 413 -/** // 414 - * @summary Specify template helpers available to this template. // 415 - * @locus Client // 416 - * @param {Object} helpers Dictionary of helper functions by name. // 417 - */ // 418 -Template.prototype.helpers = function (dict) { // 419 - for (var k in dict) // 420 - this.__helpers.set(k, dict[k]); // 421 -}; // 422 - // 423 -// Kind of like Blaze.currentView but for the template instance. // 424 -// This is a function, not a value -- so that not all helpers // 425 -// are implicitly dependent on the current template instance's `data` property, // 426 -// which would make them dependenct on the data context of the template // 427 -// inclusion. // 428 -Template._currentTemplateInstanceFunc = null; // 429 - // 430 -Template._withTemplateInstanceFunc = function (templateInstanceFunc, func) { // 431 - if (typeof func !== 'function') // 432 - throw new Error("Expected function, got: " + func); // 433 - var oldTmplInstanceFunc = Template._currentTemplateInstanceFunc; // 434 - try { // 435 - Template._currentTemplateInstanceFunc = templateInstanceFunc; // 436 - return func(); // 437 - } finally { // 438 - Template._currentTemplateInstanceFunc = oldTmplInstanceFunc; // 439 - } // 440 -}; // 441 - // 442 -/** // 443 - * @summary Specify event handlers for this template. // 444 - * @locus Client // 445 - * @param {EventMap} eventMap Event handlers to associate with this template. // 446 - */ // 447 -Template.prototype.events = function (eventMap) { // 448 - var template = this; // 449 - var eventMap2 = {}; // 450 - for (var k in eventMap) { // 451 - eventMap2[k] = (function (k, v) { // 452 - return function (event/*, ...*/) { // 453 - var view = this; // passed by EventAugmenter // 454 - var data = Blaze.getData(event.currentTarget); // 455 - if (data == null) // 456 - data = {}; // 457 - var args = Array.prototype.slice.call(arguments); // 458 - var tmplInstanceFunc = _.bind(view.templateInstance, view); // 459 - args.splice(1, 0, tmplInstanceFunc()); // 460 - // 461 - return Template._withTemplateInstanceFunc(tmplInstanceFunc, function () { // 462 - return v.apply(data, args); // 463 - }); // 464 - }; // 465 - })(k, eventMap[k]); // 466 - } // 467 - // 468 - template.__eventMaps.push(eventMap2); // 469 -}; // 470 - // 471 -/** // 472 - * @function // 473 - * @name instance // 474 - * @memberOf Template // 475 - * @summary The [template instance](#template_inst) corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`. - * @locus Client // 477 - * @returns {Blaze.TemplateInstance} // 478 - */ // 479 -Template.instance = function () { // 480 - return Template._currentTemplateInstanceFunc // 481 - && Template._currentTemplateInstanceFunc(); // 482 -}; // 483 - // 484 -// Note: Template.currentData() is documented to take zero arguments, // 485 -// while Blaze.getData takes up to one. // 486 - // 487 -/** // 488 - * @summary // 489 - * // 490 - * - Inside an `onCreated`, `onRendered`, or `onDestroyed` callback, returns // 491 - * the data context of the template. // 492 - * - Inside an event handler, returns the data context of the template on which // 493 - * this event handler was defined. // 494 - * - Inside a helper, returns the data context of the DOM node where the helper // 495 - * was used. // 496 - * // 497 - * Establishes a reactive dependency on the result. // 498 - * @locus Client // 499 - * @function // 500 - */ // 501 -Template.currentData = Blaze.getData; // 502 - // 503 -/** // 504 - * @summary Accesses other data contexts that enclose the current data context. // 505 - * @locus Client // 506 - * @function // 507 - * @param {Integer} [numLevels] The number of levels beyond the current data context to look. Defaults to 1. // 508 - */ // 509 -Template.parentData = Blaze._parentData; // 510 - // 511 -/** // 512 - * @summary Defines a [helper function](#template_helpers) which can be used from all templates. // 513 - * @locus Client // 514 - * @function // 515 - * @param {String} name The name of the helper function you are defining. // 516 - * @param {Function} function The helper function itself. // 517 - */ // 518 -Template.registerHelper = Blaze.registerHelper; // 519 - // 520 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/blaze/backcompat.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -UI = Blaze; // 1 - // 2 -Blaze.ReactiveVar = ReactiveVar; // 3 -UI._templateInstance = Blaze.Template.instance; // 4 - // 5 -Handlebars = {}; // 6 -Handlebars.registerHelper = Blaze.registerHelper; // 7 - // 8 -Handlebars._escape = Blaze._escape; // 9 - // 10 -// Return these from {{...}} helpers to achieve the same as returning // 11 -// strings from {{{...}}} helpers // 12 -Handlebars.SafeString = function(string) { // 13 - this.string = string; // 14 -}; // 15 -Handlebars.SafeString.prototype.toString = function() { // 16 - return this.string.toString(); // 17 -}; // 18 - // 19 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.blaze = { - Blaze: Blaze, - UI: UI, - Handlebars: Handlebars -}; - -})(); - -//# sourceMappingURL=blaze.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/blaze.js.map b/web-app/.meteor/local/build/programs/server/packages/blaze.js.map deleted file mode 100644 index d9f776c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/blaze.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["blaze/preamble.js","blaze/exceptions.js","blaze/view.js","blaze/builtins.js","blaze/lookup.js","blaze/template.js","blaze/backcompat.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,G;AACA,mB;AACA,oE;AACA,G;AACA,W;;AAEA,iE;AACA,6B;AACA,oB;AACA,gB;AACA,gB;AACA,kB;AACA,kB;AACA,kE;AACA,gB;AACA,I;AACA,gC;AACA,yB;AACA,I;;AAEA,uB;AACA,8C;AACA,I;AACA,K;;AAEA,8B;AACA,0B;;AAEA,sD;AACA,oD;AACA,2D;AACA,qB;AACA,E;;;;;;;;;;;;;;;;;;;AChCA,c;;AAEA,2E;AACA,8E;AACA,4E;AACA,sB;AACA,E;AACA,S;AACA,E;AACA,M;AACA,Q;AACA,yB;AACA,gB;AACA,0B;AACA,I;AACA,M;AACA,E;AACA,6D;;AAEA,yD;AACA,wD;AACA,iD;AACA,kC;;AAEA,4C;AACA,kC;AACA,sC;AACA,Y;AACA,G;;AAEA,kB;AACA,2B;AACA,6B;AACA,6D;AACA,8E;AACA,gC;AACA,M;;AAEA,4E;AACA,gF;AACA,gE;AACA,4E;AACA,E;;AAEA,qD;AACA,8B;AACA,a;;AAEA,sB;AACA,S;AACA,sC;AACA,iB;AACA,+D;AACA,K;AACA,I;AACA,E;;;;;;;;;;;;;;;;;;;ACvDA,0C;AACA,G;AACA,iE;AACA,2B;AACA,G;AACA,uE;AACA,uE;AACA,G;AACA,oE;AACA,gE;AACA,iC;AACA,G;AACA,kE;AACA,+D;AACA,8C;AACA,G;AACA,iE;AACA,4D;AACA,G;AACA,iE;AACA,oE;AACA,+D;AACA,yE;AACA,iE;AACA,6C;AACA,G;AACA,2B;AACA,G;AACA,oE;AACA,mE;AACA,mE;AACA,gE;AACA,sE;AACA,0E;;AAEA,G;AACA,S;AACA,8E;AACA,gB;AACA,kG;AACA,wJ;AACA,G;AACA,sC;AACA,qC;AACA,2B;AACA,wC;;AAEA,mC;AACA,8B;AACA,kB;AACA,c;AACA,G;AACA,mB;AACA,wB;;AAEA,qB;AACA,kB;AACA,mB;AACA,mB;AACA,I;;AAEA,yD;AACA,0D;AACA,kD;AACA,yB;AACA,sC;AACA,0B;AACA,2B;AACA,2B;AACA,2B;AACA,yB;AACA,wB;AACA,+E;AACA,2E;AACA,a;AACA,+E;AACA,8E;AACA,8E;AACA,6E;AACA,+E;AACA,mC;;AAEA,uB;AACA,E;;AAEA,4D;;AAEA,oD;AACA,0D;AACA,mC;AACA,E;;AAEA,sD;AACA,4D;AACA,oC;AACA,E;;AAEA,kD;AACA,kB;AACA,0B;AACA,oC;AACA,+B;AACA,kD;AACA,wB;AACA,W;AACA,O;AACA,O;AACA,I;AACA,kD;AACA,yB;AACA,a;AACA,kC;AACA,sC;AACA,Q;AACA,a;AACA,K;AACA,E;;AAEA,sD;AACA,8D;AACA,qC;AACA,E;;AAEA,sB;AACA,G;AACA,kE;AACA,6D;AACA,2D;AACA,iE;AACA,gE;AACA,4C;AACA,G;AACA,+D;AACA,qE;AACA,uE;AACA,8C;AACA,G;AACA,6C;AACA,0E;AACA,6D;AACA,6D;AACA,oC;AACA,wE;AACA,kB;;AAEA,qE;AACA,sE;AACA,mE;AACA,qE;AACA,0E;AACA,+C;AACA,I;AACA,qE;AACA,iE;AACA,sE;AACA,iE;AACA,iE;AACA,kE;AACA,0B;AACA,I;AACA,uE;AACA,oE;AACA,yE;AACA,oE;AACA,uE;AACA,0B;AACA,yB;AACA,6F;AACA,G;AACA,yB;AACA,0H;AACA,G;AACA,uB;AACA,gI;AACA,G;;AAEA,uE;AACA,6E;AACA,8E;AACA,+E;AACA,uB;AACA,6E;AACA,8E;AACA,6C;AACA,kB;AACA,4E;;AAEA,sC;AACA,qE;AACA,gG;AACA,+B;AACA,S;AACA,O;AACA,I;;AAEA,yE;AACA,gF;AACA,+E;AACA,wB;AACA,oE;AACA,uC;;AAEA,yD;;AAEA,kB;AACA,E;;AAEA,kE;AACA,kB;;AAEA,yB;AACA,+F;AACA,G;AACA,yB;AACA,4H;AACA,G;AACA,yB;AACA,gI;AACA,G;AACA,E;;AAEA,G;AACA,qE;AACA,qE;AACA,4E;AACA,0C;AACA,G;AACA,2D;AACA,kB;AACA,0B;;AAEA,uC;;AAEA,gB;AACA,2B;AACA,6E;AACA,U;AACA,qD;AACA,G;;AAEA,oC;AACA,qB;AACA,K;;AAEA,mB;AACA,E;;AAEA,8C;AACA,yB;AACA,sE;;AAEA,oC;AACA,E;;AAEA,6C;AACA,yB;AACA,sE;;AAEA,mC;AACA,E;;AAEA,+C;AACA,4C;AACA,kD;AACA,uC;AACA,0D;AACA,0B;AACA,O;AACA,K;AACA,E;;AAEA,+D;AACA,qB;AACA,wD;;AAEA,yC;AACA,wB;AACA,mB;AACA,uC;;AAEA,wC;AACA,E;;AAEA,qD;AACA,qD;AACA,4B;AACA,uB;AACA,yB;AACA,yC;;AAEA,0B;;AAEA,yD;AACA,4B;;AAEA,gE;AACA,oC;AACA,wD;AACA,S;AACA,K;;AAEA,gC;AACA,oC;AACA,wC;AACA,wB;AACA,K;;AAEA,kB;AACA,E;;AAEA,iE;AACA,+D;AACA,qD;AACA,E;AACA,oE;AACA,mE;AACA,oE;AACA,sE;AACA,kE;AACA,4D;AACA,qE;AACA,0C;AACA,8E;AACA,sC;;AAEA,e;AACA,iB;AACA,qE;AACA,iC;AACA,mC;AACA,uC;AACA,8C;AACA,yB;AACA,8B;AACA,sE;AACA,wB;AACA,kC;AACA,+B;;AAEA,yB;AACA,sD;AACA,sB;AACA,uE;AACA,4D;AACA,gD;AACA,mD;AACA,W;AACA,W;AACA,O;AACA,0B;;AAEA,sE;AACA,mE;AACA,kE;AACA,wD;AACA,wC;AACA,uB;AACA,oC;AACA,S;AACA,S;AACA,iC;;AAEA,qD;AACA,wB;AACA,uB;AACA,oE;AACA,sD;AACA,+E;AACA,Y;AACA,mE;AACA,qE;AACA,gE;AACA,+D;AACA,kE;AACA,sE;AACA,2D;AACA,2B;AACA,yD;AACA,mC;AACA,wD;AACA,2E;AACA,kC;AACA,S;AACA,0D;AACA,2D;AACA,K;AACA,K;;AAEA,qB;AACA,oB;AACA,U;AACA,gB;AACA,G;AACA,E;;AAEA,gE;AACA,oE;AACA,gE;AACA,yE;AACA,mE;AACA,oE;AACA,gE;AACA,oE;AACA,Y;AACA,iD;AACA,6D;;AAEA,0B;AACA,yD;AACA,0B;AACA,K;AACA,2B;;AAEA,2C;;AAEA,uB;AACA,sC;AACA,+B;AACA,O;AACA,U;AACA,6B;AACA,G;;AAEA,gB;AACA,E;;AAEA,wB;AACA,0D;AACA,2B;AACA,6B;AACA,oC;AACA,4B;AACA,gC;AACA,mD;;AAEA,+D;AACA,wE;AACA,I;AACA,qC;AACA,gC;AACA,oC;AACA,6D;;AAEA,2D;AACA,gF;AACA,I;AACA,+C;AACA,uE;AACA,yD;AACA,oC;AACA,6D;;AAEA,kE;AACA,8B;AACA,G;AACA,G;;AAEA,6D;AACA,wC;AACA,0C;AACA,+B;AACA,kD;AACA,E;;AAEA,+C;AACA,sD;AACA,oC;AACA,6C;AACA,E;;AAEA,wD;AACA,sD;AACA,oC;AACA,sD;AACA,E;;AAEA,kD;AACA,uB;AACA,W;AACA,0B;;AAEA,0C;;AAEA,4D;AACA,+D;AACA,iE;;AAEA,qB;AACA,8C;AACA,E;;AAEA,sC;AACA,0B;AACA,qD;AACA,E;;AAEA,6D;AACA,+D;AACA,S;AACA,yC;AACA,8B;AACA,4D;AACA,yB;AACA,uB;AACA,U;AACA,uB;AACA,6D;AACA,gC;AACA,G;AACA,E;;AAEA,G;AACA,oI;AACA,gB;AACA,qB;AACA,G;AACA,yB;;AAEA,gD;AACA,kC;AACA,O;AACA,6B;AACA,kB;AACA,a;AACA,gC;AACA,G;AACA,E;;AAEA,oD;AACA,qE;AACA,oE;AACA,U;AACA,6C;AACA,uB;AACA,yC;AACA,qC;AACA,8C;;AAEA,wC;AACA,4C;AACA,sC;AACA,W;;AAEA,O;AACA,iE;AACA,0D;AACA,4B;AACA,sC;AACA,e;AACA,iD;AACA,iD;AACA,G;AACA,E;;AAEA,sD;AACA,kD;AACA,oB;AACA,wC;AACA,8B;;AAEA,0C;AACA,mC;AACA,6C;AACA,mB;AACA,U;AACA,uB;AACA,qC;AACA,0B;AACA,uB;AACA,Q;AACA,K;AACA,sC;AACA,G;AACA,E;;AAEA,kE;AACA,6D;AACA,gB;AACA,wC;AACA,8B;;AAEA,sC;AACA,wB;AACA,qB;AACA,M;AACA,U;AACA,mB;AACA,G;AACA,E;;AAEA,G;AACA,iL;AACA,gB;AACA,qR;AACA,sH;AACA,6N;AACA,kI;AACA,G;AACA,wE;AACA,wB;AACA,yE;AACA,0E;AACA,G;;AAEA,uC;AACA,8B;AACA,0B;AACA,oB;AACA,G;;AAEA,kE;AACA,sE;AACA,4C;AACA,kE;AACA,0D;AACA,kF;AACA,qD;;AAEA,sD;;AAEA,oC;AACA,2C;;AAEA,sB;AACA,mD;AACA,G;;AAEA,c;AACA,E;;AAEA,yD;AACA,iF;AACA,+D;;AAEA,8D;AACA,oE;;AAEA,iD;AACA,E;;AAEA,G;AACA,gH;AACA,gB;AACA,kH;AACA,2J;AACA,sH;AACA,6N;AACA,kI;AACA,G;AACA,sF;AACA,iF;AACA,6C;AACA,wE;AACA,+D;AACA,E;;AAEA,G;AACA,0G;AACA,gB;AACA,mG;AACA,G;AACA,gC;AACA,8D;AACA,oE;;AAEA,gB;AACA,6B;AACA,iC;AACA,gD;AACA,uB;AACA,sB;AACA,K;;AAEA,uD;AACA,G;AACA,E;;AAEA,G;AACA,2D;AACA,gB;AACA,oI;AACA,G;AACA,+C;AACA,sD;;AAEA,4E;AACA,E;;AAEA,G;AACA,2G;AACA,gB;AACA,oI;AACA,iG;AACA,G;AACA,6D;AACA,sD;;AAEA,2D;AACA,gD;AACA,E;;AAEA,yD;AACA,mC;AACA,0E;;AAEA,qE;AACA,kC;AACA,0B;AACA,sB;AACA,G;AACA,sD;;AAEA,iB;AACA,yC;AACA,6C;AACA,6C;AACA,+C;AACA,qD;;AAEA,kE;AACA,E;;AAEA,G;AACA,uJ;AACA,gB;AACA,iH;AACA,G;AACA,0C;AACA,c;;AAEA,wB;AACA,oC;AACA,mD;AACA,6B;AACA,4C;AACA,4C;AACA,0D;AACA,qC;AACA,8C;AACA,mD;AACA,U;AACA,oD;AACA,G;;AAEA,gD;AACA,E;;AAEA,kB;AACA,2C;AACA,iE;AACA,iD;;AAEA,6B;AACA,4C;;AAEA,gC;AACA,E;;AAEA,+B;;AAEA,G;AACA,sF;AACA,gB;AACA,mG;AACA,G;AACA,qD;AACA,2B;;AAEA,4C;AACA,8C;AACA,6B;AACA,yB;AACA,G;;AAEA,8D;AACA,6C;AACA,wB;AACA,2C;AACA,mD;AACA,yD;AACA,0D;AACA,0D;AACA,U;AACA,oD;AACA,G;AACA,E;;AAEA,wD;AACA,U;AACA,yC;AACA,+B;AACA,wD;AACA,6D;AACA,4D;AACA,qD;AACA,a;AACA,gD;;AAEA,a;AACA,sC;AACA,6B;AACA,wB;AACA,U;AACA,6D;AACA,yB;AACA,gB;AACA,G;AACA,E;;AAEA,8C;AACA,0B;;AAEA,a;AACA,gC;AACA,uB;AACA,G;;AAEA,mB;AACA,E;;AAEA,+C;AACA,+C;AACA,kB;AACA,2B;AACA,gC;AACA,iB;AACA,4B;AACA,kC;AACA,U;AACA,gE;AACA,K;AACA,G;;AAEA,a;AACA,sC;AACA,6B;AACA,wB;AACA,U;AACA,gB;AACA,G;AACA,E;;AAEA,+D;AACA,0C;AACA,mB;;AAEA,uB;AACA,iD;;AAEA,yE;AACA,+C;AACA,uC;AACA,wE;AACA,yC;AACA,wC;AACA,+B;AACA,iB;;AAEA,sC;AACA,uC;AACA,gD;AACA,uC;AACA,0B;AACA,2D;AACA,0B;AACA,oD;AACA,wC;AACA,6D;AACA,6D;AACA,e;AACA,Y;AACA,+B;AACA,iC;AACA,c;AACA,S;AACA,O;AACA,K;;AAEA,oC;AACA,kC;AACA,e;AACA,O;AACA,uB;AACA,K;AACA,E;;;;;;;;;;;;;;;;;;;ACp3BA,6C;AACA,iD;AACA,iB;AACA,iB;AACA,E;;AAEA,G;AACA,uE;AACA,gB;AACA,wK;AACA,qG;AACA,G;AACA,2C;AACA,6C;;AAEA,iC;;AAEA,kC;AACA,qC;AACA,sC;AACA,gC;AACA,iC;AACA,qC;AACA,Y;AACA,6B;AACA,K;AACA,K;;AAEA,c;AACA,E;;AAEA,G;AACA,iE;AACA,gB;AACA,wM;AACA,qG;AACA,sL;AACA,G;AACA,kE;AACA,qC;;AAEA,6D;AACA,+C;AACA,qC;AACA,K;AACA,qC;AACA,kC;AACA,8B;AACA,4D;AACA,+C;AACA,qC;AACA,K;;AAEA,c;AACA,E;;AAEA,G;AACA,gD;AACA,gB;AACA,wL;AACA,qG;AACA,sL;AACA,G;AACA,gE;AACA,uE;AACA,E;;AAEA,G;AACA,qF;AACA,gB;AACA,8H;AACA,qG;AACA,yK;AACA,G;AACA,wD;AACA,iD;AACA,wC;AACA,gC;AACA,sC;AACA,qD;AACA,qC;AACA,K;AACA,oB;AACA,K;AACA,gC;AACA,wB;AACA,8B;AACA,6B;AACA,qC;AACA,+B;AACA,oC;;AAEA,sC;AACA,qD;AACA,gE;AACA,oD;AACA,kC;AACA,qC;AACA,0C;;AAEA,+D;AACA,mC;AACA,Q;AACA,2C;AACA,yC;AACA,mE;AACA,8B;;AAEA,0C;AACA,gD;AACA,0C;AACA,sC;AACA,iD;AACA,0C;AACA,a;;AAEA,sE;AACA,uD;AACA,kB;AACA,mE;AACA,W;AACA,W;AACA,Q;AACA,6C;AACA,yC;AACA,8B;AACA,0C;AACA,gD;AACA,0C;AACA,mD;AACA,+D;AACA,yC;AACA,2C;AACA,uC;AACA,4D;AACA,gC;AACA,a;AACA,kB;AACA,sD;AACA,W;AACA,W;AACA,Q;AACA,yD;AACA,yC;AACA,0C;AACA,gD;AACA,kB;AACA,yB;AACA,qC;AACA,kE;AACA,oB;AACA,yD;AACA,a;AACA,0C;AACA,W;AACA,W;AACA,Q;AACA,wD;AACA,yC;AACA,0C;AACA,gD;AACA,0C;AACA,8D;AACA,kB;AACA,oD;AACA,+C;AACA,0C;AACA,kD;AACA,W;AACA,W;AACA,O;AACA,O;;AAEA,uD;AACA,iC;AACA,mC;AACA,mD;AACA,K;AACA,K;;AAEA,wC;AACA,4B;AACA,iC;AACA,K;;AAEA,kB;AACA,E;;AAEA,mD;AACA,Q;;AAEA,oB;AACA,kC;AACA,2B;AACA,iB;AACA,M;AACA,G;;AAEA,+E;AACA,6E;AACA,6E;AACA,4E;AACA,0D;AACA,4E;AACA,qE;AACA,iC;AACA,I;AACA,0E;AACA,mE;AACA,oC;AACA,iC;AACA,uE;AACA,0D;AACA,K;AACA,4B;AACA,gE;AACA,Y;AACA,uB;AACA,K;AACA,I;;AAEA,wC;AACA,yC;;AAEA,mE;AACA,yE;AACA,sD;AACA,4C;AACA,wC;AACA,K;AACA,wC;AACA,yC;AACA,K;;AAEA,mB;AACA,I;;AAEA,qD;AACA,4B;AACA,W;AACA,E;;AAEA,oE;AACA,6D;AACA,2C;;AAEA,iE;AACA,oE;AACA,qE;AACA,qE;AACA,kC;AACA,uC;;AAEA,kC;AACA,8C;AACA,iC;AACA,K;AACA,c;AACA,E;;AAEA,wB;AACA,yD;;;;;;;;;;;;;;;;;;;ACrQA,0B;;AAEA,yC;AACA,qE;AACA,8C;AACA,oC;AACA,E;;AAEA,6C;AACA,8B;AACA,a;AACA,2B;AACA,E;;AAEA,oE;AACA,+B;AACA,oC;AACA,gC;AACA,wB;AACA,iC;AACA,uB;AACA,kB;AACA,sC;AACA,M;AACA,G;AACA,W;AACA,E;;AAEA,4B;;AAEA,8E;AACA,0B;AACA,oC;;AAEA,qC;AACA,8C;AACA,4C;AACA,mC;AACA,Y;AACA,oB;AACA,K;AACA,G;;AAEA,qB;AACA,yB;AACA,gC;AACA,kC;AACA,2D;AACA,gD;AACA,yE;AACA,gF;AACA,+C;AACA,O;AACA,K;AACA,0B;AACA,G;;AAEA,c;AACA,E;;AAEA,6C;AACA,gC;AACA,a;AACA,G;;AAEA,sB;AACA,oB;AACA,yB;;AAEA,+E;AACA,mF;AACA,O;AACA,I;AACA,E;;AAEA,0D;AACA,6D;AACA,4D;AACA,uD;AACA,wD;AACA,2D;AACA,mC;AACA,E;AACA,yD;AACA,kD;AACA,E;AACA,sD;AACA,0D;AACA,0C;AACA,yD;AACA,+B;AACA,qD;AACA,a;AACA,wB;;AAEA,8B;AACA,4D;AACA,G;;AAEA,yB;AACA,mE;AACA,0C;AACA,8B;AACA,uE;;AAEA,yE;;AAEA,wB;AACA,sE;AACA,kE;AACA,0D;AACA,gE;AACA,gC;AACA,kD;AACA,kE;AACA,yB;AACA,U;AACA,wB;AACA,sD;AACA,iC;AACA,qD;AACA,qD;AACA,O;AACA,yD;AACA,qD;AACA,O;AACA,iB;AACA,oB;AACA,yB;AACA,oC;AACA,iC;AACA,2D;AACA,S;AACA,iB;AACA,O;AACA,sC;AACA,M;AACA,G;AACA,c;AACA,E;;AAEA,kC;AACA,6C;AACA,yD;AACA,uE;AACA,uB;AACA,e;AACA,G;AACA,sC;AACA,iD;AACA,6C;AACA,G;;AAEA,gB;AACA,gB;AACA,uB;AACA,yD;AACA,+B;AACA,E;;;AAGA,uD;AACA,4C;AACA,E;;;;;;;;;;;;;;;;;;;ACnKA,mD;AACA,E;AACA,qE;AACA,0C;AACA,E;AACA,sE;AACA,2B;;AAEA,G;AACA,S;AACA,0G;AACA,gB;AACA,uH;AACA,+L;AACA,G;AACA,sD;AACA,yC;AACA,2B;AACA,wD;;AAEA,uC;AACA,kC;AACA,8B;AACA,kB;AACA,G;AACA,mC;AACA,8D;AACA,2C;AACA,yD;;AAEA,2B;AACA,uC;;AAEA,iC;AACA,wB;;AAEA,qB;AACA,gB;AACA,iB;AACA,iB;AACA,I;AACA,E;AACA,8B;;AAEA,+B;AACA,2C;AACA,wB;AACA,E;AACA,mD;AACA,0B;AACA,E;AACA,2C;AACA,4B;AACA,E;;AAEA,G;AACA,oF;AACA,gB;AACA,wC;AACA,G;AACA,iC;AACA,uC;AACA,E;;AAEA,G;AACA,mB;AACA,Y;AACA,qB;AACA,0F;AACA,mE;AACA,gB;AACA,G;AACA,8C;AACA,mC;AACA,E;;AAEA,G;AACA,oB;AACA,Y;AACA,qB;AACA,wG;AACA,mE;AACA,gB;AACA,G;AACA,+C;AACA,oC;AACA,E;;AAEA,G;AACA,qB;AACA,Y;AACA,qB;AACA,qH;AACA,mE;AACA,gB;AACA,G;AACA,gD;AACA,qC;AACA,E;;AAEA,qD;AACA,kB;AACA,mD;AACA,sE;AACA,mE;AACA,6B;AACA,uD;AACA,mB;AACA,E;;AAEA,oD;AACA,qC;AACA,qC;AACA,iB;AACA,yD;AACA,oC;AACA,O;AACA,O;AACA,E;;AAEA,qE;AACA,kB;AACA,4D;AACA,uB;;AAEA,+B;AACA,sE;AACA,4B;AACA,6D;;AAEA,4D;AACA,sC;AACA,iC;AACA,e;;AAEA,yE;AACA,oE;AACA,yE;AACA,mE;AACA,kE;AACA,sE;AACA,mD;AACA,0D;AACA,O;;AAEA,6C;AACA,0C;AACA,S;AACA,O;AACA,G;;AAEA,4D;AACA,uC;AACA,4E;AACA,c;AACA,sC;;AAEA,O;AACA,gB;AACA,uC;AACA,kB;AACA,sE;AACA,oB;AACA,O;AACA,oC;;AAEA,8C;AACA,kD;AACA,gD;AACA,Y;AACA,uE;AACA,4B;AACA,2B;AACA,K;;AAEA,gB;AACA,I;;AAEA,K;AACA,mB;AACA,c;AACA,uB;AACA,2E;AACA,kB;AACA,uB;AACA,K;AACA,qE;AACA,yE;AACA,iD;AACA,uD;AACA,kC;AACA,6D;AACA,K;;AAEA,K;AACA,oB;AACA,c;AACA,uB;AACA,4E;AACA,kB;AACA,uB;AACA,K;AACA,yD;AACA,gC;AACA,8D;AACA,K;;AAEA,K;AACA,qB;AACA,c;AACA,uB;AACA,6E;AACA,kB;AACA,uB;AACA,K;AACA,2D;AACA,oC;AACA,+D;AACA,K;;AAEA,c;AACA,E;;AAEA,G;AACA,S;AACA,4C;AACA,2B;AACA,yB;AACA,G;AACA,0C;AACA,iD;AACA,2B;AACA,4C;;AAEA,qC;AACA,qC;;AAEA,gC;;AAEA,K;AACA,e;AACA,qC;AACA,c;AACA,iF;AACA,kB;AACA,uB;AACA,K;AACA,mB;AACA,mB;;AAEA,K;AACA,oB;AACA,qC;AACA,c;AACA,qE;AACA,kB;AACA,oB;AACA,K;AACA,wB;;AAEA,K;AACA,mB;AACA,qC;AACA,c;AACA,oE;AACA,kB;AACA,oB;AACA,K;AACA,uB;;AAEA,6D;AACA,yD;AACA,+E;AACA,8E;AACA,uC;AACA,mD;AACA,6B;;AAEA,iC;AACA,E;;AAEA,G;AACA,gH;AACA,gB;AACA,uF;AACA,uB;AACA,G;AACA,0D;AACA,uB;AACA,uB;AACA,oE;AACA,oC;AACA,E;;AAEA,G;AACA,4E;AACA,gB;AACA,uF;AACA,0B;AACA,G;AACA,gE;AACA,sD;AACA,E;;AAEA,G;AACA,2E;AACA,gB;AACA,uF;AACA,wB;AACA,G;AACA,6D;AACA,gC;AACA,2B;AACA,E;;AAEA,G;AACA,4G;AACA,gB;AACA,yG;AACA,G;AACA,yD;AACA,8B;AACA,E;;AAEA,G;AACA,8E;AACA,kC;AACA,yE;AACA,2E;AACA,8E;AACA,sB;AACA,gB;AACA,0E;AACA,6B;AACA,8E;AACA,a;AACA,0E;AACA,2E;AACA,wC;AACA,G;AACA,yE;AACA,kB;;AAEA,6C;AACA,kC;;AAEA,0C;AACA,qB;AACA,oB;AACA,iC;AACA,kC;AACA,qC;AACA,2B;AACA,sE;AACA,+C;AACA,qE;AACA,wB;AACA,6B;AACA,K;AACA,G;;AAEA,gB;AACA,oC;AACA,uC;AACA,0E;AACA,6D;AACA,gD;;AAEA,+E;AACA,gF;AACA,c;AACA,+B;AACA,sC;AACA,K;;AAEA,qB;AACA,wB;AACA,K;AACA,I;AACA,uB;;AAEA,wD;;AAEA,sD;AACA,qD;;AAEA,8E;AACA,4E;AACA,a;AACA,6B;AACA,sC;AACA,K;AACA,G;;AAEA,mB;AACA,E;;AAEA,G;AACA,+E;AACA,uE;AACA,4E;AACA,S;AACA,G;AACA,mE;AACA,iC;;AAEA,2E;AACA,0B;AACA,K;;AAEA,4B;AACA,E;;AAEA,G;AACA,gE;AACA,gB;AACA,kE;AACA,G;AACA,8C;AACA,qB;AACA,mC;AACA,E;;AAEA,gE;AACA,6D;AACA,+E;AACA,uE;AACA,a;AACA,6C;;AAEA,4E;AACA,iC;AACA,uD;AACA,kE;AACA,O;AACA,iE;AACA,kB;AACA,a;AACA,gE;AACA,G;AACA,E;;AAEA,G;AACA,qD;AACA,gB;AACA,6E;AACA,G;AACA,iD;AACA,sB;AACA,qB;AACA,2B;AACA,qC;AACA,wC;AACA,oD;AACA,sD;AACA,yB;AACA,oB;AACA,yD;AACA,mE;AACA,8C;;AAEA,iF;AACA,qC;AACA,W;AACA,Q;AACA,uB;AACA,G;;AAEA,uC;AACA,E;;AAEA,G;AACA,Y;AACA,iB;AACA,qB;AACA,mK;AACA,gB;AACA,oC;AACA,G;AACA,iC;AACA,8C;AACA,+C;AACA,E;;AAEA,qE;AACA,uC;;AAEA,G;AACA,W;AACA,E;AACA,4E;AACA,oC;AACA,+E;AACA,kC;AACA,+E;AACA,Y;AACA,E;AACA,mD;AACA,gB;AACA,Y;AACA,G;AACA,qC;;AAEA,G;AACA,+E;AACA,gB;AACA,Y;AACA,4G;AACA,G;AACA,wC;;AAEA,G;AACA,gG;AACA,gB;AACA,Y;AACA,yE;AACA,yD;AACA,G;AACA,+C;;;;;;;;;;;;;;;;;;;ACtgBA,W;;AAEA,gC;AACA,+C;;AAEA,gB;AACA,iD;;AAEA,mC;;AAEA,qE;AACA,iC;AACA,0C;AACA,uB;AACA,E;AACA,uD;AACA,gC;AACA,E","file":"/packages/blaze.js","sourcesContent":["/**\n * @namespace Blaze\n * @summary The namespace for all Blaze-related methods and classes.\n */\nBlaze = {};\n\n// Utility to HTML-escape a string. Included for legacy reasons.\nBlaze._escape = (function() {\n var escape_map = {\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n \"`\": \"`\", /* IE allows backtick-delimited attributes?? */\n \"&\": \"&\"\n };\n var escape_one = function(c) {\n return escape_map[c];\n };\n\n return function (x) {\n return x.replace(/[&<>\"'`]/g, escape_one);\n };\n})();\n\nBlaze._warn = function (msg) {\n msg = 'Warning: ' + msg;\n\n if ((typeof Log !== 'undefined') && Log && Log.warn)\n Log.warn(msg); // use Meteor's \"logging\" package\n else if ((typeof console !== 'undefined') && console.log)\n console.log(msg);\n};\n","var debugFunc;\n\n// We call into user code in many places, and it's nice to catch exceptions\n// propagated from user code immediately so that the whole system doesn't just\n// break. Catching exceptions is easy; reporting them is hard. This helper\n// reports exceptions.\n//\n// Usage:\n//\n// ```\n// try {\n// // ... someStuff ...\n// } catch (e) {\n// reportUIException(e);\n// }\n// ```\n//\n// An optional second argument overrides the default message.\n\n// Set this to `true` to cause `reportException` to throw\n// the next exception rather than reporting it. This is\n// useful in unit tests that test error messages.\nBlaze._throwNextException = false;\n\nBlaze._reportException = function (e, msg) {\n if (Blaze._throwNextException) {\n Blaze._throwNextException = false;\n throw e;\n }\n\n if (! debugFunc)\n // adapted from Tracker\n debugFunc = function () {\n return (typeof Meteor !== \"undefined\" ? Meteor._debug :\n ((typeof console !== \"undefined\") && console.log ? console.log :\n function () {}));\n };\n\n // In Chrome, `e.stack` is a multiline string that starts with the message\n // and contains a stack trace. Furthermore, `console.log` makes it clickable.\n // `console.log` supplies the space between the two arguments.\n debugFunc()(msg || 'Exception caught in template:', e.stack || e.message);\n};\n\nBlaze._wrapCatchingExceptions = function (f, where) {\n if (typeof f !== 'function')\n return f;\n\n return function () {\n try {\n return f.apply(this, arguments);\n } catch (e) {\n Blaze._reportException(e, 'Exception in ' + where + ':');\n }\n };\n};\n","/// [new] Blaze.View([name], renderMethod)\n///\n/// Blaze.View is the building block of reactive DOM. Views have\n/// the following features:\n///\n/// * lifecycle callbacks - Views are created, rendered, and destroyed,\n/// and callbacks can be registered to fire when these things happen.\n///\n/// * parent pointer - A View points to its parentView, which is the\n/// View that caused it to be rendered. These pointers form a\n/// hierarchy or tree of Views.\n///\n/// * render() method - A View's render() method specifies the DOM\n/// (or HTML) content of the View. If the method establishes\n/// reactive dependencies, it may be re-run.\n///\n/// * a DOMRange - If a View is rendered to DOM, its position and\n/// extent in the DOM are tracked using a DOMRange object.\n///\n/// When a View is constructed by calling Blaze.View, the View is\n/// not yet considered \"created.\" It doesn't have a parentView yet,\n/// and no logic has been run to initialize the View. All real\n/// work is deferred until at least creation time, when the onViewCreated\n/// callbacks are fired, which happens when the View is \"used\" in\n/// some way that requires it to be rendered.\n///\n/// ...more lifecycle stuff\n///\n/// `name` is an optional string tag identifying the View. The only\n/// time it's used is when looking in the View tree for a View of a\n/// particular name; for example, data contexts are stored on Views\n/// of name \"with\". Names are also useful when debugging, so in\n/// general it's good for functions that create Views to set the name.\n/// Views associated with templates have names of the form \"Template.foo\".\n\n/**\n * @class\n * @summary Constructor for a View, which represents a reactive region of DOM.\n * @locus Client\n * @param {String} [name] Optional. A name for this type of View. See [`view.name`](#view_name).\n * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). In this function, `this` is bound to the View.\n */\nBlaze.View = function (name, render) {\n if (! (this instanceof Blaze.View))\n // called without `new`\n return new Blaze.View(name, render);\n\n if (typeof name === 'function') {\n // omitted \"name\" argument\n render = name;\n name = '';\n }\n this.name = name;\n this._render = render;\n\n this._callbacks = {\n created: null,\n rendered: null,\n destroyed: null\n };\n\n // Setting all properties here is good for readability,\n // and also may help Chrome optimize the code by keeping\n // the View object from changing shape too much.\n this.isCreated = false;\n this._isCreatedForExpansion = false;\n this.isRendered = false;\n this._isAttached = false;\n this.isDestroyed = false;\n this._isInRender = false;\n this.parentView = null;\n this._domrange = null;\n // This flag is normally set to false except for the cases when view's parent\n // was generated as part of expanding some syntactic sugar expressions or\n // methods.\n // Ex.: Blaze.renderWithData is an equivalent to creating a view with regular\n // Blaze.render and wrapping it into {{#with data}}{{/with}} view. Since the\n // users don't know anything about these generated parent views, Blaze needs\n // this information to be available on views to make smarter decisions. For\n // example: removing the generated parent view with the view on Blaze.remove.\n this._hasGeneratedParent = false;\n\n this.renderCount = 0;\n};\n\nBlaze.View.prototype._render = function () { return null; };\n\nBlaze.View.prototype.onViewCreated = function (cb) {\n this._callbacks.created = this._callbacks.created || [];\n this._callbacks.created.push(cb);\n};\n\nBlaze.View.prototype._onViewRendered = function (cb) {\n this._callbacks.rendered = this._callbacks.rendered || [];\n this._callbacks.rendered.push(cb);\n};\n\nBlaze.View.prototype.onViewReady = function (cb) {\n var self = this;\n var fire = function () {\n Tracker.afterFlush(function () {\n if (! self.isDestroyed) {\n Blaze._withCurrentView(self, function () {\n cb.call(self);\n });\n }\n });\n };\n self._onViewRendered(function onViewRendered() {\n if (self.isDestroyed)\n return;\n if (! self._domrange.attached)\n self._domrange.onAttached(fire);\n else\n fire();\n });\n};\n\nBlaze.View.prototype.onViewDestroyed = function (cb) {\n this._callbacks.destroyed = this._callbacks.destroyed || [];\n this._callbacks.destroyed.push(cb);\n};\n\n/// View#autorun(func)\n///\n/// Sets up a Tracker autorun that is \"scoped\" to this View in two\n/// important ways: 1) Blaze.currentView is automatically set\n/// on every re-run, and 2) the autorun is stopped when the\n/// View is destroyed. As with Tracker.autorun, the first run of\n/// the function is immediate, and a Computation object that can\n/// be used to stop the autorun is returned.\n///\n/// View#autorun is meant to be called from View callbacks like\n/// onViewCreated, or from outside the rendering process. It may not\n/// be called before the onViewCreated callbacks are fired (too early),\n/// or from a render() method (too confusing).\n///\n/// Typically, autoruns that update the state\n/// of the View (as in Blaze.With) should be started from an onViewCreated\n/// callback. Autoruns that update the DOM should be started\n/// from either onViewCreated (guarded against the absence of\n/// view._domrange), or onViewReady.\nBlaze.View.prototype.autorun = function (f, _inViewScope, displayName) {\n var self = this;\n\n // The restrictions on when View#autorun can be called are in order\n // to avoid bad patterns, like creating a Blaze.View and immediately\n // calling autorun on it. A freshly created View is not ready to\n // have logic run on it; it doesn't have a parentView, for example.\n // It's when the View is materialized or expanded that the onViewCreated\n // handlers are fired and the View starts up.\n //\n // Letting the render() method call `this.autorun()` is problematic\n // because of re-render. The best we can do is to stop the old\n // autorun and start a new one for each render, but that's a pattern\n // we try to avoid internally because it leads to helpers being\n // called extra times, in the case where the autorun causes the\n // view to re-render (and thus the autorun to be torn down and a\n // new one established).\n //\n // We could lift these restrictions in various ways. One interesting\n // idea is to allow you to call `view.autorun` after instantiating\n // `view`, and automatically wrap it in `view.onViewCreated`, deferring\n // the autorun so that it starts at an appropriate time. However,\n // then we can't return the Computation object to the caller, because\n // it doesn't exist yet.\n if (! self.isCreated) {\n throw new Error(\"View#autorun must be called from the created callback at the earliest\");\n }\n if (this._isInRender) {\n throw new Error(\"Can't call View#autorun from inside render(); try calling it from the created or rendered callback\");\n }\n if (Tracker.active) {\n throw new Error(\"Can't call View#autorun from a Tracker Computation; try calling it from the created or rendered callback\");\n }\n\n // Each local variable allocate additional space on each frame of the\n // execution stack. When too many variables are allocated on stack, you can\n // run out of memory on stack running a deep recursion (which is typical for\n // Blaze functions) and get stackoverlow error. (The size of the stack varies\n // between browsers).\n // The trick we use here is to allocate only one variable on stack `locals`\n // that keeps references to all the rest. Since locals is allocated on heap,\n // we don't take up any space on the stack.\n var locals = {};\n locals.templateInstanceFunc = Blaze.Template._currentTemplateInstanceFunc;\n\n locals.f = function viewAutorun(c) {\n return Blaze._withCurrentView(_inViewScope || self, function () {\n return Blaze.Template._withTemplateInstanceFunc(locals.templateInstanceFunc, function () {\n return f.call(self, c);\n });\n });\n };\n\n // Give the autorun function a better name for debugging and profiling.\n // The `displayName` property is not part of the spec but browsers like Chrome\n // and Firefox prefer it in debuggers over the name function was declared by.\n locals.f.displayName =\n (self.name || 'anonymous') + ':' + (displayName || 'anonymous');\n locals.c = Tracker.autorun(locals.f);\n\n self.onViewDestroyed(function () { locals.c.stop(); });\n\n return locals.c;\n};\n\nBlaze.View.prototype._errorIfShouldntCallSubscribe = function () {\n var self = this;\n\n if (! self.isCreated) {\n throw new Error(\"View#subscribe must be called from the created callback at the earliest\");\n }\n if (self._isInRender) {\n throw new Error(\"Can't call View#subscribe from inside render(); try calling it from the created or rendered callback\");\n }\n if (self.isDestroyed) {\n throw new Error(\"Can't call View#subscribe from inside the destroyed callback, try calling it inside created or rendered.\");\n }\n};\n\n/**\n * Just like Blaze.View#autorun, but with Meteor.subscribe instead of\n * Tracker.autorun. Stop the subscription when the view is destroyed.\n * @return {SubscriptionHandle} A handle to the subscription so that you can\n * see if it is ready, or stop it manually\n */\nBlaze.View.prototype.subscribe = function (args, options) {\n var self = this;\n options = {} || options;\n\n self._errorIfShouldntCallSubscribe();\n\n var subHandle;\n if (options.connection) {\n subHandle = options.connection.subscribe.apply(options.connection, args);\n } else {\n subHandle = Meteor.subscribe.apply(Meteor, args);\n }\n\n self.onViewDestroyed(function () {\n subHandle.stop();\n });\n\n return subHandle;\n};\n\nBlaze.View.prototype.firstNode = function () {\n if (! this._isAttached)\n throw new Error(\"View must be attached before accessing its DOM\");\n\n return this._domrange.firstNode();\n};\n\nBlaze.View.prototype.lastNode = function () {\n if (! this._isAttached)\n throw new Error(\"View must be attached before accessing its DOM\");\n\n return this._domrange.lastNode();\n};\n\nBlaze._fireCallbacks = function (view, which) {\n Blaze._withCurrentView(view, function () {\n Tracker.nonreactive(function fireCallbacks() {\n var cbs = view._callbacks[which];\n for (var i = 0, N = (cbs && cbs.length); i < N; i++)\n cbs[i].call(view);\n });\n });\n};\n\nBlaze._createView = function (view, parentView, forExpansion) {\n if (view.isCreated)\n throw new Error(\"Can't render the same View twice\");\n\n view.parentView = (parentView || null);\n view.isCreated = true;\n if (forExpansion)\n view._isCreatedForExpansion = true;\n\n Blaze._fireCallbacks(view, 'created');\n};\n\nvar doFirstRender = function (view, initialContent) {\n var domrange = new Blaze._DOMRange(initialContent);\n view._domrange = domrange;\n domrange.view = view;\n view.isRendered = true;\n Blaze._fireCallbacks(view, 'rendered');\n\n var teardownHook = null;\n\n domrange.onAttached(function attached(range, element) {\n view._isAttached = true;\n\n teardownHook = Blaze._DOMBackend.Teardown.onElementTeardown(\n element, function teardown() {\n Blaze._destroyView(view, true /* _skipNodes */);\n });\n });\n\n // tear down the teardown hook\n view.onViewDestroyed(function () {\n teardownHook && teardownHook.stop();\n teardownHook = null;\n });\n\n return domrange;\n};\n\n// Take an uncreated View `view` and create and render it to DOM,\n// setting up the autorun that updates the View. Returns a new\n// DOMRange, which has been associated with the View.\n//\n// The private arguments `_workStack` and `_intoArray` are passed in\n// by Blaze._materializeDOM. If provided, then we avoid the mutual\n// recursion of calling back into Blaze._materializeDOM so that deep\n// View hierarchies don't blow the stack. Instead, we push tasks onto\n// workStack for the initial rendering and subsequent setup of the\n// View, and they are done after we return. When there is a\n// _workStack, we do not return the new DOMRange, but instead push it\n// into _intoArray from a _workStack task.\nBlaze._materializeView = function (view, parentView, _workStack, _intoArray) {\n Blaze._createView(view, parentView);\n\n var domrange;\n var lastHtmljs;\n // We don't expect to be called in a Computation, but just in case,\n // wrap in Tracker.nonreactive.\n Tracker.nonreactive(function () {\n view.autorun(function doRender(c) {\n // `view.autorun` sets the current view.\n view.renderCount++;\n view._isInRender = true;\n // Any dependencies that should invalidate this Computation come\n // from this line:\n var htmljs = view._render();\n view._isInRender = false;\n\n if (! c.firstRun) {\n Tracker.nonreactive(function doMaterialize() {\n // re-render\n var rangesAndNodes = Blaze._materializeDOM(htmljs, [], view);\n if (! Blaze._isContentEqual(lastHtmljs, htmljs)) {\n domrange.setMembers(rangesAndNodes);\n Blaze._fireCallbacks(view, 'rendered');\n }\n });\n }\n lastHtmljs = htmljs;\n\n // Causes any nested views to stop immediately, not when we call\n // `setMembers` the next time around the autorun. Otherwise,\n // helpers in the DOM tree to be replaced might be scheduled\n // to re-run before we have a chance to stop them.\n Tracker.onInvalidate(function () {\n if (domrange) {\n domrange.destroyMembers();\n }\n });\n }, undefined, 'materialize');\n\n // first render. lastHtmljs is the first htmljs.\n var initialContents;\n if (! _workStack) {\n initialContents = Blaze._materializeDOM(lastHtmljs, [], view);\n domrange = doFirstRender(view, initialContents);\n initialContents = null; // help GC because we close over this scope a lot\n } else {\n // We're being called from Blaze._materializeDOM, so to avoid\n // recursion and save stack space, provide a description of the\n // work to be done instead of doing it. Tasks pushed onto\n // _workStack will be done in LIFO order after we return.\n // The work will still be done within a Tracker.nonreactive,\n // because it will be done by some call to Blaze._materializeDOM\n // (which is always called in a Tracker.nonreactive).\n initialContents = [];\n // push this function first so that it happens last\n _workStack.push(function () {\n domrange = doFirstRender(view, initialContents);\n initialContents = null; // help GC because of all the closures here\n _intoArray.push(domrange);\n });\n // now push the task that calculates initialContents\n _workStack.push([lastHtmljs, initialContents, view]);\n }\n });\n\n if (! _workStack) {\n return domrange;\n } else {\n return null;\n }\n};\n\n// Expands a View to HTMLjs, calling `render` recursively on all\n// Views and evaluating any dynamic attributes. Calls the `created`\n// callback, but not the `materialized` or `rendered` callbacks.\n// Destroys the view immediately, unless called in a Tracker Computation,\n// in which case the view will be destroyed when the Computation is\n// invalidated. If called in a Tracker Computation, the result is a\n// reactive string; that is, the Computation will be invalidated\n// if any changes are made to the view or subviews that might affect\n// the HTML.\nBlaze._expandView = function (view, parentView) {\n Blaze._createView(view, parentView, true /*forExpansion*/);\n\n view._isInRender = true;\n var htmljs = Blaze._withCurrentView(view, function () {\n return view._render();\n });\n view._isInRender = false;\n\n var result = Blaze._expand(htmljs, view);\n\n if (Tracker.active) {\n Tracker.onInvalidate(function () {\n Blaze._destroyView(view);\n });\n } else {\n Blaze._destroyView(view);\n }\n\n return result;\n};\n\n// Options: `parentView`\nBlaze._HTMLJSExpander = HTML.TransformingVisitor.extend();\nBlaze._HTMLJSExpander.def({\n visitObject: function (x) {\n if (x instanceof Blaze.Template)\n x = x.constructView();\n if (x instanceof Blaze.View)\n return Blaze._expandView(x, this.parentView);\n\n // this will throw an error; other objects are not allowed!\n return HTML.TransformingVisitor.prototype.visitObject.call(this, x);\n },\n visitAttributes: function (attrs) {\n // expand dynamic attributes\n if (typeof attrs === 'function')\n attrs = Blaze._withCurrentView(this.parentView, attrs);\n\n // call super (e.g. for case where `attrs` is an array)\n return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs);\n },\n visitAttribute: function (name, value, tag) {\n // expand attribute values that are functions. Any attribute value\n // that contains Views must be wrapped in a function.\n if (typeof value === 'function')\n value = Blaze._withCurrentView(this.parentView, value);\n\n return HTML.TransformingVisitor.prototype.visitAttribute.call(\n this, name, value, tag);\n }\n});\n\n// Return Blaze.currentView, but only if it is being rendered\n// (i.e. we are in its render() method).\nvar currentViewIfRendering = function () {\n var view = Blaze.currentView;\n return (view && view._isInRender) ? view : null;\n};\n\nBlaze._expand = function (htmljs, parentView) {\n parentView = parentView || currentViewIfRendering();\n return (new Blaze._HTMLJSExpander(\n {parentView: parentView})).visit(htmljs);\n};\n\nBlaze._expandAttributes = function (attrs, parentView) {\n parentView = parentView || currentViewIfRendering();\n return (new Blaze._HTMLJSExpander(\n {parentView: parentView})).visitAttributes(attrs);\n};\n\nBlaze._destroyView = function (view, _skipNodes) {\n if (view.isDestroyed)\n return;\n view.isDestroyed = true;\n\n Blaze._fireCallbacks(view, 'destroyed');\n\n // Destroy views and elements recursively. If _skipNodes,\n // only recurse up to views, not elements, for the case where\n // the backend (jQuery) is recursing over the elements already.\n\n if (view._domrange)\n view._domrange.destroyMembers(_skipNodes);\n};\n\nBlaze._destroyNode = function (node) {\n if (node.nodeType === 1)\n Blaze._DOMBackend.Teardown.tearDownElement(node);\n};\n\n// Are the HTMLjs entities `a` and `b` the same? We could be\n// more elaborate here but the point is to catch the most basic\n// cases.\nBlaze._isContentEqual = function (a, b) {\n if (a instanceof HTML.Raw) {\n return (b instanceof HTML.Raw) && (a.value === b.value);\n } else if (a == null) {\n return (b == null);\n } else {\n return (a === b) &&\n ((typeof a === 'number') || (typeof a === 'boolean') ||\n (typeof a === 'string'));\n }\n};\n\n/**\n * @summary The View corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`.\n * @locus Client\n * @type {Blaze.View}\n */\nBlaze.currentView = null;\n\nBlaze._withCurrentView = function (view, func) {\n var oldView = Blaze.currentView;\n try {\n Blaze.currentView = view;\n return func();\n } finally {\n Blaze.currentView = oldView;\n }\n};\n\n// Blaze.render publicly takes a View or a Template.\n// Privately, it takes any HTMLJS (extended with Views and Templates)\n// except null or undefined, or a function that returns any extended\n// HTMLJS.\nvar checkRenderContent = function (content) {\n if (content === null)\n throw new Error(\"Can't render null\");\n if (typeof content === 'undefined')\n throw new Error(\"Can't render undefined\");\n\n if ((content instanceof Blaze.View) ||\n (content instanceof Blaze.Template) ||\n (typeof content === 'function'))\n return;\n\n try {\n // Throw if content doesn't look like HTMLJS at the top level\n // (i.e. verify that this is an HTML.Tag, or an array,\n // or a primitive, etc.)\n (new HTML.Visitor).visit(content);\n } catch (e) {\n // Make error message suitable for public API\n throw new Error(\"Expected Template or View\");\n }\n};\n\n// For Blaze.render and Blaze.toHTML, take content and\n// wrap it in a View, unless it's a single View or\n// Template already.\nvar contentAsView = function (content) {\n checkRenderContent(content);\n\n if (content instanceof Blaze.Template) {\n return content.constructView();\n } else if (content instanceof Blaze.View) {\n return content;\n } else {\n var func = content;\n if (typeof func !== 'function') {\n func = function () {\n return content;\n };\n }\n return Blaze.View('render', func);\n }\n};\n\n// For Blaze.renderWithData and Blaze.toHTMLWithData, wrap content\n// in a function, if necessary, so it can be a content arg to\n// a Blaze.With.\nvar contentAsFunc = function (content) {\n checkRenderContent(content);\n\n if (typeof content !== 'function') {\n return function () {\n return content;\n };\n } else {\n return content;\n }\n};\n\n/**\n * @summary Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered [View](#blaze_view) which can be passed to [`Blaze.remove`](#blaze_remove).\n * @locus Client\n * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render. If a template, a View object is [constructed](#template_constructview). If a View, it must be an unrendered View, which becomes a rendered View and is returned.\n * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node.\n * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.\n * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).\n */\nBlaze.render = function (content, parentElement, nextNode, parentView) {\n if (! parentElement) {\n Blaze._warn(\"Blaze.render without a parent element is deprecated. \" +\n \"You must specify where to insert the rendered content.\");\n }\n\n if (nextNode instanceof Blaze.View) {\n // handle omitted nextNode\n parentView = nextNode;\n nextNode = null;\n }\n\n // parentElement must be a DOM node. in particular, can't be the\n // result of a call to `$`. Can't check if `parentElement instanceof\n // Node` since 'Node' is undefined in IE8.\n if (parentElement && typeof parentElement.nodeType !== 'number')\n throw new Error(\"'parentElement' must be a DOM node\");\n if (nextNode && typeof nextNode.nodeType !== 'number') // 'nextNode' is optional\n throw new Error(\"'nextNode' must be a DOM node\");\n\n parentView = parentView || currentViewIfRendering();\n\n var view = contentAsView(content);\n Blaze._materializeView(view, parentView);\n\n if (parentElement) {\n view._domrange.attach(parentElement, nextNode);\n }\n\n return view;\n};\n\nBlaze.insert = function (view, parentElement, nextNode) {\n Blaze._warn(\"Blaze.insert has been deprecated. Specify where to insert the \" +\n \"rendered content in the call to Blaze.render.\");\n\n if (! (view && (view._domrange instanceof Blaze._DOMRange)))\n throw new Error(\"Expected template rendered with Blaze.render\");\n\n view._domrange.attach(parentElement, nextNode);\n};\n\n/**\n * @summary Renders a template or View to DOM nodes with a data context. Otherwise identical to `Blaze.render`.\n * @locus Client\n * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render.\n * @param {Object|Function} data The data context to use, or a function returning a data context. If a function is provided, it will be reactively re-run.\n * @param {DOMNode} parentNode The node that will be the parent of the rendered template. It must be an Element node.\n * @param {DOMNode} [nextNode] Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.\n * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).\n */\nBlaze.renderWithData = function (content, data, parentElement, nextNode, parentView) {\n // We defer the handling of optional arguments to Blaze.render. At this point,\n // `nextNode` may actually be `parentView`.\n return Blaze.render(Blaze._TemplateWith(data, contentAsFunc(content)),\n parentElement, nextNode, parentView);\n};\n\n/**\n * @summary Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it.\n * @locus Client\n * @param {Blaze.View} renderedView The return value from `Blaze.render` or `Blaze.renderWithData`.\n */\nBlaze.remove = function (view) {\n if (! (view && (view._domrange instanceof Blaze._DOMRange)))\n throw new Error(\"Expected template rendered with Blaze.render\");\n\n while (view) {\n if (! view.isDestroyed) {\n var range = view._domrange;\n if (range.attached && ! range.parentRange)\n range.detach();\n range.destroy();\n }\n\n view = view._hasGeneratedParent && view.parentView;\n }\n};\n\n/**\n * @summary Renders a template or View to a string of HTML.\n * @locus Client\n * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.\n */\nBlaze.toHTML = function (content, parentView) {\n parentView = parentView || currentViewIfRendering();\n\n return HTML.toHTML(Blaze._expandView(contentAsView(content), parentView));\n};\n\n/**\n * @summary Renders a template or View to HTML with a data context. Otherwise identical to `Blaze.toHTML`.\n * @locus Client\n * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.\n * @param {Object|Function} data The data context to use, or a function returning a data context.\n */\nBlaze.toHTMLWithData = function (content, data, parentView) {\n parentView = parentView || currentViewIfRendering();\n\n return HTML.toHTML(Blaze._expandView(Blaze._TemplateWith(\n data, contentAsFunc(content)), parentView));\n};\n\nBlaze._toText = function (htmljs, parentView, textMode) {\n if (typeof htmljs === 'function')\n throw new Error(\"Blaze._toText doesn't take a function, just HTMLjs\");\n\n if ((parentView != null) && ! (parentView instanceof Blaze.View)) {\n // omitted parentView argument\n textMode = parentView;\n parentView = null;\n }\n parentView = parentView || currentViewIfRendering();\n\n if (! textMode)\n throw new Error(\"textMode required\");\n if (! (textMode === HTML.TEXTMODE.STRING ||\n textMode === HTML.TEXTMODE.RCDATA ||\n textMode === HTML.TEXTMODE.ATTRIBUTE))\n throw new Error(\"Unknown textMode: \" + textMode);\n\n return HTML.toText(Blaze._expand(htmljs, parentView), textMode);\n};\n\n/**\n * @summary Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template.\n * @locus Client\n * @param {DOMElement|Blaze.View} [elementOrView] Optional. An element that was rendered by a Meteor, or a View.\n */\nBlaze.getData = function (elementOrView) {\n var theWith;\n\n if (! elementOrView) {\n theWith = Blaze.getView('with');\n } else if (elementOrView instanceof Blaze.View) {\n var view = elementOrView;\n theWith = (view.name === 'with' ? view :\n Blaze.getView(view, 'with'));\n } else if (typeof elementOrView.nodeType === 'number') {\n if (elementOrView.nodeType !== 1)\n throw new Error(\"Expected DOM element\");\n theWith = Blaze.getView(elementOrView, 'with');\n } else {\n throw new Error(\"Expected DOM element or View\");\n }\n\n return theWith ? theWith.dataVar.get() : null;\n};\n\n// For back-compat\nBlaze.getElementData = function (element) {\n Blaze._warn(\"Blaze.getElementData has been deprecated. Use \" +\n \"Blaze.getData(element) instead.\");\n\n if (element.nodeType !== 1)\n throw new Error(\"Expected DOM element\");\n\n return Blaze.getData(element);\n};\n\n// Both arguments are optional.\n\n/**\n * @summary Gets either the current View, or the View enclosing the given DOM element.\n * @locus Client\n * @param {DOMElement} [element] Optional. If specified, the View enclosing `element` is returned.\n */\nBlaze.getView = function (elementOrView, _viewName) {\n var viewName = _viewName;\n\n if ((typeof elementOrView) === 'string') {\n // omitted elementOrView; viewName present\n viewName = elementOrView;\n elementOrView = null;\n }\n\n // We could eventually shorten the code by folding the logic\n // from the other methods into this method.\n if (! elementOrView) {\n return Blaze._getCurrentView(viewName);\n } else if (elementOrView instanceof Blaze.View) {\n return Blaze._getParentView(elementOrView, viewName);\n } else if (typeof elementOrView.nodeType === 'number') {\n return Blaze._getElementView(elementOrView, viewName);\n } else {\n throw new Error(\"Expected DOM element or View\");\n }\n};\n\n// Gets the current view or its nearest ancestor of name\n// `name`.\nBlaze._getCurrentView = function (name) {\n var view = Blaze.currentView;\n // Better to fail in cases where it doesn't make sense\n // to use Blaze._getCurrentView(). There will be a current\n // view anywhere it does. You can check Blaze.currentView\n // if you want to know whether there is one or not.\n if (! view)\n throw new Error(\"There is no current view\");\n\n if (name) {\n while (view && view.name !== name)\n view = view.parentView;\n return view || null;\n } else {\n // Blaze._getCurrentView() with no arguments just returns\n // Blaze.currentView.\n return view;\n }\n};\n\nBlaze._getParentView = function (view, name) {\n var v = view.parentView;\n\n if (name) {\n while (v && v.name !== name)\n v = v.parentView;\n }\n\n return v || null;\n};\n\nBlaze._getElementView = function (elem, name) {\n var range = Blaze._DOMRange.forElement(elem);\n var view = null;\n while (range && ! view) {\n view = (range.view || null);\n if (! view) {\n if (range.parentRange)\n range = range.parentRange;\n else\n range = Blaze._DOMRange.forElement(range.parentElement);\n }\n }\n\n if (name) {\n while (view && view.name !== name)\n view = view.parentView;\n return view || null;\n } else {\n return view;\n }\n};\n\nBlaze._addEventMap = function (view, eventMap, thisInHandler) {\n thisInHandler = (thisInHandler || null);\n var handles = [];\n\n if (! view._domrange)\n throw new Error(\"View must have a DOMRange\");\n\n view._domrange.onAttached(function attached_eventMaps(range, element) {\n _.each(eventMap, function (handler, spec) {\n var clauses = spec.split(/,\\s+/);\n // iterate over clauses of spec, e.g. ['click .foo', 'click .bar']\n _.each(clauses, function (clause) {\n var parts = clause.split(/\\s+/);\n if (parts.length === 0)\n return;\n\n var newEvents = parts.shift();\n var selector = parts.join(' ');\n handles.push(Blaze._EventSupport.listen(\n element, newEvents, selector,\n function (evt) {\n if (! range.containsElement(evt.currentTarget))\n return null;\n var handlerThis = thisInHandler || this;\n var handlerArgs = arguments;\n return Blaze._withCurrentView(view, function () {\n return handler.apply(handlerThis, handlerArgs);\n });\n },\n range, function (r) {\n return r.parentRange;\n }));\n });\n });\n });\n\n view.onViewDestroyed(function () {\n _.each(handles, function (h) {\n h.stop();\n });\n handles.length = 0;\n });\n};\n","Blaze._calculateCondition = function (cond) {\n if (cond instanceof Array && cond.length === 0)\n cond = false;\n return !! cond;\n};\n\n/**\n * @summary Constructs a View that renders content with a data context.\n * @locus Client\n * @param {Object|Function} data An object to use as the data context, or a function returning such an object. If a function is provided, it will be reactively re-run.\n * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content).\n */\nBlaze.With = function (data, contentFunc) {\n var view = Blaze.View('with', contentFunc);\n\n view.dataVar = new ReactiveVar;\n\n view.onViewCreated(function () {\n if (typeof data === 'function') {\n // `data` is a reactive function\n view.autorun(function () {\n view.dataVar.set(data());\n }, view.parentView, 'setData');\n } else {\n view.dataVar.set(data);\n }\n });\n\n return view;\n};\n\n/**\n * @summary Constructs a View that renders content conditionally.\n * @locus Client\n * @param {Function} conditionFunc A function to reactively re-run. Whether the result is truthy or falsy determines whether `contentFunc` or `elseFunc` is shown. An empty array is considered falsy.\n * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content).\n * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the \"else\" case.\n */\nBlaze.If = function (conditionFunc, contentFunc, elseFunc, _not) {\n var conditionVar = new ReactiveVar;\n\n var view = Blaze.View(_not ? 'unless' : 'if', function () {\n return conditionVar.get() ? contentFunc() :\n (elseFunc ? elseFunc() : null);\n });\n view.__conditionVar = conditionVar;\n view.onViewCreated(function () {\n this.autorun(function () {\n var cond = Blaze._calculateCondition(conditionFunc());\n conditionVar.set(_not ? (! cond) : cond);\n }, this.parentView, 'condition');\n });\n\n return view;\n};\n\n/**\n * @summary An inverted [`Blaze.If`](#blaze_if).\n * @locus Client\n * @param {Function} conditionFunc A function to reactively re-run. If the result is falsy, `contentFunc` is shown, otherwise `elseFunc` is shown. An empty array is considered falsy.\n * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content).\n * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content). If no `elseFunc` is supplied, no content is shown in the \"else\" case.\n */\nBlaze.Unless = function (conditionFunc, contentFunc, elseFunc) {\n return Blaze.If(conditionFunc, contentFunc, elseFunc, true /*_not*/);\n};\n\n/**\n * @summary Constructs a View that renders `contentFunc` for each item in a sequence.\n * @locus Client\n * @param {Function} argFunc A function to reactively re-run. The function may return a Cursor, an array, null, or undefined.\n * @param {Function} contentFunc A Function that returns [*renderable content*](#renderable_content).\n * @param {Function} [elseFunc] Optional. A Function that returns [*renderable content*](#renderable_content) to display in the case when there are no items to display.\n */\nBlaze.Each = function (argFunc, contentFunc, elseFunc) {\n var eachView = Blaze.View('each', function () {\n var subviews = this.initialSubviews;\n this.initialSubviews = null;\n if (this._isCreatedForExpansion) {\n this.expandedValueDep = new Tracker.Dependency;\n this.expandedValueDep.depend();\n }\n return subviews;\n });\n eachView.initialSubviews = [];\n eachView.numItems = 0;\n eachView.inElseMode = false;\n eachView.stopHandle = null;\n eachView.contentFunc = contentFunc;\n eachView.elseFunc = elseFunc;\n eachView.argVar = new ReactiveVar;\n\n eachView.onViewCreated(function () {\n // We evaluate argFunc in an autorun to make sure\n // Blaze.currentView is always set when it runs (rather than\n // passing argFunc straight to ObserveSequence).\n eachView.autorun(function () {\n eachView.argVar.set(argFunc());\n }, eachView.parentView, 'collection');\n\n eachView.stopHandle = ObserveSequence.observe(function () {\n return eachView.argVar.get();\n }, {\n addedAt: function (id, item, index) {\n Tracker.nonreactive(function () {\n var newItemView = Blaze.With(item, eachView.contentFunc);\n eachView.numItems++;\n\n if (eachView.expandedValueDep) {\n eachView.expandedValueDep.changed();\n } else if (eachView._domrange) {\n if (eachView.inElseMode) {\n eachView._domrange.removeMember(0);\n eachView.inElseMode = false;\n }\n\n var range = Blaze._materializeView(newItemView, eachView);\n eachView._domrange.addMember(range, index);\n } else {\n eachView.initialSubviews.splice(index, 0, newItemView);\n }\n });\n },\n removedAt: function (id, item, index) {\n Tracker.nonreactive(function () {\n eachView.numItems--;\n if (eachView.expandedValueDep) {\n eachView.expandedValueDep.changed();\n } else if (eachView._domrange) {\n eachView._domrange.removeMember(index);\n if (eachView.elseFunc && eachView.numItems === 0) {\n eachView.inElseMode = true;\n eachView._domrange.addMember(\n Blaze._materializeView(\n Blaze.View('each_else',eachView.elseFunc),\n eachView), 0);\n }\n } else {\n eachView.initialSubviews.splice(index, 1);\n }\n });\n },\n changedAt: function (id, newItem, oldItem, index) {\n Tracker.nonreactive(function () {\n if (eachView.expandedValueDep) {\n eachView.expandedValueDep.changed();\n } else {\n var itemView;\n if (eachView._domrange) {\n itemView = eachView._domrange.getMember(index).view;\n } else {\n itemView = eachView.initialSubviews[index];\n }\n itemView.dataVar.set(newItem);\n }\n });\n },\n movedTo: function (id, item, fromIndex, toIndex) {\n Tracker.nonreactive(function () {\n if (eachView.expandedValueDep) {\n eachView.expandedValueDep.changed();\n } else if (eachView._domrange) {\n eachView._domrange.moveMember(fromIndex, toIndex);\n } else {\n var subviews = eachView.initialSubviews;\n var itemView = subviews[fromIndex];\n subviews.splice(fromIndex, 1);\n subviews.splice(toIndex, 0, itemView);\n }\n });\n }\n });\n\n if (eachView.elseFunc && eachView.numItems === 0) {\n eachView.inElseMode = true;\n eachView.initialSubviews[0] =\n Blaze.View('each_else', eachView.elseFunc);\n }\n });\n\n eachView.onViewDestroyed(function () {\n if (eachView.stopHandle)\n eachView.stopHandle.stop();\n });\n\n return eachView;\n};\n\nBlaze._TemplateWith = function (arg, contentFunc) {\n var w;\n\n var argFunc = arg;\n if (typeof arg !== 'function') {\n argFunc = function () {\n return arg;\n };\n }\n\n // This is a little messy. When we compile `{{> Template.contentBlock}}`, we\n // wrap it in Blaze._InOuterTemplateScope in order to skip the intermediate\n // parent Views in the current template. However, when there's an argument\n // (`{{> Template.contentBlock arg}}`), the argument needs to be evaluated\n // in the original scope. There's no good order to nest\n // Blaze._InOuterTemplateScope and Spacebars.TemplateWith to achieve this,\n // so we wrap argFunc to run it in the \"original parentView\" of the\n // Blaze._InOuterTemplateScope.\n //\n // To make this better, reconsider _InOuterTemplateScope as a primitive.\n // Longer term, evaluate expressions in the proper lexical scope.\n var wrappedArgFunc = function () {\n var viewToEvaluateArg = null;\n if (w.parentView && w.parentView.name === 'InOuterTemplateScope') {\n viewToEvaluateArg = w.parentView.originalParentView;\n }\n if (viewToEvaluateArg) {\n return Blaze._withCurrentView(viewToEvaluateArg, argFunc);\n } else {\n return argFunc();\n }\n };\n\n var wrappedContentFunc = function () {\n var content = contentFunc.call(this);\n\n // Since we are generating the Blaze._TemplateWith view for the\n // user, set the flag on the child view. If `content` is a template,\n // construct the View so that we can set the flag.\n if (content instanceof Blaze.Template) {\n content = content.constructView();\n }\n if (content instanceof Blaze.View) {\n content._hasGeneratedParent = true;\n }\n\n return content;\n };\n\n w = Blaze.With(wrappedArgFunc, wrappedContentFunc);\n w.__isTemplateWith = true;\n return w;\n};\n\nBlaze._InOuterTemplateScope = function (templateView, contentFunc) {\n var view = Blaze.View('InOuterTemplateScope', contentFunc);\n var parentView = templateView.parentView;\n\n // Hack so that if you call `{{> foo bar}}` and it expands into\n // `{{#with bar}}{{> foo}}{{/with}}`, and then `foo` is a template\n // that inserts `{{> Template.contentBlock}}`, the data context for\n // `Template.contentBlock` is not `bar` but the one enclosing that.\n if (parentView.__isTemplateWith)\n parentView = parentView.parentView;\n\n view.onViewCreated(function () {\n this.originalParentView = this.parentView;\n this.parentView = parentView;\n });\n return view;\n};\n\n// XXX COMPAT WITH 0.9.0\nBlaze.InOuterTemplateScope = Blaze._InOuterTemplateScope;\n","Blaze._globalHelpers = {};\n\n// Documented as Template.registerHelper.\n// This definition also provides back-compat for `UI.registerHelper`.\nBlaze.registerHelper = function (name, func) {\n Blaze._globalHelpers[name] = func;\n};\n\nvar bindIfIsFunction = function (x, target) {\n if (typeof x !== 'function')\n return x;\n return _.bind(x, target);\n};\n\n// If `x` is a function, binds the value of `this` for that function\n// to the current data context.\nvar bindDataContext = function (x) {\n if (typeof x === 'function') {\n return function () {\n var data = Blaze.getData();\n if (data == null)\n data = {};\n return x.apply(data, arguments);\n };\n }\n return x;\n};\n\nBlaze._OLDSTYLE_HELPER = {};\n\nvar getTemplateHelper = Blaze._getTemplateHelper = function (template, name) {\n // XXX COMPAT WITH 0.9.3\n var isKnownOldStyleHelper = false;\n\n if (template.__helpers.has(name)) {\n var helper = template.__helpers.get(name);\n if (helper === Blaze._OLDSTYLE_HELPER) {\n isKnownOldStyleHelper = true;\n } else {\n return helper;\n }\n }\n\n // old-style helper\n if (name in template) {\n // Only warn once per helper\n if (! isKnownOldStyleHelper) {\n template.__helpers.set(name, Blaze._OLDSTYLE_HELPER);\n if (! template._NOWARN_OLDSTYLE_HELPERS) {\n Blaze._warn('Assigning helper with `' + template.viewName + '.' +\n name + ' = ...` is deprecated. Use `' + template.viewName +\n '.helpers(...)` instead.');\n }\n }\n return template[name];\n }\n\n return null;\n};\n\nvar wrapHelper = function (f, templateFunc) {\n if (typeof f !== \"function\") {\n return f;\n }\n\n return function () {\n var self = this;\n var args = arguments;\n\n return Blaze.Template._withTemplateInstanceFunc(templateFunc, function () {\n return Blaze._wrapCatchingExceptions(f, 'template helper').apply(self, args);\n });\n };\n};\n\n// Looks up a name, like \"foo\" or \"..\", as a helper of the\n// current template; a global helper; the name of a template;\n// or a property of the data context. Called on the View of\n// a template (i.e. a View with a `.template` property,\n// where the helpers are). Used for the first name in a\n// \"path\" in a template tag, like \"foo\" in `{{foo.bar}}` or\n// \"..\" in `{{frobulate ../blah}}`.\n//\n// Returns a function, a non-function value, or null. If\n// a function is found, it is bound appropriately.\n//\n// NOTE: This function must not establish any reactive\n// dependencies itself. If there is any reactivity in the\n// value, lookup should return a function.\nBlaze.View.prototype.lookup = function (name, _options) {\n var template = this.template;\n var lookupTemplate = _options && _options.template;\n var helper;\n var boundTmplInstance;\n\n if (this.templateInstance) {\n boundTmplInstance = _.bind(this.templateInstance, this);\n }\n\n if (/^\\./.test(name)) {\n // starts with a dot. must be a series of dots which maps to an\n // ancestor of the appropriate height.\n if (!/^(\\.)+$/.test(name))\n throw new Error(\"id starting with dot must be a series of dots\");\n\n return Blaze._parentData(name.length - 1, true /*_functionWrapped*/);\n\n } else if (template &&\n ((helper = getTemplateHelper(template, name)) != null)) {\n return wrapHelper(bindDataContext(helper), boundTmplInstance);\n } else if (lookupTemplate && (name in Blaze.Template) &&\n (Blaze.Template[name] instanceof Blaze.Template)) {\n return Blaze.Template[name];\n } else if (Blaze._globalHelpers[name] != null) {\n return wrapHelper(bindDataContext(Blaze._globalHelpers[name]),\n boundTmplInstance);\n } else {\n return function () {\n var isCalledAsFunction = (arguments.length > 0);\n var data = Blaze.getData();\n if (lookupTemplate && ! (data && data[name])) {\n throw new Error(\"No such template: \" + name);\n }\n if (isCalledAsFunction && ! (data && data[name])) {\n throw new Error(\"No such function: \" + name);\n }\n if (! data)\n return null;\n var x = data[name];\n if (typeof x !== 'function') {\n if (isCalledAsFunction) {\n throw new Error(\"Can't call non-function: \" + x);\n }\n return x;\n }\n return x.apply(data, arguments);\n };\n }\n return null;\n};\n\n// Implement Spacebars' {{../..}}.\n// @param height {Number} The number of '..'s\nBlaze._parentData = function (height, _functionWrapped) {\n // If height is null or undefined, we default to 1, the first parent.\n if (height == null) {\n height = 1;\n }\n var theWith = Blaze.getView('with');\n for (var i = 0; (i < height) && theWith; i++) {\n theWith = Blaze.getView(theWith, 'with');\n }\n\n if (! theWith)\n return null;\n if (_functionWrapped)\n return function () { return theWith.dataVar.get(); };\n return theWith.dataVar.get();\n};\n\n\nBlaze.View.prototype.lookupTemplate = function (name) {\n return this.lookup(name, {template:true});\n};\n","// [new] Blaze.Template([viewName], renderFunction)\n//\n// `Blaze.Template` is the class of templates, like `Template.foo` in\n// Meteor, which is `instanceof Template`.\n//\n// `viewKind` is a string that looks like \"Template.foo\" for templates\n// defined by the compiler.\n\n/**\n * @class\n * @summary Constructor for a Template, which is used to construct Views with particular name and content.\n * @locus Client\n * @param {String} [viewName] Optional. A name for Views constructed by this Template. See [`view.name`](#view_name).\n * @param {Function} renderFunction A function that returns [*renderable content*](#renderable_content). This function is used as the `renderFunction` for Views constructed by this Template.\n */\nBlaze.Template = function (viewName, renderFunction) {\n if (! (this instanceof Blaze.Template))\n // called without `new`\n return new Blaze.Template(viewName, renderFunction);\n\n if (typeof viewName === 'function') {\n // omitted \"viewName\" argument\n renderFunction = viewName;\n viewName = '';\n }\n if (typeof viewName !== 'string')\n throw new Error(\"viewName must be a String (or omitted)\");\n if (typeof renderFunction !== 'function')\n throw new Error(\"renderFunction must be a function\");\n\n this.viewName = viewName;\n this.renderFunction = renderFunction;\n\n this.__helpers = new HelperMap;\n this.__eventMaps = [];\n\n this._callbacks = {\n created: [],\n rendered: [],\n destroyed: []\n };\n};\nvar Template = Blaze.Template;\n\nvar HelperMap = function () {};\nHelperMap.prototype.get = function (name) {\n return this[' '+name];\n};\nHelperMap.prototype.set = function (name, helper) {\n this[' '+name] = helper;\n};\nHelperMap.prototype.has = function (name) {\n return (' '+name) in this;\n};\n\n/**\n * @summary Returns true if `value` is a template object like `Template.myTemplate`.\n * @locus Client\n * @param {Any} value The value to test.\n */\nBlaze.isTemplate = function (t) {\n return (t instanceof Blaze.Template);\n};\n\n/**\n * @name onCreated\n * @instance\n * @memberOf Template\n * @summary Register a function to be called when an instance of this template is created.\n * @param {Function} callback A function to be added as a callback.\n * @locus Client\n */\nTemplate.prototype.onCreated = function (cb) {\n this._callbacks.created.push(cb);\n};\n\n/**\n * @name onRendered\n * @instance\n * @memberOf Template\n * @summary Register a function to be called when an instance of this template is inserted into the DOM.\n * @param {Function} callback A function to be added as a callback.\n * @locus Client\n */\nTemplate.prototype.onRendered = function (cb) {\n this._callbacks.rendered.push(cb);\n};\n\n/**\n * @name onDestroyed\n * @instance\n * @memberOf Template\n * @summary Register a function to be called when an instance of this template is removed from the DOM and destroyed.\n * @param {Function} callback A function to be added as a callback.\n * @locus Client\n */\nTemplate.prototype.onDestroyed = function (cb) {\n this._callbacks.destroyed.push(cb);\n};\n\nTemplate.prototype._getCallbacks = function (which) {\n var self = this;\n var callbacks = self[which] ? [self[which]] : [];\n // Fire all callbacks added with the new API (Template.onRendered())\n // as well as the old-style callback (e.g. Template.rendered) for\n // backwards-compatibility.\n callbacks = callbacks.concat(self._callbacks[which]);\n return callbacks;\n};\n\nvar fireCallbacks = function (callbacks, template) {\n Template._withTemplateInstanceFunc(\n function () { return template; },\n function () {\n for (var i = 0, N = callbacks.length; i < N; i++) {\n callbacks[i].call(template);\n }\n });\n};\n\nTemplate.prototype.constructView = function (contentFunc, elseFunc) {\n var self = this;\n var view = Blaze.View(self.viewName, self.renderFunction);\n view.template = self;\n\n view.templateContentBlock = (\n contentFunc ? new Template('(contentBlock)', contentFunc) : null);\n view.templateElseBlock = (\n elseFunc ? new Template('(elseBlock)', elseFunc) : null);\n\n if (self.__eventMaps || typeof self.events === 'object') {\n view._onViewRendered(function () {\n if (view.renderCount !== 1)\n return;\n\n if (! self.__eventMaps.length && typeof self.events === \"object\") {\n // Provide limited back-compat support for `.events = {...}`\n // syntax. Pass `template.events` to the original `.events(...)`\n // function. This code must run only once per template, in\n // order to not bind the handlers more than once, which is\n // ensured by the fact that we only do this when `__eventMaps`\n // is falsy, and we cause it to be set now.\n Template.prototype.events.call(self, self.events);\n }\n\n _.each(self.__eventMaps, function (m) {\n Blaze._addEventMap(view, m, view);\n });\n });\n }\n\n view._templateInstance = new Blaze.TemplateInstance(view);\n view.templateInstance = function () {\n // Update data, firstNode, and lastNode, and return the TemplateInstance\n // object.\n var inst = view._templateInstance;\n\n /**\n * @instance\n * @memberOf Blaze.TemplateInstance\n * @name data\n * @summary The data context of this instance's latest invocation.\n * @locus Client\n */\n inst.data = Blaze.getData(view);\n\n if (view._domrange && !view.isDestroyed) {\n inst.firstNode = view._domrange.firstNode();\n inst.lastNode = view._domrange.lastNode();\n } else {\n // on 'created' or 'destroyed' callbacks we don't have a DomRange\n inst.firstNode = null;\n inst.lastNode = null;\n }\n\n return inst;\n };\n\n /**\n * @name created\n * @instance\n * @memberOf Template\n * @summary Provide a callback when an instance of a template is created.\n * @locus Client\n * @deprecated in 1.1\n */\n // To avoid situations when new callbacks are added in between view\n // instantiation and event being fired, decide on all callbacks to fire\n // immediately and then fire them on the event.\n var createdCallbacks = self._getCallbacks('created');\n view.onViewCreated(function () {\n fireCallbacks(createdCallbacks, view.templateInstance());\n });\n\n /**\n * @name rendered\n * @instance\n * @memberOf Template\n * @summary Provide a callback when an instance of a template is rendered.\n * @locus Client\n * @deprecated in 1.1\n */\n var renderedCallbacks = self._getCallbacks('rendered');\n view.onViewReady(function () {\n fireCallbacks(renderedCallbacks, view.templateInstance());\n });\n\n /**\n * @name destroyed\n * @instance\n * @memberOf Template\n * @summary Provide a callback when an instance of a template is destroyed.\n * @locus Client\n * @deprecated in 1.1\n */\n var destroyedCallbacks = self._getCallbacks('destroyed');\n view.onViewDestroyed(function () {\n fireCallbacks(destroyedCallbacks, view.templateInstance());\n });\n\n return view;\n};\n\n/**\n * @class\n * @summary The class for template instances\n * @param {Blaze.View} view\n * @instanceName template\n */\nBlaze.TemplateInstance = function (view) {\n if (! (this instanceof Blaze.TemplateInstance))\n // called without `new`\n return new Blaze.TemplateInstance(view);\n\n if (! (view instanceof Blaze.View))\n throw new Error(\"View required\");\n\n view._templateInstance = this;\n\n /**\n * @name view\n * @memberOf Blaze.TemplateInstance\n * @instance\n * @summary The [View](#blaze_view) object for this invocation of the template.\n * @locus Client\n * @type {Blaze.View}\n */\n this.view = view;\n this.data = null;\n\n /**\n * @name firstNode\n * @memberOf Blaze.TemplateInstance\n * @instance\n * @summary The first top-level DOM node in this template instance.\n * @locus Client\n * @type {DOMNode}\n */\n this.firstNode = null;\n\n /**\n * @name lastNode\n * @memberOf Blaze.TemplateInstance\n * @instance\n * @summary The last top-level DOM node in this template instance.\n * @locus Client\n * @type {DOMNode}\n */\n this.lastNode = null;\n\n // This dependency is used to identify state transitions in\n // _subscriptionHandles which could cause the result of\n // TemplateInstance#subscriptionsReady to change. Basically this is triggered\n // whenever a new subscription handle is added or when a subscription handle\n // is removed and they are not ready.\n this._allSubsReadyDep = new Tracker.Dependency();\n this._allSubsReady = false;\n\n this._subscriptionHandles = {};\n};\n\n/**\n * @summary Find all elements matching `selector` in this template instance, and return them as a JQuery object.\n * @locus Client\n * @param {String} selector The CSS selector to match, scoped to the template contents.\n * @returns {DOMNode[]}\n */\nBlaze.TemplateInstance.prototype.$ = function (selector) {\n var view = this.view;\n if (! view._domrange)\n throw new Error(\"Can't use $ on template instance with no DOM\");\n return view._domrange.$(selector);\n};\n\n/**\n * @summary Find all elements matching `selector` in this template instance.\n * @locus Client\n * @param {String} selector The CSS selector to match, scoped to the template contents.\n * @returns {DOMElement[]}\n */\nBlaze.TemplateInstance.prototype.findAll = function (selector) {\n return Array.prototype.slice.call(this.$(selector));\n};\n\n/**\n * @summary Find one element matching `selector` in this template instance.\n * @locus Client\n * @param {String} selector The CSS selector to match, scoped to the template contents.\n * @returns {DOMElement}\n */\nBlaze.TemplateInstance.prototype.find = function (selector) {\n var result = this.$(selector);\n return result[0] || null;\n};\n\n/**\n * @summary A version of [Tracker.autorun](#tracker_autorun) that is stopped when the template is destroyed.\n * @locus Client\n * @param {Function} runFunc The function to run. It receives one argument: a Tracker.Computation object.\n */\nBlaze.TemplateInstance.prototype.autorun = function (f) {\n return this.view.autorun(f);\n};\n\n/**\n * @summary A version of [Meteor.subscribe](#meteor_subscribe) that is stopped\n * when the template is destroyed.\n * @return {SubscriptionHandle} The subscription handle to the newly made\n * subscription. Call `handle.stop()` to manually stop the subscription, or\n * `handle.ready()` to find out if this particular subscription has loaded all\n * of its inital data.\n * @locus Client\n * @param {String} name Name of the subscription. Matches the name of the\n * server's `publish()` call.\n * @param {Any} [arg1,arg2...] Optional arguments passed to publisher function\n * on server.\n * @param {Function|Object} [callbacks] Optional. May include `onStop` and\n * `onReady` callbacks. If a function is passed instead of an object, it is\n * interpreted as an `onReady` callback.\n */\nBlaze.TemplateInstance.prototype.subscribe = function (/* arguments */) {\n var self = this;\n\n var subHandles = self._subscriptionHandles;\n var args = _.toArray(arguments);\n\n // Duplicate logic from Meteor.subscribe\n var callbacks = {};\n if (args.length) {\n var lastParam = _.last(args);\n if (_.isFunction(lastParam)) {\n callbacks.onReady = args.pop();\n } else if (lastParam &&\n // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use\n // onStop with an error callback instead.\n _.any([lastParam.onReady, lastParam.onError, lastParam.onStop],\n _.isFunction)) {\n callbacks = args.pop();\n }\n }\n\n var subHandle;\n var oldStopped = callbacks.onStop;\n callbacks.onStop = function (error) {\n // When the subscription is stopped, remove it from the set of tracked\n // subscriptions to avoid this list growing without bound\n delete subHandles[subHandle.subscriptionId];\n\n // Removing a subscription can only change the result of subscriptionsReady\n // if we are not ready (that subscription could be the one blocking us being\n // ready).\n if (! self._allSubsReady) {\n self._allSubsReadyDep.changed();\n }\n\n if (oldStopped) {\n oldStopped(error);\n }\n };\n args.push(callbacks);\n\n subHandle = self.view.subscribe.call(self.view, args);\n\n if (! _.has(subHandles, subHandle.subscriptionId)) {\n subHandles[subHandle.subscriptionId] = subHandle;\n\n // Adding a new subscription will always cause us to transition from ready\n // to not ready, but if we are already not ready then this can't make us\n // ready.\n if (self._allSubsReady) {\n self._allSubsReadyDep.changed();\n }\n }\n\n return subHandle;\n};\n\n/**\n * @summary A reactive function that returns true when all of the subscriptions\n * called with [this.subscribe](#TemplateInstance-subscribe) are ready.\n * @return {Boolean} True if all subscriptions on this template instance are\n * ready.\n */\nBlaze.TemplateInstance.prototype.subscriptionsReady = function () {\n this._allSubsReadyDep.depend();\n\n this._allSubsReady = _.all(this._subscriptionHandles, function (handle) {\n return handle.ready();\n });\n\n return this._allSubsReady;\n};\n\n/**\n * @summary Specify template helpers available to this template.\n * @locus Client\n * @param {Object} helpers Dictionary of helper functions by name.\n */\nTemplate.prototype.helpers = function (dict) {\n for (var k in dict)\n this.__helpers.set(k, dict[k]);\n};\n\n// Kind of like Blaze.currentView but for the template instance.\n// This is a function, not a value -- so that not all helpers\n// are implicitly dependent on the current template instance's `data` property,\n// which would make them dependenct on the data context of the template\n// inclusion.\nTemplate._currentTemplateInstanceFunc = null;\n\nTemplate._withTemplateInstanceFunc = function (templateInstanceFunc, func) {\n if (typeof func !== 'function')\n throw new Error(\"Expected function, got: \" + func);\n var oldTmplInstanceFunc = Template._currentTemplateInstanceFunc;\n try {\n Template._currentTemplateInstanceFunc = templateInstanceFunc;\n return func();\n } finally {\n Template._currentTemplateInstanceFunc = oldTmplInstanceFunc;\n }\n};\n\n/**\n * @summary Specify event handlers for this template.\n * @locus Client\n * @param {EventMap} eventMap Event handlers to associate with this template.\n */\nTemplate.prototype.events = function (eventMap) {\n var template = this;\n var eventMap2 = {};\n for (var k in eventMap) {\n eventMap2[k] = (function (k, v) {\n return function (event/*, ...*/) {\n var view = this; // passed by EventAugmenter\n var data = Blaze.getData(event.currentTarget);\n if (data == null)\n data = {};\n var args = Array.prototype.slice.call(arguments);\n var tmplInstanceFunc = _.bind(view.templateInstance, view);\n args.splice(1, 0, tmplInstanceFunc());\n\n return Template._withTemplateInstanceFunc(tmplInstanceFunc, function () {\n return v.apply(data, args);\n });\n };\n })(k, eventMap[k]);\n }\n\n template.__eventMaps.push(eventMap2);\n};\n\n/**\n * @function\n * @name instance\n * @memberOf Template\n * @summary The [template instance](#template_inst) corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, `null`.\n * @locus Client\n * @returns {Blaze.TemplateInstance}\n */\nTemplate.instance = function () {\n return Template._currentTemplateInstanceFunc\n && Template._currentTemplateInstanceFunc();\n};\n\n// Note: Template.currentData() is documented to take zero arguments,\n// while Blaze.getData takes up to one.\n\n/**\n * @summary\n *\n * - Inside an `onCreated`, `onRendered`, or `onDestroyed` callback, returns\n * the data context of the template.\n * - Inside an event handler, returns the data context of the template on which\n * this event handler was defined.\n * - Inside a helper, returns the data context of the DOM node where the helper\n * was used.\n *\n * Establishes a reactive dependency on the result.\n * @locus Client\n * @function\n */\nTemplate.currentData = Blaze.getData;\n\n/**\n * @summary Accesses other data contexts that enclose the current data context.\n * @locus Client\n * @function\n * @param {Integer} [numLevels] The number of levels beyond the current data context to look. Defaults to 1.\n */\nTemplate.parentData = Blaze._parentData;\n\n/**\n * @summary Defines a [helper function](#template_helpers) which can be used from all templates.\n * @locus Client\n * @function\n * @param {String} name The name of the helper function you are defining.\n * @param {Function} function The helper function itself.\n */\nTemplate.registerHelper = Blaze.registerHelper;\n","UI = Blaze;\n\nBlaze.ReactiveVar = ReactiveVar;\nUI._templateInstance = Blaze.Template.instance;\n\nHandlebars = {};\nHandlebars.registerHelper = Blaze.registerHelper;\n\nHandlebars._escape = Blaze._escape;\n\n// Return these from {{...}} helpers to achieve the same as returning\n// strings from {{{...}}} helpers\nHandlebars.SafeString = function(string) {\n this.string = string;\n};\nHandlebars.SafeString.prototype.toString = function() {\n return this.string.toString();\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js b/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js deleted file mode 100644 index 9e1b347..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js +++ /dev/null @@ -1,141 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var SpacebarsCompiler = Package['spacebars-compiler'].SpacebarsCompiler; -var Spacebars = Package.spacebars.Spacebars; -var HTML = Package.htmljs.HTML; -var Blaze = Package.blaze.Blaze; -var UI = Package.blaze.UI; -var Handlebars = Package.blaze.Handlebars; - -/* Package-scope variables */ -var Boilerplate; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////// -// // -// packages/boilerplate-generator/boilerplate-generator.js // -// // -/////////////////////////////////////////////////////////////////////////////////// - // -var fs = Npm.require('fs'); // 1 -var path = Npm.require('path'); // 2 - // 3 -// Copied from webapp_server // 4 -var readUtf8FileSync = function (filename) { // 5 - return Meteor.wrapAsync(fs.readFile)(filename, 'utf8'); // 6 -}; // 7 - // 8 -Boilerplate = function (arch, manifest, options) { // 9 - var self = this; // 10 - options = options || {}; // 11 - self.template = _getTemplate(arch); // 12 - self.baseData = null; // 13 - self.func = null; // 14 - // 15 - self._generateBoilerplateFromManifestAndSource( // 16 - manifest, // 17 - self.template, // 18 - options // 19 - ); // 20 -}; // 21 - // 22 -// The 'extraData' argument can be used to extend 'self.baseData'. Its // 23 -// purpose is to allow you to specify data that you might not know at // 24 -// the time that you construct the Boilerplate object. (e.g. it is used // 25 -// by 'webapp' to specify data that is only known at request-time). // 26 -Boilerplate.prototype.toHTML = function (extraData) { // 27 - var self = this; // 28 - // 29 - if (! self.baseData || ! self.func) // 30 - throw new Error('Boilerplate did not instantiate correctly.'); // 31 - // 32 - return "\n" + // 33 - Blaze.toHTML(Blaze.With(_.extend(self.baseData, extraData), // 34 - self.func)); // 35 -}; // 36 - // 37 -// XXX Exported to allow client-side only changes to rebuild the boilerplate // 38 -// without requiring a full server restart. // 39 -// Produces an HTML string with given manifest and boilerplateSource. // 40 -// Optionally takes urlMapper in case urls from manifest need to be prefixed // 41 -// or rewritten. // 42 -// Optionally takes pathMapper for resolving relative file system paths. // 43 -// Optionally allows to override fields of the data context. // 44 -Boilerplate.prototype._generateBoilerplateFromManifestAndSource = // 45 - function (manifest, boilerplateSource, options) { // 46 - var self = this; // 47 - // map to the identity by default // 48 - var urlMapper = options.urlMapper || _.identity; // 49 - var pathMapper = options.pathMapper || _.identity; // 50 - // 51 - var boilerplateBaseData = { // 52 - css: [], // 53 - js: [], // 54 - head: '', // 55 - body: '', // 56 - meteorManifest: JSON.stringify(manifest) // 57 - }; // 58 - // 59 - // allow the caller to extend the default base data // 60 - _.extend(boilerplateBaseData, options.baseDataExtension); // 61 - // 62 - _.each(manifest, function (item) { // 63 - var urlPath = urlMapper(item.url); // 64 - var itemObj = { url: urlPath }; // 65 - // 66 - if (options.inline) { // 67 - itemObj.scriptContent = readUtf8FileSync( // 68 - pathMapper(item.path)); // 69 - itemObj.inline = true; // 70 - } // 71 - // 72 - if (item.type === 'css' && item.where === 'client') { // 73 - boilerplateBaseData.css.push(itemObj); // 74 - } // 75 - if (item.type === 'js' && item.where === 'client') { // 76 - boilerplateBaseData.js.push(itemObj); // 77 - } // 78 - if (item.type === 'head') { // 79 - boilerplateBaseData.head = // 80 - readUtf8FileSync(pathMapper(item.path)); // 81 - } // 82 - if (item.type === 'body') { // 83 - boilerplateBaseData.body = // 84 - readUtf8FileSync(pathMapper(item.path)); // 85 - } // 86 - }); // 87 - var boilerplateRenderCode = SpacebarsCompiler.compile( // 88 - boilerplateSource, { isBody: true }); // 89 - // 90 - // Note that we are actually depending on eval's local environment capture // 91 - // so that UI and HTML are visible to the eval'd code. // 92 - // XXX the template we are evaluating relies on the fact that UI is globally // 93 - // available. // 94 - global.UI = UI; // 95 - self.func = eval(boilerplateRenderCode); // 96 - self.baseData = boilerplateBaseData; // 97 -}; // 98 - // 99 -var _getTemplate = _.memoize(function (arch) { // 100 - var filename = 'boilerplate_' + arch + '.html'; // 101 - return Assets.getText(filename); // 102 -}); // 103 - // 104 -/////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['boilerplate-generator'] = { - Boilerplate: Boilerplate -}; - -})(); - -//# sourceMappingURL=boilerplate-generator.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js.map b/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js.map deleted file mode 100644 index 9456a33..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["boilerplate-generator/boilerplate-generator.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,2B;AACA,+B;;AAEA,4B;AACA,4C;AACA,yD;AACA,E;;AAEA,kD;AACA,kB;AACA,0B;AACA,qC;AACA,uB;AACA,mB;;AAEA,iD;AACA,a;AACA,kB;AACA,W;AACA,I;AACA,E;;AAEA,sE;AACA,qE;AACA,uE;AACA,mE;AACA,qD;AACA,kB;;AAEA,qC;AACA,kE;;AAEA,+B;AACA,+D;AACA,wC;AACA,E;;AAEA,4E;AACA,2C;AACA,qE;AACA,4E;AACA,gB;AACA,wE;AACA,4D;AACA,iE;AACA,mD;AACA,oB;AACA,qC;AACA,oD;AACA,sD;;AAEA,+B;AACA,c;AACA,a;AACA,e;AACA,e;AACA,8C;AACA,M;;AAEA,uD;AACA,6D;;AAEA,sC;AACA,wC;AACA,qC;;AAEA,2B;AACA,iD;AACA,iC;AACA,8B;AACA,O;;AAEA,2D;AACA,8C;AACA,O;AACA,0D;AACA,6C;AACA,O;AACA,iC;AACA,kC;AACA,kD;AACA,O;AACA,iC;AACA,kC;AACA,kD;AACA,O;AACA,O;AACA,0D;AACA,2C;;AAEA,8E;AACA,0D;AACA,gF;AACA,mB;AACA,mB;AACA,4C;AACA,wC;AACA,E;;AAEA,8C;AACA,iD;AACA,kC;AACA,G","file":"/packages/boilerplate-generator.js","sourcesContent":["var fs = Npm.require('fs');\nvar path = Npm.require('path');\n\n// Copied from webapp_server\nvar readUtf8FileSync = function (filename) {\n return Meteor.wrapAsync(fs.readFile)(filename, 'utf8');\n};\n\nBoilerplate = function (arch, manifest, options) {\n var self = this;\n options = options || {};\n self.template = _getTemplate(arch);\n self.baseData = null;\n self.func = null;\n\n self._generateBoilerplateFromManifestAndSource(\n manifest,\n self.template,\n options\n );\n};\n\n// The 'extraData' argument can be used to extend 'self.baseData'. Its\n// purpose is to allow you to specify data that you might not know at\n// the time that you construct the Boilerplate object. (e.g. it is used\n// by 'webapp' to specify data that is only known at request-time).\nBoilerplate.prototype.toHTML = function (extraData) {\n var self = this;\n\n if (! self.baseData || ! self.func)\n throw new Error('Boilerplate did not instantiate correctly.');\n\n return \"\\n\" +\n Blaze.toHTML(Blaze.With(_.extend(self.baseData, extraData),\n self.func));\n};\n\n// XXX Exported to allow client-side only changes to rebuild the boilerplate\n// without requiring a full server restart.\n// Produces an HTML string with given manifest and boilerplateSource.\n// Optionally takes urlMapper in case urls from manifest need to be prefixed\n// or rewritten.\n// Optionally takes pathMapper for resolving relative file system paths.\n// Optionally allows to override fields of the data context.\nBoilerplate.prototype._generateBoilerplateFromManifestAndSource =\n function (manifest, boilerplateSource, options) {\n var self = this;\n // map to the identity by default\n var urlMapper = options.urlMapper || _.identity;\n var pathMapper = options.pathMapper || _.identity;\n\n var boilerplateBaseData = {\n css: [],\n js: [],\n head: '',\n body: '',\n meteorManifest: JSON.stringify(manifest)\n };\n\n // allow the caller to extend the default base data\n _.extend(boilerplateBaseData, options.baseDataExtension);\n\n _.each(manifest, function (item) {\n var urlPath = urlMapper(item.url);\n var itemObj = { url: urlPath };\n\n if (options.inline) {\n itemObj.scriptContent = readUtf8FileSync(\n pathMapper(item.path));\n itemObj.inline = true;\n }\n\n if (item.type === 'css' && item.where === 'client') {\n boilerplateBaseData.css.push(itemObj);\n }\n if (item.type === 'js' && item.where === 'client') {\n boilerplateBaseData.js.push(itemObj);\n }\n if (item.type === 'head') {\n boilerplateBaseData.head =\n readUtf8FileSync(pathMapper(item.path));\n }\n if (item.type === 'body') {\n boilerplateBaseData.body =\n readUtf8FileSync(pathMapper(item.path));\n }\n });\n var boilerplateRenderCode = SpacebarsCompiler.compile(\n boilerplateSource, { isBody: true });\n\n // Note that we are actually depending on eval's local environment capture\n // so that UI and HTML are visible to the eval'd code.\n // XXX the template we are evaluating relies on the fact that UI is globally\n // available.\n global.UI = UI;\n self.func = eval(boilerplateRenderCode);\n self.baseData = boilerplateBaseData;\n};\n\nvar _getTemplate = _.memoize(function (arch) {\n var filename = 'boilerplate_' + arch + '.html';\n return Assets.getText(filename);\n});\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/callback-hook.js b/web-app/.meteor/local/build/programs/server/packages/callback-hook.js deleted file mode 100644 index cbc466f..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/callback-hook.js +++ /dev/null @@ -1,139 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; - -/* Package-scope variables */ -var Hook; - -(function () { - -////////////////////////////////////////////////////////////////////////////////// -// // -// packages/callback-hook/hook.js // -// // -////////////////////////////////////////////////////////////////////////////////// - // -// XXX This pattern is under development. Do not add more callsites // 1 -// using this package for now. See: // 2 -// https://meteor.hackpad.com/Design-proposal-Hooks-YxvgEW06q6f // 3 -// // 4 -// Encapsulates the pattern of registering callbacks on a hook. // 5 -// // 6 -// The `each` method of the hook calls its iterator function argument // 7 -// with each registered callback. This allows the hook to // 8 -// conditionally decide not to call the callback (if, for example, the // 9 -// observed object has been closed or terminated). // 10 -// // 11 -// Callbacks are bound with `Meteor.bindEnvironment`, so they will be // 12 -// called with the Meteor environment of the calling code that // 13 -// registered the callback. // 14 -// // 15 -// Registering a callback returns an object with a single `stop` // 16 -// method which unregisters the callback. // 17 -// // 18 -// The code is careful to allow a callback to be safely unregistered // 19 -// while the callbacks are being iterated over. // 20 -// // 21 -// If the hook is configured with the `exceptionHandler` option, the // 22 -// handler will be called if a called callback throws an exception. // 23 -// By default (if the exception handler doesn't itself throw an // 24 -// exception, or if the iterator function doesn't return a falsy value // 25 -// to terminate the calling of callbacks), the remaining callbacks // 26 -// will still be called. // 27 -// // 28 -// Alternatively, the `debugPrintExceptions` option can be specified // 29 -// as string describing the callback. On an exception the string and // 30 -// the exception will be printed to the console log with // 31 -// `Meteor._debug`, and the exception otherwise ignored. // 32 -// // 33 -// If an exception handler isn't specified, exceptions thrown in the // 34 -// callback will propagate up to the iterator function, and will // 35 -// terminate calling the remaining callbacks if not caught. // 36 - // 37 -Hook = function (options) { // 38 - var self = this; // 39 - options = options || {}; // 40 - self.nextCallbackId = 0; // 41 - self.callbacks = {}; // 42 - // 43 - if (options.exceptionHandler) // 44 - self.exceptionHandler = options.exceptionHandler; // 45 - else if (options.debugPrintExceptions) { // 46 - if (! _.isString(options.debugPrintExceptions)) // 47 - throw new Error("Hook option debugPrintExceptions should be a string"); // 48 - self.exceptionHandler = options.debugPrintExceptions; // 49 - } // 50 -}; // 51 - // 52 -_.extend(Hook.prototype, { // 53 - register: function (callback) { // 54 - var self = this; // 55 - // 56 - callback = Meteor.bindEnvironment( // 57 - callback, // 58 - self.exceptionHandler || function (exception) { // 59 - // Note: this relies on the undocumented fact that if bindEnvironment's // 60 - // onException throws, and you are invoking the callback either in the // 61 - // browser or from within a Fiber in Node, the exception is propagated. // 62 - throw exception; // 63 - } // 64 - ); // 65 - // 66 - var id = self.nextCallbackId++; // 67 - self.callbacks[id] = callback; // 68 - // 69 - return { // 70 - stop: function () { // 71 - delete self.callbacks[id]; // 72 - } // 73 - }; // 74 - }, // 75 - // 76 - // For each registered callback, call the passed iterator function // 77 - // with the callback. // 78 - // // 79 - // The iterator function can choose whether or not to call the // 80 - // callback. (For example, it might not call the callback if the // 81 - // observed object has been closed or terminated). // 82 - // // 83 - // The iteration is stopped if the iterator function returns a falsy // 84 - // value or throws an exception. // 85 - // // 86 - each: function (iterator) { // 87 - var self = this; // 88 - // 89 - // Invoking bindEnvironment'd callbacks outside of a Fiber in Node doesn't // 90 - // run them to completion (and exceptions thrown from onException are not // 91 - // propagated), so we need to be in a Fiber. // 92 - Meteor._nodeCodeMustBeInFiber(); // 93 - // 94 - var ids = _.keys(self.callbacks); // 95 - for (var i = 0; i < ids.length; ++i) { // 96 - var id = ids[i]; // 97 - // check to see if the callback was removed during iteration // 98 - if (_.has(self.callbacks, id)) { // 99 - var callback = self.callbacks[id]; // 100 - // 101 - if (! iterator(callback)) // 102 - break; // 103 - } // 104 - } // 105 - } // 106 -}); // 107 - // 108 -////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['callback-hook'] = { - Hook: Hook -}; - -})(); - -//# sourceMappingURL=callback-hook.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/callback-hook.js.map b/web-app/.meteor/local/build/programs/server/packages/callback-hook.js.map deleted file mode 100644 index ecc48f9..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/callback-hook.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["callback-hook/hook.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,mE;AACA,mC;AACA,+D;AACA,E;AACA,+D;AACA,E;AACA,qE;AACA,0D;AACA,sE;AACA,kD;AACA,E;AACA,qE;AACA,8D;AACA,2B;AACA,E;AACA,gE;AACA,yC;AACA,E;AACA,oE;AACA,+C;AACA,E;AACA,oE;AACA,mE;AACA,+D;AACA,sE;AACA,kE;AACA,wB;AACA,E;AACA,oE;AACA,qE;AACA,wD;AACA,wD;AACA,E;AACA,oE;AACA,gE;AACA,2D;;AAEA,2B;AACA,kB;AACA,0B;AACA,0B;AACA,sB;;AAEA,+B;AACA,qD;AACA,0C;AACA,mD;AACA,6E;AACA,yD;AACA,G;AACA,E;;AAEA,0B;AACA,iC;AACA,oB;;AAEA,sC;AACA,e;AACA,qD;AACA,+E;AACA,8E;AACA,+E;AACA,wB;AACA,O;AACA,M;;AAEA,mC;AACA,kC;;AAEA,Y;AACA,yB;AACA,kC;AACA,O;AACA,M;AACA,I;;AAEA,oE;AACA,uB;AACA,I;AACA,gE;AACA,mE;AACA,oD;AACA,I;AACA,sE;AACA,kC;AACA,I;AACA,6B;AACA,oB;;AAEA,8E;AACA,6E;AACA,gD;AACA,oC;;AAEA,qC;AACA,4C;AACA,sB;AACA,kE;AACA,sC;AACA,0C;;AAEA,iC;AACA,gB;AACA,O;AACA,K;AACA,G;AACA,G","file":"/packages/callback-hook.js","sourcesContent":["// XXX This pattern is under development. Do not add more callsites\n// using this package for now. See:\n// https://meteor.hackpad.com/Design-proposal-Hooks-YxvgEW06q6f\n//\n// Encapsulates the pattern of registering callbacks on a hook.\n//\n// The `each` method of the hook calls its iterator function argument\n// with each registered callback. This allows the hook to\n// conditionally decide not to call the callback (if, for example, the\n// observed object has been closed or terminated).\n//\n// Callbacks are bound with `Meteor.bindEnvironment`, so they will be\n// called with the Meteor environment of the calling code that\n// registered the callback.\n//\n// Registering a callback returns an object with a single `stop`\n// method which unregisters the callback.\n//\n// The code is careful to allow a callback to be safely unregistered\n// while the callbacks are being iterated over.\n//\n// If the hook is configured with the `exceptionHandler` option, the\n// handler will be called if a called callback throws an exception.\n// By default (if the exception handler doesn't itself throw an\n// exception, or if the iterator function doesn't return a falsy value\n// to terminate the calling of callbacks), the remaining callbacks\n// will still be called.\n//\n// Alternatively, the `debugPrintExceptions` option can be specified\n// as string describing the callback. On an exception the string and\n// the exception will be printed to the console log with\n// `Meteor._debug`, and the exception otherwise ignored.\n//\n// If an exception handler isn't specified, exceptions thrown in the\n// callback will propagate up to the iterator function, and will\n// terminate calling the remaining callbacks if not caught.\n\nHook = function (options) {\n var self = this;\n options = options || {};\n self.nextCallbackId = 0;\n self.callbacks = {};\n\n if (options.exceptionHandler)\n self.exceptionHandler = options.exceptionHandler;\n else if (options.debugPrintExceptions) {\n if (! _.isString(options.debugPrintExceptions))\n throw new Error(\"Hook option debugPrintExceptions should be a string\");\n self.exceptionHandler = options.debugPrintExceptions;\n }\n};\n\n_.extend(Hook.prototype, {\n register: function (callback) {\n var self = this;\n\n callback = Meteor.bindEnvironment(\n callback,\n self.exceptionHandler || function (exception) {\n // Note: this relies on the undocumented fact that if bindEnvironment's\n // onException throws, and you are invoking the callback either in the\n // browser or from within a Fiber in Node, the exception is propagated.\n throw exception;\n }\n );\n\n var id = self.nextCallbackId++;\n self.callbacks[id] = callback;\n\n return {\n stop: function () {\n delete self.callbacks[id];\n }\n };\n },\n\n // For each registered callback, call the passed iterator function\n // with the callback.\n //\n // The iterator function can choose whether or not to call the\n // callback. (For example, it might not call the callback if the\n // observed object has been closed or terminated).\n //\n // The iteration is stopped if the iterator function returns a falsy\n // value or throws an exception.\n //\n each: function (iterator) {\n var self = this;\n\n // Invoking bindEnvironment'd callbacks outside of a Fiber in Node doesn't\n // run them to completion (and exceptions thrown from onException are not\n // propagated), so we need to be in a Fiber.\n Meteor._nodeCodeMustBeInFiber();\n\n var ids = _.keys(self.callbacks);\n for (var i = 0; i < ids.length; ++i) {\n var id = ids[i];\n // check to see if the callback was removed during iteration\n if (_.has(self.callbacks, id)) {\n var callback = self.callbacks[id];\n\n if (! iterator(callback))\n break;\n }\n }\n }\n});\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/check.js b/web-app/.meteor/local/build/programs/server/packages/check.js deleted file mode 100644 index 97b6c53..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/check.js +++ /dev/null @@ -1,416 +0,0 @@ -(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 -}; - -})(); - -//# sourceMappingURL=check.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/check.js.map b/web-app/.meteor/local/build/programs/server/packages/check.js.map deleted file mode 100644 index ff2996d..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/check.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["check/match.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,W;;AAEA,uC;AACA,2B;;AAEA,4D;;AAEA,G;AACA,mE;AACA,kE;AACA,E;AACA,4E;AACA,uB;AACA,kB;AACA,wC;AACA,qD;AACA,kB;AACA,G;AACA,mC;AACA,qD;AACA,I;AACA,mE;AACA,0E;AACA,sE;AACA,wE;AACA,yE;AACA,8D;AACA,oE;AACA,iB;AACA,+B;AACA,O;AACA,iC;AACA,iB;AACA,iD;AACA,6C;AACA,c;AACA,G;AACA,E;;AAEA,G;AACA,mB;AACA,0D;AACA,G;AACA,S;AACA,gC;AACA,iC;AACA,I;AACA,mC;AACA,2C;AACA,I;AACA,mB;AACA,+B;AACA,gC;AACA,I;AACA,uC;AACA,wC;AACA,I;AACA,wC;AACA,yC;AACA,I;AACA,wC;AACA,2B;;AAEA,mE;AACA,6D;AACA,yC;AACA,6E;AACA,gF;AACA,a;AACA,qC;AACA,mB;AACA,gF;AACA,+D;AACA,gE;AACA,K;;AAEA,gF;AACA,8E;AACA,oD;AACA,gF;AACA,4E;AACA,+E;;AAEA,K;AACA,4D;AACA,oB;AACA,0C;AACA,uE;AACA,K;AACA,mC;AACA,S;AACA,mC;AACA,kB;AACA,iB;AACA,mC;AACA,qB;AACA,8B;AACA,c;AACA,K;AACA,I;;AAEA,gF;AACA,gF;AACA,0C;AACA,I;AACA,8E;AACA,4D;AACA,2E;AACA,oC;AACA,O;AACA,2E;AACA,wD;AACA,kB;AACA,G;AACA,E;;AAEA,mC;AACA,yB;AACA,E;;AAEA,gC;AACA,yB;AACA,uE;AACA,yB;AACA,E;;AAEA,kC;AACA,6B;AACA,E;;AAEA,0C;AACA,yB;AACA,E;;AAEA,2C;AACA,yB;AACA,E;;AAEA,oB;AACA,qB;AACA,qB;AACA,uB;AACA,uE;AACA,0B;AACA,0B;AACA,E;;AAEA,8C;AACA,oB;AACA,4B;AACA,W;;AAEA,wB;AACA,sD;AACA,iD;AACA,yC;AACA,8C;AACA,e;AACA,yE;AACA,0C;AACA,K;AACA,G;AACA,yB;AACA,uB;AACA,a;AACA,0E;AACA,G;;AAEA,sE;AACA,mE;AACA,0B;AACA,a;AACA,4D;AACA,kD;AACA,G;;AAEA,qD;AACA,kC;AACA,+E;AACA,gF;AACA,uE;AACA,kD;AACA,6E;AACA,oD;AACA,2D;AACA,Y;AACA,kD;AACA,8E;AACA,G;;AAEA,yD;AACA,yB;AACA,wC;;AAEA,iE;AACA,iC;AACA,6B;AACA,oE;AACA,4C;AACA,qD;AACA,6E;AACA,K;;AAEA,kD;AACA,W;AACA,+C;AACA,qB;AACA,yC;AACA,mD;AACA,S;AACA,kB;AACA,O;AACA,O;AACA,W;AACA,G;;AAEA,2E;AACA,6D;AACA,iC;AACA,iC;AACA,a;AACA,iC;AACA,2D;AACA,G;;;AAGA,kC;AACA,sD;;AAEA,iC;AACA,sD;AACA,W;AACA,gD;AACA,iC;AACA,e;AACA,qB;AACA,4E;AACA,kB;AACA,0C;AACA,oB;AACA,O;AACA,K;AACA,iC;AACA,6E;AACA,G;;AAEA,uE;AACA,iB;AACA,oC;AACA,iC;AACA,a;AACA,wD;AACA,oE;AACA,G;;AAEA,iC;AACA,wB;AACA,2C;AACA,8B;AACA,8B;AACA,G;AACA,4C;AACA,8B;AACA,0C;AACA,sC;AACA,G;;AAEA,kC;AACA,qD;;AAEA,2E;AACA,6E;AACA,+D;AACA,gC;AACA,kE;AACA,qB;AACA,uD;AACA,mC;AACA,mD;;AAEA,4B;AACA,4B;AACA,8C;AACA,uC;AACA,iD;AACA,Q;AACA,yC;AACA,K;;AAEA,0C;AACA,S;AACA,yC;AACA,sD;AACA,qC;AACA,gD;AACA,sD;AACA,c;AACA,gC;AACA,+C;AACA,gC;AACA,uD;AACA,S;AACA,O;AACA,mB;AACA,qC;AACA,+C;AACA,gB;AACA,K;AACA,K;;AAEA,uD;AACA,uD;AACA,K;AACA,E;;AAEA,oD;AACA,kB;AACA,0E;AACA,2B;AACA,4B;AACA,6E;AACA,4E;AACA,+B;AACA,sB;AACA,iC;AACA,E;;AAEA,qC;AACA,8B;AACA,oB;AACA,sC;AACA,a;AACA,8E;AACA,0E;AACA,0B;AACA,mD;AACA,0D;AACA,K;AACA,I;AACA,uC;AACA,oB;AACA,gD;AACA,+E;AACA,4E;AACA,gB;AACA,mE;AACA,gF;AACA,+B;AACA,oB;AACA,O;AACA,K;AACA,iB;AACA,I;AACA,uD;AACA,oB;AACA,8B;AACA,+D;AACA,wC;AACA,G;AACA,G;;AAEA,+E;AACA,0E;AACA,yE;AACA,uE;AACA,8E;AACA,8E;AACA,gB;;AAEA,uD;AACA,qB;AACA,yC;AACA,yD;AACA,0B;AACA,+E;AACA,gC;;AAEA,8B;AACA,4B;AACA,oB;AACA,E","file":"/packages/check.js","sourcesContent":["// XXX docs\n\n// Things we explicitly do NOT support:\n// - heterogenous arrays\n\nvar currentArgumentChecker = new Meteor.EnvironmentVariable;\n\n/**\n * @summary Check that a value matches a [pattern](#matchpatterns).\n * If the value does not match the pattern, throw a `Match.Error`.\n *\n * Particularly useful to assert that arguments to a function have the right\n * types and structure.\n * @locus Anywhere\n * @param {Any} value The value to check\n * @param {MatchPattern} pattern The pattern to match\n * `value` against\n */\ncheck = function (value, pattern) {\n // Record that check got called, if somebody cared.\n //\n // We use getOrNullIfOutsideFiber so that it's OK to call check()\n // from non-Fiber server contexts; the downside is that if you forget to\n // bindEnvironment on some random callback in your method/publisher,\n // it might not find the argumentChecker and you'll get an error about\n // not checking an argument that it looks like you're checking (instead\n // of just getting a \"Node code must run in a Fiber\" error).\n var argChecker = currentArgumentChecker.getOrNullIfOutsideFiber();\n if (argChecker)\n argChecker.checking(value);\n try {\n checkSubtree(value, pattern);\n } catch (err) {\n if ((err instanceof Match.Error) && err.path)\n err.message += \" in field \" + err.path;\n throw err;\n }\n};\n\n/**\n * @namespace Match\n * @summary The namespace for all Match types and methods.\n */\nMatch = {\n Optional: function (pattern) {\n return new Optional(pattern);\n },\n OneOf: function (/*arguments*/) {\n return new OneOf(_.toArray(arguments));\n },\n Any: ['__any__'],\n Where: function (condition) {\n return new Where(condition);\n },\n ObjectIncluding: function (pattern) {\n return new ObjectIncluding(pattern);\n },\n ObjectWithValues: function (pattern) {\n return new ObjectWithValues(pattern);\n },\n // Matches only signed 32-bit integers\n Integer: ['__integer__'],\n\n // XXX matchers should know how to describe themselves for errors\n Error: Meteor.makeErrorType(\"Match.Error\", function (msg) {\n this.message = \"Match error: \" + msg;\n // The path of the value that failed to match. Initially empty, this gets\n // populated by catching and rethrowing the exception as it goes back up the\n // stack.\n // E.g.: \"vals[3].entity.created\"\n this.path = \"\";\n // If this gets sent over DDP, don't give full internal details but at least\n // provide something better than 500 Internal server error.\n this.sanitizedError = new Meteor.Error(400, \"Match failed\");\n }),\n\n // Tests to see if value matches pattern. Unlike check, it merely returns true\n // or false (unless an error other than Match.Error was thrown). It does not\n // interact with _failIfArgumentsAreNotAllChecked.\n // XXX maybe also implement a Match.match which returns more information about\n // failures but without using exception handling or doing what check()\n // does with _failIfArgumentsAreNotAllChecked and Meteor.Error conversion\n\n /**\n * @summary Returns true if the value matches the pattern.\n * @locus Anywhere\n * @param {Any} value The value to check\n * @param {MatchPattern} pattern The pattern to match `value` against\n */\n test: function (value, pattern) {\n try {\n checkSubtree(value, pattern);\n return true;\n } catch (e) {\n if (e instanceof Match.Error)\n return false;\n // Rethrow other errors.\n throw e;\n }\n },\n\n // Runs `f.apply(context, args)`. If check() is not called on every element of\n // `args` (either directly or in the first level of an array), throws an error\n // (using `description` in the message).\n //\n _failIfArgumentsAreNotAllChecked: function (f, context, args, description) {\n var argChecker = new ArgumentChecker(args, description);\n var result = currentArgumentChecker.withValue(argChecker, function () {\n return f.apply(context, args);\n });\n // If f didn't itself throw, make sure it checked all of its arguments.\n argChecker.throwUnlessAllArgumentsHaveBeenChecked();\n return result;\n }\n};\n\nvar Optional = function (pattern) {\n this.pattern = pattern;\n};\n\nvar OneOf = function (choices) {\n if (_.isEmpty(choices))\n throw new Error(\"Must provide at least one choice to Match.OneOf\");\n this.choices = choices;\n};\n\nvar Where = function (condition) {\n this.condition = condition;\n};\n\nvar ObjectIncluding = function (pattern) {\n this.pattern = pattern;\n};\n\nvar ObjectWithValues = function (pattern) {\n this.pattern = pattern;\n};\n\nvar typeofChecks = [\n [String, \"string\"],\n [Number, \"number\"],\n [Boolean, \"boolean\"],\n // While we don't allow undefined in EJSON, this is good for optional\n // arguments with OneOf.\n [undefined, \"undefined\"]\n];\n\nvar checkSubtree = function (value, pattern) {\n // Match anything!\n if (pattern === Match.Any)\n return;\n\n // Basic atomic types.\n // Do not match boxed objects (e.g. String, Boolean)\n for (var i = 0; i < typeofChecks.length; ++i) {\n if (pattern === typeofChecks[i][0]) {\n if (typeof value === typeofChecks[i][1])\n return;\n throw new Match.Error(\"Expected \" + typeofChecks[i][1] + \", got \" +\n typeof value);\n }\n }\n if (pattern === null) {\n if (value === null)\n return;\n throw new Match.Error(\"Expected null, got \" + EJSON.stringify(value));\n }\n\n // Strings and numbers match literally. Goes well with Match.OneOf.\n if (typeof pattern === \"string\" || typeof pattern === \"number\") {\n if (value === pattern)\n return;\n throw new Match.Error(\"Expected \" + pattern + \", got \" +\n EJSON.stringify(value));\n }\n\n // Match.Integer is special type encoded with array\n if (pattern === Match.Integer) {\n // There is no consistent and reliable way to check if variable is a 64-bit\n // integer. One of the popular solutions is to get reminder of division by 1\n // but this method fails on really large floats with big precision.\n // E.g.: 1.348192308491824e+23 % 1 === 0 in V8\n // Bitwise operators work consistantly but always cast variable to 32-bit\n // signed integer according to JavaScript specs.\n if (typeof value === \"number\" && (value | 0) === value)\n return\n throw new Match.Error(\"Expected Integer, got \"\n + (value instanceof Object ? EJSON.stringify(value) : value));\n }\n\n // \"Object\" is shorthand for Match.ObjectIncluding({});\n if (pattern === Object)\n pattern = Match.ObjectIncluding({});\n\n // Array (checked AFTER Any, which is implemented as an Array).\n if (pattern instanceof Array) {\n if (pattern.length !== 1)\n throw Error(\"Bad pattern: arrays must have one type element\" +\n EJSON.stringify(pattern));\n if (!_.isArray(value) && !_.isArguments(value)) {\n throw new Match.Error(\"Expected array, got \" + EJSON.stringify(value));\n }\n\n _.each(value, function (valueElement, index) {\n try {\n checkSubtree(valueElement, pattern[0]);\n } catch (err) {\n if (err instanceof Match.Error) {\n err.path = _prependPath(index, err.path);\n }\n throw err;\n }\n });\n return;\n }\n\n // Arbitrary validation checks. The condition can return false or throw a\n // Match.Error (ie, it can internally use check()) to fail.\n if (pattern instanceof Where) {\n if (pattern.condition(value))\n return;\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.Where validation\");\n }\n\n\n if (pattern instanceof Optional)\n pattern = Match.OneOf(undefined, pattern.pattern);\n\n if (pattern instanceof OneOf) {\n for (var i = 0; i < pattern.choices.length; ++i) {\n try {\n checkSubtree(value, pattern.choices[i]);\n // No error? Yay, return.\n return;\n } catch (err) {\n // Other errors should be thrown. Match errors just mean try another\n // choice.\n if (!(err instanceof Match.Error))\n throw err;\n }\n }\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.OneOf or Match.Optional validation\");\n }\n\n // A function that isn't something we special-case is assumed to be a\n // constructor.\n if (pattern instanceof Function) {\n if (value instanceof pattern)\n return;\n throw new Match.Error(\"Expected \" + (pattern.name ||\n \"particular constructor\"));\n }\n\n var unknownKeysAllowed = false;\n var unknownKeyPattern;\n if (pattern instanceof ObjectIncluding) {\n unknownKeysAllowed = true;\n pattern = pattern.pattern;\n }\n if (pattern instanceof ObjectWithValues) {\n unknownKeysAllowed = true;\n unknownKeyPattern = [pattern.pattern];\n pattern = {}; // no required keys\n }\n\n if (typeof pattern !== \"object\")\n throw Error(\"Bad pattern: unknown pattern type\");\n\n // An object, with required and optional keys. Note that this does NOT do\n // structural matches against objects of special types that happen to match\n // the pattern: this really needs to be a plain old {Object}!\n if (typeof value !== 'object')\n throw new Match.Error(\"Expected object, got \" + typeof value);\n if (value === null)\n throw new Match.Error(\"Expected object, got null\");\n if (value.constructor !== Object)\n throw new Match.Error(\"Expected plain object\");\n\n var requiredPatterns = {};\n var optionalPatterns = {};\n _.each(pattern, function (subPattern, key) {\n if (subPattern instanceof Optional)\n optionalPatterns[key] = subPattern.pattern;\n else\n requiredPatterns[key] = subPattern;\n });\n\n _.each(value, function (subValue, key) {\n try {\n if (_.has(requiredPatterns, key)) {\n checkSubtree(subValue, requiredPatterns[key]);\n delete requiredPatterns[key];\n } else if (_.has(optionalPatterns, key)) {\n checkSubtree(subValue, optionalPatterns[key]);\n } else {\n if (!unknownKeysAllowed)\n throw new Match.Error(\"Unknown key\");\n if (unknownKeyPattern) {\n checkSubtree(subValue, unknownKeyPattern[0]);\n }\n }\n } catch (err) {\n if (err instanceof Match.Error)\n err.path = _prependPath(key, err.path);\n throw err;\n }\n });\n\n _.each(requiredPatterns, function (subPattern, key) {\n throw new Match.Error(\"Missing key '\" + key + \"'\");\n });\n};\n\nvar ArgumentChecker = function (args, description) {\n var self = this;\n // Make a SHALLOW copy of the arguments. (We'll be doing identity checks\n // against its contents.)\n self.args = _.clone(args);\n // Since the common case will be to check arguments in order, and we splice\n // out arguments when we check them, make it so we splice out from the end\n // rather than the beginning.\n self.args.reverse();\n self.description = description;\n};\n\n_.extend(ArgumentChecker.prototype, {\n checking: function (value) {\n var self = this;\n if (self._checkingOneValue(value))\n return;\n // Allow check(arguments, [String]) or check(arguments.slice(1), [String])\n // or check([foo, bar], [String]) to count... but only if value wasn't\n // itself an argument.\n if (_.isArray(value) || _.isArguments(value)) {\n _.each(value, _.bind(self._checkingOneValue, self));\n }\n },\n _checkingOneValue: function (value) {\n var self = this;\n for (var i = 0; i < self.args.length; ++i) {\n // Is this value one of the arguments? (This can have a false positive if\n // the argument is an interned primitive, but it's still a good enough\n // check.)\n // (NaN is not === to itself, so we have to check specially.)\n if (value === self.args[i] || (_.isNaN(value) && _.isNaN(self.args[i]))) {\n self.args.splice(i, 1);\n return true;\n }\n }\n return false;\n },\n throwUnlessAllArgumentsHaveBeenChecked: function () {\n var self = this;\n if (!_.isEmpty(self.args))\n throw new Error(\"Did not check() all arguments during \" +\n self.description);\n }\n});\n\nvar _jsKeywords = [\"do\", \"if\", \"in\", \"for\", \"let\", \"new\", \"try\", \"var\", \"case\",\n \"else\", \"enum\", \"eval\", \"false\", \"null\", \"this\", \"true\", \"void\", \"with\",\n \"break\", \"catch\", \"class\", \"const\", \"super\", \"throw\", \"while\", \"yield\",\n \"delete\", \"export\", \"import\", \"public\", \"return\", \"static\", \"switch\",\n \"typeof\", \"default\", \"extends\", \"finally\", \"package\", \"private\", \"continue\",\n \"debugger\", \"function\", \"arguments\", \"interface\", \"protected\", \"implements\",\n \"instanceof\"];\n\n// Assumes the base of path is already escaped properly\n// returns key + base\nvar _prependPath = function (key, base) {\n if ((typeof key) === \"number\" || key.match(/^[0-9]+$/))\n key = \"[\" + key + \"]\";\n else if (!key.match(/^[a-z_$][0-9a-z_$]*$/i) || _.contains(_jsKeywords, key))\n key = JSON.stringify([key]);\n\n if (base && base[0] !== \"[\")\n return key + '.' + base;\n return key + base;\n};\n\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js b/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js deleted file mode 100644 index 727a99c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['d3js:d3'] = {}; - -})(); - -//# sourceMappingURL=d3js_d3.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js.map b/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js.map deleted file mode 100644 index 11ecca8..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/d3js_d3.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/d3js:d3.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/ddp.js b/web-app/.meteor/local/build/programs/server/packages/ddp.js deleted file mode 100644 index 9ed6004..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ddp.js +++ /dev/null @@ -1,4781 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var check = Package.check.check; -var Match = Package.check.Match; -var Random = Package.random.Random; -var EJSON = Package.ejson.EJSON; -var _ = Package.underscore._; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; -var Log = Package.logging.Log; -var Retry = Package.retry.Retry; -var Hook = Package['callback-hook'].Hook; -var LocalCollection = Package.minimongo.LocalCollection; -var Minimongo = Package.minimongo.Minimongo; - -/* Package-scope variables */ -var DDP, DDPServer, LivedataTest, toSockjsUrl, toWebsocketUrl, StreamServer, Heartbeat, Server, SUPPORTED_DDP_VERSIONS, MethodInvocation, parseDDP, stringifyDDP, RandomStream, makeRpcSeed, allConnections; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/common.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/** // 1 - * @namespace DDP // 2 - * @summary The namespace for DDP-related methods. // 3 - */ // 4 -DDP = {}; // 5 -LivedataTest = {}; // 6 - // 7 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/stream_client_nodejs.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// @param endpoint {String} URL to Meteor app // 1 -// "http://subdomain.meteor.com/" or "/" or // 2 -// "ddp+sockjs://foo-**.meteor.com/sockjs" // 3 -// // 4 -// We do some rewriting of the URL to eventually make it "ws://" or "wss://", // 5 -// whatever was passed in. At the very least, what Meteor.absoluteUrl() returns // 6 -// us should work. // 7 -// // 8 -// We don't do any heartbeating. (The logic that did this in sockjs was removed, // 9 -// because it used a built-in sockjs mechanism. We could do it with WebSocket // 10 -// ping frames or with DDP-level messages.) // 11 -LivedataTest.ClientStream = function (endpoint, options) { // 12 - var self = this; // 13 - options = options || {}; // 14 - // 15 - self.options = _.extend({ // 16 - retry: true // 17 - }, options); // 18 - // 19 - self.client = null; // created in _launchConnection // 20 - self.endpoint = endpoint; // 21 - // 22 - self.headers = self.options.headers || {}; // 23 - // 24 - self._initCommon(self.options); // 25 - // 26 - //// Kickoff! // 27 - self._launchConnection(); // 28 -}; // 29 - // 30 -_.extend(LivedataTest.ClientStream.prototype, { // 31 - // 32 - // data is a utf8 string. Data sent while not connected is dropped on // 33 - // the floor, and it is up the user of this API to retransmit lost // 34 - // messages on 'reset' // 35 - send: function (data) { // 36 - var self = this; // 37 - if (self.currentStatus.connected) { // 38 - self.client.send(data); // 39 - } // 40 - }, // 41 - // 42 - // Changes where this connection points // 43 - _changeUrl: function (url) { // 44 - var self = this; // 45 - self.endpoint = url; // 46 - }, // 47 - // 48 - _onConnect: function (client) { // 49 - var self = this; // 50 - // 51 - if (client !== self.client) { // 52 - // This connection is not from the last call to _launchConnection. // 53 - // But _launchConnection calls _cleanup which closes previous connections. // 54 - // It's our belief that this stifles future 'open' events, but maybe // 55 - // we are wrong? // 56 - throw new Error("Got open from inactive client " + !!self.client); // 57 - } // 58 - // 59 - if (self._forcedToDisconnect) { // 60 - // We were asked to disconnect between trying to open the connection and // 61 - // actually opening it. Let's just pretend this never happened. // 62 - self.client.close(); // 63 - self.client = null; // 64 - return; // 65 - } // 66 - // 67 - if (self.currentStatus.connected) { // 68 - // We already have a connection. It must have been the case that we // 69 - // started two parallel connection attempts (because we wanted to // 70 - // 'reconnect now' on a hanging connection and we had no way to cancel the // 71 - // connection attempt.) But this shouldn't happen (similarly to the client // 72 - // !== self.client check above). // 73 - throw new Error("Two parallel connections?"); // 74 - } // 75 - // 76 - self._clearConnectionTimer(); // 77 - // 78 - // update status // 79 - self.currentStatus.status = "connected"; // 80 - self.currentStatus.connected = true; // 81 - self.currentStatus.retryCount = 0; // 82 - self.statusChanged(); // 83 - // 84 - // fire resets. This must come after status change so that clients // 85 - // can call send from within a reset callback. // 86 - _.each(self.eventCallbacks.reset, function (callback) { callback(); }); // 87 - }, // 88 - // 89 - _cleanup: function (maybeError) { // 90 - var self = this; // 91 - // 92 - self._clearConnectionTimer(); // 93 - if (self.client) { // 94 - var client = self.client; // 95 - self.client = null; // 96 - client.close(); // 97 - // 98 - _.each(self.eventCallbacks.disconnect, function (callback) { // 99 - callback(maybeError); // 100 - }); // 101 - } // 102 - }, // 103 - // 104 - _clearConnectionTimer: function () { // 105 - var self = this; // 106 - // 107 - if (self.connectionTimer) { // 108 - clearTimeout(self.connectionTimer); // 109 - self.connectionTimer = null; // 110 - } // 111 - }, // 112 - // 113 - _getProxyUrl: function (targetUrl) { // 114 - var self = this; // 115 - // Similar to code in tools/http-helpers.js. // 116 - var proxy = process.env.HTTP_PROXY || process.env.http_proxy || null; // 117 - // if we're going to a secure url, try the https_proxy env variable first. // 118 - if (targetUrl.match(/^wss:/)) { // 119 - proxy = process.env.HTTPS_PROXY || process.env.https_proxy || proxy; // 120 - } // 121 - return proxy; // 122 - }, // 123 - // 124 - _launchConnection: function () { // 125 - var self = this; // 126 - self._cleanup(); // cleanup the old socket, if there was one. // 127 - // 128 - // Since server-to-server DDP is still an experimental feature, we only // 129 - // require the module if we actually create a server-to-server // 130 - // connection. // 131 - var FayeWebSocket = Npm.require('faye-websocket'); // 132 - // 133 - var targetUrl = toWebsocketUrl(self.endpoint); // 134 - var fayeOptions = { headers: self.headers }; // 135 - var proxyUrl = self._getProxyUrl(targetUrl); // 136 - if (proxyUrl) { // 137 - fayeOptions.proxy = { origin: proxyUrl }; // 138 - }; // 139 - // 140 - // We would like to specify 'ddp' as the subprotocol here. The npm module we // 141 - // used to use as a client would fail the handshake if we ask for a // 142 - // subprotocol and the server doesn't send one back (and sockjs doesn't). // 143 - // Faye doesn't have that behavior; it's unclear from reading RFC 6455 if // 144 - // Faye is erroneous or not. So for now, we don't specify protocols. // 145 - var subprotocols = []; // 146 - // 147 - var client = self.client = new FayeWebSocket.Client( // 148 - targetUrl, subprotocols, fayeOptions); // 149 - // 150 - self._clearConnectionTimer(); // 151 - self.connectionTimer = Meteor.setTimeout( // 152 - function () { // 153 - self._lostConnection( // 154 - new DDP.ConnectionError("DDP connection timed out")); // 155 - }, // 156 - self.CONNECT_TIMEOUT); // 157 - // 158 - self.client.on('open', Meteor.bindEnvironment(function () { // 159 - return self._onConnect(client); // 160 - }, "stream connect callback")); // 161 - // 162 - var clientOnIfCurrent = function (event, description, f) { // 163 - self.client.on(event, Meteor.bindEnvironment(function () { // 164 - // Ignore events from any connection we've already cleaned up. // 165 - if (client !== self.client) // 166 - return; // 167 - f.apply(this, arguments); // 168 - }, description)); // 169 - }; // 170 - // 171 - clientOnIfCurrent('error', 'stream error callback', function (error) { // 172 - if (!self.options._dontPrintErrors) // 173 - Meteor._debug("stream error", error.message); // 174 - // 175 - // Faye's 'error' object is not a JS error (and among other things, // 176 - // doesn't stringify well). Convert it to one. // 177 - self._lostConnection(new DDP.ConnectionError(error.message)); // 178 - }); // 179 - // 180 - // 181 - clientOnIfCurrent('close', 'stream close callback', function () { // 182 - self._lostConnection(); // 183 - }); // 184 - // 185 - // 186 - clientOnIfCurrent('message', 'stream message callback', function (message) { // 187 - // Ignore binary frames, where message.data is a Buffer // 188 - if (typeof message.data !== "string") // 189 - return; // 190 - // 191 - _.each(self.eventCallbacks.message, function (callback) { // 192 - callback(message.data); // 193 - }); // 194 - }); // 195 - } // 196 -}); // 197 - // 198 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/stream_client_common.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// XXX from Underscore.String (http://epeli.github.com/underscore.string/) // 1 -var startsWith = function(str, starts) { // 2 - return str.length >= starts.length && // 3 - str.substring(0, starts.length) === starts; // 4 -}; // 5 -var endsWith = function(str, ends) { // 6 - return str.length >= ends.length && // 7 - str.substring(str.length - ends.length) === ends; // 8 -}; // 9 - // 10 -// @param url {String} URL to Meteor app, eg: // 11 -// "/" or "madewith.meteor.com" or "https://foo.meteor.com" // 12 -// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs" // 13 -// @returns {String} URL to the endpoint with the specific scheme and subPath, e.g. // 14 -// for scheme "http" and subPath "sockjs" // 15 -// "http://subdomain.meteor.com/sockjs" or "/sockjs" // 16 -// or "https://ddp--1234-foo.meteor.com/sockjs" // 17 -var translateUrl = function(url, newSchemeBase, subPath) { // 18 - if (! newSchemeBase) { // 19 - newSchemeBase = "http"; // 20 - } // 21 - // 22 - var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//); // 23 - var httpUrlMatch = url.match(/^http(s?):\/\//); // 24 - var newScheme; // 25 - if (ddpUrlMatch) { // 26 - // Remove scheme and split off the host. // 27 - var urlAfterDDP = url.substr(ddpUrlMatch[0].length); // 28 - newScheme = ddpUrlMatch[1] === "i" ? newSchemeBase : newSchemeBase + "s"; // 29 - var slashPos = urlAfterDDP.indexOf('/'); // 30 - var host = // 31 - slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos); // 32 - var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos); // 33 - // 34 - // In the host (ONLY!), change '*' characters into random digits. This // 35 - // allows different stream connections to connect to different hostnames // 36 - // and avoid browser per-hostname connection limits. // 37 - host = host.replace(/\*/g, function () { // 38 - return Math.floor(Random.fraction()*10); // 39 - }); // 40 - // 41 - return newScheme + '://' + host + rest; // 42 - } else if (httpUrlMatch) { // 43 - newScheme = !httpUrlMatch[1] ? newSchemeBase : newSchemeBase + "s"; // 44 - var urlAfterHttp = url.substr(httpUrlMatch[0].length); // 45 - url = newScheme + "://" + urlAfterHttp; // 46 - } // 47 - // 48 - // Prefix FQDNs but not relative URLs // 49 - if (url.indexOf("://") === -1 && !startsWith(url, "/")) { // 50 - url = newSchemeBase + "://" + url; // 51 - } // 52 - // 53 - // XXX This is not what we should be doing: if I have a site // 54 - // deployed at "/foo", then DDP.connect("/") should actually connect // 55 - // to "/", not to "/foo". "/" is an absolute path. (Contrast: if // 56 - // deployed at "/foo", it would be reasonable for DDP.connect("bar") // 57 - // to connect to "/foo/bar"). // 58 - // // 59 - // We should make this properly honor absolute paths rather than // 60 - // forcing the path to be relative to the site root. Simultaneously, // 61 - // we should set DDP_DEFAULT_CONNECTION_URL to include the site // 62 - // root. See also client_convenience.js #RationalizingRelativeDDPURLs // 63 - url = Meteor._relativeToSiteRootUrl(url); // 64 - // 65 - if (endsWith(url, "/")) // 66 - return url + subPath; // 67 - else // 68 - return url + "/" + subPath; // 69 -}; // 70 - // 71 -toSockjsUrl = function (url) { // 72 - return translateUrl(url, "http", "sockjs"); // 73 -}; // 74 - // 75 -toWebsocketUrl = function (url) { // 76 - var ret = translateUrl(url, "ws", "websocket"); // 77 - return ret; // 78 -}; // 79 - // 80 -LivedataTest.toSockjsUrl = toSockjsUrl; // 81 - // 82 - // 83 -_.extend(LivedataTest.ClientStream.prototype, { // 84 - // 85 - // Register for callbacks. // 86 - on: function (name, callback) { // 87 - var self = this; // 88 - // 89 - if (name !== 'message' && name !== 'reset' && name !== 'disconnect') // 90 - throw new Error("unknown event type: " + name); // 91 - // 92 - if (!self.eventCallbacks[name]) // 93 - self.eventCallbacks[name] = []; // 94 - self.eventCallbacks[name].push(callback); // 95 - }, // 96 - // 97 - // 98 - _initCommon: function (options) { // 99 - var self = this; // 100 - options = options || {}; // 101 - // 102 - //// Constants // 103 - // 104 - // how long to wait until we declare the connection attempt // 105 - // failed. // 106 - self.CONNECT_TIMEOUT = options.connectTimeoutMs || 10000; // 107 - // 108 - self.eventCallbacks = {}; // name -> [callback] // 109 - // 110 - self._forcedToDisconnect = false; // 111 - // 112 - //// Reactive status // 113 - self.currentStatus = { // 114 - status: "connecting", // 115 - connected: false, // 116 - retryCount: 0 // 117 - }; // 118 - // 119 - // 120 - self.statusListeners = typeof Tracker !== 'undefined' && new Tracker.Dependency; // 121 - self.statusChanged = function () { // 122 - if (self.statusListeners) // 123 - self.statusListeners.changed(); // 124 - }; // 125 - // 126 - //// Retry logic // 127 - self._retry = new Retry; // 128 - self.connectionTimer = null; // 129 - // 130 - }, // 131 - // 132 - // Trigger a reconnect. // 133 - reconnect: function (options) { // 134 - var self = this; // 135 - options = options || {}; // 136 - // 137 - if (options.url) { // 138 - self._changeUrl(options.url); // 139 - } // 140 - // 141 - if (options._sockjsOptions) { // 142 - self.options._sockjsOptions = options._sockjsOptions; // 143 - } // 144 - // 145 - if (self.currentStatus.connected) { // 146 - if (options._force || options.url) { // 147 - // force reconnect. // 148 - self._lostConnection(new DDP.ForcedReconnectError); // 149 - } // else, noop. // 150 - return; // 151 - } // 152 - // 153 - // if we're mid-connection, stop it. // 154 - if (self.currentStatus.status === "connecting") { // 155 - // Pretend it's a clean close. // 156 - self._lostConnection(); // 157 - } // 158 - // 159 - self._retry.clear(); // 160 - self.currentStatus.retryCount -= 1; // don't count manual retries // 161 - self._retryNow(); // 162 - }, // 163 - // 164 - disconnect: function (options) { // 165 - var self = this; // 166 - options = options || {}; // 167 - // 168 - // Failed is permanent. If we're failed, don't let people go back // 169 - // online by calling 'disconnect' then 'reconnect'. // 170 - if (self._forcedToDisconnect) // 171 - return; // 172 - // 173 - // If _permanent is set, permanently disconnect a stream. Once a stream // 174 - // is forced to disconnect, it can never reconnect. This is for // 175 - // error cases such as ddp version mismatch, where trying again // 176 - // won't fix the problem. // 177 - if (options._permanent) { // 178 - self._forcedToDisconnect = true; // 179 - } // 180 - // 181 - self._cleanup(); // 182 - self._retry.clear(); // 183 - // 184 - self.currentStatus = { // 185 - status: (options._permanent ? "failed" : "offline"), // 186 - connected: false, // 187 - retryCount: 0 // 188 - }; // 189 - // 190 - if (options._permanent && options._error) // 191 - self.currentStatus.reason = options._error; // 192 - // 193 - self.statusChanged(); // 194 - }, // 195 - // 196 - // maybeError is set unless it's a clean protocol-level close. // 197 - _lostConnection: function (maybeError) { // 198 - var self = this; // 199 - // 200 - self._cleanup(maybeError); // 201 - self._retryLater(maybeError); // sets status. no need to do it here. // 202 - }, // 203 - // 204 - // fired when we detect that we've gone online. try to reconnect // 205 - // immediately. // 206 - _online: function () { // 207 - // if we've requested to be offline by disconnecting, don't reconnect. // 208 - if (this.currentStatus.status != "offline") // 209 - this.reconnect(); // 210 - }, // 211 - // 212 - _retryLater: function (maybeError) { // 213 - var self = this; // 214 - // 215 - var timeout = 0; // 216 - if (self.options.retry || // 217 - (maybeError && maybeError.errorType === "DDP.ForcedReconnectError")) { // 218 - timeout = self._retry.retryLater( // 219 - self.currentStatus.retryCount, // 220 - _.bind(self._retryNow, self) // 221 - ); // 222 - self.currentStatus.status = "waiting"; // 223 - self.currentStatus.retryTime = (new Date()).getTime() + timeout; // 224 - } else { // 225 - self.currentStatus.status = "failed"; // 226 - delete self.currentStatus.retryTime; // 227 - } // 228 - // 229 - self.currentStatus.connected = false; // 230 - self.statusChanged(); // 231 - }, // 232 - // 233 - _retryNow: function () { // 234 - var self = this; // 235 - // 236 - if (self._forcedToDisconnect) // 237 - return; // 238 - // 239 - self.currentStatus.retryCount += 1; // 240 - self.currentStatus.status = "connecting"; // 241 - self.currentStatus.connected = false; // 242 - delete self.currentStatus.retryTime; // 243 - self.statusChanged(); // 244 - // 245 - self._launchConnection(); // 246 - }, // 247 - // 248 - // 249 - // Get current status. Reactive. // 250 - status: function () { // 251 - var self = this; // 252 - if (self.statusListeners) // 253 - self.statusListeners.depend(); // 254 - return self.currentStatus; // 255 - } // 256 -}); // 257 - // 258 -DDP.ConnectionError = Meteor.makeErrorType( // 259 - "DDP.ConnectionError", function (message) { // 260 - var self = this; // 261 - self.message = message; // 262 -}); // 263 - // 264 -DDP.ForcedReconnectError = Meteor.makeErrorType( // 265 - "DDP.ForcedReconnectError", function () {}); // 266 - // 267 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/stream_server.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var url = Npm.require('url'); // 1 - // 2 -var pathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ""; // 3 - // 4 -StreamServer = function () { // 5 - var self = this; // 6 - self.registration_callbacks = []; // 7 - self.open_sockets = []; // 8 - // 9 - // Because we are installing directly onto WebApp.httpServer instead of using // 10 - // WebApp.app, we have to process the path prefix ourselves. // 11 - self.prefix = pathPrefix + '/sockjs'; // 12 - // routepolicy is only a weak dependency, because we don't need it if we're // 13 - // just doing server-to-server DDP as a client. // 14 - if (Package.routepolicy) { // 15 - Package.routepolicy.RoutePolicy.declare(self.prefix + '/', 'network'); // 16 - } // 17 - // 18 - // set up sockjs // 19 - var sockjs = Npm.require('sockjs'); // 20 - var serverOptions = { // 21 - prefix: self.prefix, // 22 - log: function() {}, // 23 - // this is the default, but we code it explicitly because we depend // 24 - // on it in stream_client:HEARTBEAT_TIMEOUT // 25 - heartbeat_delay: 45000, // 26 - // The default disconnect_delay is 5 seconds, but if the server ends up CPU // 27 - // bound for that much time, SockJS might not notice that the user has // 28 - // reconnected because the timer (of disconnect_delay ms) can fire before // 29 - // SockJS processes the new connection. Eventually we'll fix this by not // 30 - // combining CPU-heavy processing with SockJS termination (eg a proxy which // 31 - // converts to Unix sockets) but for now, raise the delay. // 32 - disconnect_delay: 60 * 1000, // 33 - // Set the USE_JSESSIONID environment variable to enable setting the // 34 - // JSESSIONID cookie. This is useful for setting up proxies with // 35 - // session affinity. // 36 - jsessionid: !!process.env.USE_JSESSIONID // 37 - }; // 38 - // 39 - // If you know your server environment (eg, proxies) will prevent websockets // 40 - // from ever working, set $DISABLE_WEBSOCKETS and SockJS clients (ie, // 41 - // browsers) will not waste time attempting to use them. // 42 - // (Your server will still have a /websocket endpoint.) // 43 - if (process.env.DISABLE_WEBSOCKETS) // 44 - serverOptions.websocket = false; // 45 - // 46 - self.server = sockjs.createServer(serverOptions); // 47 - if (!Package.webapp) { // 48 - throw new Error("Cannot create a DDP server without the webapp package"); // 49 - } // 50 - // Install the sockjs handlers, but we want to keep around our own particular // 51 - // request handler that adjusts idle timeouts while we have an outstanding // 52 - // request. This compensates for the fact that sockjs removes all listeners // 53 - // for "request" to add its own. // 54 - Package.webapp.WebApp.httpServer.removeListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback); // 55 - self.server.installHandlers(Package.webapp.WebApp.httpServer); // 56 - Package.webapp.WebApp.httpServer.addListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback); // 57 - // 58 - // Support the /websocket endpoint // 59 - self._redirectWebsocketEndpoint(); // 60 - // 61 - self.server.on('connection', function (socket) { // 62 - socket.send = function (data) { // 63 - socket.write(data); // 64 - }; // 65 - socket.on('close', function () { // 66 - self.open_sockets = _.without(self.open_sockets, socket); // 67 - }); // 68 - self.open_sockets.push(socket); // 69 - // 70 - // XXX COMPAT WITH 0.6.6. Send the old style welcome message, which // 71 - // will force old clients to reload. Remove this once we're not // 72 - // concerned about people upgrading from a pre-0.7.0 release. Also, // 73 - // remove the clause in the client that ignores the welcome message // 74 - // (livedata_connection.js) // 75 - socket.send(JSON.stringify({server_id: "0"})); // 76 - // 77 - // call all our callbacks when we get a new socket. they will do the // 78 - // work of setting up handlers and such for specific messages. // 79 - _.each(self.registration_callbacks, function (callback) { // 80 - callback(socket); // 81 - }); // 82 - }); // 83 - // 84 -}; // 85 - // 86 -_.extend(StreamServer.prototype, { // 87 - // call my callback when a new socket connects. // 88 - // also call it for all current connections. // 89 - register: function (callback) { // 90 - var self = this; // 91 - self.registration_callbacks.push(callback); // 92 - _.each(self.all_sockets(), function (socket) { // 93 - callback(socket); // 94 - }); // 95 - }, // 96 - // 97 - // get a list of all sockets // 98 - all_sockets: function () { // 99 - var self = this; // 100 - return _.values(self.open_sockets); // 101 - }, // 102 - // 103 - // Redirect /websocket to /sockjs/websocket in order to not expose // 104 - // sockjs to clients that want to use raw websockets // 105 - _redirectWebsocketEndpoint: function() { // 106 - var self = this; // 107 - // Unfortunately we can't use a connect middleware here since // 108 - // sockjs installs itself prior to all existing listeners // 109 - // (meaning prior to any connect middlewares) so we need to take // 110 - // an approach similar to overshadowListeners in // 111 - // https://github.com/sockjs/sockjs-node/blob/cf820c55af6a9953e16558555a31decea554f70e/src/utils.coffee // 112 - _.each(['request', 'upgrade'], function(event) { // 113 - var httpServer = Package.webapp.WebApp.httpServer; // 114 - var oldHttpServerListeners = httpServer.listeners(event).slice(0); // 115 - httpServer.removeAllListeners(event); // 116 - // 117 - // request and upgrade have different arguments passed but // 118 - // we only care about the first one which is always request // 119 - var newListener = function(request /*, moreArguments */) { // 120 - // Store arguments for use within the closure below // 121 - var args = arguments; // 122 - // 123 - // Rewrite /websocket and /websocket/ urls to /sockjs/websocket while // 124 - // preserving query string. // 125 - var parsedUrl = url.parse(request.url); // 126 - if (parsedUrl.pathname === pathPrefix + '/websocket' || // 127 - parsedUrl.pathname === pathPrefix + '/websocket/') { // 128 - parsedUrl.pathname = self.prefix + '/websocket'; // 129 - request.url = url.format(parsedUrl); // 130 - } // 131 - _.each(oldHttpServerListeners, function(oldListener) { // 132 - oldListener.apply(httpServer, args); // 133 - }); // 134 - }; // 135 - httpServer.addListener(event, newListener); // 136 - }); // 137 - } // 138 -}); // 139 - // 140 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/heartbeat.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Heartbeat options: // 1 -// heartbeatInterval: interval to send pings, in milliseconds. // 2 -// heartbeatTimeout: timeout to close the connection if a reply isn't // 3 -// received, in milliseconds. // 4 -// sendPing: function to call to send a ping on the connection. // 5 -// onTimeout: function to call to close the connection. // 6 - // 7 -Heartbeat = function (options) { // 8 - var self = this; // 9 - // 10 - self.heartbeatInterval = options.heartbeatInterval; // 11 - self.heartbeatTimeout = options.heartbeatTimeout; // 12 - self._sendPing = options.sendPing; // 13 - self._onTimeout = options.onTimeout; // 14 - // 15 - self._heartbeatIntervalHandle = null; // 16 - self._heartbeatTimeoutHandle = null; // 17 -}; // 18 - // 19 -_.extend(Heartbeat.prototype, { // 20 - stop: function () { // 21 - var self = this; // 22 - self._clearHeartbeatIntervalTimer(); // 23 - self._clearHeartbeatTimeoutTimer(); // 24 - }, // 25 - // 26 - start: function () { // 27 - var self = this; // 28 - self.stop(); // 29 - self._startHeartbeatIntervalTimer(); // 30 - }, // 31 - // 32 - _startHeartbeatIntervalTimer: function () { // 33 - var self = this; // 34 - self._heartbeatIntervalHandle = Meteor.setTimeout( // 35 - _.bind(self._heartbeatIntervalFired, self), // 36 - self.heartbeatInterval // 37 - ); // 38 - }, // 39 - // 40 - _startHeartbeatTimeoutTimer: function () { // 41 - var self = this; // 42 - self._heartbeatTimeoutHandle = Meteor.setTimeout( // 43 - _.bind(self._heartbeatTimeoutFired, self), // 44 - self.heartbeatTimeout // 45 - ); // 46 - }, // 47 - // 48 - _clearHeartbeatIntervalTimer: function () { // 49 - var self = this; // 50 - if (self._heartbeatIntervalHandle) { // 51 - Meteor.clearTimeout(self._heartbeatIntervalHandle); // 52 - self._heartbeatIntervalHandle = null; // 53 - } // 54 - }, // 55 - // 56 - _clearHeartbeatTimeoutTimer: function () { // 57 - var self = this; // 58 - if (self._heartbeatTimeoutHandle) { // 59 - Meteor.clearTimeout(self._heartbeatTimeoutHandle); // 60 - self._heartbeatTimeoutHandle = null; // 61 - } // 62 - }, // 63 - // 64 - // The heartbeat interval timer is fired when we should send a ping. // 65 - _heartbeatIntervalFired: function () { // 66 - var self = this; // 67 - self._heartbeatIntervalHandle = null; // 68 - self._sendPing(); // 69 - // Wait for a pong. // 70 - self._startHeartbeatTimeoutTimer(); // 71 - }, // 72 - // 73 - // The heartbeat timeout timer is fired when we sent a ping, but we // 74 - // timed out waiting for the pong. // 75 - _heartbeatTimeoutFired: function () { // 76 - var self = this; // 77 - self._heartbeatTimeoutHandle = null; // 78 - self._onTimeout(); // 79 - }, // 80 - // 81 - pingReceived: function () { // 82 - var self = this; // 83 - // We know the connection is alive if we receive a ping, so we // 84 - // don't need to send a ping ourselves. Reset the interval timer. // 85 - if (self._heartbeatIntervalHandle) { // 86 - self._clearHeartbeatIntervalTimer(); // 87 - self._startHeartbeatIntervalTimer(); // 88 - } // 89 - }, // 90 - // 91 - pongReceived: function () { // 92 - var self = this; // 93 - // 94 - // Receiving a pong means we won't timeout, so clear the timeout // 95 - // timer and start the interval again. // 96 - if (self._heartbeatTimeoutHandle) { // 97 - self._clearHeartbeatTimeoutTimer(); // 98 - self._startHeartbeatIntervalTimer(); // 99 - } // 100 - } // 101 -}); // 102 - // 103 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/livedata_server.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -DDPServer = {}; // 1 - // 2 -var Fiber = Npm.require('fibers'); // 3 - // 4 -// This file contains classes: // 5 -// * Session - The server's connection to a single DDP client // 6 -// * Subscription - A single subscription for a single client // 7 -// * Server - An entire server that may talk to > 1 client. A DDP endpoint. // 8 -// // 9 -// Session and Subscription are file scope. For now, until we freeze // 10 -// the interface, Server is package scope (in the future it should be // 11 -// exported.) // 12 - // 13 -// Represents a single document in a SessionCollectionView // 14 -var SessionDocumentView = function () { // 15 - var self = this; // 16 - self.existsIn = {}; // set of subscriptionHandle // 17 - self.dataByKey = {}; // key-> [ {subscriptionHandle, value} by precedence] // 18 -}; // 19 - // 20 -_.extend(SessionDocumentView.prototype, { // 21 - // 22 - getFields: function () { // 23 - var self = this; // 24 - var ret = {}; // 25 - _.each(self.dataByKey, function (precedenceList, key) { // 26 - ret[key] = precedenceList[0].value; // 27 - }); // 28 - return ret; // 29 - }, // 30 - // 31 - clearField: function (subscriptionHandle, key, changeCollector) { // 32 - var self = this; // 33 - // Publish API ignores _id if present in fields // 34 - if (key === "_id") // 35 - return; // 36 - var precedenceList = self.dataByKey[key]; // 37 - // 38 - // It's okay to clear fields that didn't exist. No need to throw // 39 - // an error. // 40 - if (!precedenceList) // 41 - return; // 42 - // 43 - var removedValue = undefined; // 44 - for (var i = 0; i < precedenceList.length; i++) { // 45 - var precedence = precedenceList[i]; // 46 - if (precedence.subscriptionHandle === subscriptionHandle) { // 47 - // The view's value can only change if this subscription is the one that // 48 - // used to have precedence. // 49 - if (i === 0) // 50 - removedValue = precedence.value; // 51 - precedenceList.splice(i, 1); // 52 - break; // 53 - } // 54 - } // 55 - if (_.isEmpty(precedenceList)) { // 56 - delete self.dataByKey[key]; // 57 - changeCollector[key] = undefined; // 58 - } else if (removedValue !== undefined && // 59 - !EJSON.equals(removedValue, precedenceList[0].value)) { // 60 - changeCollector[key] = precedenceList[0].value; // 61 - } // 62 - }, // 63 - // 64 - changeField: function (subscriptionHandle, key, value, // 65 - changeCollector, isAdd) { // 66 - var self = this; // 67 - // Publish API ignores _id if present in fields // 68 - if (key === "_id") // 69 - return; // 70 - // 71 - // Don't share state with the data passed in by the user. // 72 - value = EJSON.clone(value); // 73 - // 74 - if (!_.has(self.dataByKey, key)) { // 75 - self.dataByKey[key] = [{subscriptionHandle: subscriptionHandle, // 76 - value: value}]; // 77 - changeCollector[key] = value; // 78 - return; // 79 - } // 80 - var precedenceList = self.dataByKey[key]; // 81 - var elt; // 82 - if (!isAdd) { // 83 - elt = _.find(precedenceList, function (precedence) { // 84 - return precedence.subscriptionHandle === subscriptionHandle; // 85 - }); // 86 - } // 87 - // 88 - if (elt) { // 89 - if (elt === precedenceList[0] && !EJSON.equals(value, elt.value)) { // 90 - // this subscription is changing the value of this field. // 91 - changeCollector[key] = value; // 92 - } // 93 - elt.value = value; // 94 - } else { // 95 - // this subscription is newly caring about this field // 96 - precedenceList.push({subscriptionHandle: subscriptionHandle, value: value}); // 97 - } // 98 - // 99 - } // 100 -}); // 101 - // 102 -/** // 103 - * Represents a client's view of a single collection // 104 - * @param {String} collectionName Name of the collection it represents // 105 - * @param {Object.} sessionCallbacks The callbacks for added, changed, removed // 106 - * @class SessionCollectionView // 107 - */ // 108 -var SessionCollectionView = function (collectionName, sessionCallbacks) { // 109 - var self = this; // 110 - self.collectionName = collectionName; // 111 - self.documents = {}; // 112 - self.callbacks = sessionCallbacks; // 113 -}; // 114 - // 115 -LivedataTest.SessionCollectionView = SessionCollectionView; // 116 - // 117 - // 118 -_.extend(SessionCollectionView.prototype, { // 119 - // 120 - isEmpty: function () { // 121 - var self = this; // 122 - return _.isEmpty(self.documents); // 123 - }, // 124 - // 125 - diff: function (previous) { // 126 - var self = this; // 127 - LocalCollection._diffObjects(previous.documents, self.documents, { // 128 - both: _.bind(self.diffDocument, self), // 129 - // 130 - rightOnly: function (id, nowDV) { // 131 - self.callbacks.added(self.collectionName, id, nowDV.getFields()); // 132 - }, // 133 - // 134 - leftOnly: function (id, prevDV) { // 135 - self.callbacks.removed(self.collectionName, id); // 136 - } // 137 - }); // 138 - }, // 139 - // 140 - diffDocument: function (id, prevDV, nowDV) { // 141 - var self = this; // 142 - var fields = {}; // 143 - LocalCollection._diffObjects(prevDV.getFields(), nowDV.getFields(), { // 144 - both: function (key, prev, now) { // 145 - if (!EJSON.equals(prev, now)) // 146 - fields[key] = now; // 147 - }, // 148 - rightOnly: function (key, now) { // 149 - fields[key] = now; // 150 - }, // 151 - leftOnly: function(key, prev) { // 152 - fields[key] = undefined; // 153 - } // 154 - }); // 155 - self.callbacks.changed(self.collectionName, id, fields); // 156 - }, // 157 - // 158 - added: function (subscriptionHandle, id, fields) { // 159 - var self = this; // 160 - var docView = self.documents[id]; // 161 - var added = false; // 162 - if (!docView) { // 163 - added = true; // 164 - docView = new SessionDocumentView(); // 165 - self.documents[id] = docView; // 166 - } // 167 - docView.existsIn[subscriptionHandle] = true; // 168 - var changeCollector = {}; // 169 - _.each(fields, function (value, key) { // 170 - docView.changeField( // 171 - subscriptionHandle, key, value, changeCollector, true); // 172 - }); // 173 - if (added) // 174 - self.callbacks.added(self.collectionName, id, changeCollector); // 175 - else // 176 - self.callbacks.changed(self.collectionName, id, changeCollector); // 177 - }, // 178 - // 179 - changed: function (subscriptionHandle, id, changed) { // 180 - var self = this; // 181 - var changedResult = {}; // 182 - var docView = self.documents[id]; // 183 - if (!docView) // 184 - throw new Error("Could not find element with id " + id + " to change"); // 185 - _.each(changed, function (value, key) { // 186 - if (value === undefined) // 187 - docView.clearField(subscriptionHandle, key, changedResult); // 188 - else // 189 - docView.changeField(subscriptionHandle, key, value, changedResult); // 190 - }); // 191 - self.callbacks.changed(self.collectionName, id, changedResult); // 192 - }, // 193 - // 194 - removed: function (subscriptionHandle, id) { // 195 - var self = this; // 196 - var docView = self.documents[id]; // 197 - if (!docView) { // 198 - var err = new Error("Removed nonexistent document " + id); // 199 - throw err; // 200 - } // 201 - delete docView.existsIn[subscriptionHandle]; // 202 - if (_.isEmpty(docView.existsIn)) { // 203 - // it is gone from everyone // 204 - self.callbacks.removed(self.collectionName, id); // 205 - delete self.documents[id]; // 206 - } else { // 207 - var changed = {}; // 208 - // remove this subscription from every precedence list // 209 - // and record the changes // 210 - _.each(docView.dataByKey, function (precedenceList, key) { // 211 - docView.clearField(subscriptionHandle, key, changed); // 212 - }); // 213 - // 214 - self.callbacks.changed(self.collectionName, id, changed); // 215 - } // 216 - } // 217 -}); // 218 - // 219 -/******************************************************************************/ // 220 -/* Session */ // 221 -/******************************************************************************/ // 222 - // 223 -var Session = function (server, version, socket, options) { // 224 - var self = this; // 225 - self.id = Random.id(); // 226 - // 227 - self.server = server; // 228 - self.version = version; // 229 - // 230 - self.initialized = false; // 231 - self.socket = socket; // 232 - // 233 - // set to null when the session is destroyed. multiple places below // 234 - // use this to determine if the session is alive or not. // 235 - self.inQueue = new Meteor._DoubleEndedQueue(); // 236 - // 237 - self.blocked = false; // 238 - self.workerRunning = false; // 239 - // 240 - // Sub objects for active subscriptions // 241 - self._namedSubs = {}; // 242 - self._universalSubs = []; // 243 - // 244 - self.userId = null; // 245 - // 246 - self.collectionViews = {}; // 247 - // 248 - // Set this to false to not send messages when collectionViews are // 249 - // modified. This is done when rerunning subs in _setUserId and those messages // 250 - // are calculated via a diff instead. // 251 - self._isSending = true; // 252 - // 253 - // If this is true, don't start a newly-created universal publisher on this // 254 - // session. The session will take care of starting it when appropriate. // 255 - self._dontStartNewUniversalSubs = false; // 256 - // 257 - // when we are rerunning subscriptions, any ready messages // 258 - // we want to buffer up for when we are done rerunning subscriptions // 259 - self._pendingReady = []; // 260 - // 261 - // List of callbacks to call when this connection is closed. // 262 - self._closeCallbacks = []; // 263 - // 264 - // 265 - // XXX HACK: If a sockjs connection, save off the URL. This is // 266 - // temporary and will go away in the near future. // 267 - self._socketUrl = socket.url; // 268 - // 269 - // Allow tests to disable responding to pings. // 270 - self._respondToPings = options.respondToPings; // 271 - // 272 - // This object is the public interface to the session. In the public // 273 - // API, it is called the `connection` object. Internally we call it // 274 - // a `connectionHandle` to avoid ambiguity. // 275 - self.connectionHandle = { // 276 - id: self.id, // 277 - close: function () { // 278 - self.close(); // 279 - }, // 280 - onClose: function (fn) { // 281 - var cb = Meteor.bindEnvironment(fn, "connection onClose callback"); // 282 - if (self.inQueue) { // 283 - self._closeCallbacks.push(cb); // 284 - } else { // 285 - // if we're already closed, call the callback. // 286 - Meteor.defer(cb); // 287 - } // 288 - }, // 289 - clientAddress: self._clientAddress(), // 290 - httpHeaders: self.socket.headers // 291 - }; // 292 - // 293 - socket.send(stringifyDDP({msg: 'connected', // 294 - session: self.id})); // 295 - // On initial connect, spin up all the universal publishers. // 296 - Fiber(function () { // 297 - self.startUniversalSubs(); // 298 - }).run(); // 299 - // 300 - if (version !== 'pre1' && options.heartbeatInterval !== 0) { // 301 - self.heartbeat = new Heartbeat({ // 302 - heartbeatInterval: options.heartbeatInterval, // 303 - heartbeatTimeout: options.heartbeatTimeout, // 304 - onTimeout: function () { // 305 - self.close(); // 306 - }, // 307 - sendPing: function () { // 308 - self.send({msg: 'ping'}); // 309 - } // 310 - }); // 311 - self.heartbeat.start(); // 312 - } // 313 - // 314 - Package.facts && Package.facts.Facts.incrementServerFact( // 315 - "livedata", "sessions", 1); // 316 -}; // 317 - // 318 -_.extend(Session.prototype, { // 319 - // 320 - sendReady: function (subscriptionIds) { // 321 - var self = this; // 322 - if (self._isSending) // 323 - self.send({msg: "ready", subs: subscriptionIds}); // 324 - else { // 325 - _.each(subscriptionIds, function (subscriptionId) { // 326 - self._pendingReady.push(subscriptionId); // 327 - }); // 328 - } // 329 - }, // 330 - // 331 - sendAdded: function (collectionName, id, fields) { // 332 - var self = this; // 333 - if (self._isSending) // 334 - self.send({msg: "added", collection: collectionName, id: id, fields: fields}); // 335 - }, // 336 - // 337 - sendChanged: function (collectionName, id, fields) { // 338 - var self = this; // 339 - if (_.isEmpty(fields)) // 340 - return; // 341 - // 342 - if (self._isSending) { // 343 - self.send({ // 344 - msg: "changed", // 345 - collection: collectionName, // 346 - id: id, // 347 - fields: fields // 348 - }); // 349 - } // 350 - }, // 351 - // 352 - sendRemoved: function (collectionName, id) { // 353 - var self = this; // 354 - if (self._isSending) // 355 - self.send({msg: "removed", collection: collectionName, id: id}); // 356 - }, // 357 - // 358 - getSendCallbacks: function () { // 359 - var self = this; // 360 - return { // 361 - added: _.bind(self.sendAdded, self), // 362 - changed: _.bind(self.sendChanged, self), // 363 - removed: _.bind(self.sendRemoved, self) // 364 - }; // 365 - }, // 366 - // 367 - getCollectionView: function (collectionName) { // 368 - var self = this; // 369 - if (_.has(self.collectionViews, collectionName)) { // 370 - return self.collectionViews[collectionName]; // 371 - } // 372 - var ret = new SessionCollectionView(collectionName, // 373 - self.getSendCallbacks()); // 374 - self.collectionViews[collectionName] = ret; // 375 - return ret; // 376 - }, // 377 - // 378 - added: function (subscriptionHandle, collectionName, id, fields) { // 379 - var self = this; // 380 - var view = self.getCollectionView(collectionName); // 381 - view.added(subscriptionHandle, id, fields); // 382 - }, // 383 - // 384 - removed: function (subscriptionHandle, collectionName, id) { // 385 - var self = this; // 386 - var view = self.getCollectionView(collectionName); // 387 - view.removed(subscriptionHandle, id); // 388 - if (view.isEmpty()) { // 389 - delete self.collectionViews[collectionName]; // 390 - } // 391 - }, // 392 - // 393 - changed: function (subscriptionHandle, collectionName, id, fields) { // 394 - var self = this; // 395 - var view = self.getCollectionView(collectionName); // 396 - view.changed(subscriptionHandle, id, fields); // 397 - }, // 398 - // 399 - startUniversalSubs: function () { // 400 - var self = this; // 401 - // Make a shallow copy of the set of universal handlers and start them. If // 402 - // additional universal publishers start while we're running them (due to // 403 - // yielding), they will run separately as part of Server.publish. // 404 - var handlers = _.clone(self.server.universal_publish_handlers); // 405 - _.each(handlers, function (handler) { // 406 - self._startSubscription(handler); // 407 - }); // 408 - }, // 409 - // 410 - // Destroy this session and unregister it at the server. // 411 - close: function () { // 412 - var self = this; // 413 - // 414 - // Destroy this session, even if it's not registered at the // 415 - // server. Stop all processing and tear everything down. If a socket // 416 - // was attached, close it. // 417 - // 418 - // Already destroyed. // 419 - if (! self.inQueue) // 420 - return; // 421 - // 422 - // Drop the merge box data immediately. // 423 - self.inQueue = null; // 424 - self.collectionViews = {}; // 425 - // 426 - if (self.heartbeat) { // 427 - self.heartbeat.stop(); // 428 - self.heartbeat = null; // 429 - } // 430 - // 431 - if (self.socket) { // 432 - self.socket.close(); // 433 - self.socket._meteorSession = null; // 434 - } // 435 - // 436 - Package.facts && Package.facts.Facts.incrementServerFact( // 437 - "livedata", "sessions", -1); // 438 - // 439 - Meteor.defer(function () { // 440 - // stop callbacks can yield, so we defer this on close. // 441 - // sub._isDeactivated() detects that we set inQueue to null and // 442 - // treats it as semi-deactivated (it will ignore incoming callbacks, etc). // 443 - self._deactivateAllSubscriptions(); // 444 - // 445 - // Defer calling the close callbacks, so that the caller closing // 446 - // the session isn't waiting for all the callbacks to complete. // 447 - _.each(self._closeCallbacks, function (callback) { // 448 - callback(); // 449 - }); // 450 - }); // 451 - // 452 - // Unregister the session. // 453 - self.server._removeSession(self); // 454 - }, // 455 - // 456 - // Send a message (doing nothing if no socket is connected right now.) // 457 - // It should be a JSON object (it will be stringified.) // 458 - send: function (msg) { // 459 - var self = this; // 460 - if (self.socket) { // 461 - if (Meteor._printSentDDP) // 462 - Meteor._debug("Sent DDP", stringifyDDP(msg)); // 463 - self.socket.send(stringifyDDP(msg)); // 464 - } // 465 - }, // 466 - // 467 - // Send a connection error. // 468 - sendError: function (reason, offendingMessage) { // 469 - var self = this; // 470 - var msg = {msg: 'error', reason: reason}; // 471 - if (offendingMessage) // 472 - msg.offendingMessage = offendingMessage; // 473 - self.send(msg); // 474 - }, // 475 - // 476 - // Process 'msg' as an incoming message. (But as a guard against // 477 - // race conditions during reconnection, ignore the message if // 478 - // 'socket' is not the currently connected socket.) // 479 - // // 480 - // We run the messages from the client one at a time, in the order // 481 - // given by the client. The message handler is passed an idempotent // 482 - // function 'unblock' which it may call to allow other messages to // 483 - // begin running in parallel in another fiber (for example, a method // 484 - // that wants to yield.) Otherwise, it is automatically unblocked // 485 - // when it returns. // 486 - // // 487 - // Actually, we don't have to 'totally order' the messages in this // 488 - // way, but it's the easiest thing that's correct. (unsub needs to // 489 - // be ordered against sub, methods need to be ordered against each // 490 - // other.) // 491 - processMessage: function (msg_in) { // 492 - var self = this; // 493 - if (!self.inQueue) // we have been destroyed. // 494 - return; // 495 - // 496 - // Respond to ping and pong messages immediately without queuing. // 497 - // If the negotiated DDP version is "pre1" which didn't support // 498 - // pings, preserve the "pre1" behavior of responding with a "bad // 499 - // request" for the unknown messages. // 500 - // // 501 - // Fibers are needed because heartbeat uses Meteor.setTimeout, which // 502 - // needs a Fiber. We could actually use regular setTimeout and avoid // 503 - // these new fibers, but it is easier to just make everything use // 504 - // Meteor.setTimeout and not think too hard. // 505 - if (self.version !== 'pre1' && msg_in.msg === 'ping') { // 506 - if (self._respondToPings) // 507 - self.send({msg: "pong", id: msg_in.id}); // 508 - if (self.heartbeat) // 509 - Fiber(function () { // 510 - self.heartbeat.pingReceived(); // 511 - }).run(); // 512 - return; // 513 - } // 514 - if (self.version !== 'pre1' && msg_in.msg === 'pong') { // 515 - if (self.heartbeat) // 516 - Fiber(function () { // 517 - self.heartbeat.pongReceived(); // 518 - }).run(); // 519 - return; // 520 - } // 521 - // 522 - self.inQueue.push(msg_in); // 523 - if (self.workerRunning) // 524 - return; // 525 - self.workerRunning = true; // 526 - // 527 - var processNext = function () { // 528 - var msg = self.inQueue && self.inQueue.shift(); // 529 - if (!msg) { // 530 - self.workerRunning = false; // 531 - return; // 532 - } // 533 - // 534 - Fiber(function () { // 535 - var blocked = true; // 536 - // 537 - var unblock = function () { // 538 - if (!blocked) // 539 - return; // idempotent // 540 - blocked = false; // 541 - processNext(); // 542 - }; // 543 - // 544 - if (_.has(self.protocol_handlers, msg.msg)) // 545 - self.protocol_handlers[msg.msg].call(self, msg, unblock); // 546 - else // 547 - self.sendError('Bad request', msg); // 548 - unblock(); // in case the handler didn't already do it // 549 - }).run(); // 550 - }; // 551 - // 552 - processNext(); // 553 - }, // 554 - // 555 - protocol_handlers: { // 556 - sub: function (msg) { // 557 - var self = this; // 558 - // 559 - // reject malformed messages // 560 - if (typeof (msg.id) !== "string" || // 561 - typeof (msg.name) !== "string" || // 562 - (('params' in msg) && !(msg.params instanceof Array))) { // 563 - self.sendError("Malformed subscription", msg); // 564 - return; // 565 - } // 566 - // 567 - if (!self.server.publish_handlers[msg.name]) { // 568 - self.send({ // 569 - msg: 'nosub', id: msg.id, // 570 - error: new Meteor.Error(404, "Subscription not found")}); // 571 - return; // 572 - } // 573 - // 574 - if (_.has(self._namedSubs, msg.id)) // 575 - // subs are idempotent, or rather, they are ignored if a sub // 576 - // with that id already exists. this is important during // 577 - // reconnect. // 578 - return; // 579 - // 580 - var handler = self.server.publish_handlers[msg.name]; // 581 - self._startSubscription(handler, msg.id, msg.params, msg.name); // 582 - // 583 - }, // 584 - // 585 - unsub: function (msg) { // 586 - var self = this; // 587 - // 588 - self._stopSubscription(msg.id); // 589 - }, // 590 - // 591 - method: function (msg, unblock) { // 592 - var self = this; // 593 - // 594 - // reject malformed messages // 595 - // For now, we silently ignore unknown attributes, // 596 - // for forwards compatibility. // 597 - if (typeof (msg.id) !== "string" || // 598 - typeof (msg.method) !== "string" || // 599 - (('params' in msg) && !(msg.params instanceof Array)) || // 600 - (('randomSeed' in msg) && (typeof msg.randomSeed !== "string"))) { // 601 - self.sendError("Malformed method invocation", msg); // 602 - return; // 603 - } // 604 - // 605 - var randomSeed = msg.randomSeed || null; // 606 - // 607 - // set up to mark the method as satisfied once all observers // 608 - // (and subscriptions) have reacted to any writes that were // 609 - // done. // 610 - var fence = new DDPServer._WriteFence; // 611 - fence.onAllCommitted(function () { // 612 - // Retire the fence so that future writes are allowed. // 613 - // This means that callbacks like timers are free to use // 614 - // the fence, and if they fire before it's armed (for // 615 - // example, because the method waits for them) their // 616 - // writes will be included in the fence. // 617 - fence.retire(); // 618 - self.send({ // 619 - msg: 'updated', methods: [msg.id]}); // 620 - }); // 621 - // 622 - // find the handler // 623 - var handler = self.server.method_handlers[msg.method]; // 624 - if (!handler) { // 625 - self.send({ // 626 - msg: 'result', id: msg.id, // 627 - error: new Meteor.Error(404, "Method not found")}); // 628 - fence.arm(); // 629 - return; // 630 - } // 631 - // 632 - var setUserId = function(userId) { // 633 - self._setUserId(userId); // 634 - }; // 635 - // 636 - var invocation = new MethodInvocation({ // 637 - isSimulation: false, // 638 - userId: self.userId, // 639 - setUserId: setUserId, // 640 - unblock: unblock, // 641 - connection: self.connectionHandle, // 642 - randomSeed: randomSeed // 643 - }); // 644 - try { // 645 - var result = DDPServer._CurrentWriteFence.withValue(fence, function () { // 646 - return DDP._CurrentInvocation.withValue(invocation, function () { // 647 - return maybeAuditArgumentChecks( // 648 - handler, invocation, msg.params, "call to '" + msg.method + "'"); // 649 - }); // 650 - }); // 651 - } catch (e) { // 652 - var exception = e; // 653 - } // 654 - // 655 - fence.arm(); // we're done adding writes to the fence // 656 - unblock(); // unblock, if the method hasn't done it already // 657 - // 658 - exception = wrapInternalException( // 659 - exception, "while invoking method '" + msg.method + "'"); // 660 - // 661 - // send response and add to cache // 662 - var payload = // 663 - exception ? {error: exception} : (result !== undefined ? // 664 - {result: result} : {}); // 665 - self.send(_.extend({msg: 'result', id: msg.id}, payload)); // 666 - } // 667 - }, // 668 - // 669 - _eachSub: function (f) { // 670 - var self = this; // 671 - _.each(self._namedSubs, f); // 672 - _.each(self._universalSubs, f); // 673 - }, // 674 - // 675 - _diffCollectionViews: function (beforeCVs) { // 676 - var self = this; // 677 - LocalCollection._diffObjects(beforeCVs, self.collectionViews, { // 678 - both: function (collectionName, leftValue, rightValue) { // 679 - rightValue.diff(leftValue); // 680 - }, // 681 - rightOnly: function (collectionName, rightValue) { // 682 - _.each(rightValue.documents, function (docView, id) { // 683 - self.sendAdded(collectionName, id, docView.getFields()); // 684 - }); // 685 - }, // 686 - leftOnly: function (collectionName, leftValue) { // 687 - _.each(leftValue.documents, function (doc, id) { // 688 - self.sendRemoved(collectionName, id); // 689 - }); // 690 - } // 691 - }); // 692 - }, // 693 - // 694 - // Sets the current user id in all appropriate contexts and reruns // 695 - // all subscriptions // 696 - _setUserId: function(userId) { // 697 - var self = this; // 698 - // 699 - if (userId !== null && typeof userId !== "string") // 700 - throw new Error("setUserId must be called on string or null, not " + // 701 - typeof userId); // 702 - // 703 - // Prevent newly-created universal subscriptions from being added to our // 704 - // session; they will be found below when we call startUniversalSubs. // 705 - // // 706 - // (We don't have to worry about named subscriptions, because we only add // 707 - // them when we process a 'sub' message. We are currently processing a // 708 - // 'method' message, and the method did not unblock, because it is illegal // 709 - // to call setUserId after unblock. Thus we cannot be concurrently adding a // 710 - // new named subscription.) // 711 - self._dontStartNewUniversalSubs = true; // 712 - // 713 - // Prevent current subs from updating our collectionViews and call their // 714 - // stop callbacks. This may yield. // 715 - self._eachSub(function (sub) { // 716 - sub._deactivate(); // 717 - }); // 718 - // 719 - // All subs should now be deactivated. Stop sending messages to the client, // 720 - // save the state of the published collections, reset to an empty view, and // 721 - // update the userId. // 722 - self._isSending = false; // 723 - var beforeCVs = self.collectionViews; // 724 - self.collectionViews = {}; // 725 - self.userId = userId; // 726 - // 727 - // Save the old named subs, and reset to having no subscriptions. // 728 - var oldNamedSubs = self._namedSubs; // 729 - self._namedSubs = {}; // 730 - self._universalSubs = []; // 731 - // 732 - _.each(oldNamedSubs, function (sub, subscriptionId) { // 733 - self._namedSubs[subscriptionId] = sub._recreate(); // 734 - // nb: if the handler throws or calls this.error(), it will in fact // 735 - // immediately send its 'nosub'. This is OK, though. // 736 - self._namedSubs[subscriptionId]._runHandler(); // 737 - }); // 738 - // 739 - // Allow newly-created universal subs to be started on our connection in // 740 - // parallel with the ones we're spinning up here, and spin up universal // 741 - // subs. // 742 - self._dontStartNewUniversalSubs = false; // 743 - self.startUniversalSubs(); // 744 - // 745 - // Start sending messages again, beginning with the diff from the previous // 746 - // state of the world to the current state. No yields are allowed during // 747 - // this diff, so that other changes cannot interleave. // 748 - Meteor._noYieldsAllowed(function () { // 749 - self._isSending = true; // 750 - self._diffCollectionViews(beforeCVs); // 751 - if (!_.isEmpty(self._pendingReady)) { // 752 - self.sendReady(self._pendingReady); // 753 - self._pendingReady = []; // 754 - } // 755 - }); // 756 - }, // 757 - // 758 - _startSubscription: function (handler, subId, params, name) { // 759 - var self = this; // 760 - // 761 - var sub = new Subscription( // 762 - self, handler, subId, params, name); // 763 - if (subId) // 764 - self._namedSubs[subId] = sub; // 765 - else // 766 - self._universalSubs.push(sub); // 767 - // 768 - sub._runHandler(); // 769 - }, // 770 - // 771 - // tear down specified subscription // 772 - _stopSubscription: function (subId, error) { // 773 - var self = this; // 774 - // 775 - var subName = null; // 776 - // 777 - if (subId && self._namedSubs[subId]) { // 778 - subName = self._namedSubs[subId]._name; // 779 - self._namedSubs[subId]._removeAllDocuments(); // 780 - self._namedSubs[subId]._deactivate(); // 781 - delete self._namedSubs[subId]; // 782 - } // 783 - // 784 - var response = {msg: 'nosub', id: subId}; // 785 - // 786 - if (error) { // 787 - response.error = wrapInternalException( // 788 - error, // 789 - subName ? ("from sub " + subName + " id " + subId) // 790 - : ("from sub id " + subId)); // 791 - } // 792 - // 793 - self.send(response); // 794 - }, // 795 - // 796 - // tear down all subscriptions. Note that this does NOT send removed or nosub // 797 - // messages, since we assume the client is gone. // 798 - _deactivateAllSubscriptions: function () { // 799 - var self = this; // 800 - // 801 - _.each(self._namedSubs, function (sub, id) { // 802 - sub._deactivate(); // 803 - }); // 804 - self._namedSubs = {}; // 805 - // 806 - _.each(self._universalSubs, function (sub) { // 807 - sub._deactivate(); // 808 - }); // 809 - self._universalSubs = []; // 810 - }, // 811 - // 812 - // Determine the remote client's IP address, based on the // 813 - // HTTP_FORWARDED_COUNT environment variable representing how many // 814 - // proxies the server is behind. // 815 - _clientAddress: function () { // 816 - var self = this; // 817 - // 818 - // For the reported client address for a connection to be correct, // 819 - // the developer must set the HTTP_FORWARDED_COUNT environment // 820 - // variable to an integer representing the number of hops they // 821 - // expect in the `x-forwarded-for` header. E.g., set to "1" if the // 822 - // server is behind one proxy. // 823 - // // 824 - // This could be computed once at startup instead of every time. // 825 - var httpForwardedCount = parseInt(process.env['HTTP_FORWARDED_COUNT']) || 0; // 826 - // 827 - if (httpForwardedCount === 0) // 828 - return self.socket.remoteAddress; // 829 - // 830 - var forwardedFor = self.socket.headers["x-forwarded-for"]; // 831 - if (! _.isString(forwardedFor)) // 832 - return null; // 833 - forwardedFor = forwardedFor.trim().split(/\s*,\s*/); // 834 - // 835 - // Typically the first value in the `x-forwarded-for` header is // 836 - // the original IP address of the client connecting to the first // 837 - // proxy. However, the end user can easily spoof the header, in // 838 - // which case the first value(s) will be the fake IP address from // 839 - // the user pretending to be a proxy reporting the original IP // 840 - // address value. By counting HTTP_FORWARDED_COUNT back from the // 841 - // end of the list, we ensure that we get the IP address being // 842 - // reported by *our* first proxy. // 843 - // 844 - if (httpForwardedCount < 0 || httpForwardedCount > forwardedFor.length) // 845 - return null; // 846 - // 847 - return forwardedFor[forwardedFor.length - httpForwardedCount]; // 848 - } // 849 -}); // 850 - // 851 -/******************************************************************************/ // 852 -/* Subscription */ // 853 -/******************************************************************************/ // 854 - // 855 -// ctor for a sub handle: the input to each publish function // 856 - // 857 -// Instance name is this because it's usually referred to as this inside a // 858 -// publish // 859 -/** // 860 - * @summary The server's side of a subscription // 861 - * @class Subscription // 862 - * @instanceName this // 863 - */ // 864 -var Subscription = function ( // 865 - session, handler, subscriptionId, params, name) { // 866 - var self = this; // 867 - self._session = session; // type is Session // 868 - // 869 - /** // 870 - * @summary Access inside the publish function. The incoming [connection](#meteor_onconnection) for this subscription. - * @locus Server // 872 - * @name connection // 873 - * @memberOf Subscription // 874 - * @instance // 875 - */ // 876 - self.connection = session.connectionHandle; // public API object // 877 - // 878 - self._handler = handler; // 879 - // 880 - // my subscription ID (generated by client, undefined for universal subs). // 881 - self._subscriptionId = subscriptionId; // 882 - // undefined for universal subs // 883 - self._name = name; // 884 - // 885 - self._params = params || []; // 886 - // 887 - // Only named subscriptions have IDs, but we need some sort of string // 888 - // internally to keep track of all subscriptions inside // 889 - // SessionDocumentViews. We use this subscriptionHandle for that. // 890 - if (self._subscriptionId) { // 891 - self._subscriptionHandle = 'N' + self._subscriptionId; // 892 - } else { // 893 - self._subscriptionHandle = 'U' + Random.id(); // 894 - } // 895 - // 896 - // has _deactivate been called? // 897 - self._deactivated = false; // 898 - // 899 - // stop callbacks to g/c this sub. called w/ zero arguments. // 900 - self._stopCallbacks = []; // 901 - // 902 - // the set of (collection, documentid) that this subscription has // 903 - // an opinion about // 904 - self._documents = {}; // 905 - // 906 - // remember if we are ready. // 907 - self._ready = false; // 908 - // 909 - // Part of the public API: the user of this sub. // 910 - // 911 - /** // 912 - * @summary Access inside the publish function. The id of the logged-in user, or `null` if no user is logged in. // 913 - * @locus Server // 914 - * @memberOf Subscription // 915 - * @name userId // 916 - * @instance // 917 - */ // 918 - self.userId = session.userId; // 919 - // 920 - // For now, the id filter is going to default to // 921 - // the to/from DDP methods on LocalCollection, to // 922 - // specifically deal with mongo/minimongo ObjectIds. // 923 - // 924 - // Later, you will be able to make this be "raw" // 925 - // if you want to publish a collection that you know // 926 - // just has strings for keys and no funny business, to // 927 - // a ddp consumer that isn't minimongo // 928 - // 929 - self._idFilter = { // 930 - idStringify: LocalCollection._idStringify, // 931 - idParse: LocalCollection._idParse // 932 - }; // 933 - // 934 - Package.facts && Package.facts.Facts.incrementServerFact( // 935 - "livedata", "subscriptions", 1); // 936 -}; // 937 - // 938 -_.extend(Subscription.prototype, { // 939 - _runHandler: function () { // 940 - // XXX should we unblock() here? Either before running the publish // 941 - // function, or before running _publishCursor. // 942 - // // 943 - // Right now, each publish function blocks all future publishes and // 944 - // methods waiting on data from Mongo (or whatever else the function // 945 - // blocks on). This probably slows page load in common cases. // 946 - // 947 - var self = this; // 948 - try { // 949 - var res = maybeAuditArgumentChecks( // 950 - self._handler, self, EJSON.clone(self._params), // 951 - // It's OK that this would look weird for universal subscriptions, // 952 - // because they have no arguments so there can never be an // 953 - // audit-argument-checks failure. // 954 - "publisher '" + self._name + "'"); // 955 - } catch (e) { // 956 - self.error(e); // 957 - return; // 958 - } // 959 - // 960 - // Did the handler call this.error or this.stop? // 961 - if (self._isDeactivated()) // 962 - return; // 963 - // 964 - // SPECIAL CASE: Instead of writing their own callbacks that invoke // 965 - // this.added/changed/ready/etc, the user can just return a collection // 966 - // cursor or array of cursors from the publish function; we call their // 967 - // _publishCursor method which starts observing the cursor and publishes the // 968 - // results. Note that _publishCursor does NOT call ready(). // 969 - // // 970 - // XXX This uses an undocumented interface which only the Mongo cursor // 971 - // interface publishes. Should we make this interface public and encourage // 972 - // users to implement it themselves? Arguably, it's unnecessary; users can // 973 - // already write their own functions like // 974 - // var publishMyReactiveThingy = function (name, handler) { // 975 - // Meteor.publish(name, function () { // 976 - // var reactiveThingy = handler(); // 977 - // reactiveThingy.publishMe(); // 978 - // }); // 979 - // }; // 980 - var isCursor = function (c) { // 981 - return c && c._publishCursor; // 982 - }; // 983 - if (isCursor(res)) { // 984 - try { // 985 - res._publishCursor(self); // 986 - } catch (e) { // 987 - self.error(e); // 988 - return; // 989 - } // 990 - // _publishCursor only returns after the initial added callbacks have run. // 991 - // mark subscription as ready. // 992 - self.ready(); // 993 - } else if (_.isArray(res)) { // 994 - // check all the elements are cursors // 995 - if (! _.all(res, isCursor)) { // 996 - self.error(new Error("Publish function returned an array of non-Cursors")); // 997 - return; // 998 - } // 999 - // find duplicate collection names // 1000 - // XXX we should support overlapping cursors, but that would require the // 1001 - // merge box to allow overlap within a subscription // 1002 - var collectionNames = {}; // 1003 - for (var i = 0; i < res.length; ++i) { // 1004 - var collectionName = res[i]._getCollectionName(); // 1005 - if (_.has(collectionNames, collectionName)) { // 1006 - self.error(new Error( // 1007 - "Publish function returned multiple cursors for collection " + // 1008 - collectionName)); // 1009 - return; // 1010 - } // 1011 - collectionNames[collectionName] = true; // 1012 - }; // 1013 - // 1014 - try { // 1015 - _.each(res, function (cur) { // 1016 - cur._publishCursor(self); // 1017 - }); // 1018 - } catch (e) { // 1019 - self.error(e); // 1020 - return; // 1021 - } // 1022 - self.ready(); // 1023 - } else if (res) { // 1024 - // truthy values other than cursors or arrays are probably a // 1025 - // user mistake (possible returning a Mongo document via, say, // 1026 - // `coll.findOne()`). // 1027 - self.error(new Error("Publish function can only return a Cursor or " // 1028 - + "an array of Cursors")); // 1029 - } // 1030 - }, // 1031 - // 1032 - // This calls all stop callbacks and prevents the handler from updating any // 1033 - // SessionCollectionViews further. It's used when the user unsubscribes or // 1034 - // disconnects, as well as during setUserId re-runs. It does *NOT* send // 1035 - // removed messages for the published objects; if that is necessary, call // 1036 - // _removeAllDocuments first. // 1037 - _deactivate: function() { // 1038 - var self = this; // 1039 - if (self._deactivated) // 1040 - return; // 1041 - self._deactivated = true; // 1042 - self._callStopCallbacks(); // 1043 - Package.facts && Package.facts.Facts.incrementServerFact( // 1044 - "livedata", "subscriptions", -1); // 1045 - }, // 1046 - // 1047 - _callStopCallbacks: function () { // 1048 - var self = this; // 1049 - // tell listeners, so they can clean up // 1050 - var callbacks = self._stopCallbacks; // 1051 - self._stopCallbacks = []; // 1052 - _.each(callbacks, function (callback) { // 1053 - callback(); // 1054 - }); // 1055 - }, // 1056 - // 1057 - // Send remove messages for every document. // 1058 - _removeAllDocuments: function () { // 1059 - var self = this; // 1060 - Meteor._noYieldsAllowed(function () { // 1061 - _.each(self._documents, function(collectionDocs, collectionName) { // 1062 - // Iterate over _.keys instead of the dictionary itself, since we'll be // 1063 - // mutating it. // 1064 - _.each(_.keys(collectionDocs), function (strId) { // 1065 - self.removed(collectionName, self._idFilter.idParse(strId)); // 1066 - }); // 1067 - }); // 1068 - }); // 1069 - }, // 1070 - // 1071 - // Returns a new Subscription for the same session with the same // 1072 - // initial creation parameters. This isn't a clone: it doesn't have // 1073 - // the same _documents cache, stopped state or callbacks; may have a // 1074 - // different _subscriptionHandle, and gets its userId from the // 1075 - // session, not from this object. // 1076 - _recreate: function () { // 1077 - var self = this; // 1078 - return new Subscription( // 1079 - self._session, self._handler, self._subscriptionId, self._params, // 1080 - self._name); // 1081 - }, // 1082 - // 1083 - /** // 1084 - * @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error). - * @locus Server // 1086 - * @param {Error} error The error to pass to the client. // 1087 - * @instance // 1088 - * @memberOf Subscription // 1089 - */ // 1090 - error: function (error) { // 1091 - var self = this; // 1092 - if (self._isDeactivated()) // 1093 - return; // 1094 - self._session._stopSubscription(self._subscriptionId, error); // 1095 - }, // 1096 - // 1097 - // Note that while our DDP client will notice that you've called stop() on the // 1098 - // server (and clean up its _subscriptions table) we don't actually provide a // 1099 - // mechanism for an app to notice this (the subscribe onError callback only // 1100 - // triggers if there is an error). // 1101 - // 1102 - /** // 1103 - * @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error. - * @locus Server // 1105 - * @instance // 1106 - * @memberOf Subscription // 1107 - */ // 1108 - stop: function () { // 1109 - var self = this; // 1110 - if (self._isDeactivated()) // 1111 - return; // 1112 - self._session._stopSubscription(self._subscriptionId); // 1113 - }, // 1114 - // 1115 - /** // 1116 - * @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped. - * @locus Server // 1118 - * @memberOf Subscription // 1119 - * @instance // 1120 - * @param {Function} func The callback function // 1121 - */ // 1122 - onStop: function (callback) { // 1123 - var self = this; // 1124 - if (self._isDeactivated()) // 1125 - callback(); // 1126 - else // 1127 - self._stopCallbacks.push(callback); // 1128 - }, // 1129 - // 1130 - // This returns true if the sub has been deactivated, *OR* if the session was // 1131 - // destroyed but the deferred call to _deactivateAllSubscriptions hasn't // 1132 - // happened yet. // 1133 - _isDeactivated: function () { // 1134 - var self = this; // 1135 - return self._deactivated || self._session.inQueue === null; // 1136 - }, // 1137 - // 1138 - /** // 1139 - * @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set. - * @locus Server // 1141 - * @memberOf Subscription // 1142 - * @instance // 1143 - * @param {String} collection The name of the collection that contains the new document. // 1144 - * @param {String} id The new document's ID. // 1145 - * @param {Object} fields The fields in the new document. If `_id` is present it is ignored. // 1146 - */ // 1147 - added: function (collectionName, id, fields) { // 1148 - var self = this; // 1149 - if (self._isDeactivated()) // 1150 - return; // 1151 - id = self._idFilter.idStringify(id); // 1152 - Meteor._ensure(self._documents, collectionName)[id] = true; // 1153 - self._session.added(self._subscriptionHandle, collectionName, id, fields); // 1154 - }, // 1155 - // 1156 - /** // 1157 - * @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified. - * @locus Server // 1159 - * @memberOf Subscription // 1160 - * @instance // 1161 - * @param {String} collection The name of the collection that contains the changed document. // 1162 - * @param {String} id The changed document's ID. // 1163 - * @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored. - */ // 1165 - changed: function (collectionName, id, fields) { // 1166 - var self = this; // 1167 - if (self._isDeactivated()) // 1168 - return; // 1169 - id = self._idFilter.idStringify(id); // 1170 - self._session.changed(self._subscriptionHandle, collectionName, id, fields); // 1171 - }, // 1172 - // 1173 - /** // 1174 - * @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set. - * @locus Server // 1176 - * @memberOf Subscription // 1177 - * @instance // 1178 - * @param {String} collection The name of the collection that the document has been removed from. // 1179 - * @param {String} id The ID of the document that has been removed. // 1180 - */ // 1181 - removed: function (collectionName, id) { // 1182 - var self = this; // 1183 - if (self._isDeactivated()) // 1184 - return; // 1185 - id = self._idFilter.idStringify(id); // 1186 - // We don't bother to delete sets of things in a collection if the // 1187 - // collection is empty. It could break _removeAllDocuments. // 1188 - delete self._documents[collectionName][id]; // 1189 - self._session.removed(self._subscriptionHandle, collectionName, id); // 1190 - }, // 1191 - // 1192 - /** // 1193 - * @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. - * @locus Server // 1195 - * @memberOf Subscription // 1196 - * @instance // 1197 - */ // 1198 - ready: function () { // 1199 - var self = this; // 1200 - if (self._isDeactivated()) // 1201 - return; // 1202 - if (!self._subscriptionId) // 1203 - return; // unnecessary but ignored for universal sub // 1204 - if (!self._ready) { // 1205 - self._session.sendReady([self._subscriptionId]); // 1206 - self._ready = true; // 1207 - } // 1208 - } // 1209 -}); // 1210 - // 1211 -/******************************************************************************/ // 1212 -/* Server */ // 1213 -/******************************************************************************/ // 1214 - // 1215 -Server = function (options) { // 1216 - var self = this; // 1217 - // 1218 - // The default heartbeat interval is 30 seconds on the server and 35 // 1219 - // seconds on the client. Since the client doesn't need to send a // 1220 - // ping as long as it is receiving pings, this means that pings // 1221 - // normally go from the server to the client. // 1222 - // // 1223 - // Note: Troposphere depends on the ability to mutate // 1224 - // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life. // 1225 - self.options = _.defaults(options || {}, { // 1226 - heartbeatInterval: 30000, // 1227 - heartbeatTimeout: 15000, // 1228 - // For testing, allow responding to pings to be disabled. // 1229 - respondToPings: true // 1230 - }); // 1231 - // 1232 - // Map of callbacks to call when a new connection comes in to the // 1233 - // server and completes DDP version negotiation. Use an object instead // 1234 - // of an array so we can safely remove one from the list while // 1235 - // iterating over it. // 1236 - self.onConnectionHook = new Hook({ // 1237 - debugPrintExceptions: "onConnection callback" // 1238 - }); // 1239 - // 1240 - self.publish_handlers = {}; // 1241 - self.universal_publish_handlers = []; // 1242 - // 1243 - self.method_handlers = {}; // 1244 - // 1245 - self.sessions = {}; // map from id to session // 1246 - // 1247 - self.stream_server = new StreamServer; // 1248 - // 1249 - self.stream_server.register(function (socket) { // 1250 - // socket implements the SockJSConnection interface // 1251 - socket._meteorSession = null; // 1252 - // 1253 - var sendError = function (reason, offendingMessage) { // 1254 - var msg = {msg: 'error', reason: reason}; // 1255 - if (offendingMessage) // 1256 - msg.offendingMessage = offendingMessage; // 1257 - socket.send(stringifyDDP(msg)); // 1258 - }; // 1259 - // 1260 - socket.on('data', function (raw_msg) { // 1261 - if (Meteor._printReceivedDDP) { // 1262 - Meteor._debug("Received DDP", raw_msg); // 1263 - } // 1264 - try { // 1265 - try { // 1266 - var msg = parseDDP(raw_msg); // 1267 - } catch (err) { // 1268 - sendError('Parse error'); // 1269 - return; // 1270 - } // 1271 - if (msg === null || !msg.msg) { // 1272 - sendError('Bad request', msg); // 1273 - return; // 1274 - } // 1275 - // 1276 - if (msg.msg === 'connect') { // 1277 - if (socket._meteorSession) { // 1278 - sendError("Already connected", msg); // 1279 - return; // 1280 - } // 1281 - Fiber(function () { // 1282 - self._handleConnect(socket, msg); // 1283 - }).run(); // 1284 - return; // 1285 - } // 1286 - // 1287 - if (!socket._meteorSession) { // 1288 - sendError('Must connect first', msg); // 1289 - return; // 1290 - } // 1291 - socket._meteorSession.processMessage(msg); // 1292 - } catch (e) { // 1293 - // XXX print stack nicely // 1294 - Meteor._debug("Internal exception while processing message", msg, // 1295 - e.message, e.stack); // 1296 - } // 1297 - }); // 1298 - // 1299 - socket.on('close', function () { // 1300 - if (socket._meteorSession) { // 1301 - Fiber(function () { // 1302 - socket._meteorSession.close(); // 1303 - }).run(); // 1304 - } // 1305 - }); // 1306 - }); // 1307 -}; // 1308 - // 1309 -_.extend(Server.prototype, { // 1310 - // 1311 - /** // 1312 - * @summary Register a callback to be called when a new DDP connection is made to the server. // 1313 - * @locus Server // 1314 - * @param {function} callback The function to call when a new DDP connection is established. // 1315 - * @memberOf Meteor // 1316 - */ // 1317 - onConnection: function (fn) { // 1318 - var self = this; // 1319 - return self.onConnectionHook.register(fn); // 1320 - }, // 1321 - // 1322 - _handleConnect: function (socket, msg) { // 1323 - var self = this; // 1324 - // 1325 - // The connect message must specify a version and an array of supported // 1326 - // versions, and it must claim to support what it is proposing. // 1327 - if (!(typeof (msg.version) === 'string' && // 1328 - _.isArray(msg.support) && // 1329 - _.all(msg.support, _.isString) && // 1330 - _.contains(msg.support, msg.version))) { // 1331 - socket.send(stringifyDDP({msg: 'failed', // 1332 - version: SUPPORTED_DDP_VERSIONS[0]})); // 1333 - socket.close(); // 1334 - return; // 1335 - } // 1336 - // 1337 - // In the future, handle session resumption: something like: // 1338 - // socket._meteorSession = self.sessions[msg.session] // 1339 - var version = calculateVersion(msg.support, SUPPORTED_DDP_VERSIONS); // 1340 - // 1341 - if (msg.version !== version) { // 1342 - // The best version to use (according to the client's stated preferences) // 1343 - // is not the one the client is trying to use. Inform them about the best // 1344 - // version to use. // 1345 - socket.send(stringifyDDP({msg: 'failed', version: version})); // 1346 - socket.close(); // 1347 - return; // 1348 - } // 1349 - // 1350 - // Yay, version matches! Create a new session. // 1351 - // Note: Troposphere depends on the ability to mutate // 1352 - // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life. // 1353 - socket._meteorSession = new Session(self, version, socket, self.options); // 1354 - self.sessions[socket._meteorSession.id] = socket._meteorSession; // 1355 - self.onConnectionHook.each(function (callback) { // 1356 - if (socket._meteorSession) // 1357 - callback(socket._meteorSession.connectionHandle); // 1358 - return true; // 1359 - }); // 1360 - }, // 1361 - /** // 1362 - * Register a publish handler function. // 1363 - * // 1364 - * @param name {String} identifier for query // 1365 - * @param handler {Function} publish handler // 1366 - * @param options {Object} // 1367 - * // 1368 - * Server will call handler function on each new subscription, // 1369 - * either when receiving DDP sub message for a named subscription, or on // 1370 - * DDP connect for a universal subscription. // 1371 - * // 1372 - * If name is null, this will be a subscription that is // 1373 - * automatically established and permanently on for all connected // 1374 - * client, instead of a subscription that can be turned on and off // 1375 - * with subscribe(). // 1376 - * // 1377 - * options to contain: // 1378 - * - (mostly internal) is_auto: true if generated automatically // 1379 - * from an autopublish hook. this is for cosmetic purposes only // 1380 - * (it lets us determine whether to print a warning suggesting // 1381 - * that you turn off autopublish.) // 1382 - */ // 1383 - // 1384 - /** // 1385 - * @summary Publish a record set. // 1386 - * @memberOf Meteor // 1387 - * @locus Server // 1388 - * @param {String} name Name of the record set. If `null`, the set has no name, and the record set is automatically sent to all connected clients. - * @param {Function} func Function called on the server each time a client subscribes. Inside the function, `this` is the publish handler object, described below. If the client passed arguments to `subscribe`, the function is called with the same arguments. - */ // 1391 - publish: function (name, handler, options) { // 1392 - var self = this; // 1393 - // 1394 - options = options || {}; // 1395 - // 1396 - if (name && name in self.publish_handlers) { // 1397 - Meteor._debug("Ignoring duplicate publish named '" + name + "'"); // 1398 - return; // 1399 - } // 1400 - // 1401 - if (Package.autopublish && !options.is_auto) { // 1402 - // They have autopublish on, yet they're trying to manually // 1403 - // picking stuff to publish. They probably should turn off // 1404 - // autopublish. (This check isn't perfect -- if you create a // 1405 - // publish before you turn on autopublish, it won't catch // 1406 - // it. But this will definitely handle the simple case where // 1407 - // you've added the autopublish package to your app, and are // 1408 - // calling publish from your app code.) // 1409 - if (!self.warned_about_autopublish) { // 1410 - self.warned_about_autopublish = true; // 1411 - Meteor._debug( // 1412 -"** You've set up some data subscriptions with Meteor.publish(), but\n" + // 1413 -"** you still have autopublish turned on. Because autopublish is still\n" + // 1414 -"** on, your Meteor.publish() calls won't have much effect. All data\n" + // 1415 -"** will still be sent to all clients.\n" + // 1416 -"**\n" + // 1417 -"** Turn off autopublish by removing the autopublish package:\n" + // 1418 -"**\n" + // 1419 -"** $ meteor remove autopublish\n" + // 1420 -"**\n" + // 1421 -"** .. and make sure you have Meteor.publish() and Meteor.subscribe() calls\n" + // 1422 -"** for each collection that you want clients to see.\n"); // 1423 - } // 1424 - } // 1425 - // 1426 - if (name) // 1427 - self.publish_handlers[name] = handler; // 1428 - else { // 1429 - self.universal_publish_handlers.push(handler); // 1430 - // Spin up the new publisher on any existing session too. Run each // 1431 - // session's subscription in a new Fiber, so that there's no change for // 1432 - // self.sessions to change while we're running this loop. // 1433 - _.each(self.sessions, function (session) { // 1434 - if (!session._dontStartNewUniversalSubs) { // 1435 - Fiber(function() { // 1436 - session._startSubscription(handler); // 1437 - }).run(); // 1438 - } // 1439 - }); // 1440 - } // 1441 - }, // 1442 - // 1443 - _removeSession: function (session) { // 1444 - var self = this; // 1445 - if (self.sessions[session.id]) { // 1446 - delete self.sessions[session.id]; // 1447 - } // 1448 - }, // 1449 - // 1450 - /** // 1451 - * @summary Defines functions that can be invoked over the network by clients. // 1452 - * @locus Anywhere // 1453 - * @param {Object} methods Dictionary whose keys are method names and values are functions. // 1454 - * @memberOf Meteor // 1455 - */ // 1456 - methods: function (methods) { // 1457 - var self = this; // 1458 - _.each(methods, function (func, name) { // 1459 - if (self.method_handlers[name]) // 1460 - throw new Error("A method named '" + name + "' is already defined"); // 1461 - self.method_handlers[name] = func; // 1462 - }); // 1463 - }, // 1464 - // 1465 - call: function (name /*, arguments */) { // 1466 - // if it's a function, the last argument is the result callback, // 1467 - // not a parameter to the remote method. // 1468 - var args = Array.prototype.slice.call(arguments, 1); // 1469 - if (args.length && typeof args[args.length - 1] === "function") // 1470 - var callback = args.pop(); // 1471 - return this.apply(name, args, callback); // 1472 - }, // 1473 - // 1474 - // @param options {Optional Object} // 1475 - // @param callback {Optional Function} // 1476 - apply: function (name, args, options, callback) { // 1477 - var self = this; // 1478 - // 1479 - // We were passed 3 arguments. They may be either (name, args, options) // 1480 - // or (name, args, callback) // 1481 - if (!callback && typeof options === 'function') { // 1482 - callback = options; // 1483 - options = {}; // 1484 - } // 1485 - options = options || {}; // 1486 - // 1487 - if (callback) // 1488 - // It's not really necessary to do this, since we immediately // 1489 - // run the callback in this fiber before returning, but we do it // 1490 - // anyway for regularity. // 1491 - // XXX improve error message (and how we report it) // 1492 - callback = Meteor.bindEnvironment( // 1493 - callback, // 1494 - "delivering result of invoking '" + name + "'" // 1495 - ); // 1496 - // 1497 - // Run the handler // 1498 - var handler = self.method_handlers[name]; // 1499 - var exception; // 1500 - if (!handler) { // 1501 - exception = new Meteor.Error(404, "Method not found"); // 1502 - } else { // 1503 - // If this is a method call from within another method, get the // 1504 - // user state from the outer method, otherwise don't allow // 1505 - // setUserId to be called // 1506 - var userId = null; // 1507 - var setUserId = function() { // 1508 - throw new Error("Can't call setUserId on a server initiated method call"); // 1509 - }; // 1510 - var connection = null; // 1511 - var currentInvocation = DDP._CurrentInvocation.get(); // 1512 - if (currentInvocation) { // 1513 - userId = currentInvocation.userId; // 1514 - setUserId = function(userId) { // 1515 - currentInvocation.setUserId(userId); // 1516 - }; // 1517 - connection = currentInvocation.connection; // 1518 - } // 1519 - // 1520 - var invocation = new MethodInvocation({ // 1521 - isSimulation: false, // 1522 - userId: userId, // 1523 - setUserId: setUserId, // 1524 - connection: connection, // 1525 - randomSeed: makeRpcSeed(currentInvocation, name) // 1526 - }); // 1527 - try { // 1528 - var result = DDP._CurrentInvocation.withValue(invocation, function () { // 1529 - return maybeAuditArgumentChecks( // 1530 - handler, invocation, EJSON.clone(args), "internal call to '" + // 1531 - name + "'"); // 1532 - }); // 1533 - result = EJSON.clone(result); // 1534 - } catch (e) { // 1535 - exception = e; // 1536 - } // 1537 - } // 1538 - // 1539 - // Return the result in whichever way the caller asked for it. Note that we // 1540 - // do NOT block on the write fence in an analogous way to how the client // 1541 - // blocks on the relevant data being visible, so you are NOT guaranteed that // 1542 - // cursor observe callbacks have fired when your callback is invoked. (We // 1543 - // can change this if there's a real use case.) // 1544 - if (callback) { // 1545 - callback(exception, result); // 1546 - return undefined; // 1547 - } // 1548 - if (exception) // 1549 - throw exception; // 1550 - return result; // 1551 - }, // 1552 - // 1553 - _urlForSession: function (sessionId) { // 1554 - var self = this; // 1555 - var session = self.sessions[sessionId]; // 1556 - if (session) // 1557 - return session._socketUrl; // 1558 - else // 1559 - return null; // 1560 - } // 1561 -}); // 1562 - // 1563 -var calculateVersion = function (clientSupportedVersions, // 1564 - serverSupportedVersions) { // 1565 - var correctVersion = _.find(clientSupportedVersions, function (version) { // 1566 - return _.contains(serverSupportedVersions, version); // 1567 - }); // 1568 - if (!correctVersion) { // 1569 - correctVersion = serverSupportedVersions[0]; // 1570 - } // 1571 - return correctVersion; // 1572 -}; // 1573 - // 1574 -LivedataTest.calculateVersion = calculateVersion; // 1575 - // 1576 - // 1577 -// "blind" exceptions other than those that were deliberately thrown to signal // 1578 -// errors to the client // 1579 -var wrapInternalException = function (exception, context) { // 1580 - if (!exception || exception instanceof Meteor.Error) // 1581 - return exception; // 1582 - // 1583 - // tests can set the 'expected' flag on an exception so it won't go to the // 1584 - // server log // 1585 - if (!exception.expected) { // 1586 - Meteor._debug("Exception " + context, exception.stack); // 1587 - if (exception.sanitizedError) { // 1588 - Meteor._debug("Sanitized and reported to the client as:", exception.sanitizedError.message); // 1589 - Meteor._debug(); // 1590 - } // 1591 - } // 1592 - // 1593 - // Did the error contain more details that could have been useful if caught in // 1594 - // server code (or if thrown from non-client-originated code), but also // 1595 - // provided a "sanitized" version with more context than 500 Internal server // 1596 - // error? Use that. // 1597 - if (exception.sanitizedError) { // 1598 - if (exception.sanitizedError instanceof Meteor.Error) // 1599 - return exception.sanitizedError; // 1600 - Meteor._debug("Exception " + context + " provides a sanitizedError that " + // 1601 - "is not a Meteor.Error; ignoring"); // 1602 - } // 1603 - // 1604 - return new Meteor.Error(500, "Internal server error"); // 1605 -}; // 1606 - // 1607 - // 1608 -// Audit argument checks, if the audit-argument-checks package exists (it is a // 1609 -// weak dependency of this package). // 1610 -var maybeAuditArgumentChecks = function (f, context, args, description) { // 1611 - args = args || []; // 1612 - if (Package['audit-argument-checks']) { // 1613 - return Match._failIfArgumentsAreNotAllChecked( // 1614 - f, context, args, description); // 1615 - } // 1616 - return f.apply(context, args); // 1617 -}; // 1618 - // 1619 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/writefence.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var path = Npm.require('path'); // 1 -var Future = Npm.require(path.join('fibers', 'future')); // 2 - // 3 -// A write fence collects a group of writes, and provides a callback // 4 -// when all of the writes are fully committed and propagated (all // 5 -// observers have been notified of the write and acknowledged it.) // 6 -// // 7 -DDPServer._WriteFence = function () { // 8 - var self = this; // 9 - // 10 - self.armed = false; // 11 - self.fired = false; // 12 - self.retired = false; // 13 - self.outstanding_writes = 0; // 14 - self.completion_callbacks = []; // 15 -}; // 16 - // 17 -// The current write fence. When there is a current write fence, code // 18 -// that writes to databases should register their writes with it using // 19 -// beginWrite(). // 20 -// // 21 -DDPServer._CurrentWriteFence = new Meteor.EnvironmentVariable; // 22 - // 23 -_.extend(DDPServer._WriteFence.prototype, { // 24 - // Start tracking a write, and return an object to represent it. The // 25 - // object has a single method, committed(). This method should be // 26 - // called when the write is fully committed and propagated. You can // 27 - // continue to add writes to the WriteFence up until it is triggered // 28 - // (calls its callbacks because all writes have committed.) // 29 - beginWrite: function () { // 30 - var self = this; // 31 - // 32 - if (self.retired) // 33 - return { committed: function () {} }; // 34 - // 35 - if (self.fired) // 36 - throw new Error("fence has already activated -- too late to add writes"); // 37 - // 38 - self.outstanding_writes++; // 39 - var committed = false; // 40 - return { // 41 - committed: function () { // 42 - if (committed) // 43 - throw new Error("committed called twice on the same write"); // 44 - committed = true; // 45 - self.outstanding_writes--; // 46 - self._maybeFire(); // 47 - } // 48 - }; // 49 - }, // 50 - // 51 - // Arm the fence. Once the fence is armed, and there are no more // 52 - // uncommitted writes, it will activate. // 53 - arm: function () { // 54 - var self = this; // 55 - if (self === DDPServer._CurrentWriteFence.get()) // 56 - throw Error("Can't arm the current fence"); // 57 - self.armed = true; // 58 - self._maybeFire(); // 59 - }, // 60 - // 61 - // Register a function to be called when the fence fires. // 62 - onAllCommitted: function (func) { // 63 - var self = this; // 64 - if (self.fired) // 65 - throw new Error("fence has already activated -- too late to " + // 66 - "add a callback"); // 67 - self.completion_callbacks.push(func); // 68 - }, // 69 - // 70 - // Convenience function. Arms the fence, then blocks until it fires. // 71 - armAndWait: function () { // 72 - var self = this; // 73 - var future = new Future; // 74 - self.onAllCommitted(function () { // 75 - future['return'](); // 76 - }); // 77 - self.arm(); // 78 - future.wait(); // 79 - }, // 80 - // 81 - _maybeFire: function () { // 82 - var self = this; // 83 - if (self.fired) // 84 - throw new Error("write fence already activated?"); // 85 - if (self.armed && !self.outstanding_writes) { // 86 - self.fired = true; // 87 - _.each(self.completion_callbacks, function (f) {f(self);}); // 88 - self.completion_callbacks = []; // 89 - } // 90 - }, // 91 - // 92 - // Deactivate this fence so that adding more writes has no effect. // 93 - // The fence must have already fired. // 94 - retire: function () { // 95 - var self = this; // 96 - if (! self.fired) // 97 - throw new Error("Can't retire a fence that hasn't fired."); // 98 - self.retired = true; // 99 - } // 100 -}); // 101 - // 102 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/crossbar.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// A "crossbar" is a class that provides structured notification registration. // 1 -// See _match for the definition of how a notification matches a trigger. // 2 -// All notifications and triggers must have a string key named 'collection'. // 3 - // 4 -DDPServer._Crossbar = function (options) { // 5 - var self = this; // 6 - options = options || {}; // 7 - // 8 - self.nextId = 1; // 9 - // map from collection name (string) -> listener id -> object. each object has // 10 - // keys 'trigger', 'callback'. // 11 - self.listenersByCollection = {}; // 12 - self.factPackage = options.factPackage || "livedata"; // 13 - self.factName = options.factName || null; // 14 -}; // 15 - // 16 -_.extend(DDPServer._Crossbar.prototype, { // 17 - // Listen for notification that match 'trigger'. A notification // 18 - // matches if it has the key-value pairs in trigger as a // 19 - // subset. When a notification matches, call 'callback', passing // 20 - // the actual notification. // 21 - // // 22 - // Returns a listen handle, which is an object with a method // 23 - // stop(). Call stop() to stop listening. // 24 - // // 25 - // XXX It should be legal to call fire() from inside a listen() // 26 - // callback? // 27 - listen: function (trigger, callback) { // 28 - var self = this; // 29 - var id = self.nextId++; // 30 - // 31 - if (typeof(trigger.collection) !== 'string') { // 32 - throw Error("Trigger lacks collection!"); // 33 - } // 34 - // 35 - var collection = trigger.collection; // save in case trigger is mutated // 36 - var record = {trigger: EJSON.clone(trigger), callback: callback}; // 37 - if (! _.has(self.listenersByCollection, collection)) { // 38 - self.listenersByCollection[collection] = {}; // 39 - } // 40 - self.listenersByCollection[collection][id] = record; // 41 - // 42 - if (self.factName && Package.facts) { // 43 - Package.facts.Facts.incrementServerFact( // 44 - self.factPackage, self.factName, 1); // 45 - } // 46 - // 47 - return { // 48 - stop: function () { // 49 - if (self.factName && Package.facts) { // 50 - Package.facts.Facts.incrementServerFact( // 51 - self.factPackage, self.factName, -1); // 52 - } // 53 - delete self.listenersByCollection[collection][id]; // 54 - if (_.isEmpty(self.listenersByCollection[collection])) { // 55 - delete self.listenersByCollection[collection]; // 56 - } // 57 - } // 58 - }; // 59 - }, // 60 - // 61 - // Fire the provided 'notification' (an object whose attribute // 62 - // values are all JSON-compatibile) -- inform all matching listeners // 63 - // (registered with listen()). // 64 - // // 65 - // If fire() is called inside a write fence, then each of the // 66 - // listener callbacks will be called inside the write fence as well. // 67 - // // 68 - // The listeners may be invoked in parallel, rather than serially. // 69 - fire: function (notification) { // 70 - var self = this; // 71 - // 72 - if (typeof(notification.collection) !== 'string') { // 73 - throw Error("Notification lacks collection!"); // 74 - } // 75 - // 76 - if (! _.has(self.listenersByCollection, notification.collection)) // 77 - return; // 78 - // 79 - var listenersForCollection = // 80 - self.listenersByCollection[notification.collection]; // 81 - var callbackIds = []; // 82 - _.each(listenersForCollection, function (l, id) { // 83 - if (self._matches(notification, l.trigger)) { // 84 - callbackIds.push(id); // 85 - } // 86 - }); // 87 - // 88 - // Listener callbacks can yield, so we need to first find all the ones that // 89 - // match in a single iteration over self.listenersByCollection (which can't // 90 - // be mutated during this iteration), and then invoke the matching // 91 - // callbacks, checking before each call to ensure they haven't stopped. // 92 - // Note that we don't have to check that // 93 - // self.listenersByCollection[notification.collection] still === // 94 - // listenersForCollection, because the only way that stops being true is if // 95 - // listenersForCollection first gets reduced down to the empty object (and // 96 - // then never gets increased again). // 97 - _.each(callbackIds, function (id) { // 98 - if (_.has(listenersForCollection, id)) { // 99 - listenersForCollection[id].callback(notification); // 100 - } // 101 - }); // 102 - }, // 103 - // 104 - // A notification matches a trigger if all keys that exist in both are equal. // 105 - // // 106 - // Examples: // 107 - // N:{collection: "C"} matches T:{collection: "C"} // 108 - // (a non-targeted write to a collection matches a // 109 - // non-targeted query) // 110 - // N:{collection: "C", id: "X"} matches T:{collection: "C"} // 111 - // (a targeted write to a collection matches a non-targeted query) // 112 - // N:{collection: "C"} matches T:{collection: "C", id: "X"} // 113 - // (a non-targeted write to a collection matches a // 114 - // targeted query) // 115 - // N:{collection: "C", id: "X"} matches T:{collection: "C", id: "X"} // 116 - // (a targeted write to a collection matches a targeted query targeted // 117 - // at the same document) // 118 - // N:{collection: "C", id: "X"} does not match T:{collection: "C", id: "Y"} // 119 - // (a targeted write to a collection does not match a targeted query // 120 - // targeted at a different document) // 121 - _matches: function (notification, trigger) { // 122 - // Most notifications that use the crossbar have a string `collection` and // 123 - // maybe an `id` that is a string or ObjectID. We're already dividing up // 124 - // triggers by collection, but let's fast-track "nope, different ID" (and // 125 - // avoid the overly generic EJSON.equals). This makes a noticeable // 126 - // performance difference; see https://github.com/meteor/meteor/pull/3697 // 127 - if (typeof(notification.id) === 'string' && // 128 - typeof(trigger.id) === 'string' && // 129 - notification.id !== trigger.id) { // 130 - return false; // 131 - } // 132 - if (notification.id instanceof LocalCollection._ObjectID && // 133 - trigger.id instanceof LocalCollection._ObjectID && // 134 - ! notification.id.equals(trigger.id)) { // 135 - return false; // 136 - } // 137 - // 138 - return _.all(trigger, function (triggerValue, key) { // 139 - return !_.has(notification, key) || // 140 - EJSON.equals(triggerValue, notification[key]); // 141 - }); // 142 - } // 143 -}); // 144 - // 145 -// The "invalidation crossbar" is a specific instance used by the DDP server to // 146 -// implement write fence notifications. Listener callbacks on this crossbar // 147 -// should call beginWrite on the current write fence before they return, if they // 148 -// want to delay the write fence from firing (ie, the DDP method-data-updated // 149 -// message from being sent). // 150 -DDPServer._InvalidationCrossbar = new DDPServer._Crossbar({ // 151 - factName: "invalidation-crossbar-listeners" // 152 -}); // 153 - // 154 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/livedata_common.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// All the supported versions (for both the client and server) // 1 -// These must be in order of preference; most favored-first // 2 -SUPPORTED_DDP_VERSIONS = [ '1', 'pre2', 'pre1' ]; // 3 - // 4 -LivedataTest.SUPPORTED_DDP_VERSIONS = SUPPORTED_DDP_VERSIONS; // 5 - // 6 -// Instance name is this because it is usually referred to as this inside a // 7 -// method definition // 8 -/** // 9 - * @summary The state for a single invocation of a method, referenced by this // 10 - * inside a method definition. // 11 - * @param {Object} options // 12 - * @instanceName this // 13 - */ // 14 -MethodInvocation = function (options) { // 15 - var self = this; // 16 - // 17 - // true if we're running not the actual method, but a stub (that is, // 18 - // if we're on a client (which may be a browser, or in the future a // 19 - // server connecting to another server) and presently running a // 20 - // simulation of a server-side method for latency compensation // 21 - // purposes). not currently true except in a client such as a browser, // 22 - // since there's usually no point in running stubs unless you have a // 23 - // zero-latency connection to the user. // 24 - // 25 - /** // 26 - * @summary Access inside a method invocation. Boolean value, true if this invocation is a stub. // 27 - * @locus Anywhere // 28 - * @name isSimulation // 29 - * @memberOf MethodInvocation // 30 - * @instance // 31 - * @type {Boolean} // 32 - */ // 33 - this.isSimulation = options.isSimulation; // 34 - // 35 - // call this function to allow other method invocations (from the // 36 - // same client) to continue running without waiting for this one to // 37 - // complete. // 38 - this._unblock = options.unblock || function () {}; // 39 - this._calledUnblock = false; // 40 - // 41 - // current user id // 42 - // 43 - /** // 44 - * @summary The id of the user that made this method call, or `null` if no user was logged in. // 45 - * @locus Anywhere // 46 - * @name userId // 47 - * @memberOf MethodInvocation // 48 - * @instance // 49 - */ // 50 - this.userId = options.userId; // 51 - // 52 - // sets current user id in all appropriate server contexts and // 53 - // reruns subscriptions // 54 - this._setUserId = options.setUserId || function () {}; // 55 - // 56 - // On the server, the connection this method call came in on. // 57 - // 58 - /** // 59 - * @summary Access inside a method invocation. The [connection](#meteor_onconnection) that this method was received on. `null` if the method is not associated with a connection, eg. a server initiated method call. - * @locus Server // 61 - * @name connection // 62 - * @memberOf MethodInvocation // 63 - * @instance // 64 - */ // 65 - this.connection = options.connection; // 66 - // 67 - // The seed for randomStream value generation // 68 - this.randomSeed = options.randomSeed; // 69 - // 70 - // This is set by RandomStream.get; and holds the random stream state // 71 - this.randomStream = null; // 72 -}; // 73 - // 74 -_.extend(MethodInvocation.prototype, { // 75 - /** // 76 - * @summary Call inside a method invocation. Allow subsequent method from this client to begin running in a new fiber. - * @locus Server // 78 - * @memberOf MethodInvocation // 79 - * @instance // 80 - */ // 81 - unblock: function () { // 82 - var self = this; // 83 - self._calledUnblock = true; // 84 - self._unblock(); // 85 - }, // 86 - // 87 - /** // 88 - * @summary Set the logged in user. // 89 - * @locus Server // 90 - * @memberOf MethodInvocation // 91 - * @instance // 92 - * @param {String | null} userId The value that should be returned by `userId` on this connection. // 93 - */ // 94 - setUserId: function(userId) { // 95 - var self = this; // 96 - if (self._calledUnblock) // 97 - throw new Error("Can't call setUserId in a method after calling unblock"); // 98 - self.userId = userId; // 99 - self._setUserId(userId); // 100 - } // 101 -}); // 102 - // 103 -parseDDP = function (stringMessage) { // 104 - try { // 105 - var msg = JSON.parse(stringMessage); // 106 - } catch (e) { // 107 - Meteor._debug("Discarding message with invalid JSON", stringMessage); // 108 - return null; // 109 - } // 110 - // DDP messages must be objects. // 111 - if (msg === null || typeof msg !== 'object') { // 112 - Meteor._debug("Discarding non-object DDP message", stringMessage); // 113 - return null; // 114 - } // 115 - // 116 - // massage msg to get it into "abstract ddp" rather than "wire ddp" format. // 117 - // 118 - // switch between "cleared" rep of unsetting fields and "undefined" // 119 - // rep of same // 120 - if (_.has(msg, 'cleared')) { // 121 - if (!_.has(msg, 'fields')) // 122 - msg.fields = {}; // 123 - _.each(msg.cleared, function (clearKey) { // 124 - msg.fields[clearKey] = undefined; // 125 - }); // 126 - delete msg.cleared; // 127 - } // 128 - // 129 - _.each(['fields', 'params', 'result'], function (field) { // 130 - if (_.has(msg, field)) // 131 - msg[field] = EJSON._adjustTypesFromJSONValue(msg[field]); // 132 - }); // 133 - // 134 - return msg; // 135 -}; // 136 - // 137 -stringifyDDP = function (msg) { // 138 - var copy = EJSON.clone(msg); // 139 - // swizzle 'changed' messages from 'fields undefined' rep to 'fields // 140 - // and cleared' rep // 141 - if (_.has(msg, 'fields')) { // 142 - var cleared = []; // 143 - _.each(msg.fields, function (value, key) { // 144 - if (value === undefined) { // 145 - cleared.push(key); // 146 - delete copy.fields[key]; // 147 - } // 148 - }); // 149 - if (!_.isEmpty(cleared)) // 150 - copy.cleared = cleared; // 151 - if (_.isEmpty(copy.fields)) // 152 - delete copy.fields; // 153 - } // 154 - // adjust types to basic // 155 - _.each(['fields', 'params', 'result'], function (field) { // 156 - if (_.has(copy, field)) // 157 - copy[field] = EJSON._adjustTypesToJSONValue(copy[field]); // 158 - }); // 159 - if (msg.id && typeof msg.id !== 'string') { // 160 - throw new Error("Message id is not a string"); // 161 - } // 162 - return JSON.stringify(copy); // 163 -}; // 164 - // 165 -// This is private but it's used in a few places. accounts-base uses // 166 -// it to get the current user. accounts-password uses it to stash SRP // 167 -// state in the DDP session. Meteor.setTimeout and friends clear // 168 -// it. We can probably find a better way to factor this. // 169 -DDP._CurrentInvocation = new Meteor.EnvironmentVariable; // 170 - // 171 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/random_stream.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// RandomStream allows for generation of pseudo-random values, from a seed. // 1 -// // 2 -// We use this for consistent 'random' numbers across the client and server. // 3 -// We want to generate probably-unique IDs on the client, and we ideally want // 4 -// the server to generate the same IDs when it executes the method. // 5 -// // 6 -// For generated values to be the same, we must seed ourselves the same way, // 7 -// and we must keep track of the current state of our pseudo-random generators. // 8 -// We call this state the scope. By default, we use the current DDP method // 9 -// invocation as our scope. DDP now allows the client to specify a randomSeed. // 10 -// If a randomSeed is provided it will be used to seed our random sequences. // 11 -// In this way, client and server method calls will generate the same values. // 12 -// // 13 -// We expose multiple named streams; each stream is independent // 14 -// and is seeded differently (but predictably from the name). // 15 -// By using multiple streams, we support reordering of requests, // 16 -// as long as they occur on different streams. // 17 -// // 18 -// @param options {Optional Object} // 19 -// seed: Array or value - Seed value(s) for the generator. // 20 -// If an array, will be used as-is // 21 -// If a value, will be converted to a single-value array // 22 -// If omitted, a random array will be used as the seed. // 23 -RandomStream = function (options) { // 24 - var self = this; // 25 - // 26 - this.seed = [].concat(options.seed || randomToken()); // 27 - // 28 - this.sequences = {}; // 29 -}; // 30 - // 31 -// Returns a random string of sufficient length for a random seed. // 32 -// This is a placeholder function; a similar function is planned // 33 -// for Random itself; when that is added we should remove this function, // 34 -// and call Random's randomToken instead. // 35 -function randomToken() { // 36 - return Random.hexString(20); // 37 -}; // 38 - // 39 -// Returns the random stream with the specified name, in the specified scope. // 40 -// If scope is null (or otherwise falsey) then we will use Random, which will // 41 -// give us as random numbers as possible, but won't produce the same // 42 -// values across client and server. // 43 -// However, scope will normally be the current DDP method invocation, so // 44 -// we'll use the stream with the specified name, and we should get consistent // 45 -// values on the client and server sides of a method call. // 46 -RandomStream.get = function (scope, name) { // 47 - if (!name) { // 48 - name = "default"; // 49 - } // 50 - if (!scope) { // 51 - // There was no scope passed in; // 52 - // the sequence won't actually be reproducible. // 53 - return Random; // 54 - } // 55 - var randomStream = scope.randomStream; // 56 - if (!randomStream) { // 57 - scope.randomStream = randomStream = new RandomStream({ // 58 - seed: scope.randomSeed // 59 - }); // 60 - } // 61 - return randomStream._sequence(name); // 62 -}; // 63 - // 64 -// Returns the named sequence of pseudo-random values. // 65 -// The scope will be DDP._CurrentInvocation.get(), so the stream will produce // 66 -// consistent values for method calls on the client and server. // 67 -DDP.randomStream = function (name) { // 68 - var scope = DDP._CurrentInvocation.get(); // 69 - return RandomStream.get(scope, name); // 70 -}; // 71 - // 72 -// Creates a randomSeed for passing to a method call. // 73 -// Note that we take enclosing as an argument, // 74 -// though we expect it to be DDP._CurrentInvocation.get() // 75 -// However, we often evaluate makeRpcSeed lazily, and thus the relevant // 76 -// invocation may not be the one currently in scope. // 77 -// If enclosing is null, we'll use Random and values won't be repeatable. // 78 -makeRpcSeed = function (enclosing, methodName) { // 79 - var stream = RandomStream.get(enclosing, '/rpc/' + methodName); // 80 - return stream.hexString(20); // 81 -}; // 82 - // 83 -_.extend(RandomStream.prototype, { // 84 - // Get a random sequence with the specified name, creating it if does not exist. // 85 - // New sequences are seeded with the seed concatenated with the name. // 86 - // By passing a seed into Random.create, we use the Alea generator. // 87 - _sequence: function (name) { // 88 - var self = this; // 89 - // 90 - var sequence = self.sequences[name] || null; // 91 - if (sequence === null) { // 92 - var sequenceSeed = self.seed.concat(name); // 93 - for (var i = 0; i < sequenceSeed.length; i++) { // 94 - if (_.isFunction(sequenceSeed[i])) { // 95 - sequenceSeed[i] = sequenceSeed[i](); // 96 - } // 97 - } // 98 - self.sequences[name] = sequence = Random.createWithSeeds.apply(null, sequenceSeed); // 99 - } // 100 - return sequence; // 101 - } // 102 -}); // 103 - // 104 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/livedata_connection.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -if (Meteor.isServer) { // 1 - var path = Npm.require('path'); // 2 - var Fiber = Npm.require('fibers'); // 3 - var Future = Npm.require(path.join('fibers', 'future')); // 4 -} // 5 - // 6 -// @param url {String|Object} URL to Meteor app, // 7 -// or an object as a test hook (see code) // 8 -// Options: // 9 -// reloadWithOutstanding: is it OK to reload if there are outstanding methods? // 10 -// headers: extra headers to send on the websockets connection, for // 11 -// server-to-server DDP only // 12 -// _sockjsOptions: Specifies options to pass through to the sockjs client // 13 -// onDDPNegotiationVersionFailure: callback when version negotiation fails. // 14 -// // 15 -// XXX There should be a way to destroy a DDP connection, causing all // 16 -// outstanding method calls to fail. // 17 -// // 18 -// XXX Our current way of handling failure and reconnection is great // 19 -// for an app (where we want to tolerate being disconnected as an // 20 -// expect state, and keep trying forever to reconnect) but cumbersome // 21 -// for something like a command line tool that wants to make a // 22 -// connection, call a method, and print an error if connection // 23 -// fails. We should have better usability in the latter case (while // 24 -// still transparently reconnecting if it's just a transient failure // 25 -// or the server migrating us). // 26 -var Connection = function (url, options) { // 27 - var self = this; // 28 - options = _.extend({ // 29 - onConnected: function () {}, // 30 - onDDPVersionNegotiationFailure: function (description) { // 31 - Meteor._debug(description); // 32 - }, // 33 - heartbeatInterval: 35000, // 34 - heartbeatTimeout: 15000, // 35 - // These options are only for testing. // 36 - reloadWithOutstanding: false, // 37 - supportedDDPVersions: SUPPORTED_DDP_VERSIONS, // 38 - retry: true, // 39 - respondToPings: true // 40 - }, options); // 41 - // 42 - // If set, called when we reconnect, queuing method calls _before_ the // 43 - // existing outstanding ones. This is the only data member that is part of the // 44 - // public API! // 45 - self.onReconnect = null; // 46 - // 47 - // as a test hook, allow passing a stream instead of a url. // 48 - if (typeof url === "object") { // 49 - self._stream = url; // 50 - } else { // 51 - self._stream = new LivedataTest.ClientStream(url, { // 52 - retry: options.retry, // 53 - headers: options.headers, // 54 - _sockjsOptions: options._sockjsOptions, // 55 - // Used to keep some tests quiet, or for other cases in which // 56 - // the right thing to do with connection errors is to silently // 57 - // fail (e.g. sending package usage stats). At some point we // 58 - // should have a real API for handling client-stream-level // 59 - // errors. // 60 - _dontPrintErrors: options._dontPrintErrors, // 61 - connectTimeoutMs: options.connectTimeoutMs // 62 - }); // 63 - } // 64 - // 65 - self._lastSessionId = null; // 66 - self._versionSuggestion = null; // The last proposed DDP version. // 67 - self._version = null; // The DDP version agreed on by client and server. // 68 - self._stores = {}; // name -> object with methods // 69 - self._methodHandlers = {}; // name -> func // 70 - self._nextMethodId = 1; // 71 - self._supportedDDPVersions = options.supportedDDPVersions; // 72 - // 73 - self._heartbeatInterval = options.heartbeatInterval; // 74 - self._heartbeatTimeout = options.heartbeatTimeout; // 75 - // 76 - // Tracks methods which the user has tried to call but which have not yet // 77 - // called their user callback (ie, they are waiting on their result or for all // 78 - // of their writes to be written to the local cache). Map from method ID to // 79 - // MethodInvoker object. // 80 - self._methodInvokers = {}; // 81 - // 82 - // Tracks methods which the user has called but whose result messages have not // 83 - // arrived yet. // 84 - // // 85 - // _outstandingMethodBlocks is an array of blocks of methods. Each block // 86 - // represents a set of methods that can run at the same time. The first block // 87 - // represents the methods which are currently in flight; subsequent blocks // 88 - // must wait for previous blocks to be fully finished before they can be sent // 89 - // to the server. // 90 - // // 91 - // Each block is an object with the following fields: // 92 - // - methods: a list of MethodInvoker objects // 93 - // - wait: a boolean; if true, this block had a single method invoked with // 94 - // the "wait" option // 95 - // // 96 - // There will never be adjacent blocks with wait=false, because the only thing // 97 - // that makes methods need to be serialized is a wait method. // 98 - // // 99 - // Methods are removed from the first block when their "result" is // 100 - // received. The entire first block is only removed when all of the in-flight // 101 - // methods have received their results (so the "methods" list is empty) *AND* // 102 - // all of the data written by those methods are visible in the local cache. So // 103 - // it is possible for the first block's methods list to be empty, if we are // 104 - // still waiting for some objects to quiesce. // 105 - // // 106 - // Example: // 107 - // _outstandingMethodBlocks = [ // 108 - // {wait: false, methods: []}, // 109 - // {wait: true, methods: []}, // 110 - // {wait: false, methods: [, // 111 - // ]}] // 112 - // This means that there were some methods which were sent to the server and // 113 - // which have returned their results, but some of the data written by // 114 - // the methods may not be visible in the local cache. Once all that data is // 115 - // visible, we will send a 'login' method. Once the login method has returned // 116 - // and all the data is visible (including re-running subs if userId changes), // 117 - // we will send the 'foo' and 'bar' methods in parallel. // 118 - self._outstandingMethodBlocks = []; // 119 - // 120 - // method ID -> array of objects with keys 'collection' and 'id', listing // 121 - // documents written by a given method's stub. keys are associated with // 122 - // methods whose stub wrote at least one document, and whose data-done message // 123 - // has not yet been received. // 124 - self._documentsWrittenByStub = {}; // 125 - // collection -> IdMap of "server document" object. A "server document" has: // 126 - // - "document": the version of the document according the // 127 - // server (ie, the snapshot before a stub wrote it, amended by any changes // 128 - // received from the server) // 129 - // It is undefined if we think the document does not exist // 130 - // - "writtenByStubs": a set of method IDs whose stubs wrote to the document // 131 - // whose "data done" messages have not yet been processed // 132 - self._serverDocuments = {}; // 133 - // 134 - // Array of callbacks to be called after the next update of the local // 135 - // cache. Used for: // 136 - // - Calling methodInvoker.dataVisible and sub ready callbacks after // 137 - // the relevant data is flushed. // 138 - // - Invoking the callbacks of "half-finished" methods after reconnect // 139 - // quiescence. Specifically, methods whose result was received over the old // 140 - // connection (so we don't re-send it) but whose data had not been made // 141 - // visible. // 142 - self._afterUpdateCallbacks = []; // 143 - // 144 - // In two contexts, we buffer all incoming data messages and then process them // 145 - // all at once in a single update: // 146 - // - During reconnect, we buffer all data messages until all subs that had // 147 - // been ready before reconnect are ready again, and all methods that are // 148 - // active have returned their "data done message"; then // 149 - // - During the execution of a "wait" method, we buffer all data messages // 150 - // until the wait method gets its "data done" message. (If the wait method // 151 - // occurs during reconnect, it doesn't get any special handling.) // 152 - // all data messages are processed in one update. // 153 - // // 154 - // The following fields are used for this "quiescence" process. // 155 - // 156 - // This buffers the messages that aren't being processed yet. // 157 - self._messagesBufferedUntilQuiescence = []; // 158 - // Map from method ID -> true. Methods are removed from this when their // 159 - // "data done" message is received, and we will not quiesce until it is // 160 - // empty. // 161 - self._methodsBlockingQuiescence = {}; // 162 - // map from sub ID -> true for subs that were ready (ie, called the sub // 163 - // ready callback) before reconnect but haven't become ready again yet // 164 - self._subsBeingRevived = {}; // map from sub._id -> true // 165 - // if true, the next data update should reset all stores. (set during // 166 - // reconnect.) // 167 - self._resetStores = false; // 168 - // 169 - // name -> array of updates for (yet to be created) collections // 170 - self._updatesForUnknownStores = {}; // 171 - // if we're blocking a migration, the retry func // 172 - self._retryMigrate = null; // 173 - // 174 - // metadata for subscriptions. Map from sub ID to object with keys: // 175 - // - id // 176 - // - name // 177 - // - params // 178 - // - inactive (if true, will be cleaned up if not reused in re-run) // 179 - // - ready (has the 'ready' message been received?) // 180 - // - readyCallback (an optional callback to call when ready) // 181 - // - errorCallback (an optional callback to call if the sub terminates with // 182 - // an error, XXX COMPAT WITH 1.0.3.1) // 183 - // - stopCallback (an optional callback to call when the sub terminates // 184 - // for any reason, with an error argument if an error triggered the stop) // 185 - self._subscriptions = {}; // 186 - // 187 - // Reactive userId. // 188 - self._userId = null; // 189 - self._userIdDeps = new Tracker.Dependency; // 190 - // 191 - // Block auto-reload while we're waiting for method responses. // 192 - if (Meteor.isClient && Package.reload && !options.reloadWithOutstanding) { // 193 - Package.reload.Reload._onMigrate(function (retry) { // 194 - if (!self._readyToMigrate()) { // 195 - if (self._retryMigrate) // 196 - throw new Error("Two migrations in progress?"); // 197 - self._retryMigrate = retry; // 198 - return false; // 199 - } else { // 200 - return [true]; // 201 - } // 202 - }); // 203 - } // 204 - // 205 - var onMessage = function (raw_msg) { // 206 - try { // 207 - var msg = parseDDP(raw_msg); // 208 - } catch (e) { // 209 - Meteor._debug("Exception while parsing DDP", e); // 210 - return; // 211 - } // 212 - // 213 - if (msg === null || !msg.msg) { // 214 - // XXX COMPAT WITH 0.6.6. ignore the old welcome message for back // 215 - // compat. Remove this 'if' once the server stops sending welcome // 216 - // messages (stream_server.js). // 217 - if (! (msg && msg.server_id)) // 218 - Meteor._debug("discarding invalid livedata message", msg); // 219 - return; // 220 - } // 221 - // 222 - if (msg.msg === 'connected') { // 223 - self._version = self._versionSuggestion; // 224 - self._livedata_connected(msg); // 225 - options.onConnected(); // 226 - } // 227 - else if (msg.msg == 'failed') { // 228 - if (_.contains(self._supportedDDPVersions, msg.version)) { // 229 - self._versionSuggestion = msg.version; // 230 - self._stream.reconnect({_force: true}); // 231 - } else { // 232 - var description = // 233 - "DDP version negotiation failed; server requested version " + msg.version; // 234 - self._stream.disconnect({_permanent: true, _error: description}); // 235 - options.onDDPVersionNegotiationFailure(description); // 236 - } // 237 - } // 238 - else if (msg.msg === 'ping') { // 239 - if (options.respondToPings) // 240 - self._send({msg: "pong", id: msg.id}); // 241 - if (self._heartbeat) // 242 - self._heartbeat.pingReceived(); // 243 - } // 244 - else if (msg.msg === 'pong') { // 245 - if (self._heartbeat) { // 246 - self._heartbeat.pongReceived(); // 247 - } // 248 - } // 249 - else if (_.include(['added', 'changed', 'removed', 'ready', 'updated'], msg.msg)) // 250 - self._livedata_data(msg); // 251 - else if (msg.msg === 'nosub') // 252 - self._livedata_nosub(msg); // 253 - else if (msg.msg === 'result') // 254 - self._livedata_result(msg); // 255 - else if (msg.msg === 'error') // 256 - self._livedata_error(msg); // 257 - else // 258 - Meteor._debug("discarding unknown livedata message type", msg); // 259 - }; // 260 - // 261 - var onReset = function () { // 262 - // Send a connect message at the beginning of the stream. // 263 - // NOTE: reset is called even on the first connection, so this is // 264 - // the only place we send this message. // 265 - var msg = {msg: 'connect'}; // 266 - if (self._lastSessionId) // 267 - msg.session = self._lastSessionId; // 268 - msg.version = self._versionSuggestion || self._supportedDDPVersions[0]; // 269 - self._versionSuggestion = msg.version; // 270 - msg.support = self._supportedDDPVersions; // 271 - self._send(msg); // 272 - // 273 - // Now, to minimize setup latency, go ahead and blast out all of // 274 - // our pending methods ands subscriptions before we've even taken // 275 - // the necessary RTT to know if we successfully reconnected. (1) // 276 - // They're supposed to be idempotent; (2) even if we did // 277 - // reconnect, we're not sure what messages might have gotten lost // 278 - // (in either direction) since we were disconnected (TCP being // 279 - // sloppy about that.) // 280 - // 281 - // If the current block of methods all got their results (but didn't all get // 282 - // their data visible), discard the empty block now. // 283 - if (! _.isEmpty(self._outstandingMethodBlocks) && // 284 - _.isEmpty(self._outstandingMethodBlocks[0].methods)) { // 285 - self._outstandingMethodBlocks.shift(); // 286 - } // 287 - // 288 - // Mark all messages as unsent, they have not yet been sent on this // 289 - // connection. // 290 - _.each(self._methodInvokers, function (m) { // 291 - m.sentMessage = false; // 292 - }); // 293 - // 294 - // If an `onReconnect` handler is set, call it first. Go through // 295 - // some hoops to ensure that methods that are called from within // 296 - // `onReconnect` get executed _before_ ones that were originally // 297 - // outstanding (since `onReconnect` is used to re-establish auth // 298 - // certificates) // 299 - if (self.onReconnect) // 300 - self._callOnReconnectAndSendAppropriateOutstandingMethods(); // 301 - else // 302 - self._sendOutstandingMethods(); // 303 - // 304 - // add new subscriptions at the end. this way they take effect after // 305 - // the handlers and we don't see flicker. // 306 - _.each(self._subscriptions, function (sub, id) { // 307 - self._send({ // 308 - msg: 'sub', // 309 - id: id, // 310 - name: sub.name, // 311 - params: sub.params // 312 - }); // 313 - }); // 314 - }; // 315 - // 316 - var onDisconnect = function () { // 317 - if (self._heartbeat) { // 318 - self._heartbeat.stop(); // 319 - self._heartbeat = null; // 320 - } // 321 - }; // 322 - // 323 - if (Meteor.isServer) { // 324 - self._stream.on('message', Meteor.bindEnvironment(onMessage, Meteor._debug)); // 325 - self._stream.on('reset', Meteor.bindEnvironment(onReset, Meteor._debug)); // 326 - self._stream.on('disconnect', Meteor.bindEnvironment(onDisconnect, Meteor._debug)); // 327 - } else { // 328 - self._stream.on('message', onMessage); // 329 - self._stream.on('reset', onReset); // 330 - self._stream.on('disconnect', onDisconnect); // 331 - } // 332 -}; // 333 - // 334 -// A MethodInvoker manages sending a method to the server and calling the user's // 335 -// callbacks. On construction, it registers itself in the connection's // 336 -// _methodInvokers map; it removes itself once the method is fully finished and // 337 -// the callback is invoked. This occurs when it has both received a result, // 338 -// and the data written by it is fully visible. // 339 -var MethodInvoker = function (options) { // 340 - var self = this; // 341 - // 342 - // Public (within this file) fields. // 343 - self.methodId = options.methodId; // 344 - self.sentMessage = false; // 345 - // 346 - self._callback = options.callback; // 347 - self._connection = options.connection; // 348 - self._message = options.message; // 349 - self._onResultReceived = options.onResultReceived || function () {}; // 350 - self._wait = options.wait; // 351 - self._methodResult = null; // 352 - self._dataVisible = false; // 353 - // 354 - // Register with the connection. // 355 - self._connection._methodInvokers[self.methodId] = self; // 356 -}; // 357 -_.extend(MethodInvoker.prototype, { // 358 - // Sends the method message to the server. May be called additional times if // 359 - // we lose the connection and reconnect before receiving a result. // 360 - sendMessage: function () { // 361 - var self = this; // 362 - // This function is called before sending a method (including resending on // 363 - // reconnect). We should only (re)send methods where we don't already have a // 364 - // result! // 365 - if (self.gotResult()) // 366 - throw new Error("sendingMethod is called on method with result"); // 367 - // 368 - // If we're re-sending it, it doesn't matter if data was written the first // 369 - // time. // 370 - self._dataVisible = false; // 371 - // 372 - self.sentMessage = true; // 373 - // 374 - // If this is a wait method, make all data messages be buffered until it is // 375 - // done. // 376 - if (self._wait) // 377 - self._connection._methodsBlockingQuiescence[self.methodId] = true; // 378 - // 379 - // Actually send the message. // 380 - self._connection._send(self._message); // 381 - }, // 382 - // Invoke the callback, if we have both a result and know that all data has // 383 - // been written to the local cache. // 384 - _maybeInvokeCallback: function () { // 385 - var self = this; // 386 - if (self._methodResult && self._dataVisible) { // 387 - // Call the callback. (This won't throw: the callback was wrapped with // 388 - // bindEnvironment.) // 389 - self._callback(self._methodResult[0], self._methodResult[1]); // 390 - // 391 - // Forget about this method. // 392 - delete self._connection._methodInvokers[self.methodId]; // 393 - // 394 - // Let the connection know that this method is finished, so it can try to // 395 - // move on to the next block of methods. // 396 - self._connection._outstandingMethodFinished(); // 397 - } // 398 - }, // 399 - // Call with the result of the method from the server. Only may be called // 400 - // once; once it is called, you should not call sendMessage again. // 401 - // If the user provided an onResultReceived callback, call it immediately. // 402 - // Then invoke the main callback if data is also visible. // 403 - receiveResult: function (err, result) { // 404 - var self = this; // 405 - if (self.gotResult()) // 406 - throw new Error("Methods should only receive results once"); // 407 - self._methodResult = [err, result]; // 408 - self._onResultReceived(err, result); // 409 - self._maybeInvokeCallback(); // 410 - }, // 411 - // Call this when all data written by the method is visible. This means that // 412 - // the method has returns its "data is done" message *AND* all server // 413 - // documents that are buffered at that time have been written to the local // 414 - // cache. Invokes the main callback if the result has been received. // 415 - dataVisible: function () { // 416 - var self = this; // 417 - self._dataVisible = true; // 418 - self._maybeInvokeCallback(); // 419 - }, // 420 - // True if receiveResult has been called. // 421 - gotResult: function () { // 422 - var self = this; // 423 - return !!self._methodResult; // 424 - } // 425 -}); // 426 - // 427 -_.extend(Connection.prototype, { // 428 - // 'name' is the name of the data on the wire that should go in the // 429 - // store. 'wrappedStore' should be an object with methods beginUpdate, update, // 430 - // endUpdate, saveOriginals, retrieveOriginals. see Collection for an example. // 431 - registerStore: function (name, wrappedStore) { // 432 - var self = this; // 433 - // 434 - if (name in self._stores) // 435 - return false; // 436 - // 437 - // Wrap the input object in an object which makes any store method not // 438 - // implemented by 'store' into a no-op. // 439 - var store = {}; // 440 - _.each(['update', 'beginUpdate', 'endUpdate', 'saveOriginals', // 441 - 'retrieveOriginals'], function (method) { // 442 - store[method] = function () { // 443 - return (wrappedStore[method] // 444 - ? wrappedStore[method].apply(wrappedStore, arguments) // 445 - : undefined); // 446 - }; // 447 - }); // 448 - // 449 - self._stores[name] = store; // 450 - // 451 - var queued = self._updatesForUnknownStores[name]; // 452 - if (queued) { // 453 - store.beginUpdate(queued.length, false); // 454 - _.each(queued, function (msg) { // 455 - store.update(msg); // 456 - }); // 457 - store.endUpdate(); // 458 - delete self._updatesForUnknownStores[name]; // 459 - } // 460 - // 461 - return true; // 462 - }, // 463 - // 464 - /** // 465 - * @memberOf Meteor // 466 - * @summary Subscribe to a record set. Returns a handle that provides // 467 - * `stop()` and `ready()` methods. // 468 - * @locus Client // 469 - * @param {String} name Name of the subscription. Matches the name of the // 470 - * server's `publish()` call. // 471 - * @param {Any} [arg1,arg2...] Optional arguments passed to publisher // 472 - * function on server. // 473 - * @param {Function|Object} [callbacks] Optional. May include `onStop` // 474 - * and `onReady` callbacks. If there is an error, it is passed as an // 475 - * argument to `onStop`. If a function is passed instead of an object, it // 476 - * is interpreted as an `onReady` callback. // 477 - */ // 478 - subscribe: function (name /* .. [arguments] .. (callback|callbacks) */) { // 479 - var self = this; // 480 - // 481 - var params = Array.prototype.slice.call(arguments, 1); // 482 - var callbacks = {}; // 483 - if (params.length) { // 484 - var lastParam = params[params.length - 1]; // 485 - if (_.isFunction(lastParam)) { // 486 - callbacks.onReady = params.pop(); // 487 - } else if (lastParam && // 488 - // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use // 489 - // onStop with an error callback instead. // 490 - _.any([lastParam.onReady, lastParam.onError, lastParam.onStop], // 491 - _.isFunction)) { // 492 - callbacks = params.pop(); // 493 - } // 494 - } // 495 - // 496 - // Is there an existing sub with the same name and param, run in an // 497 - // invalidated Computation? This will happen if we are rerunning an // 498 - // existing computation. // 499 - // // 500 - // For example, consider a rerun of: // 501 - // // 502 - // Tracker.autorun(function () { // 503 - // Meteor.subscribe("foo", Session.get("foo")); // 504 - // Meteor.subscribe("bar", Session.get("bar")); // 505 - // }); // 506 - // // 507 - // If "foo" has changed but "bar" has not, we will match the "bar" // 508 - // subcribe to an existing inactive subscription in order to not // 509 - // unsub and resub the subscription unnecessarily. // 510 - // // 511 - // We only look for one such sub; if there are N apparently-identical subs // 512 - // being invalidated, we will require N matching subscribe calls to keep // 513 - // them all active. // 514 - var existing = _.find(self._subscriptions, function (sub) { // 515 - return sub.inactive && sub.name === name && // 516 - EJSON.equals(sub.params, params); // 517 - }); // 518 - // 519 - var id; // 520 - if (existing) { // 521 - id = existing.id; // 522 - existing.inactive = false; // reactivate // 523 - // 524 - if (callbacks.onReady) { // 525 - // If the sub is not already ready, replace any ready callback with the // 526 - // one provided now. (It's not really clear what users would expect for // 527 - // an onReady callback inside an autorun; the semantics we provide is // 528 - // that at the time the sub first becomes ready, we call the last // 529 - // onReady callback provided, if any.) // 530 - if (!existing.ready) // 531 - existing.readyCallback = callbacks.onReady; // 532 - } // 533 - // 534 - // XXX COMPAT WITH 1.0.3.1 we used to have onError but now we call // 535 - // onStop with an optional error argument // 536 - if (callbacks.onError) { // 537 - // Replace existing callback if any, so that errors aren't // 538 - // double-reported. // 539 - existing.errorCallback = callbacks.onError; // 540 - } // 541 - // 542 - if (callbacks.onStop) { // 543 - existing.stopCallback = callbacks.onStop; // 544 - } // 545 - } else { // 546 - // New sub! Generate an id, save it locally, and send message. // 547 - id = Random.id(); // 548 - self._subscriptions[id] = { // 549 - id: id, // 550 - name: name, // 551 - params: EJSON.clone(params), // 552 - inactive: false, // 553 - ready: false, // 554 - readyDeps: new Tracker.Dependency, // 555 - readyCallback: callbacks.onReady, // 556 - // XXX COMPAT WITH 1.0.3.1 #errorCallback // 557 - errorCallback: callbacks.onError, // 558 - stopCallback: callbacks.onStop, // 559 - connection: self, // 560 - remove: function() { // 561 - delete this.connection._subscriptions[this.id]; // 562 - this.ready && this.readyDeps.changed(); // 563 - }, // 564 - stop: function() { // 565 - this.connection._send({msg: 'unsub', id: id}); // 566 - this.remove(); // 567 - // 568 - if (callbacks.onStop) { // 569 - callbacks.onStop(); // 570 - } // 571 - } // 572 - }; // 573 - self._send({msg: 'sub', id: id, name: name, params: params}); // 574 - } // 575 - // 576 - // return a handle to the application. // 577 - var handle = { // 578 - stop: function () { // 579 - if (!_.has(self._subscriptions, id)) // 580 - return; // 581 - // 582 - self._subscriptions[id].stop(); // 583 - }, // 584 - ready: function () { // 585 - // return false if we've unsubscribed. // 586 - if (!_.has(self._subscriptions, id)) // 587 - return false; // 588 - var record = self._subscriptions[id]; // 589 - record.readyDeps.depend(); // 590 - return record.ready; // 591 - }, // 592 - subscriptionId: id // 593 - }; // 594 - // 595 - if (Tracker.active) { // 596 - // We're in a reactive computation, so we'd like to unsubscribe when the // 597 - // computation is invalidated... but not if the rerun just re-subscribes // 598 - // to the same subscription! When a rerun happens, we use onInvalidate // 599 - // as a change to mark the subscription "inactive" so that it can // 600 - // be reused from the rerun. If it isn't reused, it's killed from // 601 - // an afterFlush. // 602 - Tracker.onInvalidate(function (c) { // 603 - if (_.has(self._subscriptions, id)) // 604 - self._subscriptions[id].inactive = true; // 605 - // 606 - Tracker.afterFlush(function () { // 607 - if (_.has(self._subscriptions, id) && // 608 - self._subscriptions[id].inactive) // 609 - handle.stop(); // 610 - }); // 611 - }); // 612 - } // 613 - // 614 - return handle; // 615 - }, // 616 - // 617 - // options: // 618 - // - onLateError {Function(error)} called if an error was received after the ready event. // 619 - // (errors received before ready cause an error to be thrown) // 620 - _subscribeAndWait: function (name, args, options) { // 621 - var self = this; // 622 - var f = new Future(); // 623 - var ready = false; // 624 - var handle; // 625 - args = args || []; // 626 - args.push({ // 627 - onReady: function () { // 628 - ready = true; // 629 - f['return'](); // 630 - }, // 631 - onError: function (e) { // 632 - if (!ready) // 633 - f['throw'](e); // 634 - else // 635 - options && options.onLateError && options.onLateError(e); // 636 - } // 637 - }); // 638 - // 639 - handle = self.subscribe.apply(self, [name].concat(args)); // 640 - f.wait(); // 641 - return handle; // 642 - }, // 643 - // 644 - methods: function (methods) { // 645 - var self = this; // 646 - _.each(methods, function (func, name) { // 647 - if (self._methodHandlers[name]) // 648 - throw new Error("A method named '" + name + "' is already defined"); // 649 - self._methodHandlers[name] = func; // 650 - }); // 651 - }, // 652 - // 653 - /** // 654 - * @memberOf Meteor // 655 - * @summary Invokes a method passing any number of arguments. // 656 - * @locus Anywhere // 657 - * @param {String} name Name of method to invoke // 658 - * @param {EJSONable} [arg1,arg2...] Optional method arguments // 659 - * @param {Function} [asyncCallback] Optional callback, which is called asynchronously with the error or result after the method is complete. If not provided, the method runs synchronously if possible (see below). - */ // 661 - call: function (name /* .. [arguments] .. callback */) { // 662 - // if it's a function, the last argument is the result callback, // 663 - // not a parameter to the remote method. // 664 - var args = Array.prototype.slice.call(arguments, 1); // 665 - if (args.length && typeof args[args.length - 1] === "function") // 666 - var callback = args.pop(); // 667 - return this.apply(name, args, callback); // 668 - }, // 669 - // 670 - // @param options {Optional Object} // 671 - // wait: Boolean - Should we wait to call this until all current methods // 672 - // are fully finished, and block subsequent method calls // 673 - // until this method is fully finished? // 674 - // (does not affect methods called from within this method) // 675 - // onResultReceived: Function - a callback to call as soon as the method // 676 - // result is received. the data written by // 677 - // the method may not yet be in the cache! // 678 - // returnStubValue: Boolean - If true then in cases where we would have // 679 - // otherwise discarded the stub's return value // 680 - // and returned undefined, instead we go ahead // 681 - // and return it. Specifically, this is any // 682 - // time other than when (a) we are already // 683 - // inside a stub or (b) we are in Node and no // 684 - // callback was provided. Currently we require // 685 - // this flag to be explicitly passed to reduce // 686 - // the likelihood that stub return values will // 687 - // be confused with server return values; we // 688 - // may improve this in future. // 689 - // @param callback {Optional Function} // 690 - // 691 - /** // 692 - * @memberOf Meteor // 693 - * @summary Invoke a method passing an array of arguments. // 694 - * @locus Anywhere // 695 - * @param {String} name Name of method to invoke // 696 - * @param {EJSONable[]} args Method arguments // 697 - * @param {Object} [options] // 698 - * @param {Boolean} options.wait (Client only) If true, don't send this method until all previous method calls have completed, and don't send any subsequent method calls until this one is completed. - * @param {Function} options.onResultReceived (Client only) This callback is invoked with the error or result of the method (just like `asyncCallback`) as soon as the error or result is available. The local cache may not yet reflect the writes performed by the method. - * @param {Function} [asyncCallback] Optional callback; same semantics as in [`Meteor.call`](#meteor_call). // 701 - */ // 702 - apply: function (name, args, options, callback) { // 703 - var self = this; // 704 - // 705 - // We were passed 3 arguments. They may be either (name, args, options) // 706 - // or (name, args, callback) // 707 - if (!callback && typeof options === 'function') { // 708 - callback = options; // 709 - options = {}; // 710 - } // 711 - options = options || {}; // 712 - // 713 - if (callback) { // 714 - // XXX would it be better form to do the binding in stream.on, // 715 - // or caller, instead of here? // 716 - // XXX improve error message (and how we report it) // 717 - callback = Meteor.bindEnvironment( // 718 - callback, // 719 - "delivering result of invoking '" + name + "'" // 720 - ); // 721 - } // 722 - // 723 - // Keep our args safe from mutation (eg if we don't send the message for a // 724 - // while because of a wait method). // 725 - args = EJSON.clone(args); // 726 - // 727 - // Lazily allocate method ID once we know that it'll be needed. // 728 - var methodId = (function () { // 729 - var id; // 730 - return function () { // 731 - if (id === undefined) // 732 - id = '' + (self._nextMethodId++); // 733 - return id; // 734 - }; // 735 - })(); // 736 - // 737 - var enclosing = DDP._CurrentInvocation.get(); // 738 - var alreadyInSimulation = enclosing && enclosing.isSimulation; // 739 - // 740 - // Lazily generate a randomSeed, only if it is requested by the stub. // 741 - // The random streams only have utility if they're used on both the client // 742 - // and the server; if the client doesn't generate any 'random' values // 743 - // then we don't expect the server to generate any either. // 744 - // Less commonly, the server may perform different actions from the client, // 745 - // and may in fact generate values where the client did not, but we don't // 746 - // have any client-side values to match, so even here we may as well just // 747 - // use a random seed on the server. In that case, we don't pass the // 748 - // randomSeed to save bandwidth, and we don't even generate it to save a // 749 - // bit of CPU and to avoid consuming entropy. // 750 - var randomSeed = null; // 751 - var randomSeedGenerator = function () { // 752 - if (randomSeed === null) { // 753 - randomSeed = makeRpcSeed(enclosing, name); // 754 - } // 755 - return randomSeed; // 756 - }; // 757 - // 758 - // Run the stub, if we have one. The stub is supposed to make some // 759 - // temporary writes to the database to give the user a smooth experience // 760 - // until the actual result of executing the method comes back from the // 761 - // server (whereupon the temporary writes to the database will be reversed // 762 - // during the beginUpdate/endUpdate process.) // 763 - // // 764 - // Normally, we ignore the return value of the stub (even if it is an // 765 - // exception), in favor of the real return value from the server. The // 766 - // exception is if the *caller* is a stub. In that case, we're not going // 767 - // to do a RPC, so we use the return value of the stub as our return // 768 - // value. // 769 - // 770 - var stub = self._methodHandlers[name]; // 771 - if (stub) { // 772 - var setUserId = function(userId) { // 773 - self.setUserId(userId); // 774 - }; // 775 - // 776 - var invocation = new MethodInvocation({ // 777 - isSimulation: true, // 778 - userId: self.userId(), // 779 - setUserId: setUserId, // 780 - randomSeed: function () { return randomSeedGenerator(); } // 781 - }); // 782 - // 783 - if (!alreadyInSimulation) // 784 - self._saveOriginals(); // 785 - // 786 - try { // 787 - // Note that unlike in the corresponding server code, we never audit // 788 - // that stubs check() their arguments. // 789 - var stubReturnValue = DDP._CurrentInvocation.withValue(invocation, function () { // 790 - if (Meteor.isServer) { // 791 - // Because saveOriginals and retrieveOriginals aren't reentrant, // 792 - // don't allow stubs to yield. // 793 - return Meteor._noYieldsAllowed(function () { // 794 - // re-clone, so that the stub can't affect our caller's values // 795 - return stub.apply(invocation, EJSON.clone(args)); // 796 - }); // 797 - } else { // 798 - return stub.apply(invocation, EJSON.clone(args)); // 799 - } // 800 - }); // 801 - } // 802 - catch (e) { // 803 - var exception = e; // 804 - } // 805 - // 806 - if (!alreadyInSimulation) // 807 - self._retrieveAndStoreOriginals(methodId()); // 808 - } // 809 - // 810 - // If we're in a simulation, stop and return the result we have, // 811 - // rather than going on to do an RPC. If there was no stub, // 812 - // we'll end up returning undefined. // 813 - if (alreadyInSimulation) { // 814 - if (callback) { // 815 - callback(exception, stubReturnValue); // 816 - return undefined; // 817 - } // 818 - if (exception) // 819 - throw exception; // 820 - return stubReturnValue; // 821 - } // 822 - // 823 - // If an exception occurred in a stub, and we're ignoring it // 824 - // because we're doing an RPC and want to use what the server // 825 - // returns instead, log it so the developer knows. // 826 - // // 827 - // Tests can set the 'expected' flag on an exception so it won't // 828 - // go to log. // 829 - if (exception && !exception.expected) { // 830 - Meteor._debug("Exception while simulating the effect of invoking '" + // 831 - name + "'", exception, exception.stack); // 832 - } // 833 - // 834 - // 835 - // At this point we're definitely doing an RPC, and we're going to // 836 - // return the value of the RPC to the caller. // 837 - // 838 - // If the caller didn't give a callback, decide what to do. // 839 - if (!callback) { // 840 - if (Meteor.isClient) { // 841 - // On the client, we don't have fibers, so we can't block. The // 842 - // only thing we can do is to return undefined and discard the // 843 - // result of the RPC. If an error occurred then print the error // 844 - // to the console. // 845 - callback = function (err) { // 846 - err && Meteor._debug("Error invoking Method '" + name + "':", // 847 - err.message); // 848 - }; // 849 - } else { // 850 - // On the server, make the function synchronous. Throw on // 851 - // errors, return on success. // 852 - var future = new Future; // 853 - callback = future.resolver(); // 854 - } // 855 - } // 856 - // Send the RPC. Note that on the client, it is important that the // 857 - // stub have finished before we send the RPC, so that we know we have // 858 - // a complete list of which local documents the stub wrote. // 859 - var message = { // 860 - msg: 'method', // 861 - method: name, // 862 - params: args, // 863 - id: methodId() // 864 - }; // 865 - // 866 - // Send the randomSeed only if we used it // 867 - if (randomSeed !== null) { // 868 - message.randomSeed = randomSeed; // 869 - } // 870 - // 871 - var methodInvoker = new MethodInvoker({ // 872 - methodId: methodId(), // 873 - callback: callback, // 874 - connection: self, // 875 - onResultReceived: options.onResultReceived, // 876 - wait: !!options.wait, // 877 - message: message // 878 - }); // 879 - // 880 - if (options.wait) { // 881 - // It's a wait method! Wait methods go in their own block. // 882 - self._outstandingMethodBlocks.push( // 883 - {wait: true, methods: [methodInvoker]}); // 884 - } else { // 885 - // Not a wait method. Start a new block if the previous block was a wait // 886 - // block, and add it to the last block of methods. // 887 - if (_.isEmpty(self._outstandingMethodBlocks) || // 888 - _.last(self._outstandingMethodBlocks).wait) // 889 - self._outstandingMethodBlocks.push({wait: false, methods: []}); // 890 - _.last(self._outstandingMethodBlocks).methods.push(methodInvoker); // 891 - } // 892 - // 893 - // If we added it to the first block, send it out now. // 894 - if (self._outstandingMethodBlocks.length === 1) // 895 - methodInvoker.sendMessage(); // 896 - // 897 - // If we're using the default callback on the server, // 898 - // block waiting for the result. // 899 - if (future) { // 900 - return future.wait(); // 901 - } // 902 - return options.returnStubValue ? stubReturnValue : undefined; // 903 - }, // 904 - // 905 - // Before calling a method stub, prepare all stores to track changes and allow // 906 - // _retrieveAndStoreOriginals to get the original versions of changed // 907 - // documents. // 908 - _saveOriginals: function () { // 909 - var self = this; // 910 - _.each(self._stores, function (s) { // 911 - s.saveOriginals(); // 912 - }); // 913 - }, // 914 - // Retrieves the original versions of all documents modified by the stub for // 915 - // method 'methodId' from all stores and saves them to _serverDocuments (keyed // 916 - // by document) and _documentsWrittenByStub (keyed by method ID). // 917 - _retrieveAndStoreOriginals: function (methodId) { // 918 - var self = this; // 919 - if (self._documentsWrittenByStub[methodId]) // 920 - throw new Error("Duplicate methodId in _retrieveAndStoreOriginals"); // 921 - // 922 - var docsWritten = []; // 923 - _.each(self._stores, function (s, collection) { // 924 - var originals = s.retrieveOriginals(); // 925 - // not all stores define retrieveOriginals // 926 - if (!originals) // 927 - return; // 928 - originals.forEach(function (doc, id) { // 929 - docsWritten.push({collection: collection, id: id}); // 930 - if (!_.has(self._serverDocuments, collection)) // 931 - self._serverDocuments[collection] = new LocalCollection._IdMap; // 932 - var serverDoc = self._serverDocuments[collection].setDefault(id, {}); // 933 - if (serverDoc.writtenByStubs) { // 934 - // We're not the first stub to write this doc. Just add our method ID // 935 - // to the record. // 936 - serverDoc.writtenByStubs[methodId] = true; // 937 - } else { // 938 - // First stub! Save the original value and our method ID. // 939 - serverDoc.document = doc; // 940 - serverDoc.flushCallbacks = []; // 941 - serverDoc.writtenByStubs = {}; // 942 - serverDoc.writtenByStubs[methodId] = true; // 943 - } // 944 - }); // 945 - }); // 946 - if (!_.isEmpty(docsWritten)) { // 947 - self._documentsWrittenByStub[methodId] = docsWritten; // 948 - } // 949 - }, // 950 - // 951 - // This is very much a private function we use to make the tests // 952 - // take up fewer server resources after they complete. // 953 - _unsubscribeAll: function () { // 954 - var self = this; // 955 - _.each(_.clone(self._subscriptions), function (sub, id) { // 956 - // Avoid killing the autoupdate subscription so that developers // 957 - // still get hot code pushes when writing tests. // 958 - // // 959 - // XXX it's a hack to encode knowledge about autoupdate here, // 960 - // but it doesn't seem worth it yet to have a special API for // 961 - // subscriptions to preserve after unit tests. // 962 - if (sub.name !== 'meteor_autoupdate_clientVersions') { // 963 - self._subscriptions[id].stop(); // 964 - } // 965 - }); // 966 - }, // 967 - // 968 - // Sends the DDP stringification of the given message object // 969 - _send: function (obj) { // 970 - var self = this; // 971 - self._stream.send(stringifyDDP(obj)); // 972 - }, // 973 - // 974 - // We detected via DDP-level heartbeats that we've lost the // 975 - // connection. Unlike `disconnect` or `close`, a lost connection // 976 - // will be automatically retried. // 977 - _lostConnection: function (error) { // 978 - var self = this; // 979 - self._stream._lostConnection(error); // 980 - }, // 981 - // 982 - /** // 983 - * @summary Get the current connection status. A reactive data source. // 984 - * @locus Client // 985 - * @memberOf Meteor // 986 - */ // 987 - status: function (/*passthrough args*/) { // 988 - var self = this; // 989 - return self._stream.status.apply(self._stream, arguments); // 990 - }, // 991 - // 992 - /** // 993 - * @summary Force an immediate reconnection attempt if the client is not connected to the server. // 994 - // 995 - This method does nothing if the client is already connected. // 996 - * @locus Client // 997 - * @memberOf Meteor // 998 - */ // 999 - reconnect: function (/*passthrough args*/) { // 1000 - var self = this; // 1001 - return self._stream.reconnect.apply(self._stream, arguments); // 1002 - }, // 1003 - // 1004 - /** // 1005 - * @summary Disconnect the client from the server. // 1006 - * @locus Client // 1007 - * @memberOf Meteor // 1008 - */ // 1009 - disconnect: function (/*passthrough args*/) { // 1010 - var self = this; // 1011 - return self._stream.disconnect.apply(self._stream, arguments); // 1012 - }, // 1013 - // 1014 - close: function () { // 1015 - var self = this; // 1016 - return self._stream.disconnect({_permanent: true}); // 1017 - }, // 1018 - // 1019 - /// // 1020 - /// Reactive user system // 1021 - /// // 1022 - userId: function () { // 1023 - var self = this; // 1024 - if (self._userIdDeps) // 1025 - self._userIdDeps.depend(); // 1026 - return self._userId; // 1027 - }, // 1028 - // 1029 - setUserId: function (userId) { // 1030 - var self = this; // 1031 - // Avoid invalidating dependents if setUserId is called with current value. // 1032 - if (self._userId === userId) // 1033 - return; // 1034 - self._userId = userId; // 1035 - if (self._userIdDeps) // 1036 - self._userIdDeps.changed(); // 1037 - }, // 1038 - // 1039 - // Returns true if we are in a state after reconnect of waiting for subs to be // 1040 - // revived or early methods to finish their data, or we are waiting for a // 1041 - // "wait" method to finish. // 1042 - _waitingForQuiescence: function () { // 1043 - var self = this; // 1044 - return (! _.isEmpty(self._subsBeingRevived) || // 1045 - ! _.isEmpty(self._methodsBlockingQuiescence)); // 1046 - }, // 1047 - // 1048 - // Returns true if any method whose message has been sent to the server has // 1049 - // not yet invoked its user callback. // 1050 - _anyMethodsAreOutstanding: function () { // 1051 - var self = this; // 1052 - return _.any(_.pluck(self._methodInvokers, 'sentMessage')); // 1053 - }, // 1054 - // 1055 - _livedata_connected: function (msg) { // 1056 - var self = this; // 1057 - // 1058 - if (self._version !== 'pre1' && self._heartbeatInterval !== 0) { // 1059 - self._heartbeat = new Heartbeat({ // 1060 - heartbeatInterval: self._heartbeatInterval, // 1061 - heartbeatTimeout: self._heartbeatTimeout, // 1062 - onTimeout: function () { // 1063 - self._lostConnection( // 1064 - new DDP.ConnectionError("DDP heartbeat timed out")); // 1065 - }, // 1066 - sendPing: function () { // 1067 - self._send({msg: 'ping'}); // 1068 - } // 1069 - }); // 1070 - self._heartbeat.start(); // 1071 - } // 1072 - // 1073 - // If this is a reconnect, we'll have to reset all stores. // 1074 - if (self._lastSessionId) // 1075 - self._resetStores = true; // 1076 - // 1077 - if (typeof (msg.session) === "string") { // 1078 - var reconnectedToPreviousSession = (self._lastSessionId === msg.session); // 1079 - self._lastSessionId = msg.session; // 1080 - } // 1081 - // 1082 - if (reconnectedToPreviousSession) { // 1083 - // Successful reconnection -- pick up where we left off. Note that right // 1084 - // now, this never happens: the server never connects us to a previous // 1085 - // session, because DDP doesn't provide enough data for the server to know // 1086 - // what messages the client has processed. We need to improve DDP to make // 1087 - // this possible, at which point we'll probably need more code here. // 1088 - return; // 1089 - } // 1090 - // 1091 - // Server doesn't have our data any more. Re-sync a new session. // 1092 - // 1093 - // Forget about messages we were buffering for unknown collections. They'll // 1094 - // be resent if still relevant. // 1095 - self._updatesForUnknownStores = {}; // 1096 - // 1097 - if (self._resetStores) { // 1098 - // Forget about the effects of stubs. We'll be resetting all collections // 1099 - // anyway. // 1100 - self._documentsWrittenByStub = {}; // 1101 - self._serverDocuments = {}; // 1102 - } // 1103 - // 1104 - // Clear _afterUpdateCallbacks. // 1105 - self._afterUpdateCallbacks = []; // 1106 - // 1107 - // Mark all named subscriptions which are ready (ie, we already called the // 1108 - // ready callback) as needing to be revived. // 1109 - // XXX We should also block reconnect quiescence until unnamed subscriptions // 1110 - // (eg, autopublish) are done re-publishing to avoid flicker! // 1111 - self._subsBeingRevived = {}; // 1112 - _.each(self._subscriptions, function (sub, id) { // 1113 - if (sub.ready) // 1114 - self._subsBeingRevived[id] = true; // 1115 - }); // 1116 - // 1117 - // Arrange for "half-finished" methods to have their callbacks run, and // 1118 - // track methods that were sent on this connection so that we don't // 1119 - // quiesce until they are all done. // 1120 - // // 1121 - // Start by clearing _methodsBlockingQuiescence: methods sent before // 1122 - // reconnect don't matter, and any "wait" methods sent on the new connection // 1123 - // that we drop here will be restored by the loop below. // 1124 - self._methodsBlockingQuiescence = {}; // 1125 - if (self._resetStores) { // 1126 - _.each(self._methodInvokers, function (invoker) { // 1127 - if (invoker.gotResult()) { // 1128 - // This method already got its result, but it didn't call its callback // 1129 - // because its data didn't become visible. We did not resend the // 1130 - // method RPC. We'll call its callback when we get a full quiesce, // 1131 - // since that's as close as we'll get to "data must be visible". // 1132 - self._afterUpdateCallbacks.push(_.bind(invoker.dataVisible, invoker)); // 1133 - } else if (invoker.sentMessage) { // 1134 - // This method has been sent on this connection (maybe as a resend // 1135 - // from the last connection, maybe from onReconnect, maybe just very // 1136 - // quickly before processing the connected message). // 1137 - // // 1138 - // We don't need to do anything special to ensure its callbacks get // 1139 - // called, but we'll count it as a method which is preventing // 1140 - // reconnect quiescence. (eg, it might be a login method that was run // 1141 - // from onReconnect, and we don't want to see flicker by seeing a // 1142 - // logged-out state.) // 1143 - self._methodsBlockingQuiescence[invoker.methodId] = true; // 1144 - } // 1145 - }); // 1146 - } // 1147 - // 1148 - self._messagesBufferedUntilQuiescence = []; // 1149 - // 1150 - // If we're not waiting on any methods or subs, we can reset the stores and // 1151 - // call the callbacks immediately. // 1152 - if (!self._waitingForQuiescence()) { // 1153 - if (self._resetStores) { // 1154 - _.each(self._stores, function (s) { // 1155 - s.beginUpdate(0, true); // 1156 - s.endUpdate(); // 1157 - }); // 1158 - self._resetStores = false; // 1159 - } // 1160 - self._runAfterUpdateCallbacks(); // 1161 - } // 1162 - }, // 1163 - // 1164 - // 1165 - _processOneDataMessage: function (msg, updates) { // 1166 - var self = this; // 1167 - // Using underscore here so as not to need to capitalize. // 1168 - self['_process_' + msg.msg](msg, updates); // 1169 - }, // 1170 - // 1171 - // 1172 - _livedata_data: function (msg) { // 1173 - var self = this; // 1174 - // 1175 - // collection name -> array of messages // 1176 - var updates = {}; // 1177 - // 1178 - if (self._waitingForQuiescence()) { // 1179 - self._messagesBufferedUntilQuiescence.push(msg); // 1180 - // 1181 - if (msg.msg === "nosub") // 1182 - delete self._subsBeingRevived[msg.id]; // 1183 - // 1184 - _.each(msg.subs || [], function (subId) { // 1185 - delete self._subsBeingRevived[subId]; // 1186 - }); // 1187 - _.each(msg.methods || [], function (methodId) { // 1188 - delete self._methodsBlockingQuiescence[methodId]; // 1189 - }); // 1190 - // 1191 - if (self._waitingForQuiescence()) // 1192 - return; // 1193 - // 1194 - // No methods or subs are blocking quiescence! // 1195 - // We'll now process and all of our buffered messages, reset all stores, // 1196 - // and apply them all at once. // 1197 - _.each(self._messagesBufferedUntilQuiescence, function (bufferedMsg) { // 1198 - self._processOneDataMessage(bufferedMsg, updates); // 1199 - }); // 1200 - self._messagesBufferedUntilQuiescence = []; // 1201 - } else { // 1202 - self._processOneDataMessage(msg, updates); // 1203 - } // 1204 - // 1205 - if (self._resetStores || !_.isEmpty(updates)) { // 1206 - // Begin a transactional update of each store. // 1207 - _.each(self._stores, function (s, storeName) { // 1208 - s.beginUpdate(_.has(updates, storeName) ? updates[storeName].length : 0, // 1209 - self._resetStores); // 1210 - }); // 1211 - self._resetStores = false; // 1212 - // 1213 - _.each(updates, function (updateMessages, storeName) { // 1214 - var store = self._stores[storeName]; // 1215 - if (store) { // 1216 - _.each(updateMessages, function (updateMessage) { // 1217 - store.update(updateMessage); // 1218 - }); // 1219 - } else { // 1220 - // Nobody's listening for this data. Queue it up until // 1221 - // someone wants it. // 1222 - // XXX memory use will grow without bound if you forget to // 1223 - // create a collection or just don't care about it... going // 1224 - // to have to do something about that. // 1225 - if (!_.has(self._updatesForUnknownStores, storeName)) // 1226 - self._updatesForUnknownStores[storeName] = []; // 1227 - Array.prototype.push.apply(self._updatesForUnknownStores[storeName], // 1228 - updateMessages); // 1229 - } // 1230 - }); // 1231 - // 1232 - // End update transaction. // 1233 - _.each(self._stores, function (s) { s.endUpdate(); }); // 1234 - } // 1235 - // 1236 - self._runAfterUpdateCallbacks(); // 1237 - }, // 1238 - // 1239 - // Call any callbacks deferred with _runWhenAllServerDocsAreFlushed whose // 1240 - // relevant docs have been flushed, as well as dataVisible callbacks at // 1241 - // reconnect-quiescence time. // 1242 - _runAfterUpdateCallbacks: function () { // 1243 - var self = this; // 1244 - var callbacks = self._afterUpdateCallbacks; // 1245 - self._afterUpdateCallbacks = []; // 1246 - _.each(callbacks, function (c) { // 1247 - c(); // 1248 - }); // 1249 - }, // 1250 - // 1251 - _pushUpdate: function (updates, collection, msg) { // 1252 - var self = this; // 1253 - if (!_.has(updates, collection)) { // 1254 - updates[collection] = []; // 1255 - } // 1256 - updates[collection].push(msg); // 1257 - }, // 1258 - // 1259 - _getServerDoc: function (collection, id) { // 1260 - var self = this; // 1261 - if (!_.has(self._serverDocuments, collection)) // 1262 - return null; // 1263 - var serverDocsForCollection = self._serverDocuments[collection]; // 1264 - return serverDocsForCollection.get(id) || null; // 1265 - }, // 1266 - // 1267 - _process_added: function (msg, updates) { // 1268 - var self = this; // 1269 - var id = LocalCollection._idParse(msg.id); // 1270 - var serverDoc = self._getServerDoc(msg.collection, id); // 1271 - if (serverDoc) { // 1272 - // Some outstanding stub wrote here. // 1273 - if (serverDoc.document !== undefined) // 1274 - throw new Error("Server sent add for existing id: " + msg.id); // 1275 - serverDoc.document = msg.fields || {}; // 1276 - serverDoc.document._id = id; // 1277 - } else { // 1278 - self._pushUpdate(updates, msg.collection, msg); // 1279 - } // 1280 - }, // 1281 - // 1282 - _process_changed: function (msg, updates) { // 1283 - var self = this; // 1284 - var serverDoc = self._getServerDoc( // 1285 - msg.collection, LocalCollection._idParse(msg.id)); // 1286 - if (serverDoc) { // 1287 - if (serverDoc.document === undefined) // 1288 - throw new Error("Server sent changed for nonexisting id: " + msg.id); // 1289 - LocalCollection._applyChanges(serverDoc.document, msg.fields); // 1290 - } else { // 1291 - self._pushUpdate(updates, msg.collection, msg); // 1292 - } // 1293 - }, // 1294 - // 1295 - _process_removed: function (msg, updates) { // 1296 - var self = this; // 1297 - var serverDoc = self._getServerDoc( // 1298 - msg.collection, LocalCollection._idParse(msg.id)); // 1299 - if (serverDoc) { // 1300 - // Some outstanding stub wrote here. // 1301 - if (serverDoc.document === undefined) // 1302 - throw new Error("Server sent removed for nonexisting id:" + msg.id); // 1303 - serverDoc.document = undefined; // 1304 - } else { // 1305 - self._pushUpdate(updates, msg.collection, { // 1306 - msg: 'removed', // 1307 - collection: msg.collection, // 1308 - id: msg.id // 1309 - }); // 1310 - } // 1311 - }, // 1312 - // 1313 - _process_updated: function (msg, updates) { // 1314 - var self = this; // 1315 - // Process "method done" messages. // 1316 - _.each(msg.methods, function (methodId) { // 1317 - _.each(self._documentsWrittenByStub[methodId], function (written) { // 1318 - var serverDoc = self._getServerDoc(written.collection, written.id); // 1319 - if (!serverDoc) // 1320 - throw new Error("Lost serverDoc for " + JSON.stringify(written)); // 1321 - if (!serverDoc.writtenByStubs[methodId]) // 1322 - throw new Error("Doc " + JSON.stringify(written) + // 1323 - " not written by method " + methodId); // 1324 - delete serverDoc.writtenByStubs[methodId]; // 1325 - if (_.isEmpty(serverDoc.writtenByStubs)) { // 1326 - // All methods whose stubs wrote this method have completed! We can // 1327 - // now copy the saved document to the database (reverting the stub's // 1328 - // change if the server did not write to this object, or applying the // 1329 - // server's writes if it did). // 1330 - // 1331 - // This is a fake ddp 'replace' message. It's just for talking // 1332 - // between livedata connections and minimongo. (We have to stringify // 1333 - // the ID because it's supposed to look like a wire message.) // 1334 - self._pushUpdate(updates, written.collection, { // 1335 - msg: 'replace', // 1336 - id: LocalCollection._idStringify(written.id), // 1337 - replace: serverDoc.document // 1338 - }); // 1339 - // Call all flush callbacks. // 1340 - _.each(serverDoc.flushCallbacks, function (c) { // 1341 - c(); // 1342 - }); // 1343 - // 1344 - // Delete this completed serverDocument. Don't bother to GC empty // 1345 - // IdMaps inside self._serverDocuments, since there probably aren't // 1346 - // many collections and they'll be written repeatedly. // 1347 - self._serverDocuments[written.collection].remove(written.id); // 1348 - } // 1349 - }); // 1350 - delete self._documentsWrittenByStub[methodId]; // 1351 - // 1352 - // We want to call the data-written callback, but we can't do so until all // 1353 - // currently buffered messages are flushed. // 1354 - var callbackInvoker = self._methodInvokers[methodId]; // 1355 - if (!callbackInvoker) // 1356 - throw new Error("No callback invoker for method " + methodId); // 1357 - self._runWhenAllServerDocsAreFlushed( // 1358 - _.bind(callbackInvoker.dataVisible, callbackInvoker)); // 1359 - }); // 1360 - }, // 1361 - // 1362 - _process_ready: function (msg, updates) { // 1363 - var self = this; // 1364 - // Process "sub ready" messages. "sub ready" messages don't take effect // 1365 - // until all current server documents have been flushed to the local // 1366 - // database. We can use a write fence to implement this. // 1367 - _.each(msg.subs, function (subId) { // 1368 - self._runWhenAllServerDocsAreFlushed(function () { // 1369 - var subRecord = self._subscriptions[subId]; // 1370 - // Did we already unsubscribe? // 1371 - if (!subRecord) // 1372 - return; // 1373 - // Did we already receive a ready message? (Oops!) // 1374 - if (subRecord.ready) // 1375 - return; // 1376 - subRecord.readyCallback && subRecord.readyCallback(); // 1377 - subRecord.ready = true; // 1378 - subRecord.readyDeps.changed(); // 1379 - }); // 1380 - }); // 1381 - }, // 1382 - // 1383 - // Ensures that "f" will be called after all documents currently in // 1384 - // _serverDocuments have been written to the local cache. f will not be called // 1385 - // if the connection is lost before then! // 1386 - _runWhenAllServerDocsAreFlushed: function (f) { // 1387 - var self = this; // 1388 - var runFAfterUpdates = function () { // 1389 - self._afterUpdateCallbacks.push(f); // 1390 - }; // 1391 - var unflushedServerDocCount = 0; // 1392 - var onServerDocFlush = function () { // 1393 - --unflushedServerDocCount; // 1394 - if (unflushedServerDocCount === 0) { // 1395 - // This was the last doc to flush! Arrange to run f after the updates // 1396 - // have been applied. // 1397 - runFAfterUpdates(); // 1398 - } // 1399 - }; // 1400 - _.each(self._serverDocuments, function (collectionDocs) { // 1401 - collectionDocs.forEach(function (serverDoc) { // 1402 - var writtenByStubForAMethodWithSentMessage = _.any( // 1403 - serverDoc.writtenByStubs, function (dummy, methodId) { // 1404 - var invoker = self._methodInvokers[methodId]; // 1405 - return invoker && invoker.sentMessage; // 1406 - }); // 1407 - if (writtenByStubForAMethodWithSentMessage) { // 1408 - ++unflushedServerDocCount; // 1409 - serverDoc.flushCallbacks.push(onServerDocFlush); // 1410 - } // 1411 - }); // 1412 - }); // 1413 - if (unflushedServerDocCount === 0) { // 1414 - // There aren't any buffered docs --- we can call f as soon as the current // 1415 - // round of updates is applied! // 1416 - runFAfterUpdates(); // 1417 - } // 1418 - }, // 1419 - // 1420 - _livedata_nosub: function (msg) { // 1421 - var self = this; // 1422 - // 1423 - // First pass it through _livedata_data, which only uses it to help get // 1424 - // towards quiescence. // 1425 - self._livedata_data(msg); // 1426 - // 1427 - // Do the rest of our processing immediately, with no // 1428 - // buffering-until-quiescence. // 1429 - // 1430 - // we weren't subbed anyway, or we initiated the unsub. // 1431 - if (!_.has(self._subscriptions, msg.id)) // 1432 - return; // 1433 - // 1434 - // XXX COMPAT WITH 1.0.3.1 #errorCallback // 1435 - var errorCallback = self._subscriptions[msg.id].errorCallback; // 1436 - var stopCallback = self._subscriptions[msg.id].stopCallback; // 1437 - // 1438 - self._subscriptions[msg.id].remove(); // 1439 - // 1440 - var meteorErrorFromMsg = function (msgArg) { // 1441 - return msgArg && msgArg.error && new Meteor.Error( // 1442 - msgArg.error.error, msgArg.error.reason, msgArg.error.details); // 1443 - } // 1444 - // 1445 - // XXX COMPAT WITH 1.0.3.1 #errorCallback // 1446 - if (errorCallback && msg.error) { // 1447 - errorCallback(meteorErrorFromMsg(msg)); // 1448 - } // 1449 - // 1450 - if (stopCallback) { // 1451 - stopCallback(meteorErrorFromMsg(msg)); // 1452 - } // 1453 - }, // 1454 - // 1455 - _process_nosub: function () { // 1456 - // This is called as part of the "buffer until quiescence" process, but // 1457 - // nosub's effect is always immediate. It only goes in the buffer at all // 1458 - // because it's possible for a nosub to be the thing that triggers // 1459 - // quiescence, if we were waiting for a sub to be revived and it dies // 1460 - // instead. // 1461 - }, // 1462 - // 1463 - _livedata_result: function (msg) { // 1464 - // id, result or error. error has error (code), reason, details // 1465 - // 1466 - var self = this; // 1467 - // 1468 - // find the outstanding request // 1469 - // should be O(1) in nearly all realistic use cases // 1470 - if (_.isEmpty(self._outstandingMethodBlocks)) { // 1471 - Meteor._debug("Received method result but no methods outstanding"); // 1472 - return; // 1473 - } // 1474 - var currentMethodBlock = self._outstandingMethodBlocks[0].methods; // 1475 - var m; // 1476 - for (var i = 0; i < currentMethodBlock.length; i++) { // 1477 - m = currentMethodBlock[i]; // 1478 - if (m.methodId === msg.id) // 1479 - break; // 1480 - } // 1481 - // 1482 - if (!m) { // 1483 - Meteor._debug("Can't match method response to original method call", msg); // 1484 - return; // 1485 - } // 1486 - // 1487 - // Remove from current method block. This may leave the block empty, but we // 1488 - // don't move on to the next block until the callback has been delivered, in // 1489 - // _outstandingMethodFinished. // 1490 - currentMethodBlock.splice(i, 1); // 1491 - // 1492 - if (_.has(msg, 'error')) { // 1493 - m.receiveResult(new Meteor.Error( // 1494 - msg.error.error, msg.error.reason, // 1495 - msg.error.details)); // 1496 - } else { // 1497 - // msg.result may be undefined if the method didn't return a // 1498 - // value // 1499 - m.receiveResult(undefined, msg.result); // 1500 - } // 1501 - }, // 1502 - // 1503 - // Called by MethodInvoker after a method's callback is invoked. If this was // 1504 - // the last outstanding method in the current block, runs the next block. If // 1505 - // there are no more methods, consider accepting a hot code push. // 1506 - _outstandingMethodFinished: function () { // 1507 - var self = this; // 1508 - if (self._anyMethodsAreOutstanding()) // 1509 - return; // 1510 - // 1511 - // No methods are outstanding. This should mean that the first block of // 1512 - // methods is empty. (Or it might not exist, if this was a method that // 1513 - // half-finished before disconnect/reconnect.) // 1514 - if (! _.isEmpty(self._outstandingMethodBlocks)) { // 1515 - var firstBlock = self._outstandingMethodBlocks.shift(); // 1516 - if (! _.isEmpty(firstBlock.methods)) // 1517 - throw new Error("No methods outstanding but nonempty block: " + // 1518 - JSON.stringify(firstBlock)); // 1519 - // 1520 - // Send the outstanding methods now in the first block. // 1521 - if (!_.isEmpty(self._outstandingMethodBlocks)) // 1522 - self._sendOutstandingMethods(); // 1523 - } // 1524 - // 1525 - // Maybe accept a hot code push. // 1526 - self._maybeMigrate(); // 1527 - }, // 1528 - // 1529 - // Sends messages for all the methods in the first block in // 1530 - // _outstandingMethodBlocks. // 1531 - _sendOutstandingMethods: function() { // 1532 - var self = this; // 1533 - if (_.isEmpty(self._outstandingMethodBlocks)) // 1534 - return; // 1535 - _.each(self._outstandingMethodBlocks[0].methods, function (m) { // 1536 - m.sendMessage(); // 1537 - }); // 1538 - }, // 1539 - // 1540 - _livedata_error: function (msg) { // 1541 - Meteor._debug("Received error from server: ", msg.reason); // 1542 - if (msg.offendingMessage) // 1543 - Meteor._debug("For: ", msg.offendingMessage); // 1544 - }, // 1545 - // 1546 - _callOnReconnectAndSendAppropriateOutstandingMethods: function() { // 1547 - var self = this; // 1548 - var oldOutstandingMethodBlocks = self._outstandingMethodBlocks; // 1549 - self._outstandingMethodBlocks = []; // 1550 - // 1551 - self.onReconnect(); // 1552 - // 1553 - if (_.isEmpty(oldOutstandingMethodBlocks)) // 1554 - return; // 1555 - // 1556 - // We have at least one block worth of old outstanding methods to try // 1557 - // again. First: did onReconnect actually send anything? If not, we just // 1558 - // restore all outstanding methods and run the first block. // 1559 - if (_.isEmpty(self._outstandingMethodBlocks)) { // 1560 - self._outstandingMethodBlocks = oldOutstandingMethodBlocks; // 1561 - self._sendOutstandingMethods(); // 1562 - return; // 1563 - } // 1564 - // 1565 - // OK, there are blocks on both sides. Special case: merge the last block of // 1566 - // the reconnect methods with the first block of the original methods, if // 1567 - // neither of them are "wait" blocks. // 1568 - if (!_.last(self._outstandingMethodBlocks).wait && // 1569 - !oldOutstandingMethodBlocks[0].wait) { // 1570 - _.each(oldOutstandingMethodBlocks[0].methods, function (m) { // 1571 - _.last(self._outstandingMethodBlocks).methods.push(m); // 1572 - // 1573 - // If this "last block" is also the first block, send the message. // 1574 - if (self._outstandingMethodBlocks.length === 1) // 1575 - m.sendMessage(); // 1576 - }); // 1577 - // 1578 - oldOutstandingMethodBlocks.shift(); // 1579 - } // 1580 - // 1581 - // Now add the rest of the original blocks on. // 1582 - _.each(oldOutstandingMethodBlocks, function (block) { // 1583 - self._outstandingMethodBlocks.push(block); // 1584 - }); // 1585 - }, // 1586 - // 1587 - // We can accept a hot code push if there are no methods in flight. // 1588 - _readyToMigrate: function() { // 1589 - var self = this; // 1590 - return _.isEmpty(self._methodInvokers); // 1591 - }, // 1592 - // 1593 - // If we were blocking a migration, see if it's now possible to continue. // 1594 - // Call whenever the set of outstanding/blocked methods shrinks. // 1595 - _maybeMigrate: function () { // 1596 - var self = this; // 1597 - if (self._retryMigrate && self._readyToMigrate()) { // 1598 - self._retryMigrate(); // 1599 - self._retryMigrate = null; // 1600 - } // 1601 - } // 1602 -}); // 1603 - // 1604 -LivedataTest.Connection = Connection; // 1605 - // 1606 -// @param url {String} URL to Meteor app, // 1607 -// e.g.: // 1608 -// "subdomain.meteor.com", // 1609 -// "http://subdomain.meteor.com", // 1610 -// "/", // 1611 -// "ddp+sockjs://ddp--****-foo.meteor.com/sockjs" // 1612 - // 1613 -/** // 1614 - * @summary Connect to the server of a different Meteor application to subscribe to its document sets and invoke its remote methods. - * @locus Anywhere // 1616 - * @param {String} url The URL of another Meteor application. // 1617 - */ // 1618 -DDP.connect = function (url, options) { // 1619 - var ret = new Connection(url, options); // 1620 - allConnections.push(ret); // hack. see below. // 1621 - return ret; // 1622 -}; // 1623 - // 1624 -// Hack for `spiderable` package: a way to see if the page is done // 1625 -// loading all the data it needs. // 1626 -// // 1627 -allConnections = []; // 1628 -DDP._allSubscriptionsReady = function () { // 1629 - return _.all(allConnections, function (conn) { // 1630 - return _.all(conn._subscriptions, function (sub) { // 1631 - return sub.ready; // 1632 - }); // 1633 - }); // 1634 -}; // 1635 - // 1636 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ddp/server_convenience.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Only create a server if we are in an environment with a HTTP server // 1 -// (as opposed to, eg, a command-line tool). // 2 -// // 3 -// Note: this whole conditional is a total hack to get around the fact that this // 4 -// package logically should be split into a ddp-client and ddp-server package; // 5 -// see https://github.com/meteor/meteor/issues/3452 // 6 -// // 7 -// Until we do that, this conditional (and the weak dependency on webapp that // 8 -// should really be a strong dependency of the ddp-server package) allows you to // 9 -// build projects which use `ddp` in Node without wanting to run a DDP server // 10 -// (ie, allows you to act as if you were using the nonexistent `ddp-client` // 11 -// server package). // 12 -if (Package.webapp) { // 13 - if (process.env.DDP_DEFAULT_CONNECTION_URL) { // 14 - __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL = // 15 - process.env.DDP_DEFAULT_CONNECTION_URL; // 16 - } // 17 - // 18 - Meteor.server = new Server; // 19 - // 20 - Meteor.refresh = function (notification) { // 21 - DDPServer._InvalidationCrossbar.fire(notification); // 22 - }; // 23 - // 24 - // Proxy the public methods of Meteor.server so they can // 25 - // be called directly on Meteor. // 26 - _.each(['publish', 'methods', 'call', 'apply', 'onConnection'], // 27 - function (name) { // 28 - Meteor[name] = _.bind(Meteor.server[name], Meteor.server); // 29 - }); // 30 -} else { // 31 - // No server? Make these empty/no-ops. // 32 - Meteor.server = null; // 33 - Meteor.refresh = function (notification) { // 34 - }; // 35 - // 36 - // Make these empty/no-ops too, so that non-webapp apps can still // 37 - // depend on/use packages that use those functions. // 38 - _.each(['publish', 'methods', 'onConnection'], // 39 - function (name) { // 40 - Meteor[name] = function () { }; // 41 - }); // 42 -} // 43 - // 44 -// Meteor.server used to be called Meteor.default_server. Provide // 45 -// backcompat as a courtesy even though it was never documented. // 46 -// XXX COMPAT WITH 0.6.4 // 47 -Meteor.default_server = Meteor.server; // 48 - // 49 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.ddp = { - DDP: DDP, - DDPServer: DDPServer, - LivedataTest: LivedataTest -}; - -})(); - -//# sourceMappingURL=ddp.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/ddp.js.map b/web-app/.meteor/local/build/programs/server/packages/ddp.js.map deleted file mode 100644 index fd1aa1e..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ddp.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["ddp/common.js","ddp/stream_client_nodejs.js","ddp/stream_client_common.js","ddp/stream_server.js","ddp/heartbeat.js","ddp/livedata_server.js","ddp/writefence.js","ddp/crossbar.js","ddp/livedata_common.js","ddp/random_stream.js","ddp/livedata_connection.js","ddp/server_convenience.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,G;AACA,iB;AACA,kD;AACA,G;AACA,S;AACA,kB;;;;;;;;;;;;;;;;;;;ACLA,6C;AACA,6C;AACA,4C;AACA,E;AACA,6E;AACA,gF;AACA,kB;AACA,E;AACA,gF;AACA,6E;AACA,2C;AACA,0D;AACA,kB;AACA,0B;;AAEA,2B;AACA,e;AACA,c;;AAEA,sD;AACA,2B;;AAEA,4C;;AAEA,iC;;AAEA,e;AACA,2B;AACA,E;;AAEA,+C;;AAEA,uE;AACA,oE;AACA,wB;AACA,yB;AACA,oB;AACA,uC;AACA,6B;AACA,K;AACA,I;;AAEA,yC;AACA,8B;AACA,oB;AACA,wB;AACA,I;;AAEA,iC;AACA,oB;;AAEA,iC;AACA,wE;AACA,gF;AACA,0E;AACA,sB;AACA,wE;AACA,K;;AAEA,mC;AACA,8E;AACA,qE;AACA,0B;AACA,yB;AACA,a;AACA,K;;AAEA,uC;AACA,yE;AACA,uE;AACA,gF;AACA,gF;AACA,sC;AACA,mD;AACA,K;;AAEA,iC;;AAEA,oB;AACA,4C;AACA,wC;AACA,sC;AACA,yB;;AAEA,sE;AACA,kD;AACA,2E;AACA,I;;AAEA,mC;AACA,oB;;AAEA,iC;AACA,sB;AACA,+B;AACA,yB;AACA,qB;;AAEA,kE;AACA,6B;AACA,S;AACA,K;AACA,I;;AAEA,sC;AACA,oB;;AAEA,+B;AACA,yC;AACA,kC;AACA,K;AACA,I;;AAEA,sC;AACA,oB;AACA,gD;AACA,yE;AACA,8E;AACA,mC;AACA,0E;AACA,K;AACA,iB;AACA,I;;AAEA,kC;AACA,oB;AACA,iE;;AAEA,2E;AACA,kE;AACA,kB;AACA,sD;;AAEA,kD;AACA,gD;AACA,gD;AACA,mB;AACA,+C;AACA,M;;AAEA,gF;AACA,uE;AACA,6E;AACA,6E;AACA,yE;AACA,0B;;AAEA,wD;AACA,4C;;AAEA,iC;AACA,6C;AACA,mB;AACA,6B;AACA,+D;AACA,Q;AACA,4B;;AAEA,+D;AACA,qC;AACA,mC;;AAEA,8D;AACA,gE;AACA,sE;AACA,mC;AACA,iB;AACA,iC;AACA,uB;AACA,M;;AAEA,0E;AACA,yC;AACA,qD;;AAEA,yE;AACA,oD;AACA,mE;AACA,O;;;AAGA,qE;AACA,6B;AACA,O;;;AAGA,gF;AACA,6D;AACA,2C;AACA,e;;AAEA,+D;AACA,+B;AACA,S;AACA,O;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACpMA,0E;AACA,wC;AACA,uC;AACA,+C;AACA,E;AACA,oC;AACA,qC;AACA,qD;AACA,E;;AAEA,6C;AACA,6D;AACA,sD;AACA,mF;AACA,yC;AACA,sD;AACA,iD;AACA,2D;AACA,wB;AACA,2B;AACA,G;;AAEA,uD;AACA,iD;AACA,gB;AACA,oB;AACA,4C;AACA,wD;AACA,6E;AACA,4C;AACA,c;AACA,0E;AACA,mE;;AAEA,0E;AACA,4E;AACA,wD;AACA,4C;AACA,8C;AACA,O;;AAEA,2C;AACA,4B;AACA,uE;AACA,0D;AACA,2C;AACA,G;;AAEA,uC;AACA,2D;AACA,sC;AACA,G;;AAEA,8D;AACA,sE;AACA,kE;AACA,sE;AACA,+B;AACA,I;AACA,kE;AACA,sE;AACA,iE;AACA,uE;AACA,2C;;AAEA,yB;AACA,yB;AACA,M;AACA,+B;AACA,E;;AAEA,8B;AACA,6C;AACA,E;;AAEA,iC;AACA,iD;AACA,a;AACA,E;;AAEA,uC;;;AAGA,+C;;AAEA,4B;AACA,iC;AACA,oB;;AAEA,wE;AACA,qD;;AAEA,mC;AACA,qC;AACA,6C;AACA,I;;;AAGA,mC;AACA,oB;AACA,4B;;AAEA,kB;;AAEA,+D;AACA,c;AACA,6D;;AAEA,mD;;AAEA,qC;;AAEA,wB;AACA,0B;AACA,2B;AACA,uB;AACA,mB;AACA,M;;;AAGA,oF;AACA,sC;AACA,+B;AACA,uC;AACA,M;;AAEA,oB;AACA,4B;AACA,gC;;AAEA,I;;AAEA,yB;AACA,iC;AACA,oB;AACA,4B;;AAEA,sB;AACA,mC;AACA,K;;AAEA,iC;AACA,2D;AACA,K;;AAEA,uC;AACA,0C;AACA,2B;AACA,2D;AACA,sB;AACA,a;AACA,K;;AAEA,wC;AACA,qD;AACA,oC;AACA,6B;AACA,K;;AAEA,wB;AACA,qE;AACA,qB;AACA,I;;AAEA,kC;AACA,oB;AACA,4B;;AAEA,qE;AACA,uD;AACA,iC;AACA,a;;AAEA,2E;AACA,mE;AACA,mE;AACA,6B;AACA,6B;AACA,sC;AACA,K;;AAEA,oB;AACA,wB;;AAEA,0B;AACA,0D;AACA,uB;AACA,mB;AACA,M;;AAEA,6C;AACA,iD;;AAEA,yB;AACA,I;;AAEA,gE;AACA,0C;AACA,oB;;AAEA,8B;AACA,wE;AACA,I;;AAEA,kE;AACA,iB;AACA,wB;AACA,0E;AACA,+C;AACA,uB;AACA,I;;AAEA,sC;AACA,oB;;AAEA,oB;AACA,6B;AACA,8E;AACA,uC;AACA,sC;AACA,oC;AACA,Q;AACA,4C;AACA,sE;AACA,Y;AACA,2C;AACA,0C;AACA,K;;AAEA,yC;AACA,yB;AACA,I;;AAEA,0B;AACA,oB;;AAEA,iC;AACA,a;;AAEA,uC;AACA,6C;AACA,yC;AACA,wC;AACA,yB;;AAEA,6B;AACA,I;;;AAGA,kC;AACA,uB;AACA,oB;AACA,6B;AACA,oC;AACA,8B;AACA,G;AACA,G;;AAEA,2C;AACA,6C;AACA,oB;AACA,2B;AACA,G;;AAEA,gD;AACA,8C;;;;;;;;;;;;;;;;;;;ACzQA,6B;;AAEA,uE;;AAEA,4B;AACA,kB;AACA,mC;AACA,yB;;AAEA,+E;AACA,8D;AACA,uC;AACA,6E;AACA,iD;AACA,4B;AACA,0E;AACA,G;;AAEA,kB;AACA,qC;AACA,uB;AACA,wB;AACA,uB;AACA,uE;AACA,+C;AACA,2B;AACA,+E;AACA,0E;AACA,6E;AACA,4E;AACA,+E;AACA,8D;AACA,gC;AACA,wE;AACA,oE;AACA,wB;AACA,4C;AACA,I;;AAEA,8E;AACA,uE;AACA,0D;AACA,yD;AACA,qC;AACA,oC;;AAEA,mD;AACA,wB;AACA,6E;AACA,G;AACA,+E;AACA,4E;AACA,8E;AACA,kC;AACA,sH;AACA,gE;AACA,mH;;AAEA,oC;AACA,oC;;AAEA,kD;AACA,mC;AACA,yB;AACA,M;AACA,oC;AACA,+D;AACA,O;AACA,mC;;AAEA,uE;AACA,mE;AACA,uE;AACA,uE;AACA,+B;AACA,kD;;AAEA,wE;AACA,kE;AACA,6D;AACA,uB;AACA,O;AACA,K;;AAEA,E;;AAEA,kC;AACA,iD;AACA,8C;AACA,iC;AACA,oB;AACA,+C;AACA,kD;AACA,uB;AACA,O;AACA,I;;AAEA,8B;AACA,4B;AACA,oB;AACA,uC;AACA,I;;AAEA,oE;AACA,sD;AACA,0C;AACA,oB;AACA,iE;AACA,6D;AACA,oE;AACA,oD;AACA,2G;AACA,oD;AACA,wD;AACA,wE;AACA,2C;;AAEA,gE;AACA,iE;AACA,gE;AACA,2D;AACA,6B;;AAEA,6E;AACA,mC;AACA,+C;AACA,+D;AACA,gE;AACA,0D;AACA,8C;AACA,S;AACA,8D;AACA,8C;AACA,W;AACA,Q;AACA,iD;AACA,O;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;AC1IA,qB;AACA,gE;AACA,uE;AACA,iC;AACA,iE;AACA,yD;;AAEA,gC;AACA,kB;;AAEA,qD;AACA,mD;AACA,oC;AACA,sC;;AAEA,uC;AACA,sC;AACA,E;;AAEA,+B;AACA,qB;AACA,oB;AACA,wC;AACA,uC;AACA,I;;AAEA,sB;AACA,oB;AACA,gB;AACA,wC;AACA,I;;AAEA,6C;AACA,oB;AACA,sD;AACA,iD;AACA,4B;AACA,M;AACA,I;;AAEA,4C;AACA,oB;AACA,qD;AACA,gD;AACA,2B;AACA,M;AACA,I;;AAEA,6C;AACA,oB;AACA,wC;AACA,yD;AACA,2C;AACA,K;AACA,I;;AAEA,4C;AACA,oB;AACA,uC;AACA,wD;AACA,0C;AACA,K;AACA,I;;AAEA,sE;AACA,wC;AACA,oB;AACA,yC;AACA,qB;AACA,uB;AACA,uC;AACA,I;;AAEA,qE;AACA,oC;AACA,uC;AACA,oB;AACA,wC;AACA,sB;AACA,I;;AAEA,6B;AACA,oB;AACA,kE;AACA,sE;AACA,wC;AACA,0C;AACA,0C;AACA,K;AACA,I;;AAEA,6B;AACA,oB;;AAEA,oE;AACA,0C;AACA,uC;AACA,yC;AACA,0C;AACA,K;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACrGA,e;;AAEA,kC;;AAEA,8B;AACA,6D;AACA,6D;AACA,2E;AACA,E;AACA,oE;AACA,qE;AACA,a;;AAEA,0D;AACA,uC;AACA,kB;AACA,kD;AACA,4E;AACA,E;;AAEA,yC;;AAEA,0B;AACA,oB;AACA,iB;AACA,2D;AACA,yC;AACA,O;AACA,e;AACA,I;;AAEA,mE;AACA,oB;AACA,mD;AACA,sB;AACA,a;AACA,6C;;AAEA,oE;AACA,gB;AACA,wB;AACA,a;;AAEA,iC;AACA,qD;AACA,yC;AACA,iE;AACA,gF;AACA,mC;AACA,oB;AACA,0C;AACA,oC;AACA,c;AACA,O;AACA,K;AACA,oC;AACA,iC;AACA,uC;AACA,4C;AACA,sE;AACA,qD;AACA,K;AACA,I;;AAEA,wD;AACA,kD;AACA,oB;AACA,mD;AACA,sB;AACA,a;;AAEA,6D;AACA,+B;;AAEA,sC;AACA,qE;AACA,6C;AACA,mC;AACA,a;AACA,K;AACA,6C;AACA,Y;AACA,iB;AACA,0D;AACA,oE;AACA,S;AACA,K;;AAEA,c;AACA,yE;AACA,iE;AACA,qC;AACA,O;AACA,wB;AACA,Y;AACA,2D;AACA,kF;AACA,K;;AAEA,G;AACA,G;;AAEA,G;AACA,oD;AACA,sE;AACA,gG;AACA,+B;AACA,G;AACA,yE;AACA,kB;AACA,uC;AACA,sB;AACA,oC;AACA,E;;AAEA,2D;;;AAGA,2C;;AAEA,wB;AACA,oB;AACA,qC;AACA,I;;AAEA,6B;AACA,oB;AACA,sE;AACA,4C;;AAEA,uC;AACA,yE;AACA,Q;;AAEA,uC;AACA,wD;AACA,O;AACA,O;AACA,I;;AAEA,8C;AACA,oB;AACA,oB;AACA,yE;AACA,uC;AACA,qC;AACA,4B;AACA,Q;AACA,sC;AACA,0B;AACA,Q;AACA,qC;AACA,gC;AACA,O;AACA,O;AACA,4D;AACA,I;;AAEA,oD;AACA,oB;AACA,qC;AACA,sB;AACA,mB;AACA,mB;AACA,0C;AACA,mC;AACA,K;AACA,gD;AACA,6B;AACA,0C;AACA,0B;AACA,+D;AACA,O;AACA,c;AACA,qE;AACA,Q;AACA,uE;AACA,I;;AAEA,uD;AACA,oB;AACA,2B;AACA,qC;AACA,iB;AACA,6E;AACA,2C;AACA,8B;AACA,mE;AACA,U;AACA,2E;AACA,O;AACA,mE;AACA,I;;AAEA,8C;AACA,oB;AACA,qC;AACA,mB;AACA,gE;AACA,gB;AACA,K;AACA,gD;AACA,sC;AACA,iC;AACA,sD;AACA,gC;AACA,Y;AACA,uB;AACA,4D;AACA,+B;AACA,gE;AACA,6D;AACA,S;;AAEA,+D;AACA,K;AACA,G;AACA,G;;AAEA,gF;AACA,gF;AACA,gF;;AAEA,2D;AACA,kB;AACA,wB;;AAEA,uB;AACA,yB;;AAEA,2B;AACA,uB;;AAEA,qE;AACA,0D;AACA,gD;;AAEA,uB;AACA,6B;;AAEA,yC;AACA,uB;AACA,2B;;AAEA,qB;;AAEA,4B;;AAEA,oE;AACA,gF;AACA,uC;AACA,yB;;AAEA,6E;AACA,yE;AACA,0C;;AAEA,4D;AACA,sE;AACA,0B;;AAEA,8D;AACA,4B;;;AAGA,gE;AACA,mD;AACA,+B;;AAEA,gD;AACA,gD;;AAEA,sE;AACA,sE;AACA,6C;AACA,2B;AACA,gB;AACA,wB;AACA,mB;AACA,M;AACA,4B;AACA,yE;AACA,yB;AACA,sC;AACA,c;AACA,sD;AACA,yB;AACA,O;AACA,M;AACA,yC;AACA,oC;AACA,I;;AAEA,6C;AACA,gD;AACA,8D;AACA,qB;AACA,8B;AACA,W;;AAEA,8D;AACA,oC;AACA,mD;AACA,iD;AACA,8B;AACA,qB;AACA,Q;AACA,6B;AACA,iC;AACA,O;AACA,O;AACA,2B;AACA,G;;AAEA,2D;AACA,+B;AACA,E;;AAEA,6B;;AAEA,yC;AACA,oB;AACA,wB;AACA,uD;AACA,U;AACA,yD;AACA,gD;AACA,S;AACA,K;AACA,I;;AAEA,oD;AACA,oB;AACA,wB;AACA,oF;AACA,I;;AAEA,sD;AACA,oB;AACA,0B;AACA,a;;AAEA,0B;AACA,iB;AACA,uB;AACA,mC;AACA,e;AACA,sB;AACA,S;AACA,K;AACA,I;;AAEA,8C;AACA,oB;AACA,wB;AACA,sE;AACA,I;;AAEA,iC;AACA,oB;AACA,Y;AACA,0C;AACA,8C;AACA,6C;AACA,M;AACA,I;;AAEA,gD;AACA,oB;AACA,sD;AACA,kD;AACA,K;AACA,uD;AACA,iE;AACA,+C;AACA,e;AACA,I;;AAEA,oE;AACA,oB;AACA,sD;AACA,+C;AACA,I;;AAEA,8D;AACA,oB;AACA,sD;AACA,yC;AACA,yB;AACA,kD;AACA,K;AACA,I;;AAEA,sE;AACA,oB;AACA,sD;AACA,iD;AACA,I;;AAEA,mC;AACA,oB;AACA,8E;AACA,6E;AACA,qE;AACA,mE;AACA,yC;AACA,uC;AACA,O;AACA,I;;AAEA,0D;AACA,sB;AACA,oB;;AAEA,+D;AACA,wE;AACA,8B;;AAEA,yB;AACA,uB;AACA,a;;AAEA,2C;AACA,wB;AACA,8B;;AAEA,yB;AACA,4B;AACA,4B;AACA,K;;AAEA,sB;AACA,0B;AACA,wC;AACA,K;;AAEA,6D;AACA,kC;;AAEA,8B;AACA,6D;AACA,qE;AACA,gF;AACA,yC;;AAEA,sE;AACA,qE;AACA,wD;AACA,mB;AACA,S;AACA,O;;AAEA,8B;AACA,qC;AACA,I;;AAEA,wE;AACA,yD;AACA,wB;AACA,oB;AACA,sB;AACA,+B;AACA,qD;AACA,0C;AACA,K;AACA,I;;AAEA,6B;AACA,kD;AACA,oB;AACA,6C;AACA,yB;AACA,8C;AACA,mB;AACA,I;;AAEA,kE;AACA,+D;AACA,qD;AACA,I;AACA,oE;AACA,qE;AACA,oE;AACA,sE;AACA,mE;AACA,qB;AACA,I;AACA,oE;AACA,oE;AACA,oE;AACA,Y;AACA,qC;AACA,oB;AACA,iD;AACA,a;;AAEA,qE;AACA,mE;AACA,oE;AACA,yC;AACA,M;AACA,wE;AACA,wE;AACA,qE;AACA,gD;AACA,2D;AACA,+B;AACA,gD;AACA,yB;AACA,2B;AACA,wC;AACA,iB;AACA,a;AACA,K;AACA,2D;AACA,yB;AACA,2B;AACA,wC;AACA,iB;AACA,a;AACA,K;;AAEA,8B;AACA,2B;AACA,a;AACA,8B;;AAEA,mC;AACA,qD;AACA,iB;AACA,mC;AACA,e;AACA,O;;AAEA,yB;AACA,2B;;AAEA,mC;AACA,uB;AACA,iC;AACA,0B;AACA,wB;AACA,U;;AAEA,mD;AACA,mE;AACA,Y;AACA,6C;AACA,8D;AACA,e;AACA,M;;AAEA,kB;AACA,I;;AAEA,sB;AACA,yB;AACA,sB;;AAEA,kC;AACA,yC;AACA,2C;AACA,kE;AACA,sD;AACA,e;AACA,O;;AAEA,oD;AACA,mB;AACA,mC;AACA,mE;AACA,e;AACA,O;;AAEA,yC;AACA,oE;AACA,gE;AACA,qB;AACA,e;;AAEA,2D;AACA,qE;;AAEA,M;;AAEA,2B;AACA,sB;;AAEA,qC;AACA,M;;AAEA,qC;AACA,sB;;AAEA,kC;AACA,wD;AACA,oC;AACA,yC;AACA,6C;AACA,kE;AACA,4E;AACA,2D;AACA,e;AACA,O;;AAEA,8C;;AAEA,kE;AACA,iE;AACA,c;AACA,4C;AACA,wC;AACA,8D;AACA,gE;AACA,6D;AACA,4D;AACA,gD;AACA,uB;AACA,mB;AACA,8C;AACA,S;;AAEA,yB;AACA,4D;AACA,qB;AACA,mB;AACA,oC;AACA,6D;AACA,oB;AACA,e;AACA,O;;AAEA,wC;AACA,gC;AACA,Q;;AAEA,6C;AACA,4B;AACA,4B;AACA,6B;AACA,yB;AACA,0C;AACA,8B;AACA,S;AACA,W;AACA,gF;AACA,2E;AACA,4C;AACA,+E;AACA,a;AACA,W;AACA,mB;AACA,0B;AACA,O;;AAEA,2D;AACA,iE;;AAEA,wC;AACA,iE;;AAEA,uC;AACA,mB;AACA,gE;AACA,iE;AACA,gE;AACA,K;AACA,I;;AAEA,0B;AACA,oB;AACA,+B;AACA,mC;AACA,I;;AAEA,8C;AACA,oB;AACA,mE;AACA,8D;AACA,mC;AACA,Q;AACA,wD;AACA,6D;AACA,kE;AACA,W;AACA,Q;AACA,sD;AACA,wD;AACA,+C;AACA,W;AACA,O;AACA,O;AACA,I;;AAEA,oE;AACA,sB;AACA,gC;AACA,oB;;AAEA,sD;AACA,0E;AACA,qC;;AAEA,4E;AACA,yE;AACA,M;AACA,6E;AACA,0E;AACA,8E;AACA,+E;AACA,+B;AACA,2C;;AAEA,4E;AACA,sC;AACA,kC;AACA,wB;AACA,O;;AAEA,+E;AACA,+E;AACA,yB;AACA,4B;AACA,yC;AACA,8B;AACA,yB;;AAEA,qE;AACA,uC;AACA,yB;AACA,6B;;AAEA,yD;AACA,wD;AACA,yE;AACA,0D;AACA,oD;AACA,O;;AAEA,4E;AACA,2E;AACA,Y;AACA,4C;AACA,8B;;AAEA,8E;AACA,4E;AACA,0D;AACA,yC;AACA,6B;AACA,2C;AACA,2C;AACA,2C;AACA,gC;AACA,O;AACA,O;AACA,I;;AAEA,+D;AACA,oB;;AAEA,+B;AACA,0C;AACA,c;AACA,mC;AACA,Q;AACA,oC;;AAEA,sB;AACA,I;;AAEA,qC;AACA,8C;AACA,oB;;AAEA,uB;;AAEA,0C;AACA,6C;AACA,mD;AACA,2C;AACA,oC;AACA,K;;AAEA,6C;;AAEA,gB;AACA,6C;AACA,c;AACA,0D;AACA,sC;AACA,K;;AAEA,wB;AACA,I;;AAEA,+E;AACA,kD;AACA,4C;AACA,oB;;AAEA,gD;AACA,wB;AACA,O;AACA,yB;;AAEA,gD;AACA,wB;AACA,O;AACA,6B;AACA,I;;AAEA,2D;AACA,oE;AACA,kC;AACA,+B;AACA,oB;;AAEA,sE;AACA,kE;AACA,kE;AACA,sE;AACA,kC;AACA,M;AACA,oE;AACA,gF;;AAEA,iC;AACA,uC;;AAEA,8D;AACA,mC;AACA,kB;AACA,wD;;AAEA,mE;AACA,oE;AACA,oE;AACA,qE;AACA,kE;AACA,qE;AACA,kE;AACA,qC;;AAEA,2E;AACA,kB;;AAEA,kE;AACA,G;AACA,G;;AAEA,gF;AACA,gF;AACA,gF;;AAEA,4D;;AAEA,0E;AACA,U;AACA,G;AACA,+C;AACA,sB;AACA,qB;AACA,G;AACA,6B;AACA,qD;AACA,kB;AACA,6C;;AAEA,K;AACA,wH;AACA,kB;AACA,sB;AACA,2B;AACA,c;AACA,K;AACA,kE;;AAEA,0B;;AAEA,4E;AACA,wC;AACA,iC;AACA,oB;;AAEA,8B;;AAEA,uE;AACA,yD;AACA,mE;AACA,6B;AACA,0D;AACA,U;AACA,iD;AACA,G;;AAEA,iC;AACA,4B;;AAEA,+D;AACA,2B;;AAEA,mE;AACA,qB;AACA,uB;;AAEA,8B;AACA,sB;;AAEA,kD;;AAEA,K;AACA,kH;AACA,kB;AACA,2B;AACA,kB;AACA,c;AACA,K;AACA,+B;;AAEA,kD;AACA,mD;AACA,sD;;AAEA,kD;AACA,sD;AACA,wD;AACA,wC;;AAEA,oB;AACA,8C;AACA,qC;AACA,I;;AAEA,2D;AACA,oC;AACA,E;;AAEA,kC;AACA,4B;AACA,sE;AACA,kD;AACA,M;AACA,uE;AACA,wE;AACA,iE;;AAEA,oB;AACA,S;AACA,yC;AACA,uD;AACA,0E;AACA,kE;AACA,yC;AACA,0C;AACA,iB;AACA,oB;AACA,a;AACA,K;;AAEA,oD;AACA,8B;AACA,a;;AAEA,uE;AACA,0E;AACA,0E;AACA,gF;AACA,+D;AACA,M;AACA,0E;AACA,8E;AACA,8E;AACA,6C;AACA,iE;AACA,6C;AACA,4C;AACA,wC;AACA,c;AACA,W;AACA,iC;AACA,mC;AACA,M;AACA,wB;AACA,W;AACA,iC;AACA,mB;AACA,sB;AACA,e;AACA,O;AACA,gF;AACA,oC;AACA,mB;AACA,gC;AACA,2C;AACA,mC;AACA,mF;AACA,e;AACA,O;AACA,wC;AACA,8E;AACA,yD;AACA,+B;AACA,4C;AACA,yD;AACA,qD;AACA,+B;AACA,0E;AACA,+B;AACA,iB;AACA,S;AACA,+C;AACA,Q;;AAEA,W;AACA,oC;AACA,mC;AACA,W;AACA,mB;AACA,sB;AACA,e;AACA,O;AACA,mB;AACA,qB;AACA,kE;AACA,oE;AACA,2B;AACA,0E;AACA,qD;AACA,K;AACA,I;;AAEA,6E;AACA,4E;AACA,yE;AACA,2E;AACA,+B;AACA,2B;AACA,oB;AACA,0B;AACA,a;AACA,6B;AACA,8B;AACA,6D;AACA,uC;AACA,I;;AAEA,mC;AACA,oB;AACA,2C;AACA,wC;AACA,6B;AACA,2C;AACA,iB;AACA,O;AACA,I;;AAEA,6C;AACA,oC;AACA,oB;AACA,yC;AACA,wE;AACA,+E;AACA,uB;AACA,yD;AACA,sE;AACA,W;AACA,S;AACA,O;AACA,I;;AAEA,kE;AACA,qE;AACA,sE;AACA,gE;AACA,mC;AACA,0B;AACA,oB;AACA,4B;AACA,uE;AACA,kB;AACA,I;;AAEA,K;AACA,kS;AACA,kB;AACA,0D;AACA,c;AACA,2B;AACA,K;AACA,2B;AACA,oB;AACA,8B;AACA,a;AACA,iE;AACA,I;;AAEA,gF;AACA,+E;AACA,6E;AACA,oC;;AAEA,K;AACA,2I;AACA,kB;AACA,c;AACA,2B;AACA,K;AACA,qB;AACA,oB;AACA,8B;AACA,a;AACA,0D;AACA,I;;AAEA,K;AACA,uH;AACA,kB;AACA,2B;AACA,c;AACA,iD;AACA,K;AACA,+B;AACA,oB;AACA,8B;AACA,iB;AACA,Q;AACA,yC;AACA,I;;AAEA,+E;AACA,0E;AACA,kB;AACA,+B;AACA,oB;AACA,+D;AACA,I;;AAEA,K;AACA,yH;AACA,kB;AACA,2B;AACA,c;AACA,0F;AACA,8C;AACA,+F;AACA,K;AACA,gD;AACA,oB;AACA,8B;AACA,a;AACA,wC;AACA,+D;AACA,8E;AACA,I;;AAEA,K;AACA,4H;AACA,kB;AACA,2B;AACA,c;AACA,8F;AACA,kD;AACA,yS;AACA,K;AACA,kD;AACA,oB;AACA,8B;AACA,a;AACA,wC;AACA,gF;AACA,I;;AAEA,K;AACA,6H;AACA,kB;AACA,2B;AACA,c;AACA,mG;AACA,qE;AACA,K;AACA,0C;AACA,oB;AACA,8B;AACA,a;AACA,wC;AACA,sE;AACA,gE;AACA,+C;AACA,wE;AACA,I;;AAEA,K;AACA,yQ;AACA,kB;AACA,2B;AACA,c;AACA,K;AACA,sB;AACA,oB;AACA,8B;AACA,a;AACA,8B;AACA,2D;AACA,uB;AACA,sD;AACA,yB;AACA,K;AACA,G;AACA,G;;AAEA,gF;AACA,gF;AACA,gF;;AAEA,6B;AACA,kB;;AAEA,sE;AACA,oE;AACA,iE;AACA,+C;AACA,I;AACA,uD;AACA,2E;AACA,4C;AACA,6B;AACA,4B;AACA,6D;AACA,wB;AACA,K;;AAEA,mE;AACA,wE;AACA,gE;AACA,uB;AACA,oC;AACA,iD;AACA,K;;AAEA,6B;AACA,uC;;AAEA,4B;;AAEA,+C;;AAEA,wC;;AAEA,iD;AACA,uD;AACA,iC;;AAEA,yD;AACA,+C;AACA,2B;AACA,gD;AACA,qC;AACA,M;;AAEA,0C;AACA,qC;AACA,+C;AACA,O;AACA,W;AACA,a;AACA,sC;AACA,uB;AACA,mC;AACA,iB;AACA,S;AACA,uC;AACA,wC;AACA,iB;AACA,S;;AAEA,oC;AACA,sC;AACA,gD;AACA,mB;AACA,W;AACA,6B;AACA,6C;AACA,mB;AACA,iB;AACA,S;;AAEA,qC;AACA,+C;AACA,iB;AACA,S;AACA,kD;AACA,mB;AACA,iC;AACA,yE;AACA,0C;AACA,O;AACA,O;;AAEA,oC;AACA,kC;AACA,2B;AACA,wC;AACA,iB;AACA,O;AACA,O;AACA,K;AACA,E;;AAEA,4B;;AAEA,K;AACA,+F;AACA,kB;AACA,8F;AACA,qB;AACA,K;AACA,+B;AACA,oB;AACA,8C;AACA,I;;AAEA,0C;AACA,oB;;AAEA,2E;AACA,mE;AACA,8C;AACA,mC;AACA,2C;AACA,kD;AACA,8C;AACA,sE;AACA,qB;AACA,a;AACA,K;;AAEA,gE;AACA,0D;AACA,wE;;AAEA,kC;AACA,+E;AACA,+E;AACA,wB;AACA,mE;AACA,qB;AACA,a;AACA,K;;AAEA,kD;AACA,yD;AACA,6E;AACA,6E;AACA,oE;AACA,oD;AACA,gC;AACA,yD;AACA,kB;AACA,O;AACA,I;AACA,K;AACA,yC;AACA,I;AACA,8C;AACA,8C;AACA,4B;AACA,I;AACA,gE;AACA,0E;AACA,8C;AACA,I;AACA,yD;AACA,mE;AACA,oE;AACA,sB;AACA,I;AACA,wB;AACA,kE;AACA,oE;AACA,mE;AACA,uC;AACA,K;;AAEA,K;AACA,mC;AACA,qB;AACA,kB;AACA,qJ;AACA,qQ;AACA,K;AACA,8C;AACA,oB;;AAEA,4B;;AAEA,gD;AACA,uE;AACA,a;AACA,K;;AAEA,kD;AACA,iE;AACA,gE;AACA,kE;AACA,+D;AACA,kE;AACA,kE;AACA,6C;AACA,2C;AACA,6C;AACA,sB;AACA,yE;AACA,2E;AACA,yE;AACA,2C;AACA,Q;AACA,kE;AACA,Q;AACA,sC;AACA,Q;AACA,gF;AACA,0D;AACA,O;AACA,K;;AAEA,a;AACA,4C;AACA,U;AACA,oD;AACA,wE;AACA,6E;AACA,+D;AACA,gD;AACA,kD;AACA,4B;AACA,gD;AACA,mB;AACA,S;AACA,S;AACA,K;AACA,I;;AAEA,sC;AACA,oB;AACA,oC;AACA,uC;AACA,K;AACA,I;;AAEA,K;AACA,gF;AACA,oB;AACA,6F;AACA,qB;AACA,K;AACA,+B;AACA,oB;AACA,2C;AACA,qC;AACA,4E;AACA,wC;AACA,O;AACA,I;;AAEA,0C;AACA,oE;AACA,4C;AACA,wD;AACA,mE;AACA,gC;AACA,4C;AACA,I;;AAEA,qC;AACA,wC;AACA,mD;AACA,oB;;AAEA,2E;AACA,gC;AACA,qD;AACA,yB;AACA,mB;AACA,K;AACA,4B;;AAEA,iB;AACA,mE;AACA,sE;AACA,+B;AACA,yD;AACA,wC;AACA,iB;AACA,sD;AACA,Q;;AAEA,sB;AACA,6C;AACA,kB;AACA,mB;AACA,4D;AACA,Y;AACA,qE;AACA,gE;AACA,+B;AACA,wB;AACA,kC;AACA,kF;AACA,Q;AACA,4B;AACA,2D;AACA,8B;AACA,0C;AACA,sC;AACA,8C;AACA,U;AACA,kD;AACA,O;;AAEA,6C;AACA,4B;AACA,uB;AACA,6B;AACA,+B;AACA,wD;AACA,S;AACA,W;AACA,+E;AACA,0C;AACA,0E;AACA,0B;AACA,W;AACA,qC;AACA,mB;AACA,sB;AACA,O;AACA,K;;AAEA,+E;AACA,4E;AACA,gF;AACA,6E;AACA,mD;AACA,mB;AACA,kC;AACA,uB;AACA,K;AACA,kB;AACA,sB;AACA,kB;AACA,I;;AAEA,wC;AACA,oB;AACA,2C;AACA,gB;AACA,gC;AACA,Q;AACA,kB;AACA,G;AACA,G;;AAEA,yD;AACA,2D;AACA,2E;AACA,wD;AACA,K;AACA,wB;AACA,gD;AACA,G;AACA,wB;AACA,E;;AAEA,iD;;;AAGA,8E;AACA,uB;AACA,2D;AACA,sD;AACA,qB;;AAEA,4E;AACA,e;AACA,4B;AACA,2D;AACA,mC;AACA,kG;AACA,sB;AACA,K;AACA,G;;AAEA,gF;AACA,yE;AACA,8E;AACA,qB;AACA,iC;AACA,yD;AACA,sC;AACA,+E;AACA,qD;AACA,G;;AAEA,wD;AACA,E;;;AAGA,8E;AACA,oC;AACA,yE;AACA,oB;AACA,yC;AACA,kD;AACA,qC;AACA,G;AACA,gC;AACA,E;;;;;;;;;;;;;;;;;;;ACjlDA,+B;AACA,wD;;AAEA,oE;AACA,iE;AACA,kE;AACA,E;AACA,qC;AACA,kB;;AAEA,qB;AACA,qB;AACA,uB;AACA,8B;AACA,iC;AACA,E;;AAEA,qE;AACA,sE;AACA,gB;AACA,E;AACA,8D;;AAEA,2C;AACA,sE;AACA,mE;AACA,qE;AACA,sE;AACA,6D;AACA,2B;AACA,oB;;AAEA,qB;AACA,2C;;AAEA,mB;AACA,+E;;AAEA,8B;AACA,0B;AACA,Y;AACA,8B;AACA,sB;AACA,sE;AACA,yB;AACA,kC;AACA,0B;AACA,O;AACA,M;AACA,I;;AAEA,kE;AACA,0C;AACA,oB;AACA,oB;AACA,oD;AACA,iD;AACA,sB;AACA,sB;AACA,I;;AAEA,2D;AACA,mC;AACA,oB;AACA,mB;AACA,qE;AACA,wC;AACA,yC;AACA,I;;AAEA,sE;AACA,2B;AACA,oB;AACA,4B;AACA,qC;AACA,yB;AACA,O;AACA,e;AACA,kB;AACA,I;;AAEA,2B;AACA,oB;AACA,mB;AACA,wD;AACA,iD;AACA,wB;AACA,iE;AACA,qC;AACA,K;AACA,I;;AAEA,oE;AACA,uC;AACA,uB;AACA,oB;AACA,qB;AACA,iE;AACA,wB;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACpGA,8E;AACA,yE;AACA,4E;;AAEA,0C;AACA,kB;AACA,0B;;AAEA,kB;AACA,gF;AACA,gC;AACA,kC;AACA,uD;AACA,2C;AACA,E;;AAEA,yC;AACA,iE;AACA,0D;AACA,kE;AACA,6B;AACA,I;AACA,8D;AACA,2C;AACA,I;AACA,iE;AACA,c;AACA,wC;AACA,oB;AACA,2B;;AAEA,kD;AACA,+C;AACA,K;;AAEA,4E;AACA,qE;AACA,0D;AACA,kD;AACA,K;AACA,wD;;AAEA,yC;AACA,8C;AACA,4C;AACA,K;;AAEA,Y;AACA,yB;AACA,6C;AACA,kD;AACA,iD;AACA,S;AACA,0D;AACA,gE;AACA,wD;AACA,S;AACA,O;AACA,M;AACA,I;;AAEA,gE;AACA,sE;AACA,gC;AACA,I;AACA,+D;AACA,sE;AACA,I;AACA,oE;AACA,iC;AACA,oB;;AAEA,uD;AACA,oD;AACA,K;;AAEA,qE;AACA,a;;AAEA,gC;AACA,8D;AACA,yB;AACA,qD;AACA,mD;AACA,6B;AACA,O;AACA,O;;AAEA,+E;AACA,+E;AACA,sE;AACA,2E;AACA,4C;AACA,oE;AACA,+E;AACA,8E;AACA,wC;AACA,uC;AACA,8C;AACA,0D;AACA,O;AACA,O;AACA,I;;AAEA,+E;AACA,I;AACA,c;AACA,qD;AACA,uD;AACA,4B;AACA,8D;AACA,uE;AACA,8D;AACA,uD;AACA,wB;AACA,uE;AACA,2E;AACA,8B;AACA,8E;AACA,yE;AACA,0C;AACA,8C;AACA,8E;AACA,4E;AACA,6E;AACA,sE;AACA,6E;AACA,+C;AACA,0C;AACA,yC;AACA,mB;AACA,K;AACA,+D;AACA,0D;AACA,+C;AACA,mB;AACA,K;;AAEA,wD;AACA,yC;AACA,sD;AACA,O;AACA,G;AACA,G;;AAEA,+E;AACA,2E;AACA,gF;AACA,6E;AACA,4B;AACA,2D;AACA,6C;AACA,G;;;;;;;;;;;;;;;;;;;ACxJA,8D;AACA,2D;AACA,iD;;AAEA,6D;;AAEA,2E;AACA,oB;AACA,G;AACA,6E;AACA,8B;AACA,0B;AACA,qB;AACA,G;AACA,uC;AACA,kB;;AAEA,sE;AACA,qE;AACA,iE;AACA,gE;AACA,wE;AACA,sE;AACA,yC;;AAEA,K;AACA,mG;AACA,oB;AACA,wB;AACA,+B;AACA,c;AACA,oB;AACA,K;AACA,2C;;AAEA,mE;AACA,qE;AACA,c;AACA,oD;AACA,8B;;AAEA,oB;;AAEA,K;AACA,gG;AACA,oB;AACA,kB;AACA,+B;AACA,c;AACA,K;AACA,+B;;AAEA,gE;AACA,yB;AACA,wD;;AAEA,+D;;AAEA,K;AACA,uN;AACA,kB;AACA,sB;AACA,+B;AACA,c;AACA,K;AACA,uC;;AAEA,+C;AACA,uC;;AAEA,uE;AACA,2B;AACA,E;;AAEA,sC;AACA,K;AACA,yH;AACA,kB;AACA,+B;AACA,c;AACA,K;AACA,wB;AACA,oB;AACA,+B;AACA,oB;AACA,I;;AAEA,K;AACA,qC;AACA,kB;AACA,+B;AACA,c;AACA,oG;AACA,K;AACA,+B;AACA,oB;AACA,4B;AACA,gF;AACA,yB;AACA,4B;AACA,G;AACA,G;;AAEA,qC;AACA,O;AACA,wC;AACA,e;AACA,yE;AACA,gB;AACA,G;AACA,kC;AACA,gD;AACA,sE;AACA,gB;AACA,G;;AAEA,6E;;AAEA,qE;AACA,gB;AACA,8B;AACA,8B;AACA,sB;AACA,6C;AACA,uC;AACA,O;AACA,uB;AACA,G;;AAEA,2D;AACA,0B;AACA,+D;AACA,K;;AAEA,a;AACA,E;;AAEA,+B;AACA,8B;AACA,sE;AACA,qB;AACA,6B;AACA,qB;AACA,8C;AACA,gC;AACA,0B;AACA,gC;AACA,O;AACA,O;AACA,4B;AACA,6B;AACA,+B;AACA,yB;AACA,G;AACA,0B;AACA,2D;AACA,2B;AACA,+D;AACA,K;AACA,6C;AACA,kD;AACA,G;AACA,8B;AACA,E;;AAEA,oE;AACA,qE;AACA,gE;AACA,wD;AACA,wD;;;;;;;;;;;;;;;;;;;ACzKA,2E;AACA,E;AACA,4E;AACA,6E;AACA,mE;AACA,E;AACA,4E;AACA,+E;AACA,0E;AACA,+E;AACA,4E;AACA,6E;AACA,E;AACA,+D;AACA,6D;AACA,gE;AACA,8C;AACA,E;AACA,mC;AACA,4D;AACA,2D;AACA,iF;AACA,gF;AACA,mC;AACA,kB;;AAEA,uD;;AAEA,sB;AACA,E;;AAEA,kE;AACA,gE;AACA,wE;AACA,yC;AACA,wB;AACA,8B;AACA,E;;AAEA,6E;AACA,6E;AACA,oE;AACA,mC;AACA,wE;AACA,6E;AACA,0D;AACA,2C;AACA,c;AACA,qB;AACA,G;AACA,e;AACA,oC;AACA,mD;AACA,kB;AACA,G;AACA,wC;AACA,sB;AACA,0D;AACA,4B;AACA,O;AACA,G;AACA,sC;AACA,E;;AAEA,sD;AACA,6E;AACA,+D;AACA,oC;AACA,2C;AACA,uC;AACA,E;;AAEA,qD;AACA,8C;AACA,yD;AACA,uE;AACA,oD;AACA,yE;AACA,gD;AACA,iE;AACA,8B;AACA,E;;AAEA,kC;AACA,kF;AACA,uE;AACA,qE;AACA,8B;AACA,oB;;AAEA,gD;AACA,4B;AACA,gD;AACA,qD;AACA,4C;AACA,8C;AACA,S;AACA,O;AACA,yF;AACA,K;AACA,oB;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACtGA,sB;AACA,iC;AACA,oC;AACA,0D;AACA,C;;AAEA,gD;AACA,2C;AACA,W;AACA,gF;AACA,qE;AACA,gC;AACA,2E;AACA,6E;AACA,E;AACA,qE;AACA,oC;AACA,E;AACA,oE;AACA,iE;AACA,qE;AACA,8D;AACA,8D;AACA,mE;AACA,oE;AACA,+B;AACA,0C;AACA,kB;AACA,sB;AACA,gC;AACA,4D;AACA,iC;AACA,M;AACA,6B;AACA,4B;AACA,0C;AACA,iC;AACA,iD;AACA,gB;AACA,wB;AACA,c;;AAEA,wE;AACA,gF;AACA,gB;AACA,0B;;AAEA,6D;AACA,gC;AACA,uB;AACA,U;AACA,uD;AACA,2B;AACA,+B;AACA,6C;AACA,mE;AACA,oE;AACA,kE;AACA,gE;AACA,gB;AACA,iD;AACA,gD;AACA,O;AACA,G;;AAEA,6B;AACA,oE;AACA,4E;AACA,mD;AACA,4C;AACA,yB;AACA,4D;;AAEA,sD;AACA,oD;;AAEA,2E;AACA,gF;AACA,6E;AACA,0B;AACA,4B;;AAEA,gF;AACA,iB;AACA,I;AACA,0E;AACA,+E;AACA,4E;AACA,+E;AACA,mB;AACA,I;AACA,uD;AACA,+C;AACA,4E;AACA,8B;AACA,I;AACA,gF;AACA,+D;AACA,I;AACA,oE;AACA,+E;AACA,+E;AACA,gF;AACA,6E;AACA,+C;AACA,I;AACA,a;AACA,kC;AACA,mC;AACA,6D;AACA,0D;AACA,4D;AACA,8E;AACA,uE;AACA,6E;AACA,+E;AACA,+E;AACA,0D;AACA,qC;;AAEA,2E;AACA,yE;AACA,gF;AACA,+B;AACA,oC;AACA,8E;AACA,4D;AACA,8E;AACA,gC;AACA,8D;AACA,8E;AACA,6D;AACA,6B;;AAEA,uE;AACA,qB;AACA,uE;AACA,qC;AACA,yE;AACA,gF;AACA,4E;AACA,gB;AACA,kC;;AAEA,gF;AACA,oC;AACA,8E;AACA,8E;AACA,6D;AACA,6E;AACA,gF;AACA,uE;AACA,mD;AACA,I;AACA,iE;;AAEA,+D;AACA,6C;AACA,yE;AACA,yE;AACA,W;AACA,uC;AACA,yE;AACA,wE;AACA,0D;AACA,uE;AACA,gB;AACA,4B;;AAEA,iE;AACA,qC;AACA,kD;AACA,4B;;AAEA,sE;AACA,W;AACA,a;AACA,e;AACA,uE;AACA,uD;AACA,gE;AACA,+E;AACA,0D;AACA,2E;AACA,+E;AACA,2B;;AAEA,qB;AACA,sB;AACA,4C;;AAEA,gE;AACA,4E;AACA,uD;AACA,oC;AACA,+B;AACA,yD;AACA,mC;AACA,qB;AACA,c;AACA,sB;AACA,O;AACA,O;AACA,G;;AAEA,sC;AACA,S;AACA,kC;AACA,iB;AACA,sD;AACA,a;AACA,K;;AAEA,mC;AACA,uE;AACA,wE;AACA,qC;AACA,mC;AACA,kE;AACA,a;AACA,K;;AAEA,kC;AACA,8C;AACA,oC;AACA,4B;AACA,K;AACA,mC;AACA,gE;AACA,8C;AACA,+C;AACA,c;AACA,yB;AACA,wF;AACA,yE;AACA,4D;AACA,O;AACA,K;AACA,kC;AACA,iC;AACA,8C;AACA,0B;AACA,uC;AACA,K;AACA,kC;AACA,4B;AACA,uC;AACA,O;AACA,K;AACA,qF;AACA,+B;AACA,iC;AACA,gC;AACA,kC;AACA,iC;AACA,iC;AACA,gC;AACA,Q;AACA,qE;AACA,I;;AAEA,6B;AACA,6D;AACA,qE;AACA,2C;AACA,+B;AACA,4B;AACA,wC;AACA,2E;AACA,0C;AACA,6C;AACA,oB;;AAEA,oE;AACA,qE;AACA,oE;AACA,4D;AACA,qE;AACA,kE;AACA,0B;;AAEA,gF;AACA,wD;AACA,qD;AACA,8D;AACA,4C;AACA,K;;AAEA,uE;AACA,kB;AACA,+C;AACA,4B;AACA,O;;AAEA,oE;AACA,oE;AACA,oE;AACA,oE;AACA,oB;AACA,yB;AACA,kE;AACA,Q;AACA,qC;;AAEA,wE;AACA,6C;AACA,oD;AACA,kB;AACA,mB;AACA,e;AACA,uB;AACA,0B;AACA,S;AACA,O;AACA,I;;AAEA,kC;AACA,0B;AACA,6B;AACA,6B;AACA,K;AACA,I;;AAEA,wB;AACA,iF;AACA,6E;AACA,uF;AACA,U;AACA,0C;AACA,sC;AACA,gD;AACA,G;AACA,E;;AAEA,gF;AACA,sE;AACA,+E;AACA,2E;AACA,+C;AACA,wC;AACA,kB;;AAEA,sC;AACA,mC;AACA,2B;;AAEA,oC;AACA,wC;AACA,kC;AACA,sE;AACA,4B;AACA,4B;AACA,4B;;AAEA,kC;AACA,yD;AACA,E;AACA,mC;AACA,8E;AACA,oE;AACA,4B;AACA,oB;AACA,8E;AACA,gF;AACA,c;AACA,yB;AACA,uE;;AAEA,8E;AACA,Y;AACA,8B;;AAEA,4B;;AAEA,+E;AACA,Y;AACA,mB;AACA,wE;;AAEA,iC;AACA,0C;AACA,I;AACA,6E;AACA,qC;AACA,qC;AACA,oB;AACA,kD;AACA,4E;AACA,0B;AACA,mE;;AAEA,kC;AACA,6D;;AAEA,+E;AACA,8C;AACA,oD;AACA,K;AACA,I;AACA,2E;AACA,oE;AACA,4E;AACA,2D;AACA,yC;AACA,oB;AACA,yB;AACA,kE;AACA,uC;AACA,wC;AACA,gC;AACA,I;AACA,8E;AACA,uE;AACA,4E;AACA,sE;AACA,4B;AACA,oB;AACA,6B;AACA,gC;AACA,I;AACA,2C;AACA,0B;AACA,oB;AACA,gC;AACA,G;AACA,G;;AAEA,gC;AACA,qE;AACA,gF;AACA,gF;AACA,gD;AACA,oB;;AAEA,6B;AACA,mB;;AAEA,0E;AACA,2C;AACA,mB;AACA,kE;AACA,qD;AACA,2C;AACA,4C;AACA,6E;AACA,qC;AACA,gB;AACA,e;;AAEA,+B;;AAEA,qD;AACA,iB;AACA,8C;AACA,qC;AACA,0B;AACA,S;AACA,wB;AACA,iD;AACA,K;;AAEA,gB;AACA,I;;AAEA,K;AACA,qB;AACA,wE;AACA,oC;AACA,kB;AACA,4E;AACA,+B;AACA,uE;AACA,wB;AACA,wE;AACA,sE;AACA,2E;AACA,6C;AACA,K;AACA,2E;AACA,oB;;AAEA,0D;AACA,uB;AACA,wB;AACA,gD;AACA,oC;AACA,yC;AACA,6B;AACA,wE;AACA,iD;AACA,uE;AACA,0B;AACA,iC;AACA,O;AACA,K;;AAEA,uE;AACA,uE;AACA,4B;AACA,M;AACA,wC;AACA,M;AACA,wC;AACA,yD;AACA,yD;AACA,c;AACA,M;AACA,sE;AACA,oE;AACA,sD;AACA,M;AACA,8E;AACA,4E;AACA,uB;AACA,+D;AACA,iD;AACA,yC;AACA,O;;AAEA,W;AACA,mB;AACA,uB;AACA,8C;;AAEA,8B;AACA,+E;AACA,+E;AACA,6E;AACA,yE;AACA,8C;AACA,4B;AACA,qD;AACA,O;;AAEA,wE;AACA,+C;AACA,8B;AACA,kE;AACA,2B;AACA,mD;AACA,O;;AAEA,6B;AACA,iD;AACA,O;AACA,Y;AACA,oE;AACA,uB;AACA,iC;AACA,e;AACA,mB;AACA,oC;AACA,wB;AACA,qB;AACA,0C;AACA,yC;AACA,iD;AACA,yC;AACA,uC;AACA,yB;AACA,4B;AACA,yD;AACA,iD;AACA,U;AACA,0B;AACA,wD;AACA,wB;;AAEA,iC;AACA,+B;AACA,W;AACA,S;AACA,Q;AACA,mE;AACA,K;;AAEA,0C;AACA,kB;AACA,yB;AACA,4C;AACA,iB;;AAEA,uC;AACA,Q;AACA,0B;AACA,8C;AACA,4C;AACA,uB;AACA,6C;AACA,kC;AACA,4B;AACA,Q;AACA,wB;AACA,M;;AAEA,yB;AACA,8E;AACA,8E;AACA,6E;AACA,uE;AACA,wE;AACA,uB;AACA,yC;AACA,2C;AACA,kD;;AAEA,wC;AACA,+C;AACA,+C;AACA,0B;AACA,W;AACA,S;AACA,K;;AAEA,kB;AACA,I;;AAEA,a;AACA,2F;AACA,mE;AACA,qD;AACA,oB;AACA,yB;AACA,sB;AACA,e;AACA,sB;AACA,e;AACA,4B;AACA,qB;AACA,sB;AACA,Q;AACA,6B;AACA,mB;AACA,wB;AACA,Y;AACA,mE;AACA,O;AACA,O;;AAEA,6D;AACA,a;AACA,kB;AACA,I;;AAEA,+B;AACA,oB;AACA,2C;AACA,qC;AACA,4E;AACA,wC;AACA,O;AACA,I;;AAEA,K;AACA,qB;AACA,+D;AACA,oB;AACA,kD;AACA,gE;AACA,uN;AACA,K;AACA,0D;AACA,oE;AACA,4C;AACA,wD;AACA,mE;AACA,gC;AACA,4C;AACA,I;;AAEA,qC;AACA,4E;AACA,4E;AACA,2D;AACA,+E;AACA,4E;AACA,2E;AACA,2E;AACA,2E;AACA,6E;AACA,6E;AACA,2E;AACA,yE;AACA,4E;AACA,8E;AACA,6E;AACA,6E;AACA,2E;AACA,6D;AACA,wC;;AAEA,K;AACA,qB;AACA,4D;AACA,oB;AACA,kD;AACA,+C;AACA,8B;AACA,wM;AACA,8Q;AACA,6G;AACA,K;AACA,mD;AACA,oB;;AAEA,2E;AACA,gC;AACA,qD;AACA,yB;AACA,mB;AACA,K;AACA,4B;;AAEA,mB;AACA,oE;AACA,oC;AACA,yD;AACA,wC;AACA,iB;AACA,sD;AACA,Q;AACA,K;;AAEA,8E;AACA,uC;AACA,6B;;AAEA,mE;AACA,iC;AACA,a;AACA,0B;AACA,6B;AACA,2C;AACA,kB;AACA,Q;AACA,S;;AAEA,iD;AACA,kE;;AAEA,yE;AACA,8E;AACA,yE;AACA,8D;AACA,+E;AACA,6E;AACA,6E;AACA,wE;AACA,4E;AACA,iD;AACA,0B;AACA,2C;AACA,gC;AACA,kD;AACA,O;AACA,wB;AACA,M;;AAEA,sE;AACA,4E;AACA,0E;AACA,8E;AACA,iD;AACA,M;AACA,yE;AACA,yE;AACA,4E;AACA,wE;AACA,a;;AAEA,0C;AACA,e;AACA,wC;AACA,+B;AACA,Q;;AAEA,6C;AACA,2B;AACA,8B;AACA,6B;AACA,iE;AACA,S;;AAEA,+B;AACA,8B;;AAEA,W;AACA,4E;AACA,8C;AACA,wF;AACA,gC;AACA,4E;AACA,0C;AACA,wD;AACA,4E;AACA,+D;AACA,e;AACA,kB;AACA,6D;AACA,W;AACA,W;AACA,O;AACA,iB;AACA,0B;AACA,O;;AAEA,+B;AACA,oD;AACA,K;;AAEA,oE;AACA,+D;AACA,wC;AACA,8B;AACA,qB;AACA,6C;AACA,yB;AACA,O;AACA,oB;AACA,wB;AACA,6B;AACA,K;;AAEA,gE;AACA,iE;AACA,sD;AACA,M;AACA,oE;AACA,iB;AACA,2C;AACA,2E;AACA,4D;AACA,K;;;AAGA,sE;AACA,iD;;AAEA,+D;AACA,oB;AACA,4B;AACA,sE;AACA,sE;AACA,uE;AACA,0B;AACA,mC;AACA,uE;AACA,4C;AACA,U;AACA,c;AACA,iE;AACA,qC;AACA,gC;AACA,qC;AACA,O;AACA,K;AACA,sE;AACA,yE;AACA,+D;AACA,mB;AACA,oB;AACA,mB;AACA,mB;AACA,oB;AACA,M;;AAEA,6C;AACA,8B;AACA,sC;AACA,K;;AAEA,2C;AACA,2B;AACA,yB;AACA,uB;AACA,iD;AACA,2B;AACA,sB;AACA,O;;AAEA,uB;AACA,gE;AACA,yC;AACA,gD;AACA,Y;AACA,8E;AACA,wD;AACA,qD;AACA,qD;AACA,uE;AACA,wE;AACA,K;;AAEA,0D;AACA,mD;AACA,kC;;AAEA,yD;AACA,oC;AACA,iB;AACA,2B;AACA,K;AACA,iE;AACA,I;;AAEA,gF;AACA,uE;AACA,e;AACA,+B;AACA,oB;AACA,uC;AACA,wB;AACA,O;AACA,I;AACA,8E;AACA,gF;AACA,mE;AACA,mD;AACA,oB;AACA,+C;AACA,0E;;AAEA,yB;AACA,mD;AACA,4C;AACA,gD;AACA,qB;AACA,e;AACA,4C;AACA,2D;AACA,sD;AACA,yE;AACA,6E;AACA,uC;AACA,+E;AACA,2B;AACA,oD;AACA,gB;AACA,mE;AACA,mC;AACA,wC;AACA,wC;AACA,oD;AACA,S;AACA,S;AACA,O;AACA,kC;AACA,2D;AACA,K;AACA,I;;AAEA,kE;AACA,wD;AACA,gC;AACA,oB;AACA,6D;AACA,qE;AACA,sD;AACA,Q;AACA,mE;AACA,mE;AACA,oD;AACA,4D;AACA,uC;AACA,O;AACA,O;AACA,I;;AAEA,8D;AACA,yB;AACA,oB;AACA,yC;AACA,I;;AAEA,6D;AACA,mE;AACA,mC;AACA,qC;AACA,oB;AACA,wC;AACA,I;;AAEA,K;AACA,wE;AACA,kB;AACA,qB;AACA,K;AACA,2C;AACA,oB;AACA,8D;AACA,I;;AAEA,K;AACA,mG;;AAEA,8D;AACA,kB;AACA,qB;AACA,K;AACA,8C;AACA,oB;AACA,iE;AACA,I;;AAEA,K;AACA,oD;AACA,kB;AACA,qB;AACA,K;AACA,+C;AACA,oB;AACA,kE;AACA,I;;AAEA,sB;AACA,oB;AACA,uD;AACA,I;;AAEA,K;AACA,0B;AACA,K;AACA,uB;AACA,oB;AACA,yB;AACA,gC;AACA,wB;AACA,I;;AAEA,gC;AACA,oB;AACA,+E;AACA,gC;AACA,a;AACA,0B;AACA,yB;AACA,iC;AACA,I;;AAEA,gF;AACA,2E;AACA,6B;AACA,sC;AACA,oB;AACA,kD;AACA,0D;AACA,I;;AAEA,6E;AACA,uC;AACA,0C;AACA,oB;AACA,+D;AACA,I;;AAEA,uC;AACA,oB;;AAEA,oE;AACA,uC;AACA,mD;AACA,iD;AACA,gC;AACA,+B;AACA,gE;AACA,U;AACA,+B;AACA,oC;AACA,S;AACA,S;AACA,8B;AACA,K;;AAEA,8D;AACA,4B;AACA,+B;;AAEA,4C;AACA,+E;AACA,wC;AACA,K;;AAEA,uC;AACA,+E;AACA,4E;AACA,gF;AACA,+E;AACA,0E;AACA,a;AACA,K;;AAEA,oE;;AAEA,+E;AACA,mC;AACA,uC;;AAEA,4B;AACA,8E;AACA,gB;AACA,wC;AACA,iC;AACA,K;;AAEA,mC;AACA,oC;;AAEA,8E;AACA,gD;AACA,gF;AACA,qE;AACA,gC;AACA,oD;AACA,oB;AACA,0C;AACA,O;;AAEA,2E;AACA,uE;AACA,uC;AACA,M;AACA,wE;AACA,gF;AACA,4D;AACA,yC;AACA,4B;AACA,uD;AACA,kC;AACA,gF;AACA,0E;AACA,4E;AACA,0E;AACA,gF;AACA,yC;AACA,4E;AACA,8E;AACA,8D;AACA,Y;AACA,6E;AACA,uE;AACA,+E;AACA,2E;AACA,+B;AACA,mE;AACA,S;AACA,S;AACA,K;;AAEA,+C;;AAEA,+E;AACA,sC;AACA,wC;AACA,8B;AACA,2C;AACA,iC;AACA,wB;AACA,W;AACA,kC;AACA,O;AACA,sC;AACA,K;AACA,I;;;AAGA,mD;AACA,oB;AACA,6D;AACA,8C;AACA,I;;;AAGA,kC;AACA,oB;;AAEA,2C;AACA,qB;;AAEA,uC;AACA,sD;;AAEA,8B;AACA,8C;;AAEA,+C;AACA,6C;AACA,S;AACA,qD;AACA,yD;AACA,S;;AAEA,uC;AACA,e;;AAEA,oD;AACA,8E;AACA,oC;AACA,4E;AACA,0D;AACA,S;AACA,iD;AACA,Y;AACA,gD;AACA,K;;AAEA,mD;AACA,oD;AACA,oD;AACA,gF;AACA,yC;AACA,S;AACA,gC;;AAEA,4D;AACA,4C;AACA,oB;AACA,2D;AACA,wC;AACA,a;AACA,gB;AACA,gE;AACA,8B;AACA,oE;AACA,qE;AACA,gD;AACA,+D;AACA,0D;AACA,8E;AACA,qD;AACA,S;AACA,S;;AAEA,gC;AACA,4D;AACA,K;;AAEA,oC;AACA,I;;AAEA,2E;AACA,yE;AACA,+B;AACA,yC;AACA,oB;AACA,+C;AACA,oC;AACA,oC;AACA,U;AACA,O;AACA,I;;AAEA,oD;AACA,oB;AACA,sC;AACA,+B;AACA,K;AACA,kC;AACA,I;;AAEA,4C;AACA,oB;AACA,kD;AACA,kB;AACA,oE;AACA,mD;AACA,I;;AAEA,2C;AACA,oB;AACA,8C;AACA,2D;AACA,oB;AACA,0C;AACA,2C;AACA,sE;AACA,4C;AACA,kC;AACA,Y;AACA,qD;AACA,K;AACA,I;;AAEA,6C;AACA,oB;AACA,uC;AACA,wD;AACA,oB;AACA,2C;AACA,6E;AACA,oE;AACA,Y;AACA,qD;AACA,K;AACA,I;;AAEA,6C;AACA,oB;AACA,uC;AACA,wD;AACA,oB;AACA,0C;AACA,2C;AACA,4E;AACA,qC;AACA,Y;AACA,iD;AACA,uB;AACA,mC;AACA,kB;AACA,S;AACA,K;AACA,I;;AAEA,6C;AACA,oB;AACA,sC;AACA,6C;AACA,yE;AACA,2E;AACA,uB;AACA,2E;AACA,gD;AACA,4D;AACA,iE;AACA,kD;AACA,kD;AACA,6E;AACA,8E;AACA,+E;AACA,wC;;AAEA,yE;AACA,+E;AACA,uE;AACA,yD;AACA,2B;AACA,yD;AACA,uC;AACA,a;AACA,sC;AACA,yD;AACA,gB;AACA,a;;AAEA,2E;AACA,6E;AACA,gE;AACA,uE;AACA,S;AACA,S;AACA,oD;;AAEA,gF;AACA,iD;AACA,2D;AACA,2B;AACA,sE;AACA,2C;AACA,8D;AACA,O;AACA,I;;AAEA,2C;AACA,oB;AACA,2E;AACA,wE;AACA,4D;AACA,uC;AACA,wD;AACA,mD;AACA,sC;AACA,uB;AACA,iB;AACA,0D;AACA,4B;AACA,iB;AACA,6D;AACA,+B;AACA,sC;AACA,S;AACA,O;AACA,I;;AAEA,qE;AACA,gF;AACA,2C;AACA,iD;AACA,oB;AACA,wC;AACA,yC;AACA,M;AACA,oC;AACA,wC;AACA,gC;AACA,0C;AACA,6E;AACA,6B;AACA,2B;AACA,O;AACA,M;AACA,6D;AACA,mD;AACA,2D;AACA,gE;AACA,yD;AACA,kD;AACA,a;AACA,qD;AACA,oC;AACA,0D;AACA,S;AACA,S;AACA,O;AACA,wC;AACA,gF;AACA,qC;AACA,yB;AACA,K;AACA,I;;AAEA,mC;AACA,oB;;AAEA,2E;AACA,0B;AACA,6B;;AAEA,yD;AACA,kC;;AAEA,2D;AACA,4C;AACA,a;;AAEA,6C;AACA,kE;AACA,gE;;AAEA,yC;;AAEA,gD;AACA,wD;AACA,uE;AACA,K;;AAEA,6C;AACA,qC;AACA,6C;AACA,K;;AAEA,uB;AACA,4C;AACA,K;AACA,I;;AAEA,+B;AACA,2E;AACA,4E;AACA,sE;AACA,yE;AACA,e;AACA,I;;AAEA,oC;AACA,mE;;AAEA,oB;;AAEA,mC;AACA,uD;AACA,mD;AACA,yE;AACA,a;AACA,K;AACA,sE;AACA,U;AACA,yD;AACA,gC;AACA,gC;AACA,c;AACA,K;;AAEA,a;AACA,gF;AACA,a;AACA,K;;AAEA,+E;AACA,gF;AACA,kC;AACA,oC;;AAEA,8B;AACA,uC;AACA,0C;AACA,4B;AACA,Y;AACA,kE;AACA,c;AACA,6C;AACA,K;AACA,I;;AAEA,+E;AACA,8E;AACA,mE;AACA,2C;AACA,oB;AACA,yC;AACA,a;;AAEA,2E;AACA,0E;AACA,kD;AACA,qD;AACA,6D;AACA,0C;AACA,uE;AACA,oD;;AAEA,6D;AACA,oD;AACA,uC;AACA,K;;AAEA,oC;AACA,yB;AACA,I;;AAEA,6D;AACA,8B;AACA,uC;AACA,oB;AACA,iD;AACA,a;AACA,mE;AACA,sB;AACA,O;AACA,I;;AAEA,mC;AACA,8D;AACA,6B;AACA,mD;AACA,I;;AAEA,oE;AACA,oB;AACA,mE;AACA,uC;;AAEA,uB;;AAEA,8C;AACA,a;;AAEA,yE;AACA,4E;AACA,+D;AACA,mD;AACA,iE;AACA,qC;AACA,a;AACA,K;;AAEA,gF;AACA,6E;AACA,yC;AACA,sD;AACA,8C;AACA,kE;AACA,8D;;AAEA,0E;AACA,uD;AACA,0B;AACA,S;;AAEA,yC;AACA,K;;AAEA,kD;AACA,yD;AACA,gD;AACA,O;AACA,I;;AAEA,qE;AACA,+B;AACA,oB;AACA,2C;AACA,I;;AAEA,2E;AACA,kE;AACA,8B;AACA,oB;AACA,uD;AACA,2B;AACA,gC;AACA,K;AACA,G;AACA,G;;AAEA,qC;;AAEA,yC;AACA,Y;AACA,8B;AACA,qC;AACA,W;AACA,qD;;AAEA,G;AACA,oI;AACA,kB;AACA,6D;AACA,G;AACA,uC;AACA,yC;AACA,+C;AACA,a;AACA,E;;AAEA,kE;AACA,iC;AACA,E;AACA,oB;AACA,0C;AACA,gD;AACA,sD;AACA,uB;AACA,O;AACA,K;AACA,E;;;;;;;;;;;;;;;;;;;AClmDA,sE;AACA,4C;AACA,E;AACA,gF;AACA,8E;AACA,mD;AACA,E;AACA,6E;AACA,gF;AACA,6E;AACA,2E;AACA,mB;AACA,qB;AACA,+C;AACA,0D;AACA,6C;AACA,G;;AAEA,6B;;AAEA,4C;AACA,uD;AACA,I;;AAEA,0D;AACA,kC;AACA,iE;AACA,0B;AACA,qE;AACA,Y;AACA,Q;AACA,wC;AACA,uB;AACA,4C;AACA,I;;AAEA,mE;AACA,qD;AACA,gD;AACA,uB;AACA,uC;AACA,S;AACA,C;;AAEA,iE;AACA,gE;AACA,wB;AACA,sC","file":"/packages/ddp.js","sourcesContent":["/**\n * @namespace DDP\n * @summary The namespace for DDP-related methods.\n */\nDDP = {};\nLivedataTest = {};\n","// @param endpoint {String} URL to Meteor app\n// \"http://subdomain.meteor.com/\" or \"/\" or\n// \"ddp+sockjs://foo-**.meteor.com/sockjs\"\n//\n// We do some rewriting of the URL to eventually make it \"ws://\" or \"wss://\",\n// whatever was passed in. At the very least, what Meteor.absoluteUrl() returns\n// us should work.\n//\n// We don't do any heartbeating. (The logic that did this in sockjs was removed,\n// because it used a built-in sockjs mechanism. We could do it with WebSocket\n// ping frames or with DDP-level messages.)\nLivedataTest.ClientStream = function (endpoint, options) {\n var self = this;\n options = options || {};\n\n self.options = _.extend({\n retry: true\n }, options);\n\n self.client = null; // created in _launchConnection\n self.endpoint = endpoint;\n\n self.headers = self.options.headers || {};\n\n self._initCommon(self.options);\n\n //// Kickoff!\n self._launchConnection();\n};\n\n_.extend(LivedataTest.ClientStream.prototype, {\n\n // data is a utf8 string. Data sent while not connected is dropped on\n // the floor, and it is up the user of this API to retransmit lost\n // messages on 'reset'\n send: function (data) {\n var self = this;\n if (self.currentStatus.connected) {\n self.client.send(data);\n }\n },\n\n // Changes where this connection points\n _changeUrl: function (url) {\n var self = this;\n self.endpoint = url;\n },\n\n _onConnect: function (client) {\n var self = this;\n\n if (client !== self.client) {\n // This connection is not from the last call to _launchConnection.\n // But _launchConnection calls _cleanup which closes previous connections.\n // It's our belief that this stifles future 'open' events, but maybe\n // we are wrong?\n throw new Error(\"Got open from inactive client \" + !!self.client);\n }\n\n if (self._forcedToDisconnect) {\n // We were asked to disconnect between trying to open the connection and\n // actually opening it. Let's just pretend this never happened.\n self.client.close();\n self.client = null;\n return;\n }\n\n if (self.currentStatus.connected) {\n // We already have a connection. It must have been the case that we\n // started two parallel connection attempts (because we wanted to\n // 'reconnect now' on a hanging connection and we had no way to cancel the\n // connection attempt.) But this shouldn't happen (similarly to the client\n // !== self.client check above).\n throw new Error(\"Two parallel connections?\");\n }\n\n self._clearConnectionTimer();\n\n // update status\n self.currentStatus.status = \"connected\";\n self.currentStatus.connected = true;\n self.currentStatus.retryCount = 0;\n self.statusChanged();\n\n // fire resets. This must come after status change so that clients\n // can call send from within a reset callback.\n _.each(self.eventCallbacks.reset, function (callback) { callback(); });\n },\n\n _cleanup: function (maybeError) {\n var self = this;\n\n self._clearConnectionTimer();\n if (self.client) {\n var client = self.client;\n self.client = null;\n client.close();\n\n _.each(self.eventCallbacks.disconnect, function (callback) {\n callback(maybeError);\n });\n }\n },\n\n _clearConnectionTimer: function () {\n var self = this;\n\n if (self.connectionTimer) {\n clearTimeout(self.connectionTimer);\n self.connectionTimer = null;\n }\n },\n\n _getProxyUrl: function (targetUrl) {\n var self = this;\n // Similar to code in tools/http-helpers.js.\n var proxy = process.env.HTTP_PROXY || process.env.http_proxy || null;\n // if we're going to a secure url, try the https_proxy env variable first.\n if (targetUrl.match(/^wss:/)) {\n proxy = process.env.HTTPS_PROXY || process.env.https_proxy || proxy;\n }\n return proxy;\n },\n\n _launchConnection: function () {\n var self = this;\n self._cleanup(); // cleanup the old socket, if there was one.\n\n // Since server-to-server DDP is still an experimental feature, we only\n // require the module if we actually create a server-to-server\n // connection.\n var FayeWebSocket = Npm.require('faye-websocket');\n\n var targetUrl = toWebsocketUrl(self.endpoint);\n var fayeOptions = { headers: self.headers };\n var proxyUrl = self._getProxyUrl(targetUrl);\n if (proxyUrl) {\n fayeOptions.proxy = { origin: proxyUrl };\n };\n\n // We would like to specify 'ddp' as the subprotocol here. The npm module we\n // used to use as a client would fail the handshake if we ask for a\n // subprotocol and the server doesn't send one back (and sockjs doesn't).\n // Faye doesn't have that behavior; it's unclear from reading RFC 6455 if\n // Faye is erroneous or not. So for now, we don't specify protocols.\n var subprotocols = [];\n\n var client = self.client = new FayeWebSocket.Client(\n targetUrl, subprotocols, fayeOptions);\n\n self._clearConnectionTimer();\n self.connectionTimer = Meteor.setTimeout(\n function () {\n self._lostConnection(\n new DDP.ConnectionError(\"DDP connection timed out\"));\n },\n self.CONNECT_TIMEOUT);\n\n self.client.on('open', Meteor.bindEnvironment(function () {\n return self._onConnect(client);\n }, \"stream connect callback\"));\n\n var clientOnIfCurrent = function (event, description, f) {\n self.client.on(event, Meteor.bindEnvironment(function () {\n // Ignore events from any connection we've already cleaned up.\n if (client !== self.client)\n return;\n f.apply(this, arguments);\n }, description));\n };\n\n clientOnIfCurrent('error', 'stream error callback', function (error) {\n if (!self.options._dontPrintErrors)\n Meteor._debug(\"stream error\", error.message);\n\n // Faye's 'error' object is not a JS error (and among other things,\n // doesn't stringify well). Convert it to one.\n self._lostConnection(new DDP.ConnectionError(error.message));\n });\n\n\n clientOnIfCurrent('close', 'stream close callback', function () {\n self._lostConnection();\n });\n\n\n clientOnIfCurrent('message', 'stream message callback', function (message) {\n // Ignore binary frames, where message.data is a Buffer\n if (typeof message.data !== \"string\")\n return;\n\n _.each(self.eventCallbacks.message, function (callback) {\n callback(message.data);\n });\n });\n }\n});\n","// XXX from Underscore.String (http://epeli.github.com/underscore.string/)\nvar startsWith = function(str, starts) {\n return str.length >= starts.length &&\n str.substring(0, starts.length) === starts;\n};\nvar endsWith = function(str, ends) {\n return str.length >= ends.length &&\n str.substring(str.length - ends.length) === ends;\n};\n\n// @param url {String} URL to Meteor app, eg:\n// \"/\" or \"madewith.meteor.com\" or \"https://foo.meteor.com\"\n// or \"ddp+sockjs://ddp--****-foo.meteor.com/sockjs\"\n// @returns {String} URL to the endpoint with the specific scheme and subPath, e.g.\n// for scheme \"http\" and subPath \"sockjs\"\n// \"http://subdomain.meteor.com/sockjs\" or \"/sockjs\"\n// or \"https://ddp--1234-foo.meteor.com/sockjs\"\nvar translateUrl = function(url, newSchemeBase, subPath) {\n if (! newSchemeBase) {\n newSchemeBase = \"http\";\n }\n\n var ddpUrlMatch = url.match(/^ddp(i?)\\+sockjs:\\/\\//);\n var httpUrlMatch = url.match(/^http(s?):\\/\\//);\n var newScheme;\n if (ddpUrlMatch) {\n // Remove scheme and split off the host.\n var urlAfterDDP = url.substr(ddpUrlMatch[0].length);\n newScheme = ddpUrlMatch[1] === \"i\" ? newSchemeBase : newSchemeBase + \"s\";\n var slashPos = urlAfterDDP.indexOf('/');\n var host =\n slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos);\n var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos);\n\n // In the host (ONLY!), change '*' characters into random digits. This\n // allows different stream connections to connect to different hostnames\n // and avoid browser per-hostname connection limits.\n host = host.replace(/\\*/g, function () {\n return Math.floor(Random.fraction()*10);\n });\n\n return newScheme + '://' + host + rest;\n } else if (httpUrlMatch) {\n newScheme = !httpUrlMatch[1] ? newSchemeBase : newSchemeBase + \"s\";\n var urlAfterHttp = url.substr(httpUrlMatch[0].length);\n url = newScheme + \"://\" + urlAfterHttp;\n }\n\n // Prefix FQDNs but not relative URLs\n if (url.indexOf(\"://\") === -1 && !startsWith(url, \"/\")) {\n url = newSchemeBase + \"://\" + url;\n }\n\n // XXX This is not what we should be doing: if I have a site\n // deployed at \"/foo\", then DDP.connect(\"/\") should actually connect\n // to \"/\", not to \"/foo\". \"/\" is an absolute path. (Contrast: if\n // deployed at \"/foo\", it would be reasonable for DDP.connect(\"bar\")\n // to connect to \"/foo/bar\").\n //\n // We should make this properly honor absolute paths rather than\n // forcing the path to be relative to the site root. Simultaneously,\n // we should set DDP_DEFAULT_CONNECTION_URL to include the site\n // root. See also client_convenience.js #RationalizingRelativeDDPURLs\n url = Meteor._relativeToSiteRootUrl(url);\n\n if (endsWith(url, \"/\"))\n return url + subPath;\n else\n return url + \"/\" + subPath;\n};\n\ntoSockjsUrl = function (url) {\n return translateUrl(url, \"http\", \"sockjs\");\n};\n\ntoWebsocketUrl = function (url) {\n var ret = translateUrl(url, \"ws\", \"websocket\");\n return ret;\n};\n\nLivedataTest.toSockjsUrl = toSockjsUrl;\n\n\n_.extend(LivedataTest.ClientStream.prototype, {\n\n // Register for callbacks.\n on: function (name, callback) {\n var self = this;\n\n if (name !== 'message' && name !== 'reset' && name !== 'disconnect')\n throw new Error(\"unknown event type: \" + name);\n\n if (!self.eventCallbacks[name])\n self.eventCallbacks[name] = [];\n self.eventCallbacks[name].push(callback);\n },\n\n\n _initCommon: function (options) {\n var self = this;\n options = options || {};\n\n //// Constants\n\n // how long to wait until we declare the connection attempt\n // failed.\n self.CONNECT_TIMEOUT = options.connectTimeoutMs || 10000;\n\n self.eventCallbacks = {}; // name -> [callback]\n\n self._forcedToDisconnect = false;\n\n //// Reactive status\n self.currentStatus = {\n status: \"connecting\",\n connected: false,\n retryCount: 0\n };\n\n\n self.statusListeners = typeof Tracker !== 'undefined' && new Tracker.Dependency;\n self.statusChanged = function () {\n if (self.statusListeners)\n self.statusListeners.changed();\n };\n\n //// Retry logic\n self._retry = new Retry;\n self.connectionTimer = null;\n\n },\n\n // Trigger a reconnect.\n reconnect: function (options) {\n var self = this;\n options = options || {};\n\n if (options.url) {\n self._changeUrl(options.url);\n }\n\n if (options._sockjsOptions) {\n self.options._sockjsOptions = options._sockjsOptions;\n }\n\n if (self.currentStatus.connected) {\n if (options._force || options.url) {\n // force reconnect.\n self._lostConnection(new DDP.ForcedReconnectError);\n } // else, noop.\n return;\n }\n\n // if we're mid-connection, stop it.\n if (self.currentStatus.status === \"connecting\") {\n // Pretend it's a clean close.\n self._lostConnection();\n }\n\n self._retry.clear();\n self.currentStatus.retryCount -= 1; // don't count manual retries\n self._retryNow();\n },\n\n disconnect: function (options) {\n var self = this;\n options = options || {};\n\n // Failed is permanent. If we're failed, don't let people go back\n // online by calling 'disconnect' then 'reconnect'.\n if (self._forcedToDisconnect)\n return;\n\n // If _permanent is set, permanently disconnect a stream. Once a stream\n // is forced to disconnect, it can never reconnect. This is for\n // error cases such as ddp version mismatch, where trying again\n // won't fix the problem.\n if (options._permanent) {\n self._forcedToDisconnect = true;\n }\n\n self._cleanup();\n self._retry.clear();\n\n self.currentStatus = {\n status: (options._permanent ? \"failed\" : \"offline\"),\n connected: false,\n retryCount: 0\n };\n\n if (options._permanent && options._error)\n self.currentStatus.reason = options._error;\n\n self.statusChanged();\n },\n\n // maybeError is set unless it's a clean protocol-level close.\n _lostConnection: function (maybeError) {\n var self = this;\n\n self._cleanup(maybeError);\n self._retryLater(maybeError); // sets status. no need to do it here.\n },\n\n // fired when we detect that we've gone online. try to reconnect\n // immediately.\n _online: function () {\n // if we've requested to be offline by disconnecting, don't reconnect.\n if (this.currentStatus.status != \"offline\")\n this.reconnect();\n },\n\n _retryLater: function (maybeError) {\n var self = this;\n\n var timeout = 0;\n if (self.options.retry ||\n (maybeError && maybeError.errorType === \"DDP.ForcedReconnectError\")) {\n timeout = self._retry.retryLater(\n self.currentStatus.retryCount,\n _.bind(self._retryNow, self)\n );\n self.currentStatus.status = \"waiting\";\n self.currentStatus.retryTime = (new Date()).getTime() + timeout;\n } else {\n self.currentStatus.status = \"failed\";\n delete self.currentStatus.retryTime;\n }\n\n self.currentStatus.connected = false;\n self.statusChanged();\n },\n\n _retryNow: function () {\n var self = this;\n\n if (self._forcedToDisconnect)\n return;\n\n self.currentStatus.retryCount += 1;\n self.currentStatus.status = \"connecting\";\n self.currentStatus.connected = false;\n delete self.currentStatus.retryTime;\n self.statusChanged();\n\n self._launchConnection();\n },\n\n\n // Get current status. Reactive.\n status: function () {\n var self = this;\n if (self.statusListeners)\n self.statusListeners.depend();\n return self.currentStatus;\n }\n});\n\nDDP.ConnectionError = Meteor.makeErrorType(\n \"DDP.ConnectionError\", function (message) {\n var self = this;\n self.message = message;\n});\n\nDDP.ForcedReconnectError = Meteor.makeErrorType(\n \"DDP.ForcedReconnectError\", function () {});\n","var url = Npm.require('url');\n\nvar pathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || \"\";\n\nStreamServer = function () {\n var self = this;\n self.registration_callbacks = [];\n self.open_sockets = [];\n\n // Because we are installing directly onto WebApp.httpServer instead of using\n // WebApp.app, we have to process the path prefix ourselves.\n self.prefix = pathPrefix + '/sockjs';\n // routepolicy is only a weak dependency, because we don't need it if we're\n // just doing server-to-server DDP as a client.\n if (Package.routepolicy) {\n Package.routepolicy.RoutePolicy.declare(self.prefix + '/', 'network');\n }\n\n // set up sockjs\n var sockjs = Npm.require('sockjs');\n var serverOptions = {\n prefix: self.prefix,\n log: function() {},\n // this is the default, but we code it explicitly because we depend\n // on it in stream_client:HEARTBEAT_TIMEOUT\n heartbeat_delay: 45000,\n // The default disconnect_delay is 5 seconds, but if the server ends up CPU\n // bound for that much time, SockJS might not notice that the user has\n // reconnected because the timer (of disconnect_delay ms) can fire before\n // SockJS processes the new connection. Eventually we'll fix this by not\n // combining CPU-heavy processing with SockJS termination (eg a proxy which\n // converts to Unix sockets) but for now, raise the delay.\n disconnect_delay: 60 * 1000,\n // Set the USE_JSESSIONID environment variable to enable setting the\n // JSESSIONID cookie. This is useful for setting up proxies with\n // session affinity.\n jsessionid: !!process.env.USE_JSESSIONID\n };\n\n // If you know your server environment (eg, proxies) will prevent websockets\n // from ever working, set $DISABLE_WEBSOCKETS and SockJS clients (ie,\n // browsers) will not waste time attempting to use them.\n // (Your server will still have a /websocket endpoint.)\n if (process.env.DISABLE_WEBSOCKETS)\n serverOptions.websocket = false;\n\n self.server = sockjs.createServer(serverOptions);\n if (!Package.webapp) {\n throw new Error(\"Cannot create a DDP server without the webapp package\");\n }\n // Install the sockjs handlers, but we want to keep around our own particular\n // request handler that adjusts idle timeouts while we have an outstanding\n // request. This compensates for the fact that sockjs removes all listeners\n // for \"request\" to add its own.\n Package.webapp.WebApp.httpServer.removeListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback);\n self.server.installHandlers(Package.webapp.WebApp.httpServer);\n Package.webapp.WebApp.httpServer.addListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback);\n\n // Support the /websocket endpoint\n self._redirectWebsocketEndpoint();\n\n self.server.on('connection', function (socket) {\n socket.send = function (data) {\n socket.write(data);\n };\n socket.on('close', function () {\n self.open_sockets = _.without(self.open_sockets, socket);\n });\n self.open_sockets.push(socket);\n\n // XXX COMPAT WITH 0.6.6. Send the old style welcome message, which\n // will force old clients to reload. Remove this once we're not\n // concerned about people upgrading from a pre-0.7.0 release. Also,\n // remove the clause in the client that ignores the welcome message\n // (livedata_connection.js)\n socket.send(JSON.stringify({server_id: \"0\"}));\n\n // call all our callbacks when we get a new socket. they will do the\n // work of setting up handlers and such for specific messages.\n _.each(self.registration_callbacks, function (callback) {\n callback(socket);\n });\n });\n\n};\n\n_.extend(StreamServer.prototype, {\n // call my callback when a new socket connects.\n // also call it for all current connections.\n register: function (callback) {\n var self = this;\n self.registration_callbacks.push(callback);\n _.each(self.all_sockets(), function (socket) {\n callback(socket);\n });\n },\n\n // get a list of all sockets\n all_sockets: function () {\n var self = this;\n return _.values(self.open_sockets);\n },\n\n // Redirect /websocket to /sockjs/websocket in order to not expose\n // sockjs to clients that want to use raw websockets\n _redirectWebsocketEndpoint: function() {\n var self = this;\n // Unfortunately we can't use a connect middleware here since\n // sockjs installs itself prior to all existing listeners\n // (meaning prior to any connect middlewares) so we need to take\n // an approach similar to overshadowListeners in\n // https://github.com/sockjs/sockjs-node/blob/cf820c55af6a9953e16558555a31decea554f70e/src/utils.coffee\n _.each(['request', 'upgrade'], function(event) {\n var httpServer = Package.webapp.WebApp.httpServer;\n var oldHttpServerListeners = httpServer.listeners(event).slice(0);\n httpServer.removeAllListeners(event);\n\n // request and upgrade have different arguments passed but\n // we only care about the first one which is always request\n var newListener = function(request /*, moreArguments */) {\n // Store arguments for use within the closure below\n var args = arguments;\n\n // Rewrite /websocket and /websocket/ urls to /sockjs/websocket while\n // preserving query string.\n var parsedUrl = url.parse(request.url);\n if (parsedUrl.pathname === pathPrefix + '/websocket' ||\n parsedUrl.pathname === pathPrefix + '/websocket/') {\n parsedUrl.pathname = self.prefix + '/websocket';\n request.url = url.format(parsedUrl);\n }\n _.each(oldHttpServerListeners, function(oldListener) {\n oldListener.apply(httpServer, args);\n });\n };\n httpServer.addListener(event, newListener);\n });\n }\n});\n","// Heartbeat options:\n// heartbeatInterval: interval to send pings, in milliseconds.\n// heartbeatTimeout: timeout to close the connection if a reply isn't\n// received, in milliseconds.\n// sendPing: function to call to send a ping on the connection.\n// onTimeout: function to call to close the connection.\n\nHeartbeat = function (options) {\n var self = this;\n\n self.heartbeatInterval = options.heartbeatInterval;\n self.heartbeatTimeout = options.heartbeatTimeout;\n self._sendPing = options.sendPing;\n self._onTimeout = options.onTimeout;\n\n self._heartbeatIntervalHandle = null;\n self._heartbeatTimeoutHandle = null;\n};\n\n_.extend(Heartbeat.prototype, {\n stop: function () {\n var self = this;\n self._clearHeartbeatIntervalTimer();\n self._clearHeartbeatTimeoutTimer();\n },\n\n start: function () {\n var self = this;\n self.stop();\n self._startHeartbeatIntervalTimer();\n },\n\n _startHeartbeatIntervalTimer: function () {\n var self = this;\n self._heartbeatIntervalHandle = Meteor.setTimeout(\n _.bind(self._heartbeatIntervalFired, self),\n self.heartbeatInterval\n );\n },\n\n _startHeartbeatTimeoutTimer: function () {\n var self = this;\n self._heartbeatTimeoutHandle = Meteor.setTimeout(\n _.bind(self._heartbeatTimeoutFired, self),\n self.heartbeatTimeout\n );\n },\n\n _clearHeartbeatIntervalTimer: function () {\n var self = this;\n if (self._heartbeatIntervalHandle) {\n Meteor.clearTimeout(self._heartbeatIntervalHandle);\n self._heartbeatIntervalHandle = null;\n }\n },\n\n _clearHeartbeatTimeoutTimer: function () {\n var self = this;\n if (self._heartbeatTimeoutHandle) {\n Meteor.clearTimeout(self._heartbeatTimeoutHandle);\n self._heartbeatTimeoutHandle = null;\n }\n },\n\n // The heartbeat interval timer is fired when we should send a ping.\n _heartbeatIntervalFired: function () {\n var self = this;\n self._heartbeatIntervalHandle = null;\n self._sendPing();\n // Wait for a pong.\n self._startHeartbeatTimeoutTimer();\n },\n\n // The heartbeat timeout timer is fired when we sent a ping, but we\n // timed out waiting for the pong.\n _heartbeatTimeoutFired: function () {\n var self = this;\n self._heartbeatTimeoutHandle = null;\n self._onTimeout();\n },\n\n pingReceived: function () {\n var self = this;\n // We know the connection is alive if we receive a ping, so we\n // don't need to send a ping ourselves. Reset the interval timer.\n if (self._heartbeatIntervalHandle) {\n self._clearHeartbeatIntervalTimer();\n self._startHeartbeatIntervalTimer();\n }\n },\n\n pongReceived: function () {\n var self = this;\n\n // Receiving a pong means we won't timeout, so clear the timeout\n // timer and start the interval again.\n if (self._heartbeatTimeoutHandle) {\n self._clearHeartbeatTimeoutTimer();\n self._startHeartbeatIntervalTimer();\n }\n }\n});\n","DDPServer = {};\n\nvar Fiber = Npm.require('fibers');\n\n// This file contains classes:\n// * Session - The server's connection to a single DDP client\n// * Subscription - A single subscription for a single client\n// * Server - An entire server that may talk to > 1 client. A DDP endpoint.\n//\n// Session and Subscription are file scope. For now, until we freeze\n// the interface, Server is package scope (in the future it should be\n// exported.)\n\n// Represents a single document in a SessionCollectionView\nvar SessionDocumentView = function () {\n var self = this;\n self.existsIn = {}; // set of subscriptionHandle\n self.dataByKey = {}; // key-> [ {subscriptionHandle, value} by precedence]\n};\n\n_.extend(SessionDocumentView.prototype, {\n\n getFields: function () {\n var self = this;\n var ret = {};\n _.each(self.dataByKey, function (precedenceList, key) {\n ret[key] = precedenceList[0].value;\n });\n return ret;\n },\n\n clearField: function (subscriptionHandle, key, changeCollector) {\n var self = this;\n // Publish API ignores _id if present in fields\n if (key === \"_id\")\n return;\n var precedenceList = self.dataByKey[key];\n\n // It's okay to clear fields that didn't exist. No need to throw\n // an error.\n if (!precedenceList)\n return;\n\n var removedValue = undefined;\n for (var i = 0; i < precedenceList.length; i++) {\n var precedence = precedenceList[i];\n if (precedence.subscriptionHandle === subscriptionHandle) {\n // The view's value can only change if this subscription is the one that\n // used to have precedence.\n if (i === 0)\n removedValue = precedence.value;\n precedenceList.splice(i, 1);\n break;\n }\n }\n if (_.isEmpty(precedenceList)) {\n delete self.dataByKey[key];\n changeCollector[key] = undefined;\n } else if (removedValue !== undefined &&\n !EJSON.equals(removedValue, precedenceList[0].value)) {\n changeCollector[key] = precedenceList[0].value;\n }\n },\n\n changeField: function (subscriptionHandle, key, value,\n changeCollector, isAdd) {\n var self = this;\n // Publish API ignores _id if present in fields\n if (key === \"_id\")\n return;\n\n // Don't share state with the data passed in by the user.\n value = EJSON.clone(value);\n\n if (!_.has(self.dataByKey, key)) {\n self.dataByKey[key] = [{subscriptionHandle: subscriptionHandle,\n value: value}];\n changeCollector[key] = value;\n return;\n }\n var precedenceList = self.dataByKey[key];\n var elt;\n if (!isAdd) {\n elt = _.find(precedenceList, function (precedence) {\n return precedence.subscriptionHandle === subscriptionHandle;\n });\n }\n\n if (elt) {\n if (elt === precedenceList[0] && !EJSON.equals(value, elt.value)) {\n // this subscription is changing the value of this field.\n changeCollector[key] = value;\n }\n elt.value = value;\n } else {\n // this subscription is newly caring about this field\n precedenceList.push({subscriptionHandle: subscriptionHandle, value: value});\n }\n\n }\n});\n\n/**\n * Represents a client's view of a single collection\n * @param {String} collectionName Name of the collection it represents\n * @param {Object.} sessionCallbacks The callbacks for added, changed, removed\n * @class SessionCollectionView\n */\nvar SessionCollectionView = function (collectionName, sessionCallbacks) {\n var self = this;\n self.collectionName = collectionName;\n self.documents = {};\n self.callbacks = sessionCallbacks;\n};\n\nLivedataTest.SessionCollectionView = SessionCollectionView;\n\n\n_.extend(SessionCollectionView.prototype, {\n\n isEmpty: function () {\n var self = this;\n return _.isEmpty(self.documents);\n },\n\n diff: function (previous) {\n var self = this;\n LocalCollection._diffObjects(previous.documents, self.documents, {\n both: _.bind(self.diffDocument, self),\n\n rightOnly: function (id, nowDV) {\n self.callbacks.added(self.collectionName, id, nowDV.getFields());\n },\n\n leftOnly: function (id, prevDV) {\n self.callbacks.removed(self.collectionName, id);\n }\n });\n },\n\n diffDocument: function (id, prevDV, nowDV) {\n var self = this;\n var fields = {};\n LocalCollection._diffObjects(prevDV.getFields(), nowDV.getFields(), {\n both: function (key, prev, now) {\n if (!EJSON.equals(prev, now))\n fields[key] = now;\n },\n rightOnly: function (key, now) {\n fields[key] = now;\n },\n leftOnly: function(key, prev) {\n fields[key] = undefined;\n }\n });\n self.callbacks.changed(self.collectionName, id, fields);\n },\n\n added: function (subscriptionHandle, id, fields) {\n var self = this;\n var docView = self.documents[id];\n var added = false;\n if (!docView) {\n added = true;\n docView = new SessionDocumentView();\n self.documents[id] = docView;\n }\n docView.existsIn[subscriptionHandle] = true;\n var changeCollector = {};\n _.each(fields, function (value, key) {\n docView.changeField(\n subscriptionHandle, key, value, changeCollector, true);\n });\n if (added)\n self.callbacks.added(self.collectionName, id, changeCollector);\n else\n self.callbacks.changed(self.collectionName, id, changeCollector);\n },\n\n changed: function (subscriptionHandle, id, changed) {\n var self = this;\n var changedResult = {};\n var docView = self.documents[id];\n if (!docView)\n throw new Error(\"Could not find element with id \" + id + \" to change\");\n _.each(changed, function (value, key) {\n if (value === undefined)\n docView.clearField(subscriptionHandle, key, changedResult);\n else\n docView.changeField(subscriptionHandle, key, value, changedResult);\n });\n self.callbacks.changed(self.collectionName, id, changedResult);\n },\n\n removed: function (subscriptionHandle, id) {\n var self = this;\n var docView = self.documents[id];\n if (!docView) {\n var err = new Error(\"Removed nonexistent document \" + id);\n throw err;\n }\n delete docView.existsIn[subscriptionHandle];\n if (_.isEmpty(docView.existsIn)) {\n // it is gone from everyone\n self.callbacks.removed(self.collectionName, id);\n delete self.documents[id];\n } else {\n var changed = {};\n // remove this subscription from every precedence list\n // and record the changes\n _.each(docView.dataByKey, function (precedenceList, key) {\n docView.clearField(subscriptionHandle, key, changed);\n });\n\n self.callbacks.changed(self.collectionName, id, changed);\n }\n }\n});\n\n/******************************************************************************/\n/* Session */\n/******************************************************************************/\n\nvar Session = function (server, version, socket, options) {\n var self = this;\n self.id = Random.id();\n\n self.server = server;\n self.version = version;\n\n self.initialized = false;\n self.socket = socket;\n\n // set to null when the session is destroyed. multiple places below\n // use this to determine if the session is alive or not.\n self.inQueue = new Meteor._DoubleEndedQueue();\n\n self.blocked = false;\n self.workerRunning = false;\n\n // Sub objects for active subscriptions\n self._namedSubs = {};\n self._universalSubs = [];\n\n self.userId = null;\n\n self.collectionViews = {};\n\n // Set this to false to not send messages when collectionViews are\n // modified. This is done when rerunning subs in _setUserId and those messages\n // are calculated via a diff instead.\n self._isSending = true;\n\n // If this is true, don't start a newly-created universal publisher on this\n // session. The session will take care of starting it when appropriate.\n self._dontStartNewUniversalSubs = false;\n\n // when we are rerunning subscriptions, any ready messages\n // we want to buffer up for when we are done rerunning subscriptions\n self._pendingReady = [];\n\n // List of callbacks to call when this connection is closed.\n self._closeCallbacks = [];\n\n\n // XXX HACK: If a sockjs connection, save off the URL. This is\n // temporary and will go away in the near future.\n self._socketUrl = socket.url;\n\n // Allow tests to disable responding to pings.\n self._respondToPings = options.respondToPings;\n\n // This object is the public interface to the session. In the public\n // API, it is called the `connection` object. Internally we call it\n // a `connectionHandle` to avoid ambiguity.\n self.connectionHandle = {\n id: self.id,\n close: function () {\n self.close();\n },\n onClose: function (fn) {\n var cb = Meteor.bindEnvironment(fn, \"connection onClose callback\");\n if (self.inQueue) {\n self._closeCallbacks.push(cb);\n } else {\n // if we're already closed, call the callback.\n Meteor.defer(cb);\n }\n },\n clientAddress: self._clientAddress(),\n httpHeaders: self.socket.headers\n };\n\n socket.send(stringifyDDP({msg: 'connected',\n session: self.id}));\n // On initial connect, spin up all the universal publishers.\n Fiber(function () {\n self.startUniversalSubs();\n }).run();\n\n if (version !== 'pre1' && options.heartbeatInterval !== 0) {\n self.heartbeat = new Heartbeat({\n heartbeatInterval: options.heartbeatInterval,\n heartbeatTimeout: options.heartbeatTimeout,\n onTimeout: function () {\n self.close();\n },\n sendPing: function () {\n self.send({msg: 'ping'});\n }\n });\n self.heartbeat.start();\n }\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"livedata\", \"sessions\", 1);\n};\n\n_.extend(Session.prototype, {\n\n sendReady: function (subscriptionIds) {\n var self = this;\n if (self._isSending)\n self.send({msg: \"ready\", subs: subscriptionIds});\n else {\n _.each(subscriptionIds, function (subscriptionId) {\n self._pendingReady.push(subscriptionId);\n });\n }\n },\n\n sendAdded: function (collectionName, id, fields) {\n var self = this;\n if (self._isSending)\n self.send({msg: \"added\", collection: collectionName, id: id, fields: fields});\n },\n\n sendChanged: function (collectionName, id, fields) {\n var self = this;\n if (_.isEmpty(fields))\n return;\n\n if (self._isSending) {\n self.send({\n msg: \"changed\",\n collection: collectionName,\n id: id,\n fields: fields\n });\n }\n },\n\n sendRemoved: function (collectionName, id) {\n var self = this;\n if (self._isSending)\n self.send({msg: \"removed\", collection: collectionName, id: id});\n },\n\n getSendCallbacks: function () {\n var self = this;\n return {\n added: _.bind(self.sendAdded, self),\n changed: _.bind(self.sendChanged, self),\n removed: _.bind(self.sendRemoved, self)\n };\n },\n\n getCollectionView: function (collectionName) {\n var self = this;\n if (_.has(self.collectionViews, collectionName)) {\n return self.collectionViews[collectionName];\n }\n var ret = new SessionCollectionView(collectionName,\n self.getSendCallbacks());\n self.collectionViews[collectionName] = ret;\n return ret;\n },\n\n added: function (subscriptionHandle, collectionName, id, fields) {\n var self = this;\n var view = self.getCollectionView(collectionName);\n view.added(subscriptionHandle, id, fields);\n },\n\n removed: function (subscriptionHandle, collectionName, id) {\n var self = this;\n var view = self.getCollectionView(collectionName);\n view.removed(subscriptionHandle, id);\n if (view.isEmpty()) {\n delete self.collectionViews[collectionName];\n }\n },\n\n changed: function (subscriptionHandle, collectionName, id, fields) {\n var self = this;\n var view = self.getCollectionView(collectionName);\n view.changed(subscriptionHandle, id, fields);\n },\n\n startUniversalSubs: function () {\n var self = this;\n // Make a shallow copy of the set of universal handlers and start them. If\n // additional universal publishers start while we're running them (due to\n // yielding), they will run separately as part of Server.publish.\n var handlers = _.clone(self.server.universal_publish_handlers);\n _.each(handlers, function (handler) {\n self._startSubscription(handler);\n });\n },\n\n // Destroy this session and unregister it at the server.\n close: function () {\n var self = this;\n\n // Destroy this session, even if it's not registered at the\n // server. Stop all processing and tear everything down. If a socket\n // was attached, close it.\n\n // Already destroyed.\n if (! self.inQueue)\n return;\n\n // Drop the merge box data immediately.\n self.inQueue = null;\n self.collectionViews = {};\n\n if (self.heartbeat) {\n self.heartbeat.stop();\n self.heartbeat = null;\n }\n\n if (self.socket) {\n self.socket.close();\n self.socket._meteorSession = null;\n }\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"livedata\", \"sessions\", -1);\n\n Meteor.defer(function () {\n // stop callbacks can yield, so we defer this on close.\n // sub._isDeactivated() detects that we set inQueue to null and\n // treats it as semi-deactivated (it will ignore incoming callbacks, etc).\n self._deactivateAllSubscriptions();\n\n // Defer calling the close callbacks, so that the caller closing\n // the session isn't waiting for all the callbacks to complete.\n _.each(self._closeCallbacks, function (callback) {\n callback();\n });\n });\n\n // Unregister the session.\n self.server._removeSession(self);\n },\n\n // Send a message (doing nothing if no socket is connected right now.)\n // It should be a JSON object (it will be stringified.)\n send: function (msg) {\n var self = this;\n if (self.socket) {\n if (Meteor._printSentDDP)\n Meteor._debug(\"Sent DDP\", stringifyDDP(msg));\n self.socket.send(stringifyDDP(msg));\n }\n },\n\n // Send a connection error.\n sendError: function (reason, offendingMessage) {\n var self = this;\n var msg = {msg: 'error', reason: reason};\n if (offendingMessage)\n msg.offendingMessage = offendingMessage;\n self.send(msg);\n },\n\n // Process 'msg' as an incoming message. (But as a guard against\n // race conditions during reconnection, ignore the message if\n // 'socket' is not the currently connected socket.)\n //\n // We run the messages from the client one at a time, in the order\n // given by the client. The message handler is passed an idempotent\n // function 'unblock' which it may call to allow other messages to\n // begin running in parallel in another fiber (for example, a method\n // that wants to yield.) Otherwise, it is automatically unblocked\n // when it returns.\n //\n // Actually, we don't have to 'totally order' the messages in this\n // way, but it's the easiest thing that's correct. (unsub needs to\n // be ordered against sub, methods need to be ordered against each\n // other.)\n processMessage: function (msg_in) {\n var self = this;\n if (!self.inQueue) // we have been destroyed.\n return;\n\n // Respond to ping and pong messages immediately without queuing.\n // If the negotiated DDP version is \"pre1\" which didn't support\n // pings, preserve the \"pre1\" behavior of responding with a \"bad\n // request\" for the unknown messages.\n //\n // Fibers are needed because heartbeat uses Meteor.setTimeout, which\n // needs a Fiber. We could actually use regular setTimeout and avoid\n // these new fibers, but it is easier to just make everything use\n // Meteor.setTimeout and not think too hard.\n if (self.version !== 'pre1' && msg_in.msg === 'ping') {\n if (self._respondToPings)\n self.send({msg: \"pong\", id: msg_in.id});\n if (self.heartbeat)\n Fiber(function () {\n self.heartbeat.pingReceived();\n }).run();\n return;\n }\n if (self.version !== 'pre1' && msg_in.msg === 'pong') {\n if (self.heartbeat)\n Fiber(function () {\n self.heartbeat.pongReceived();\n }).run();\n return;\n }\n\n self.inQueue.push(msg_in);\n if (self.workerRunning)\n return;\n self.workerRunning = true;\n\n var processNext = function () {\n var msg = self.inQueue && self.inQueue.shift();\n if (!msg) {\n self.workerRunning = false;\n return;\n }\n\n Fiber(function () {\n var blocked = true;\n\n var unblock = function () {\n if (!blocked)\n return; // idempotent\n blocked = false;\n processNext();\n };\n\n if (_.has(self.protocol_handlers, msg.msg))\n self.protocol_handlers[msg.msg].call(self, msg, unblock);\n else\n self.sendError('Bad request', msg);\n unblock(); // in case the handler didn't already do it\n }).run();\n };\n\n processNext();\n },\n\n protocol_handlers: {\n sub: function (msg) {\n var self = this;\n\n // reject malformed messages\n if (typeof (msg.id) !== \"string\" ||\n typeof (msg.name) !== \"string\" ||\n (('params' in msg) && !(msg.params instanceof Array))) {\n self.sendError(\"Malformed subscription\", msg);\n return;\n }\n\n if (!self.server.publish_handlers[msg.name]) {\n self.send({\n msg: 'nosub', id: msg.id,\n error: new Meteor.Error(404, \"Subscription not found\")});\n return;\n }\n\n if (_.has(self._namedSubs, msg.id))\n // subs are idempotent, or rather, they are ignored if a sub\n // with that id already exists. this is important during\n // reconnect.\n return;\n\n var handler = self.server.publish_handlers[msg.name];\n self._startSubscription(handler, msg.id, msg.params, msg.name);\n\n },\n\n unsub: function (msg) {\n var self = this;\n\n self._stopSubscription(msg.id);\n },\n\n method: function (msg, unblock) {\n var self = this;\n\n // reject malformed messages\n // For now, we silently ignore unknown attributes,\n // for forwards compatibility.\n if (typeof (msg.id) !== \"string\" ||\n typeof (msg.method) !== \"string\" ||\n (('params' in msg) && !(msg.params instanceof Array)) ||\n (('randomSeed' in msg) && (typeof msg.randomSeed !== \"string\"))) {\n self.sendError(\"Malformed method invocation\", msg);\n return;\n }\n\n var randomSeed = msg.randomSeed || null;\n\n // set up to mark the method as satisfied once all observers\n // (and subscriptions) have reacted to any writes that were\n // done.\n var fence = new DDPServer._WriteFence;\n fence.onAllCommitted(function () {\n // Retire the fence so that future writes are allowed.\n // This means that callbacks like timers are free to use\n // the fence, and if they fire before it's armed (for\n // example, because the method waits for them) their\n // writes will be included in the fence.\n fence.retire();\n self.send({\n msg: 'updated', methods: [msg.id]});\n });\n\n // find the handler\n var handler = self.server.method_handlers[msg.method];\n if (!handler) {\n self.send({\n msg: 'result', id: msg.id,\n error: new Meteor.Error(404, \"Method not found\")});\n fence.arm();\n return;\n }\n\n var setUserId = function(userId) {\n self._setUserId(userId);\n };\n\n var invocation = new MethodInvocation({\n isSimulation: false,\n userId: self.userId,\n setUserId: setUserId,\n unblock: unblock,\n connection: self.connectionHandle,\n randomSeed: randomSeed\n });\n try {\n var result = DDPServer._CurrentWriteFence.withValue(fence, function () {\n return DDP._CurrentInvocation.withValue(invocation, function () {\n return maybeAuditArgumentChecks(\n handler, invocation, msg.params, \"call to '\" + msg.method + \"'\");\n });\n });\n } catch (e) {\n var exception = e;\n }\n\n fence.arm(); // we're done adding writes to the fence\n unblock(); // unblock, if the method hasn't done it already\n\n exception = wrapInternalException(\n exception, \"while invoking method '\" + msg.method + \"'\");\n\n // send response and add to cache\n var payload =\n exception ? {error: exception} : (result !== undefined ?\n {result: result} : {});\n self.send(_.extend({msg: 'result', id: msg.id}, payload));\n }\n },\n\n _eachSub: function (f) {\n var self = this;\n _.each(self._namedSubs, f);\n _.each(self._universalSubs, f);\n },\n\n _diffCollectionViews: function (beforeCVs) {\n var self = this;\n LocalCollection._diffObjects(beforeCVs, self.collectionViews, {\n both: function (collectionName, leftValue, rightValue) {\n rightValue.diff(leftValue);\n },\n rightOnly: function (collectionName, rightValue) {\n _.each(rightValue.documents, function (docView, id) {\n self.sendAdded(collectionName, id, docView.getFields());\n });\n },\n leftOnly: function (collectionName, leftValue) {\n _.each(leftValue.documents, function (doc, id) {\n self.sendRemoved(collectionName, id);\n });\n }\n });\n },\n\n // Sets the current user id in all appropriate contexts and reruns\n // all subscriptions\n _setUserId: function(userId) {\n var self = this;\n\n if (userId !== null && typeof userId !== \"string\")\n throw new Error(\"setUserId must be called on string or null, not \" +\n typeof userId);\n\n // Prevent newly-created universal subscriptions from being added to our\n // session; they will be found below when we call startUniversalSubs.\n //\n // (We don't have to worry about named subscriptions, because we only add\n // them when we process a 'sub' message. We are currently processing a\n // 'method' message, and the method did not unblock, because it is illegal\n // to call setUserId after unblock. Thus we cannot be concurrently adding a\n // new named subscription.)\n self._dontStartNewUniversalSubs = true;\n\n // Prevent current subs from updating our collectionViews and call their\n // stop callbacks. This may yield.\n self._eachSub(function (sub) {\n sub._deactivate();\n });\n\n // All subs should now be deactivated. Stop sending messages to the client,\n // save the state of the published collections, reset to an empty view, and\n // update the userId.\n self._isSending = false;\n var beforeCVs = self.collectionViews;\n self.collectionViews = {};\n self.userId = userId;\n\n // Save the old named subs, and reset to having no subscriptions.\n var oldNamedSubs = self._namedSubs;\n self._namedSubs = {};\n self._universalSubs = [];\n\n _.each(oldNamedSubs, function (sub, subscriptionId) {\n self._namedSubs[subscriptionId] = sub._recreate();\n // nb: if the handler throws or calls this.error(), it will in fact\n // immediately send its 'nosub'. This is OK, though.\n self._namedSubs[subscriptionId]._runHandler();\n });\n\n // Allow newly-created universal subs to be started on our connection in\n // parallel with the ones we're spinning up here, and spin up universal\n // subs.\n self._dontStartNewUniversalSubs = false;\n self.startUniversalSubs();\n\n // Start sending messages again, beginning with the diff from the previous\n // state of the world to the current state. No yields are allowed during\n // this diff, so that other changes cannot interleave.\n Meteor._noYieldsAllowed(function () {\n self._isSending = true;\n self._diffCollectionViews(beforeCVs);\n if (!_.isEmpty(self._pendingReady)) {\n self.sendReady(self._pendingReady);\n self._pendingReady = [];\n }\n });\n },\n\n _startSubscription: function (handler, subId, params, name) {\n var self = this;\n\n var sub = new Subscription(\n self, handler, subId, params, name);\n if (subId)\n self._namedSubs[subId] = sub;\n else\n self._universalSubs.push(sub);\n\n sub._runHandler();\n },\n\n // tear down specified subscription\n _stopSubscription: function (subId, error) {\n var self = this;\n\n var subName = null;\n\n if (subId && self._namedSubs[subId]) {\n subName = self._namedSubs[subId]._name;\n self._namedSubs[subId]._removeAllDocuments();\n self._namedSubs[subId]._deactivate();\n delete self._namedSubs[subId];\n }\n\n var response = {msg: 'nosub', id: subId};\n\n if (error) {\n response.error = wrapInternalException(\n error,\n subName ? (\"from sub \" + subName + \" id \" + subId)\n : (\"from sub id \" + subId));\n }\n\n self.send(response);\n },\n\n // tear down all subscriptions. Note that this does NOT send removed or nosub\n // messages, since we assume the client is gone.\n _deactivateAllSubscriptions: function () {\n var self = this;\n\n _.each(self._namedSubs, function (sub, id) {\n sub._deactivate();\n });\n self._namedSubs = {};\n\n _.each(self._universalSubs, function (sub) {\n sub._deactivate();\n });\n self._universalSubs = [];\n },\n\n // Determine the remote client's IP address, based on the\n // HTTP_FORWARDED_COUNT environment variable representing how many\n // proxies the server is behind.\n _clientAddress: function () {\n var self = this;\n\n // For the reported client address for a connection to be correct,\n // the developer must set the HTTP_FORWARDED_COUNT environment\n // variable to an integer representing the number of hops they\n // expect in the `x-forwarded-for` header. E.g., set to \"1\" if the\n // server is behind one proxy.\n //\n // This could be computed once at startup instead of every time.\n var httpForwardedCount = parseInt(process.env['HTTP_FORWARDED_COUNT']) || 0;\n\n if (httpForwardedCount === 0)\n return self.socket.remoteAddress;\n\n var forwardedFor = self.socket.headers[\"x-forwarded-for\"];\n if (! _.isString(forwardedFor))\n return null;\n forwardedFor = forwardedFor.trim().split(/\\s*,\\s*/);\n\n // Typically the first value in the `x-forwarded-for` header is\n // the original IP address of the client connecting to the first\n // proxy. However, the end user can easily spoof the header, in\n // which case the first value(s) will be the fake IP address from\n // the user pretending to be a proxy reporting the original IP\n // address value. By counting HTTP_FORWARDED_COUNT back from the\n // end of the list, we ensure that we get the IP address being\n // reported by *our* first proxy.\n\n if (httpForwardedCount < 0 || httpForwardedCount > forwardedFor.length)\n return null;\n\n return forwardedFor[forwardedFor.length - httpForwardedCount];\n }\n});\n\n/******************************************************************************/\n/* Subscription */\n/******************************************************************************/\n\n// ctor for a sub handle: the input to each publish function\n\n// Instance name is this because it's usually referred to as this inside a\n// publish\n/**\n * @summary The server's side of a subscription\n * @class Subscription\n * @instanceName this\n */\nvar Subscription = function (\n session, handler, subscriptionId, params, name) {\n var self = this;\n self._session = session; // type is Session\n\n /**\n * @summary Access inside the publish function. The incoming [connection](#meteor_onconnection) for this subscription.\n * @locus Server\n * @name connection\n * @memberOf Subscription\n * @instance\n */\n self.connection = session.connectionHandle; // public API object\n\n self._handler = handler;\n\n // my subscription ID (generated by client, undefined for universal subs).\n self._subscriptionId = subscriptionId;\n // undefined for universal subs\n self._name = name;\n\n self._params = params || [];\n\n // Only named subscriptions have IDs, but we need some sort of string\n // internally to keep track of all subscriptions inside\n // SessionDocumentViews. We use this subscriptionHandle for that.\n if (self._subscriptionId) {\n self._subscriptionHandle = 'N' + self._subscriptionId;\n } else {\n self._subscriptionHandle = 'U' + Random.id();\n }\n\n // has _deactivate been called?\n self._deactivated = false;\n\n // stop callbacks to g/c this sub. called w/ zero arguments.\n self._stopCallbacks = [];\n\n // the set of (collection, documentid) that this subscription has\n // an opinion about\n self._documents = {};\n\n // remember if we are ready.\n self._ready = false;\n\n // Part of the public API: the user of this sub.\n\n /**\n * @summary Access inside the publish function. The id of the logged-in user, or `null` if no user is logged in.\n * @locus Server\n * @memberOf Subscription\n * @name userId\n * @instance\n */\n self.userId = session.userId;\n\n // For now, the id filter is going to default to\n // the to/from DDP methods on LocalCollection, to\n // specifically deal with mongo/minimongo ObjectIds.\n\n // Later, you will be able to make this be \"raw\"\n // if you want to publish a collection that you know\n // just has strings for keys and no funny business, to\n // a ddp consumer that isn't minimongo\n\n self._idFilter = {\n idStringify: LocalCollection._idStringify,\n idParse: LocalCollection._idParse\n };\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"livedata\", \"subscriptions\", 1);\n};\n\n_.extend(Subscription.prototype, {\n _runHandler: function () {\n // XXX should we unblock() here? Either before running the publish\n // function, or before running _publishCursor.\n //\n // Right now, each publish function blocks all future publishes and\n // methods waiting on data from Mongo (or whatever else the function\n // blocks on). This probably slows page load in common cases.\n\n var self = this;\n try {\n var res = maybeAuditArgumentChecks(\n self._handler, self, EJSON.clone(self._params),\n // It's OK that this would look weird for universal subscriptions,\n // because they have no arguments so there can never be an\n // audit-argument-checks failure.\n \"publisher '\" + self._name + \"'\");\n } catch (e) {\n self.error(e);\n return;\n }\n\n // Did the handler call this.error or this.stop?\n if (self._isDeactivated())\n return;\n\n // SPECIAL CASE: Instead of writing their own callbacks that invoke\n // this.added/changed/ready/etc, the user can just return a collection\n // cursor or array of cursors from the publish function; we call their\n // _publishCursor method which starts observing the cursor and publishes the\n // results. Note that _publishCursor does NOT call ready().\n //\n // XXX This uses an undocumented interface which only the Mongo cursor\n // interface publishes. Should we make this interface public and encourage\n // users to implement it themselves? Arguably, it's unnecessary; users can\n // already write their own functions like\n // var publishMyReactiveThingy = function (name, handler) {\n // Meteor.publish(name, function () {\n // var reactiveThingy = handler();\n // reactiveThingy.publishMe();\n // });\n // };\n var isCursor = function (c) {\n return c && c._publishCursor;\n };\n if (isCursor(res)) {\n try {\n res._publishCursor(self);\n } catch (e) {\n self.error(e);\n return;\n }\n // _publishCursor only returns after the initial added callbacks have run.\n // mark subscription as ready.\n self.ready();\n } else if (_.isArray(res)) {\n // check all the elements are cursors\n if (! _.all(res, isCursor)) {\n self.error(new Error(\"Publish function returned an array of non-Cursors\"));\n return;\n }\n // find duplicate collection names\n // XXX we should support overlapping cursors, but that would require the\n // merge box to allow overlap within a subscription\n var collectionNames = {};\n for (var i = 0; i < res.length; ++i) {\n var collectionName = res[i]._getCollectionName();\n if (_.has(collectionNames, collectionName)) {\n self.error(new Error(\n \"Publish function returned multiple cursors for collection \" +\n collectionName));\n return;\n }\n collectionNames[collectionName] = true;\n };\n\n try {\n _.each(res, function (cur) {\n cur._publishCursor(self);\n });\n } catch (e) {\n self.error(e);\n return;\n }\n self.ready();\n } else if (res) {\n // truthy values other than cursors or arrays are probably a\n // user mistake (possible returning a Mongo document via, say,\n // `coll.findOne()`).\n self.error(new Error(\"Publish function can only return a Cursor or \"\n + \"an array of Cursors\"));\n }\n },\n\n // This calls all stop callbacks and prevents the handler from updating any\n // SessionCollectionViews further. It's used when the user unsubscribes or\n // disconnects, as well as during setUserId re-runs. It does *NOT* send\n // removed messages for the published objects; if that is necessary, call\n // _removeAllDocuments first.\n _deactivate: function() {\n var self = this;\n if (self._deactivated)\n return;\n self._deactivated = true;\n self._callStopCallbacks();\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"livedata\", \"subscriptions\", -1);\n },\n\n _callStopCallbacks: function () {\n var self = this;\n // tell listeners, so they can clean up\n var callbacks = self._stopCallbacks;\n self._stopCallbacks = [];\n _.each(callbacks, function (callback) {\n callback();\n });\n },\n\n // Send remove messages for every document.\n _removeAllDocuments: function () {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n _.each(self._documents, function(collectionDocs, collectionName) {\n // Iterate over _.keys instead of the dictionary itself, since we'll be\n // mutating it.\n _.each(_.keys(collectionDocs), function (strId) {\n self.removed(collectionName, self._idFilter.idParse(strId));\n });\n });\n });\n },\n\n // Returns a new Subscription for the same session with the same\n // initial creation parameters. This isn't a clone: it doesn't have\n // the same _documents cache, stopped state or callbacks; may have a\n // different _subscriptionHandle, and gets its userId from the\n // session, not from this object.\n _recreate: function () {\n var self = this;\n return new Subscription(\n self._session, self._handler, self._subscriptionId, self._params,\n self._name);\n },\n\n /**\n * @summary Call inside the publish function. Stops this client's subscription, triggering a call on the client to the `onStop` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any. If `error` is not a [`Meteor.Error`](#meteor_error), it will be [sanitized](#meteor_error).\n * @locus Server\n * @param {Error} error The error to pass to the client.\n * @instance\n * @memberOf Subscription\n */\n error: function (error) {\n var self = this;\n if (self._isDeactivated())\n return;\n self._session._stopSubscription(self._subscriptionId, error);\n },\n\n // Note that while our DDP client will notice that you've called stop() on the\n // server (and clean up its _subscriptions table) we don't actually provide a\n // mechanism for an app to notice this (the subscribe onError callback only\n // triggers if there is an error).\n\n /**\n * @summary Call inside the publish function. Stops this client's subscription and invokes the client's `onStop` callback with no error.\n * @locus Server\n * @instance\n * @memberOf Subscription\n */\n stop: function () {\n var self = this;\n if (self._isDeactivated())\n return;\n self._session._stopSubscription(self._subscriptionId);\n },\n\n /**\n * @summary Call inside the publish function. Registers a callback function to run when the subscription is stopped.\n * @locus Server\n * @memberOf Subscription\n * @instance\n * @param {Function} func The callback function\n */\n onStop: function (callback) {\n var self = this;\n if (self._isDeactivated())\n callback();\n else\n self._stopCallbacks.push(callback);\n },\n\n // This returns true if the sub has been deactivated, *OR* if the session was\n // destroyed but the deferred call to _deactivateAllSubscriptions hasn't\n // happened yet.\n _isDeactivated: function () {\n var self = this;\n return self._deactivated || self._session.inQueue === null;\n },\n\n /**\n * @summary Call inside the publish function. Informs the subscriber that a document has been added to the record set.\n * @locus Server\n * @memberOf Subscription\n * @instance\n * @param {String} collection The name of the collection that contains the new document.\n * @param {String} id The new document's ID.\n * @param {Object} fields The fields in the new document. If `_id` is present it is ignored.\n */\n added: function (collectionName, id, fields) {\n var self = this;\n if (self._isDeactivated())\n return;\n id = self._idFilter.idStringify(id);\n Meteor._ensure(self._documents, collectionName)[id] = true;\n self._session.added(self._subscriptionHandle, collectionName, id, fields);\n },\n\n /**\n * @summary Call inside the publish function. Informs the subscriber that a document in the record set has been modified.\n * @locus Server\n * @memberOf Subscription\n * @instance\n * @param {String} collection The name of the collection that contains the changed document.\n * @param {String} id The changed document's ID.\n * @param {Object} fields The fields in the document that have changed, together with their new values. If a field is not present in `fields` it was left unchanged; if it is present in `fields` and has a value of `undefined` it was removed from the document. If `_id` is present it is ignored.\n */\n changed: function (collectionName, id, fields) {\n var self = this;\n if (self._isDeactivated())\n return;\n id = self._idFilter.idStringify(id);\n self._session.changed(self._subscriptionHandle, collectionName, id, fields);\n },\n\n /**\n * @summary Call inside the publish function. Informs the subscriber that a document has been removed from the record set.\n * @locus Server\n * @memberOf Subscription\n * @instance\n * @param {String} collection The name of the collection that the document has been removed from.\n * @param {String} id The ID of the document that has been removed.\n */\n removed: function (collectionName, id) {\n var self = this;\n if (self._isDeactivated())\n return;\n id = self._idFilter.idStringify(id);\n // We don't bother to delete sets of things in a collection if the\n // collection is empty. It could break _removeAllDocuments.\n delete self._documents[collectionName][id];\n self._session.removed(self._subscriptionHandle, collectionName, id);\n },\n\n /**\n * @summary Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the `onReady` callback passed to [`Meteor.subscribe`](#meteor_subscribe), if any.\n * @locus Server\n * @memberOf Subscription\n * @instance\n */\n ready: function () {\n var self = this;\n if (self._isDeactivated())\n return;\n if (!self._subscriptionId)\n return; // unnecessary but ignored for universal sub\n if (!self._ready) {\n self._session.sendReady([self._subscriptionId]);\n self._ready = true;\n }\n }\n});\n\n/******************************************************************************/\n/* Server */\n/******************************************************************************/\n\nServer = function (options) {\n var self = this;\n\n // The default heartbeat interval is 30 seconds on the server and 35\n // seconds on the client. Since the client doesn't need to send a\n // ping as long as it is receiving pings, this means that pings\n // normally go from the server to the client.\n //\n // Note: Troposphere depends on the ability to mutate\n // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life.\n self.options = _.defaults(options || {}, {\n heartbeatInterval: 30000,\n heartbeatTimeout: 15000,\n // For testing, allow responding to pings to be disabled.\n respondToPings: true\n });\n\n // Map of callbacks to call when a new connection comes in to the\n // server and completes DDP version negotiation. Use an object instead\n // of an array so we can safely remove one from the list while\n // iterating over it.\n self.onConnectionHook = new Hook({\n debugPrintExceptions: \"onConnection callback\"\n });\n\n self.publish_handlers = {};\n self.universal_publish_handlers = [];\n\n self.method_handlers = {};\n\n self.sessions = {}; // map from id to session\n\n self.stream_server = new StreamServer;\n\n self.stream_server.register(function (socket) {\n // socket implements the SockJSConnection interface\n socket._meteorSession = null;\n\n var sendError = function (reason, offendingMessage) {\n var msg = {msg: 'error', reason: reason};\n if (offendingMessage)\n msg.offendingMessage = offendingMessage;\n socket.send(stringifyDDP(msg));\n };\n\n socket.on('data', function (raw_msg) {\n if (Meteor._printReceivedDDP) {\n Meteor._debug(\"Received DDP\", raw_msg);\n }\n try {\n try {\n var msg = parseDDP(raw_msg);\n } catch (err) {\n sendError('Parse error');\n return;\n }\n if (msg === null || !msg.msg) {\n sendError('Bad request', msg);\n return;\n }\n\n if (msg.msg === 'connect') {\n if (socket._meteorSession) {\n sendError(\"Already connected\", msg);\n return;\n }\n Fiber(function () {\n self._handleConnect(socket, msg);\n }).run();\n return;\n }\n\n if (!socket._meteorSession) {\n sendError('Must connect first', msg);\n return;\n }\n socket._meteorSession.processMessage(msg);\n } catch (e) {\n // XXX print stack nicely\n Meteor._debug(\"Internal exception while processing message\", msg,\n e.message, e.stack);\n }\n });\n\n socket.on('close', function () {\n if (socket._meteorSession) {\n Fiber(function () {\n socket._meteorSession.close();\n }).run();\n }\n });\n });\n};\n\n_.extend(Server.prototype, {\n\n /**\n * @summary Register a callback to be called when a new DDP connection is made to the server.\n * @locus Server\n * @param {function} callback The function to call when a new DDP connection is established.\n * @memberOf Meteor\n */\n onConnection: function (fn) {\n var self = this;\n return self.onConnectionHook.register(fn);\n },\n\n _handleConnect: function (socket, msg) {\n var self = this;\n\n // The connect message must specify a version and an array of supported\n // versions, and it must claim to support what it is proposing.\n if (!(typeof (msg.version) === 'string' &&\n _.isArray(msg.support) &&\n _.all(msg.support, _.isString) &&\n _.contains(msg.support, msg.version))) {\n socket.send(stringifyDDP({msg: 'failed',\n version: SUPPORTED_DDP_VERSIONS[0]}));\n socket.close();\n return;\n }\n\n // In the future, handle session resumption: something like:\n // socket._meteorSession = self.sessions[msg.session]\n var version = calculateVersion(msg.support, SUPPORTED_DDP_VERSIONS);\n\n if (msg.version !== version) {\n // The best version to use (according to the client's stated preferences)\n // is not the one the client is trying to use. Inform them about the best\n // version to use.\n socket.send(stringifyDDP({msg: 'failed', version: version}));\n socket.close();\n return;\n }\n\n // Yay, version matches! Create a new session.\n // Note: Troposphere depends on the ability to mutate\n // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life.\n socket._meteorSession = new Session(self, version, socket, self.options);\n self.sessions[socket._meteorSession.id] = socket._meteorSession;\n self.onConnectionHook.each(function (callback) {\n if (socket._meteorSession)\n callback(socket._meteorSession.connectionHandle);\n return true;\n });\n },\n /**\n * Register a publish handler function.\n *\n * @param name {String} identifier for query\n * @param handler {Function} publish handler\n * @param options {Object}\n *\n * Server will call handler function on each new subscription,\n * either when receiving DDP sub message for a named subscription, or on\n * DDP connect for a universal subscription.\n *\n * If name is null, this will be a subscription that is\n * automatically established and permanently on for all connected\n * client, instead of a subscription that can be turned on and off\n * with subscribe().\n *\n * options to contain:\n * - (mostly internal) is_auto: true if generated automatically\n * from an autopublish hook. this is for cosmetic purposes only\n * (it lets us determine whether to print a warning suggesting\n * that you turn off autopublish.)\n */\n\n /**\n * @summary Publish a record set.\n * @memberOf Meteor\n * @locus Server\n * @param {String} name Name of the record set. If `null`, the set has no name, and the record set is automatically sent to all connected clients.\n * @param {Function} func Function called on the server each time a client subscribes. Inside the function, `this` is the publish handler object, described below. If the client passed arguments to `subscribe`, the function is called with the same arguments.\n */\n publish: function (name, handler, options) {\n var self = this;\n\n options = options || {};\n\n if (name && name in self.publish_handlers) {\n Meteor._debug(\"Ignoring duplicate publish named '\" + name + \"'\");\n return;\n }\n\n if (Package.autopublish && !options.is_auto) {\n // They have autopublish on, yet they're trying to manually\n // picking stuff to publish. They probably should turn off\n // autopublish. (This check isn't perfect -- if you create a\n // publish before you turn on autopublish, it won't catch\n // it. But this will definitely handle the simple case where\n // you've added the autopublish package to your app, and are\n // calling publish from your app code.)\n if (!self.warned_about_autopublish) {\n self.warned_about_autopublish = true;\n Meteor._debug(\n\"** You've set up some data subscriptions with Meteor.publish(), but\\n\" +\n\"** you still have autopublish turned on. Because autopublish is still\\n\" +\n\"** on, your Meteor.publish() calls won't have much effect. All data\\n\" +\n\"** will still be sent to all clients.\\n\" +\n\"**\\n\" +\n\"** Turn off autopublish by removing the autopublish package:\\n\" +\n\"**\\n\" +\n\"** $ meteor remove autopublish\\n\" +\n\"**\\n\" +\n\"** .. and make sure you have Meteor.publish() and Meteor.subscribe() calls\\n\" +\n\"** for each collection that you want clients to see.\\n\");\n }\n }\n\n if (name)\n self.publish_handlers[name] = handler;\n else {\n self.universal_publish_handlers.push(handler);\n // Spin up the new publisher on any existing session too. Run each\n // session's subscription in a new Fiber, so that there's no change for\n // self.sessions to change while we're running this loop.\n _.each(self.sessions, function (session) {\n if (!session._dontStartNewUniversalSubs) {\n Fiber(function() {\n session._startSubscription(handler);\n }).run();\n }\n });\n }\n },\n\n _removeSession: function (session) {\n var self = this;\n if (self.sessions[session.id]) {\n delete self.sessions[session.id];\n }\n },\n\n /**\n * @summary Defines functions that can be invoked over the network by clients.\n * @locus Anywhere\n * @param {Object} methods Dictionary whose keys are method names and values are functions.\n * @memberOf Meteor\n */\n methods: function (methods) {\n var self = this;\n _.each(methods, function (func, name) {\n if (self.method_handlers[name])\n throw new Error(\"A method named '\" + name + \"' is already defined\");\n self.method_handlers[name] = func;\n });\n },\n\n call: function (name /*, arguments */) {\n // if it's a function, the last argument is the result callback,\n // not a parameter to the remote method.\n var args = Array.prototype.slice.call(arguments, 1);\n if (args.length && typeof args[args.length - 1] === \"function\")\n var callback = args.pop();\n return this.apply(name, args, callback);\n },\n\n // @param options {Optional Object}\n // @param callback {Optional Function}\n apply: function (name, args, options, callback) {\n var self = this;\n\n // We were passed 3 arguments. They may be either (name, args, options)\n // or (name, args, callback)\n if (!callback && typeof options === 'function') {\n callback = options;\n options = {};\n }\n options = options || {};\n\n if (callback)\n // It's not really necessary to do this, since we immediately\n // run the callback in this fiber before returning, but we do it\n // anyway for regularity.\n // XXX improve error message (and how we report it)\n callback = Meteor.bindEnvironment(\n callback,\n \"delivering result of invoking '\" + name + \"'\"\n );\n\n // Run the handler\n var handler = self.method_handlers[name];\n var exception;\n if (!handler) {\n exception = new Meteor.Error(404, \"Method not found\");\n } else {\n // If this is a method call from within another method, get the\n // user state from the outer method, otherwise don't allow\n // setUserId to be called\n var userId = null;\n var setUserId = function() {\n throw new Error(\"Can't call setUserId on a server initiated method call\");\n };\n var connection = null;\n var currentInvocation = DDP._CurrentInvocation.get();\n if (currentInvocation) {\n userId = currentInvocation.userId;\n setUserId = function(userId) {\n currentInvocation.setUserId(userId);\n };\n connection = currentInvocation.connection;\n }\n\n var invocation = new MethodInvocation({\n isSimulation: false,\n userId: userId,\n setUserId: setUserId,\n connection: connection,\n randomSeed: makeRpcSeed(currentInvocation, name)\n });\n try {\n var result = DDP._CurrentInvocation.withValue(invocation, function () {\n return maybeAuditArgumentChecks(\n handler, invocation, EJSON.clone(args), \"internal call to '\" +\n name + \"'\");\n });\n result = EJSON.clone(result);\n } catch (e) {\n exception = e;\n }\n }\n\n // Return the result in whichever way the caller asked for it. Note that we\n // do NOT block on the write fence in an analogous way to how the client\n // blocks on the relevant data being visible, so you are NOT guaranteed that\n // cursor observe callbacks have fired when your callback is invoked. (We\n // can change this if there's a real use case.)\n if (callback) {\n callback(exception, result);\n return undefined;\n }\n if (exception)\n throw exception;\n return result;\n },\n\n _urlForSession: function (sessionId) {\n var self = this;\n var session = self.sessions[sessionId];\n if (session)\n return session._socketUrl;\n else\n return null;\n }\n});\n\nvar calculateVersion = function (clientSupportedVersions,\n serverSupportedVersions) {\n var correctVersion = _.find(clientSupportedVersions, function (version) {\n return _.contains(serverSupportedVersions, version);\n });\n if (!correctVersion) {\n correctVersion = serverSupportedVersions[0];\n }\n return correctVersion;\n};\n\nLivedataTest.calculateVersion = calculateVersion;\n\n\n// \"blind\" exceptions other than those that were deliberately thrown to signal\n// errors to the client\nvar wrapInternalException = function (exception, context) {\n if (!exception || exception instanceof Meteor.Error)\n return exception;\n\n // tests can set the 'expected' flag on an exception so it won't go to the\n // server log\n if (!exception.expected) {\n Meteor._debug(\"Exception \" + context, exception.stack);\n if (exception.sanitizedError) {\n Meteor._debug(\"Sanitized and reported to the client as:\", exception.sanitizedError.message);\n Meteor._debug();\n }\n }\n\n // Did the error contain more details that could have been useful if caught in\n // server code (or if thrown from non-client-originated code), but also\n // provided a \"sanitized\" version with more context than 500 Internal server\n // error? Use that.\n if (exception.sanitizedError) {\n if (exception.sanitizedError instanceof Meteor.Error)\n return exception.sanitizedError;\n Meteor._debug(\"Exception \" + context + \" provides a sanitizedError that \" +\n \"is not a Meteor.Error; ignoring\");\n }\n\n return new Meteor.Error(500, \"Internal server error\");\n};\n\n\n// Audit argument checks, if the audit-argument-checks package exists (it is a\n// weak dependency of this package).\nvar maybeAuditArgumentChecks = function (f, context, args, description) {\n args = args || [];\n if (Package['audit-argument-checks']) {\n return Match._failIfArgumentsAreNotAllChecked(\n f, context, args, description);\n }\n return f.apply(context, args);\n};\n","var path = Npm.require('path');\nvar Future = Npm.require(path.join('fibers', 'future'));\n\n// A write fence collects a group of writes, and provides a callback\n// when all of the writes are fully committed and propagated (all\n// observers have been notified of the write and acknowledged it.)\n//\nDDPServer._WriteFence = function () {\n var self = this;\n\n self.armed = false;\n self.fired = false;\n self.retired = false;\n self.outstanding_writes = 0;\n self.completion_callbacks = [];\n};\n\n// The current write fence. When there is a current write fence, code\n// that writes to databases should register their writes with it using\n// beginWrite().\n//\nDDPServer._CurrentWriteFence = new Meteor.EnvironmentVariable;\n\n_.extend(DDPServer._WriteFence.prototype, {\n // Start tracking a write, and return an object to represent it. The\n // object has a single method, committed(). This method should be\n // called when the write is fully committed and propagated. You can\n // continue to add writes to the WriteFence up until it is triggered\n // (calls its callbacks because all writes have committed.)\n beginWrite: function () {\n var self = this;\n\n if (self.retired)\n return { committed: function () {} };\n\n if (self.fired)\n throw new Error(\"fence has already activated -- too late to add writes\");\n\n self.outstanding_writes++;\n var committed = false;\n return {\n committed: function () {\n if (committed)\n throw new Error(\"committed called twice on the same write\");\n committed = true;\n self.outstanding_writes--;\n self._maybeFire();\n }\n };\n },\n\n // Arm the fence. Once the fence is armed, and there are no more\n // uncommitted writes, it will activate.\n arm: function () {\n var self = this;\n if (self === DDPServer._CurrentWriteFence.get())\n throw Error(\"Can't arm the current fence\");\n self.armed = true;\n self._maybeFire();\n },\n\n // Register a function to be called when the fence fires.\n onAllCommitted: function (func) {\n var self = this;\n if (self.fired)\n throw new Error(\"fence has already activated -- too late to \" +\n \"add a callback\");\n self.completion_callbacks.push(func);\n },\n\n // Convenience function. Arms the fence, then blocks until it fires.\n armAndWait: function () {\n var self = this;\n var future = new Future;\n self.onAllCommitted(function () {\n future['return']();\n });\n self.arm();\n future.wait();\n },\n\n _maybeFire: function () {\n var self = this;\n if (self.fired)\n throw new Error(\"write fence already activated?\");\n if (self.armed && !self.outstanding_writes) {\n self.fired = true;\n _.each(self.completion_callbacks, function (f) {f(self);});\n self.completion_callbacks = [];\n }\n },\n\n // Deactivate this fence so that adding more writes has no effect.\n // The fence must have already fired.\n retire: function () {\n var self = this;\n if (! self.fired)\n throw new Error(\"Can't retire a fence that hasn't fired.\");\n self.retired = true;\n }\n});\n","// A \"crossbar\" is a class that provides structured notification registration.\n// See _match for the definition of how a notification matches a trigger.\n// All notifications and triggers must have a string key named 'collection'.\n\nDDPServer._Crossbar = function (options) {\n var self = this;\n options = options || {};\n\n self.nextId = 1;\n // map from collection name (string) -> listener id -> object. each object has\n // keys 'trigger', 'callback'.\n self.listenersByCollection = {};\n self.factPackage = options.factPackage || \"livedata\";\n self.factName = options.factName || null;\n};\n\n_.extend(DDPServer._Crossbar.prototype, {\n // Listen for notification that match 'trigger'. A notification\n // matches if it has the key-value pairs in trigger as a\n // subset. When a notification matches, call 'callback', passing\n // the actual notification.\n //\n // Returns a listen handle, which is an object with a method\n // stop(). Call stop() to stop listening.\n //\n // XXX It should be legal to call fire() from inside a listen()\n // callback?\n listen: function (trigger, callback) {\n var self = this;\n var id = self.nextId++;\n\n if (typeof(trigger.collection) !== 'string') {\n throw Error(\"Trigger lacks collection!\");\n }\n\n var collection = trigger.collection; // save in case trigger is mutated\n var record = {trigger: EJSON.clone(trigger), callback: callback};\n if (! _.has(self.listenersByCollection, collection)) {\n self.listenersByCollection[collection] = {};\n }\n self.listenersByCollection[collection][id] = record;\n\n if (self.factName && Package.facts) {\n Package.facts.Facts.incrementServerFact(\n self.factPackage, self.factName, 1);\n }\n\n return {\n stop: function () {\n if (self.factName && Package.facts) {\n Package.facts.Facts.incrementServerFact(\n self.factPackage, self.factName, -1);\n }\n delete self.listenersByCollection[collection][id];\n if (_.isEmpty(self.listenersByCollection[collection])) {\n delete self.listenersByCollection[collection];\n }\n }\n };\n },\n\n // Fire the provided 'notification' (an object whose attribute\n // values are all JSON-compatibile) -- inform all matching listeners\n // (registered with listen()).\n //\n // If fire() is called inside a write fence, then each of the\n // listener callbacks will be called inside the write fence as well.\n //\n // The listeners may be invoked in parallel, rather than serially.\n fire: function (notification) {\n var self = this;\n\n if (typeof(notification.collection) !== 'string') {\n throw Error(\"Notification lacks collection!\");\n }\n\n if (! _.has(self.listenersByCollection, notification.collection))\n return;\n\n var listenersForCollection =\n self.listenersByCollection[notification.collection];\n var callbackIds = [];\n _.each(listenersForCollection, function (l, id) {\n if (self._matches(notification, l.trigger)) {\n callbackIds.push(id);\n }\n });\n\n // Listener callbacks can yield, so we need to first find all the ones that\n // match in a single iteration over self.listenersByCollection (which can't\n // be mutated during this iteration), and then invoke the matching\n // callbacks, checking before each call to ensure they haven't stopped.\n // Note that we don't have to check that\n // self.listenersByCollection[notification.collection] still ===\n // listenersForCollection, because the only way that stops being true is if\n // listenersForCollection first gets reduced down to the empty object (and\n // then never gets increased again).\n _.each(callbackIds, function (id) {\n if (_.has(listenersForCollection, id)) {\n listenersForCollection[id].callback(notification);\n }\n });\n },\n\n // A notification matches a trigger if all keys that exist in both are equal.\n //\n // Examples:\n // N:{collection: \"C\"} matches T:{collection: \"C\"}\n // (a non-targeted write to a collection matches a\n // non-targeted query)\n // N:{collection: \"C\", id: \"X\"} matches T:{collection: \"C\"}\n // (a targeted write to a collection matches a non-targeted query)\n // N:{collection: \"C\"} matches T:{collection: \"C\", id: \"X\"}\n // (a non-targeted write to a collection matches a\n // targeted query)\n // N:{collection: \"C\", id: \"X\"} matches T:{collection: \"C\", id: \"X\"}\n // (a targeted write to a collection matches a targeted query targeted\n // at the same document)\n // N:{collection: \"C\", id: \"X\"} does not match T:{collection: \"C\", id: \"Y\"}\n // (a targeted write to a collection does not match a targeted query\n // targeted at a different document)\n _matches: function (notification, trigger) {\n // Most notifications that use the crossbar have a string `collection` and\n // maybe an `id` that is a string or ObjectID. We're already dividing up\n // triggers by collection, but let's fast-track \"nope, different ID\" (and\n // avoid the overly generic EJSON.equals). This makes a noticeable\n // performance difference; see https://github.com/meteor/meteor/pull/3697\n if (typeof(notification.id) === 'string' &&\n typeof(trigger.id) === 'string' &&\n notification.id !== trigger.id) {\n return false;\n }\n if (notification.id instanceof LocalCollection._ObjectID &&\n trigger.id instanceof LocalCollection._ObjectID &&\n ! notification.id.equals(trigger.id)) {\n return false;\n }\n\n return _.all(trigger, function (triggerValue, key) {\n return !_.has(notification, key) ||\n EJSON.equals(triggerValue, notification[key]);\n });\n }\n});\n\n// The \"invalidation crossbar\" is a specific instance used by the DDP server to\n// implement write fence notifications. Listener callbacks on this crossbar\n// should call beginWrite on the current write fence before they return, if they\n// want to delay the write fence from firing (ie, the DDP method-data-updated\n// message from being sent).\nDDPServer._InvalidationCrossbar = new DDPServer._Crossbar({\n factName: \"invalidation-crossbar-listeners\"\n});\n","// All the supported versions (for both the client and server)\n// These must be in order of preference; most favored-first\nSUPPORTED_DDP_VERSIONS = [ '1', 'pre2', 'pre1' ];\n\nLivedataTest.SUPPORTED_DDP_VERSIONS = SUPPORTED_DDP_VERSIONS;\n\n// Instance name is this because it is usually referred to as this inside a\n// method definition\n/**\n * @summary The state for a single invocation of a method, referenced by this\n * inside a method definition.\n * @param {Object} options\n * @instanceName this\n */\nMethodInvocation = function (options) {\n var self = this;\n\n // true if we're running not the actual method, but a stub (that is,\n // if we're on a client (which may be a browser, or in the future a\n // server connecting to another server) and presently running a\n // simulation of a server-side method for latency compensation\n // purposes). not currently true except in a client such as a browser,\n // since there's usually no point in running stubs unless you have a\n // zero-latency connection to the user.\n\n /**\n * @summary Access inside a method invocation. Boolean value, true if this invocation is a stub.\n * @locus Anywhere\n * @name isSimulation\n * @memberOf MethodInvocation\n * @instance\n * @type {Boolean}\n */\n this.isSimulation = options.isSimulation;\n\n // call this function to allow other method invocations (from the\n // same client) to continue running without waiting for this one to\n // complete.\n this._unblock = options.unblock || function () {};\n this._calledUnblock = false;\n\n // current user id\n\n /**\n * @summary The id of the user that made this method call, or `null` if no user was logged in.\n * @locus Anywhere\n * @name userId\n * @memberOf MethodInvocation\n * @instance\n */\n this.userId = options.userId;\n\n // sets current user id in all appropriate server contexts and\n // reruns subscriptions\n this._setUserId = options.setUserId || function () {};\n\n // On the server, the connection this method call came in on.\n\n /**\n * @summary Access inside a method invocation. The [connection](#meteor_onconnection) that this method was received on. `null` if the method is not associated with a connection, eg. a server initiated method call.\n * @locus Server\n * @name connection\n * @memberOf MethodInvocation\n * @instance\n */\n this.connection = options.connection;\n\n // The seed for randomStream value generation\n this.randomSeed = options.randomSeed;\n\n // This is set by RandomStream.get; and holds the random stream state\n this.randomStream = null;\n};\n\n_.extend(MethodInvocation.prototype, {\n /**\n * @summary Call inside a method invocation. Allow subsequent method from this client to begin running in a new fiber.\n * @locus Server\n * @memberOf MethodInvocation\n * @instance\n */\n unblock: function () {\n var self = this;\n self._calledUnblock = true;\n self._unblock();\n },\n\n /**\n * @summary Set the logged in user.\n * @locus Server\n * @memberOf MethodInvocation\n * @instance\n * @param {String | null} userId The value that should be returned by `userId` on this connection.\n */\n setUserId: function(userId) {\n var self = this;\n if (self._calledUnblock)\n throw new Error(\"Can't call setUserId in a method after calling unblock\");\n self.userId = userId;\n self._setUserId(userId);\n }\n});\n\nparseDDP = function (stringMessage) {\n try {\n var msg = JSON.parse(stringMessage);\n } catch (e) {\n Meteor._debug(\"Discarding message with invalid JSON\", stringMessage);\n return null;\n }\n // DDP messages must be objects.\n if (msg === null || typeof msg !== 'object') {\n Meteor._debug(\"Discarding non-object DDP message\", stringMessage);\n return null;\n }\n\n // massage msg to get it into \"abstract ddp\" rather than \"wire ddp\" format.\n\n // switch between \"cleared\" rep of unsetting fields and \"undefined\"\n // rep of same\n if (_.has(msg, 'cleared')) {\n if (!_.has(msg, 'fields'))\n msg.fields = {};\n _.each(msg.cleared, function (clearKey) {\n msg.fields[clearKey] = undefined;\n });\n delete msg.cleared;\n }\n\n _.each(['fields', 'params', 'result'], function (field) {\n if (_.has(msg, field))\n msg[field] = EJSON._adjustTypesFromJSONValue(msg[field]);\n });\n\n return msg;\n};\n\nstringifyDDP = function (msg) {\n var copy = EJSON.clone(msg);\n // swizzle 'changed' messages from 'fields undefined' rep to 'fields\n // and cleared' rep\n if (_.has(msg, 'fields')) {\n var cleared = [];\n _.each(msg.fields, function (value, key) {\n if (value === undefined) {\n cleared.push(key);\n delete copy.fields[key];\n }\n });\n if (!_.isEmpty(cleared))\n copy.cleared = cleared;\n if (_.isEmpty(copy.fields))\n delete copy.fields;\n }\n // adjust types to basic\n _.each(['fields', 'params', 'result'], function (field) {\n if (_.has(copy, field))\n copy[field] = EJSON._adjustTypesToJSONValue(copy[field]);\n });\n if (msg.id && typeof msg.id !== 'string') {\n throw new Error(\"Message id is not a string\");\n }\n return JSON.stringify(copy);\n};\n\n// This is private but it's used in a few places. accounts-base uses\n// it to get the current user. accounts-password uses it to stash SRP\n// state in the DDP session. Meteor.setTimeout and friends clear\n// it. We can probably find a better way to factor this.\nDDP._CurrentInvocation = new Meteor.EnvironmentVariable;\n","// RandomStream allows for generation of pseudo-random values, from a seed.\n//\n// We use this for consistent 'random' numbers across the client and server.\n// We want to generate probably-unique IDs on the client, and we ideally want\n// the server to generate the same IDs when it executes the method.\n//\n// For generated values to be the same, we must seed ourselves the same way,\n// and we must keep track of the current state of our pseudo-random generators.\n// We call this state the scope. By default, we use the current DDP method\n// invocation as our scope. DDP now allows the client to specify a randomSeed.\n// If a randomSeed is provided it will be used to seed our random sequences.\n// In this way, client and server method calls will generate the same values.\n//\n// We expose multiple named streams; each stream is independent\n// and is seeded differently (but predictably from the name).\n// By using multiple streams, we support reordering of requests,\n// as long as they occur on different streams.\n//\n// @param options {Optional Object}\n// seed: Array or value - Seed value(s) for the generator.\n// If an array, will be used as-is\n// If a value, will be converted to a single-value array\n// If omitted, a random array will be used as the seed.\nRandomStream = function (options) {\n var self = this;\n\n this.seed = [].concat(options.seed || randomToken());\n\n this.sequences = {};\n};\n\n// Returns a random string of sufficient length for a random seed.\n// This is a placeholder function; a similar function is planned\n// for Random itself; when that is added we should remove this function,\n// and call Random's randomToken instead.\nfunction randomToken() {\n return Random.hexString(20);\n};\n\n// Returns the random stream with the specified name, in the specified scope.\n// If scope is null (or otherwise falsey) then we will use Random, which will\n// give us as random numbers as possible, but won't produce the same\n// values across client and server.\n// However, scope will normally be the current DDP method invocation, so\n// we'll use the stream with the specified name, and we should get consistent\n// values on the client and server sides of a method call.\nRandomStream.get = function (scope, name) {\n if (!name) {\n name = \"default\";\n }\n if (!scope) {\n // There was no scope passed in;\n // the sequence won't actually be reproducible.\n return Random;\n }\n var randomStream = scope.randomStream;\n if (!randomStream) {\n scope.randomStream = randomStream = new RandomStream({\n seed: scope.randomSeed\n });\n }\n return randomStream._sequence(name);\n};\n\n// Returns the named sequence of pseudo-random values.\n// The scope will be DDP._CurrentInvocation.get(), so the stream will produce\n// consistent values for method calls on the client and server.\nDDP.randomStream = function (name) {\n var scope = DDP._CurrentInvocation.get();\n return RandomStream.get(scope, name);\n};\n\n// Creates a randomSeed for passing to a method call.\n// Note that we take enclosing as an argument,\n// though we expect it to be DDP._CurrentInvocation.get()\n// However, we often evaluate makeRpcSeed lazily, and thus the relevant\n// invocation may not be the one currently in scope.\n// If enclosing is null, we'll use Random and values won't be repeatable.\nmakeRpcSeed = function (enclosing, methodName) {\n var stream = RandomStream.get(enclosing, '/rpc/' + methodName);\n return stream.hexString(20);\n};\n\n_.extend(RandomStream.prototype, {\n // Get a random sequence with the specified name, creating it if does not exist.\n // New sequences are seeded with the seed concatenated with the name.\n // By passing a seed into Random.create, we use the Alea generator.\n _sequence: function (name) {\n var self = this;\n\n var sequence = self.sequences[name] || null;\n if (sequence === null) {\n var sequenceSeed = self.seed.concat(name);\n for (var i = 0; i < sequenceSeed.length; i++) {\n if (_.isFunction(sequenceSeed[i])) {\n sequenceSeed[i] = sequenceSeed[i]();\n }\n }\n self.sequences[name] = sequence = Random.createWithSeeds.apply(null, sequenceSeed);\n }\n return sequence;\n }\n});\n","if (Meteor.isServer) {\n var path = Npm.require('path');\n var Fiber = Npm.require('fibers');\n var Future = Npm.require(path.join('fibers', 'future'));\n}\n\n// @param url {String|Object} URL to Meteor app,\n// or an object as a test hook (see code)\n// Options:\n// reloadWithOutstanding: is it OK to reload if there are outstanding methods?\n// headers: extra headers to send on the websockets connection, for\n// server-to-server DDP only\n// _sockjsOptions: Specifies options to pass through to the sockjs client\n// onDDPNegotiationVersionFailure: callback when version negotiation fails.\n//\n// XXX There should be a way to destroy a DDP connection, causing all\n// outstanding method calls to fail.\n//\n// XXX Our current way of handling failure and reconnection is great\n// for an app (where we want to tolerate being disconnected as an\n// expect state, and keep trying forever to reconnect) but cumbersome\n// for something like a command line tool that wants to make a\n// connection, call a method, and print an error if connection\n// fails. We should have better usability in the latter case (while\n// still transparently reconnecting if it's just a transient failure\n// or the server migrating us).\nvar Connection = function (url, options) {\n var self = this;\n options = _.extend({\n onConnected: function () {},\n onDDPVersionNegotiationFailure: function (description) {\n Meteor._debug(description);\n },\n heartbeatInterval: 35000,\n heartbeatTimeout: 15000,\n // These options are only for testing.\n reloadWithOutstanding: false,\n supportedDDPVersions: SUPPORTED_DDP_VERSIONS,\n retry: true,\n respondToPings: true\n }, options);\n\n // If set, called when we reconnect, queuing method calls _before_ the\n // existing outstanding ones. This is the only data member that is part of the\n // public API!\n self.onReconnect = null;\n\n // as a test hook, allow passing a stream instead of a url.\n if (typeof url === \"object\") {\n self._stream = url;\n } else {\n self._stream = new LivedataTest.ClientStream(url, {\n retry: options.retry,\n headers: options.headers,\n _sockjsOptions: options._sockjsOptions,\n // Used to keep some tests quiet, or for other cases in which\n // the right thing to do with connection errors is to silently\n // fail (e.g. sending package usage stats). At some point we\n // should have a real API for handling client-stream-level\n // errors.\n _dontPrintErrors: options._dontPrintErrors,\n connectTimeoutMs: options.connectTimeoutMs\n });\n }\n\n self._lastSessionId = null;\n self._versionSuggestion = null; // The last proposed DDP version.\n self._version = null; // The DDP version agreed on by client and server.\n self._stores = {}; // name -> object with methods\n self._methodHandlers = {}; // name -> func\n self._nextMethodId = 1;\n self._supportedDDPVersions = options.supportedDDPVersions;\n\n self._heartbeatInterval = options.heartbeatInterval;\n self._heartbeatTimeout = options.heartbeatTimeout;\n\n // Tracks methods which the user has tried to call but which have not yet\n // called their user callback (ie, they are waiting on their result or for all\n // of their writes to be written to the local cache). Map from method ID to\n // MethodInvoker object.\n self._methodInvokers = {};\n\n // Tracks methods which the user has called but whose result messages have not\n // arrived yet.\n //\n // _outstandingMethodBlocks is an array of blocks of methods. Each block\n // represents a set of methods that can run at the same time. The first block\n // represents the methods which are currently in flight; subsequent blocks\n // must wait for previous blocks to be fully finished before they can be sent\n // to the server.\n //\n // Each block is an object with the following fields:\n // - methods: a list of MethodInvoker objects\n // - wait: a boolean; if true, this block had a single method invoked with\n // the \"wait\" option\n //\n // There will never be adjacent blocks with wait=false, because the only thing\n // that makes methods need to be serialized is a wait method.\n //\n // Methods are removed from the first block when their \"result\" is\n // received. The entire first block is only removed when all of the in-flight\n // methods have received their results (so the \"methods\" list is empty) *AND*\n // all of the data written by those methods are visible in the local cache. So\n // it is possible for the first block's methods list to be empty, if we are\n // still waiting for some objects to quiesce.\n //\n // Example:\n // _outstandingMethodBlocks = [\n // {wait: false, methods: []},\n // {wait: true, methods: []},\n // {wait: false, methods: [,\n // ]}]\n // This means that there were some methods which were sent to the server and\n // which have returned their results, but some of the data written by\n // the methods may not be visible in the local cache. Once all that data is\n // visible, we will send a 'login' method. Once the login method has returned\n // and all the data is visible (including re-running subs if userId changes),\n // we will send the 'foo' and 'bar' methods in parallel.\n self._outstandingMethodBlocks = [];\n\n // method ID -> array of objects with keys 'collection' and 'id', listing\n // documents written by a given method's stub. keys are associated with\n // methods whose stub wrote at least one document, and whose data-done message\n // has not yet been received.\n self._documentsWrittenByStub = {};\n // collection -> IdMap of \"server document\" object. A \"server document\" has:\n // - \"document\": the version of the document according the\n // server (ie, the snapshot before a stub wrote it, amended by any changes\n // received from the server)\n // It is undefined if we think the document does not exist\n // - \"writtenByStubs\": a set of method IDs whose stubs wrote to the document\n // whose \"data done\" messages have not yet been processed\n self._serverDocuments = {};\n\n // Array of callbacks to be called after the next update of the local\n // cache. Used for:\n // - Calling methodInvoker.dataVisible and sub ready callbacks after\n // the relevant data is flushed.\n // - Invoking the callbacks of \"half-finished\" methods after reconnect\n // quiescence. Specifically, methods whose result was received over the old\n // connection (so we don't re-send it) but whose data had not been made\n // visible.\n self._afterUpdateCallbacks = [];\n\n // In two contexts, we buffer all incoming data messages and then process them\n // all at once in a single update:\n // - During reconnect, we buffer all data messages until all subs that had\n // been ready before reconnect are ready again, and all methods that are\n // active have returned their \"data done message\"; then\n // - During the execution of a \"wait\" method, we buffer all data messages\n // until the wait method gets its \"data done\" message. (If the wait method\n // occurs during reconnect, it doesn't get any special handling.)\n // all data messages are processed in one update.\n //\n // The following fields are used for this \"quiescence\" process.\n\n // This buffers the messages that aren't being processed yet.\n self._messagesBufferedUntilQuiescence = [];\n // Map from method ID -> true. Methods are removed from this when their\n // \"data done\" message is received, and we will not quiesce until it is\n // empty.\n self._methodsBlockingQuiescence = {};\n // map from sub ID -> true for subs that were ready (ie, called the sub\n // ready callback) before reconnect but haven't become ready again yet\n self._subsBeingRevived = {}; // map from sub._id -> true\n // if true, the next data update should reset all stores. (set during\n // reconnect.)\n self._resetStores = false;\n\n // name -> array of updates for (yet to be created) collections\n self._updatesForUnknownStores = {};\n // if we're blocking a migration, the retry func\n self._retryMigrate = null;\n\n // metadata for subscriptions. Map from sub ID to object with keys:\n // - id\n // - name\n // - params\n // - inactive (if true, will be cleaned up if not reused in re-run)\n // - ready (has the 'ready' message been received?)\n // - readyCallback (an optional callback to call when ready)\n // - errorCallback (an optional callback to call if the sub terminates with\n // an error, XXX COMPAT WITH 1.0.3.1)\n // - stopCallback (an optional callback to call when the sub terminates\n // for any reason, with an error argument if an error triggered the stop)\n self._subscriptions = {};\n\n // Reactive userId.\n self._userId = null;\n self._userIdDeps = new Tracker.Dependency;\n\n // Block auto-reload while we're waiting for method responses.\n if (Meteor.isClient && Package.reload && !options.reloadWithOutstanding) {\n Package.reload.Reload._onMigrate(function (retry) {\n if (!self._readyToMigrate()) {\n if (self._retryMigrate)\n throw new Error(\"Two migrations in progress?\");\n self._retryMigrate = retry;\n return false;\n } else {\n return [true];\n }\n });\n }\n\n var onMessage = function (raw_msg) {\n try {\n var msg = parseDDP(raw_msg);\n } catch (e) {\n Meteor._debug(\"Exception while parsing DDP\", e);\n return;\n }\n\n if (msg === null || !msg.msg) {\n // XXX COMPAT WITH 0.6.6. ignore the old welcome message for back\n // compat. Remove this 'if' once the server stops sending welcome\n // messages (stream_server.js).\n if (! (msg && msg.server_id))\n Meteor._debug(\"discarding invalid livedata message\", msg);\n return;\n }\n\n if (msg.msg === 'connected') {\n self._version = self._versionSuggestion;\n self._livedata_connected(msg);\n options.onConnected();\n }\n else if (msg.msg == 'failed') {\n if (_.contains(self._supportedDDPVersions, msg.version)) {\n self._versionSuggestion = msg.version;\n self._stream.reconnect({_force: true});\n } else {\n var description =\n \"DDP version negotiation failed; server requested version \" + msg.version;\n self._stream.disconnect({_permanent: true, _error: description});\n options.onDDPVersionNegotiationFailure(description);\n }\n }\n else if (msg.msg === 'ping') {\n if (options.respondToPings)\n self._send({msg: \"pong\", id: msg.id});\n if (self._heartbeat)\n self._heartbeat.pingReceived();\n }\n else if (msg.msg === 'pong') {\n if (self._heartbeat) {\n self._heartbeat.pongReceived();\n }\n }\n else if (_.include(['added', 'changed', 'removed', 'ready', 'updated'], msg.msg))\n self._livedata_data(msg);\n else if (msg.msg === 'nosub')\n self._livedata_nosub(msg);\n else if (msg.msg === 'result')\n self._livedata_result(msg);\n else if (msg.msg === 'error')\n self._livedata_error(msg);\n else\n Meteor._debug(\"discarding unknown livedata message type\", msg);\n };\n\n var onReset = function () {\n // Send a connect message at the beginning of the stream.\n // NOTE: reset is called even on the first connection, so this is\n // the only place we send this message.\n var msg = {msg: 'connect'};\n if (self._lastSessionId)\n msg.session = self._lastSessionId;\n msg.version = self._versionSuggestion || self._supportedDDPVersions[0];\n self._versionSuggestion = msg.version;\n msg.support = self._supportedDDPVersions;\n self._send(msg);\n\n // Now, to minimize setup latency, go ahead and blast out all of\n // our pending methods ands subscriptions before we've even taken\n // the necessary RTT to know if we successfully reconnected. (1)\n // They're supposed to be idempotent; (2) even if we did\n // reconnect, we're not sure what messages might have gotten lost\n // (in either direction) since we were disconnected (TCP being\n // sloppy about that.)\n\n // If the current block of methods all got their results (but didn't all get\n // their data visible), discard the empty block now.\n if (! _.isEmpty(self._outstandingMethodBlocks) &&\n _.isEmpty(self._outstandingMethodBlocks[0].methods)) {\n self._outstandingMethodBlocks.shift();\n }\n\n // Mark all messages as unsent, they have not yet been sent on this\n // connection.\n _.each(self._methodInvokers, function (m) {\n m.sentMessage = false;\n });\n\n // If an `onReconnect` handler is set, call it first. Go through\n // some hoops to ensure that methods that are called from within\n // `onReconnect` get executed _before_ ones that were originally\n // outstanding (since `onReconnect` is used to re-establish auth\n // certificates)\n if (self.onReconnect)\n self._callOnReconnectAndSendAppropriateOutstandingMethods();\n else\n self._sendOutstandingMethods();\n\n // add new subscriptions at the end. this way they take effect after\n // the handlers and we don't see flicker.\n _.each(self._subscriptions, function (sub, id) {\n self._send({\n msg: 'sub',\n id: id,\n name: sub.name,\n params: sub.params\n });\n });\n };\n\n var onDisconnect = function () {\n if (self._heartbeat) {\n self._heartbeat.stop();\n self._heartbeat = null;\n }\n };\n\n if (Meteor.isServer) {\n self._stream.on('message', Meteor.bindEnvironment(onMessage, Meteor._debug));\n self._stream.on('reset', Meteor.bindEnvironment(onReset, Meteor._debug));\n self._stream.on('disconnect', Meteor.bindEnvironment(onDisconnect, Meteor._debug));\n } else {\n self._stream.on('message', onMessage);\n self._stream.on('reset', onReset);\n self._stream.on('disconnect', onDisconnect);\n }\n};\n\n// A MethodInvoker manages sending a method to the server and calling the user's\n// callbacks. On construction, it registers itself in the connection's\n// _methodInvokers map; it removes itself once the method is fully finished and\n// the callback is invoked. This occurs when it has both received a result,\n// and the data written by it is fully visible.\nvar MethodInvoker = function (options) {\n var self = this;\n\n // Public (within this file) fields.\n self.methodId = options.methodId;\n self.sentMessage = false;\n\n self._callback = options.callback;\n self._connection = options.connection;\n self._message = options.message;\n self._onResultReceived = options.onResultReceived || function () {};\n self._wait = options.wait;\n self._methodResult = null;\n self._dataVisible = false;\n\n // Register with the connection.\n self._connection._methodInvokers[self.methodId] = self;\n};\n_.extend(MethodInvoker.prototype, {\n // Sends the method message to the server. May be called additional times if\n // we lose the connection and reconnect before receiving a result.\n sendMessage: function () {\n var self = this;\n // This function is called before sending a method (including resending on\n // reconnect). We should only (re)send methods where we don't already have a\n // result!\n if (self.gotResult())\n throw new Error(\"sendingMethod is called on method with result\");\n\n // If we're re-sending it, it doesn't matter if data was written the first\n // time.\n self._dataVisible = false;\n\n self.sentMessage = true;\n\n // If this is a wait method, make all data messages be buffered until it is\n // done.\n if (self._wait)\n self._connection._methodsBlockingQuiescence[self.methodId] = true;\n\n // Actually send the message.\n self._connection._send(self._message);\n },\n // Invoke the callback, if we have both a result and know that all data has\n // been written to the local cache.\n _maybeInvokeCallback: function () {\n var self = this;\n if (self._methodResult && self._dataVisible) {\n // Call the callback. (This won't throw: the callback was wrapped with\n // bindEnvironment.)\n self._callback(self._methodResult[0], self._methodResult[1]);\n\n // Forget about this method.\n delete self._connection._methodInvokers[self.methodId];\n\n // Let the connection know that this method is finished, so it can try to\n // move on to the next block of methods.\n self._connection._outstandingMethodFinished();\n }\n },\n // Call with the result of the method from the server. Only may be called\n // once; once it is called, you should not call sendMessage again.\n // If the user provided an onResultReceived callback, call it immediately.\n // Then invoke the main callback if data is also visible.\n receiveResult: function (err, result) {\n var self = this;\n if (self.gotResult())\n throw new Error(\"Methods should only receive results once\");\n self._methodResult = [err, result];\n self._onResultReceived(err, result);\n self._maybeInvokeCallback();\n },\n // Call this when all data written by the method is visible. This means that\n // the method has returns its \"data is done\" message *AND* all server\n // documents that are buffered at that time have been written to the local\n // cache. Invokes the main callback if the result has been received.\n dataVisible: function () {\n var self = this;\n self._dataVisible = true;\n self._maybeInvokeCallback();\n },\n // True if receiveResult has been called.\n gotResult: function () {\n var self = this;\n return !!self._methodResult;\n }\n});\n\n_.extend(Connection.prototype, {\n // 'name' is the name of the data on the wire that should go in the\n // store. 'wrappedStore' should be an object with methods beginUpdate, update,\n // endUpdate, saveOriginals, retrieveOriginals. see Collection for an example.\n registerStore: function (name, wrappedStore) {\n var self = this;\n\n if (name in self._stores)\n return false;\n\n // Wrap the input object in an object which makes any store method not\n // implemented by 'store' into a no-op.\n var store = {};\n _.each(['update', 'beginUpdate', 'endUpdate', 'saveOriginals',\n 'retrieveOriginals'], function (method) {\n store[method] = function () {\n return (wrappedStore[method]\n ? wrappedStore[method].apply(wrappedStore, arguments)\n : undefined);\n };\n });\n\n self._stores[name] = store;\n\n var queued = self._updatesForUnknownStores[name];\n if (queued) {\n store.beginUpdate(queued.length, false);\n _.each(queued, function (msg) {\n store.update(msg);\n });\n store.endUpdate();\n delete self._updatesForUnknownStores[name];\n }\n\n return true;\n },\n\n /**\n * @memberOf Meteor\n * @summary Subscribe to a record set. Returns a handle that provides\n * `stop()` and `ready()` methods.\n * @locus Client\n * @param {String} name Name of the subscription. Matches the name of the\n * server's `publish()` call.\n * @param {Any} [arg1,arg2...] Optional arguments passed to publisher\n * function on server.\n * @param {Function|Object} [callbacks] Optional. May include `onStop`\n * and `onReady` callbacks. If there is an error, it is passed as an\n * argument to `onStop`. If a function is passed instead of an object, it\n * is interpreted as an `onReady` callback.\n */\n subscribe: function (name /* .. [arguments] .. (callback|callbacks) */) {\n var self = this;\n\n var params = Array.prototype.slice.call(arguments, 1);\n var callbacks = {};\n if (params.length) {\n var lastParam = params[params.length - 1];\n if (_.isFunction(lastParam)) {\n callbacks.onReady = params.pop();\n } else if (lastParam &&\n // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use\n // onStop with an error callback instead.\n _.any([lastParam.onReady, lastParam.onError, lastParam.onStop],\n _.isFunction)) {\n callbacks = params.pop();\n }\n }\n\n // Is there an existing sub with the same name and param, run in an\n // invalidated Computation? This will happen if we are rerunning an\n // existing computation.\n //\n // For example, consider a rerun of:\n //\n // Tracker.autorun(function () {\n // Meteor.subscribe(\"foo\", Session.get(\"foo\"));\n // Meteor.subscribe(\"bar\", Session.get(\"bar\"));\n // });\n //\n // If \"foo\" has changed but \"bar\" has not, we will match the \"bar\"\n // subcribe to an existing inactive subscription in order to not\n // unsub and resub the subscription unnecessarily.\n //\n // We only look for one such sub; if there are N apparently-identical subs\n // being invalidated, we will require N matching subscribe calls to keep\n // them all active.\n var existing = _.find(self._subscriptions, function (sub) {\n return sub.inactive && sub.name === name &&\n EJSON.equals(sub.params, params);\n });\n\n var id;\n if (existing) {\n id = existing.id;\n existing.inactive = false; // reactivate\n\n if (callbacks.onReady) {\n // If the sub is not already ready, replace any ready callback with the\n // one provided now. (It's not really clear what users would expect for\n // an onReady callback inside an autorun; the semantics we provide is\n // that at the time the sub first becomes ready, we call the last\n // onReady callback provided, if any.)\n if (!existing.ready)\n existing.readyCallback = callbacks.onReady;\n }\n\n // XXX COMPAT WITH 1.0.3.1 we used to have onError but now we call\n // onStop with an optional error argument\n if (callbacks.onError) {\n // Replace existing callback if any, so that errors aren't\n // double-reported.\n existing.errorCallback = callbacks.onError;\n }\n\n if (callbacks.onStop) {\n existing.stopCallback = callbacks.onStop;\n }\n } else {\n // New sub! Generate an id, save it locally, and send message.\n id = Random.id();\n self._subscriptions[id] = {\n id: id,\n name: name,\n params: EJSON.clone(params),\n inactive: false,\n ready: false,\n readyDeps: new Tracker.Dependency,\n readyCallback: callbacks.onReady,\n // XXX COMPAT WITH 1.0.3.1 #errorCallback\n errorCallback: callbacks.onError,\n stopCallback: callbacks.onStop,\n connection: self,\n remove: function() {\n delete this.connection._subscriptions[this.id];\n this.ready && this.readyDeps.changed();\n },\n stop: function() {\n this.connection._send({msg: 'unsub', id: id});\n this.remove();\n\n if (callbacks.onStop) {\n callbacks.onStop();\n }\n }\n };\n self._send({msg: 'sub', id: id, name: name, params: params});\n }\n\n // return a handle to the application.\n var handle = {\n stop: function () {\n if (!_.has(self._subscriptions, id))\n return;\n\n self._subscriptions[id].stop();\n },\n ready: function () {\n // return false if we've unsubscribed.\n if (!_.has(self._subscriptions, id))\n return false;\n var record = self._subscriptions[id];\n record.readyDeps.depend();\n return record.ready;\n },\n subscriptionId: id\n };\n\n if (Tracker.active) {\n // We're in a reactive computation, so we'd like to unsubscribe when the\n // computation is invalidated... but not if the rerun just re-subscribes\n // to the same subscription! When a rerun happens, we use onInvalidate\n // as a change to mark the subscription \"inactive\" so that it can\n // be reused from the rerun. If it isn't reused, it's killed from\n // an afterFlush.\n Tracker.onInvalidate(function (c) {\n if (_.has(self._subscriptions, id))\n self._subscriptions[id].inactive = true;\n\n Tracker.afterFlush(function () {\n if (_.has(self._subscriptions, id) &&\n self._subscriptions[id].inactive)\n handle.stop();\n });\n });\n }\n\n return handle;\n },\n\n // options:\n // - onLateError {Function(error)} called if an error was received after the ready event.\n // (errors received before ready cause an error to be thrown)\n _subscribeAndWait: function (name, args, options) {\n var self = this;\n var f = new Future();\n var ready = false;\n var handle;\n args = args || [];\n args.push({\n onReady: function () {\n ready = true;\n f['return']();\n },\n onError: function (e) {\n if (!ready)\n f['throw'](e);\n else\n options && options.onLateError && options.onLateError(e);\n }\n });\n\n handle = self.subscribe.apply(self, [name].concat(args));\n f.wait();\n return handle;\n },\n\n methods: function (methods) {\n var self = this;\n _.each(methods, function (func, name) {\n if (self._methodHandlers[name])\n throw new Error(\"A method named '\" + name + \"' is already defined\");\n self._methodHandlers[name] = func;\n });\n },\n\n /**\n * @memberOf Meteor\n * @summary Invokes a method passing any number of arguments.\n * @locus Anywhere\n * @param {String} name Name of method to invoke\n * @param {EJSONable} [arg1,arg2...] Optional method arguments\n * @param {Function} [asyncCallback] Optional callback, which is called asynchronously with the error or result after the method is complete. If not provided, the method runs synchronously if possible (see below).\n */\n call: function (name /* .. [arguments] .. callback */) {\n // if it's a function, the last argument is the result callback,\n // not a parameter to the remote method.\n var args = Array.prototype.slice.call(arguments, 1);\n if (args.length && typeof args[args.length - 1] === \"function\")\n var callback = args.pop();\n return this.apply(name, args, callback);\n },\n\n // @param options {Optional Object}\n // wait: Boolean - Should we wait to call this until all current methods\n // are fully finished, and block subsequent method calls\n // until this method is fully finished?\n // (does not affect methods called from within this method)\n // onResultReceived: Function - a callback to call as soon as the method\n // result is received. the data written by\n // the method may not yet be in the cache!\n // returnStubValue: Boolean - If true then in cases where we would have\n // otherwise discarded the stub's return value\n // and returned undefined, instead we go ahead\n // and return it. Specifically, this is any\n // time other than when (a) we are already\n // inside a stub or (b) we are in Node and no\n // callback was provided. Currently we require\n // this flag to be explicitly passed to reduce\n // the likelihood that stub return values will\n // be confused with server return values; we\n // may improve this in future.\n // @param callback {Optional Function}\n\n /**\n * @memberOf Meteor\n * @summary Invoke a method passing an array of arguments.\n * @locus Anywhere\n * @param {String} name Name of method to invoke\n * @param {EJSONable[]} args Method arguments\n * @param {Object} [options]\n * @param {Boolean} options.wait (Client only) If true, don't send this method until all previous method calls have completed, and don't send any subsequent method calls until this one is completed.\n * @param {Function} options.onResultReceived (Client only) This callback is invoked with the error or result of the method (just like `asyncCallback`) as soon as the error or result is available. The local cache may not yet reflect the writes performed by the method.\n * @param {Function} [asyncCallback] Optional callback; same semantics as in [`Meteor.call`](#meteor_call).\n */\n apply: function (name, args, options, callback) {\n var self = this;\n\n // We were passed 3 arguments. They may be either (name, args, options)\n // or (name, args, callback)\n if (!callback && typeof options === 'function') {\n callback = options;\n options = {};\n }\n options = options || {};\n\n if (callback) {\n // XXX would it be better form to do the binding in stream.on,\n // or caller, instead of here?\n // XXX improve error message (and how we report it)\n callback = Meteor.bindEnvironment(\n callback,\n \"delivering result of invoking '\" + name + \"'\"\n );\n }\n\n // Keep our args safe from mutation (eg if we don't send the message for a\n // while because of a wait method).\n args = EJSON.clone(args);\n\n // Lazily allocate method ID once we know that it'll be needed.\n var methodId = (function () {\n var id;\n return function () {\n if (id === undefined)\n id = '' + (self._nextMethodId++);\n return id;\n };\n })();\n\n var enclosing = DDP._CurrentInvocation.get();\n var alreadyInSimulation = enclosing && enclosing.isSimulation;\n\n // Lazily generate a randomSeed, only if it is requested by the stub.\n // The random streams only have utility if they're used on both the client\n // and the server; if the client doesn't generate any 'random' values\n // then we don't expect the server to generate any either.\n // Less commonly, the server may perform different actions from the client,\n // and may in fact generate values where the client did not, but we don't\n // have any client-side values to match, so even here we may as well just\n // use a random seed on the server. In that case, we don't pass the\n // randomSeed to save bandwidth, and we don't even generate it to save a\n // bit of CPU and to avoid consuming entropy.\n var randomSeed = null;\n var randomSeedGenerator = function () {\n if (randomSeed === null) {\n randomSeed = makeRpcSeed(enclosing, name);\n }\n return randomSeed;\n };\n\n // Run the stub, if we have one. The stub is supposed to make some\n // temporary writes to the database to give the user a smooth experience\n // until the actual result of executing the method comes back from the\n // server (whereupon the temporary writes to the database will be reversed\n // during the beginUpdate/endUpdate process.)\n //\n // Normally, we ignore the return value of the stub (even if it is an\n // exception), in favor of the real return value from the server. The\n // exception is if the *caller* is a stub. In that case, we're not going\n // to do a RPC, so we use the return value of the stub as our return\n // value.\n\n var stub = self._methodHandlers[name];\n if (stub) {\n var setUserId = function(userId) {\n self.setUserId(userId);\n };\n\n var invocation = new MethodInvocation({\n isSimulation: true,\n userId: self.userId(),\n setUserId: setUserId,\n randomSeed: function () { return randomSeedGenerator(); }\n });\n\n if (!alreadyInSimulation)\n self._saveOriginals();\n\n try {\n // Note that unlike in the corresponding server code, we never audit\n // that stubs check() their arguments.\n var stubReturnValue = DDP._CurrentInvocation.withValue(invocation, function () {\n if (Meteor.isServer) {\n // Because saveOriginals and retrieveOriginals aren't reentrant,\n // don't allow stubs to yield.\n return Meteor._noYieldsAllowed(function () {\n // re-clone, so that the stub can't affect our caller's values\n return stub.apply(invocation, EJSON.clone(args));\n });\n } else {\n return stub.apply(invocation, EJSON.clone(args));\n }\n });\n }\n catch (e) {\n var exception = e;\n }\n\n if (!alreadyInSimulation)\n self._retrieveAndStoreOriginals(methodId());\n }\n\n // If we're in a simulation, stop and return the result we have,\n // rather than going on to do an RPC. If there was no stub,\n // we'll end up returning undefined.\n if (alreadyInSimulation) {\n if (callback) {\n callback(exception, stubReturnValue);\n return undefined;\n }\n if (exception)\n throw exception;\n return stubReturnValue;\n }\n\n // If an exception occurred in a stub, and we're ignoring it\n // because we're doing an RPC and want to use what the server\n // returns instead, log it so the developer knows.\n //\n // Tests can set the 'expected' flag on an exception so it won't\n // go to log.\n if (exception && !exception.expected) {\n Meteor._debug(\"Exception while simulating the effect of invoking '\" +\n name + \"'\", exception, exception.stack);\n }\n\n\n // At this point we're definitely doing an RPC, and we're going to\n // return the value of the RPC to the caller.\n\n // If the caller didn't give a callback, decide what to do.\n if (!callback) {\n if (Meteor.isClient) {\n // On the client, we don't have fibers, so we can't block. The\n // only thing we can do is to return undefined and discard the\n // result of the RPC. If an error occurred then print the error\n // to the console.\n callback = function (err) {\n err && Meteor._debug(\"Error invoking Method '\" + name + \"':\",\n err.message);\n };\n } else {\n // On the server, make the function synchronous. Throw on\n // errors, return on success.\n var future = new Future;\n callback = future.resolver();\n }\n }\n // Send the RPC. Note that on the client, it is important that the\n // stub have finished before we send the RPC, so that we know we have\n // a complete list of which local documents the stub wrote.\n var message = {\n msg: 'method',\n method: name,\n params: args,\n id: methodId()\n };\n\n // Send the randomSeed only if we used it\n if (randomSeed !== null) {\n message.randomSeed = randomSeed;\n }\n\n var methodInvoker = new MethodInvoker({\n methodId: methodId(),\n callback: callback,\n connection: self,\n onResultReceived: options.onResultReceived,\n wait: !!options.wait,\n message: message\n });\n\n if (options.wait) {\n // It's a wait method! Wait methods go in their own block.\n self._outstandingMethodBlocks.push(\n {wait: true, methods: [methodInvoker]});\n } else {\n // Not a wait method. Start a new block if the previous block was a wait\n // block, and add it to the last block of methods.\n if (_.isEmpty(self._outstandingMethodBlocks) ||\n _.last(self._outstandingMethodBlocks).wait)\n self._outstandingMethodBlocks.push({wait: false, methods: []});\n _.last(self._outstandingMethodBlocks).methods.push(methodInvoker);\n }\n\n // If we added it to the first block, send it out now.\n if (self._outstandingMethodBlocks.length === 1)\n methodInvoker.sendMessage();\n\n // If we're using the default callback on the server,\n // block waiting for the result.\n if (future) {\n return future.wait();\n }\n return options.returnStubValue ? stubReturnValue : undefined;\n },\n\n // Before calling a method stub, prepare all stores to track changes and allow\n // _retrieveAndStoreOriginals to get the original versions of changed\n // documents.\n _saveOriginals: function () {\n var self = this;\n _.each(self._stores, function (s) {\n s.saveOriginals();\n });\n },\n // Retrieves the original versions of all documents modified by the stub for\n // method 'methodId' from all stores and saves them to _serverDocuments (keyed\n // by document) and _documentsWrittenByStub (keyed by method ID).\n _retrieveAndStoreOriginals: function (methodId) {\n var self = this;\n if (self._documentsWrittenByStub[methodId])\n throw new Error(\"Duplicate methodId in _retrieveAndStoreOriginals\");\n\n var docsWritten = [];\n _.each(self._stores, function (s, collection) {\n var originals = s.retrieveOriginals();\n // not all stores define retrieveOriginals\n if (!originals)\n return;\n originals.forEach(function (doc, id) {\n docsWritten.push({collection: collection, id: id});\n if (!_.has(self._serverDocuments, collection))\n self._serverDocuments[collection] = new LocalCollection._IdMap;\n var serverDoc = self._serverDocuments[collection].setDefault(id, {});\n if (serverDoc.writtenByStubs) {\n // We're not the first stub to write this doc. Just add our method ID\n // to the record.\n serverDoc.writtenByStubs[methodId] = true;\n } else {\n // First stub! Save the original value and our method ID.\n serverDoc.document = doc;\n serverDoc.flushCallbacks = [];\n serverDoc.writtenByStubs = {};\n serverDoc.writtenByStubs[methodId] = true;\n }\n });\n });\n if (!_.isEmpty(docsWritten)) {\n self._documentsWrittenByStub[methodId] = docsWritten;\n }\n },\n\n // This is very much a private function we use to make the tests\n // take up fewer server resources after they complete.\n _unsubscribeAll: function () {\n var self = this;\n _.each(_.clone(self._subscriptions), function (sub, id) {\n // Avoid killing the autoupdate subscription so that developers\n // still get hot code pushes when writing tests.\n //\n // XXX it's a hack to encode knowledge about autoupdate here,\n // but it doesn't seem worth it yet to have a special API for\n // subscriptions to preserve after unit tests.\n if (sub.name !== 'meteor_autoupdate_clientVersions') {\n self._subscriptions[id].stop();\n }\n });\n },\n\n // Sends the DDP stringification of the given message object\n _send: function (obj) {\n var self = this;\n self._stream.send(stringifyDDP(obj));\n },\n\n // We detected via DDP-level heartbeats that we've lost the\n // connection. Unlike `disconnect` or `close`, a lost connection\n // will be automatically retried.\n _lostConnection: function (error) {\n var self = this;\n self._stream._lostConnection(error);\n },\n\n /**\n * @summary Get the current connection status. A reactive data source.\n * @locus Client\n * @memberOf Meteor\n */\n status: function (/*passthrough args*/) {\n var self = this;\n return self._stream.status.apply(self._stream, arguments);\n },\n\n /**\n * @summary Force an immediate reconnection attempt if the client is not connected to the server.\n\n This method does nothing if the client is already connected.\n * @locus Client\n * @memberOf Meteor\n */\n reconnect: function (/*passthrough args*/) {\n var self = this;\n return self._stream.reconnect.apply(self._stream, arguments);\n },\n\n /**\n * @summary Disconnect the client from the server.\n * @locus Client\n * @memberOf Meteor\n */\n disconnect: function (/*passthrough args*/) {\n var self = this;\n return self._stream.disconnect.apply(self._stream, arguments);\n },\n\n close: function () {\n var self = this;\n return self._stream.disconnect({_permanent: true});\n },\n\n ///\n /// Reactive user system\n ///\n userId: function () {\n var self = this;\n if (self._userIdDeps)\n self._userIdDeps.depend();\n return self._userId;\n },\n\n setUserId: function (userId) {\n var self = this;\n // Avoid invalidating dependents if setUserId is called with current value.\n if (self._userId === userId)\n return;\n self._userId = userId;\n if (self._userIdDeps)\n self._userIdDeps.changed();\n },\n\n // Returns true if we are in a state after reconnect of waiting for subs to be\n // revived or early methods to finish their data, or we are waiting for a\n // \"wait\" method to finish.\n _waitingForQuiescence: function () {\n var self = this;\n return (! _.isEmpty(self._subsBeingRevived) ||\n ! _.isEmpty(self._methodsBlockingQuiescence));\n },\n\n // Returns true if any method whose message has been sent to the server has\n // not yet invoked its user callback.\n _anyMethodsAreOutstanding: function () {\n var self = this;\n return _.any(_.pluck(self._methodInvokers, 'sentMessage'));\n },\n\n _livedata_connected: function (msg) {\n var self = this;\n\n if (self._version !== 'pre1' && self._heartbeatInterval !== 0) {\n self._heartbeat = new Heartbeat({\n heartbeatInterval: self._heartbeatInterval,\n heartbeatTimeout: self._heartbeatTimeout,\n onTimeout: function () {\n self._lostConnection(\n new DDP.ConnectionError(\"DDP heartbeat timed out\"));\n },\n sendPing: function () {\n self._send({msg: 'ping'});\n }\n });\n self._heartbeat.start();\n }\n\n // If this is a reconnect, we'll have to reset all stores.\n if (self._lastSessionId)\n self._resetStores = true;\n\n if (typeof (msg.session) === \"string\") {\n var reconnectedToPreviousSession = (self._lastSessionId === msg.session);\n self._lastSessionId = msg.session;\n }\n\n if (reconnectedToPreviousSession) {\n // Successful reconnection -- pick up where we left off. Note that right\n // now, this never happens: the server never connects us to a previous\n // session, because DDP doesn't provide enough data for the server to know\n // what messages the client has processed. We need to improve DDP to make\n // this possible, at which point we'll probably need more code here.\n return;\n }\n\n // Server doesn't have our data any more. Re-sync a new session.\n\n // Forget about messages we were buffering for unknown collections. They'll\n // be resent if still relevant.\n self._updatesForUnknownStores = {};\n\n if (self._resetStores) {\n // Forget about the effects of stubs. We'll be resetting all collections\n // anyway.\n self._documentsWrittenByStub = {};\n self._serverDocuments = {};\n }\n\n // Clear _afterUpdateCallbacks.\n self._afterUpdateCallbacks = [];\n\n // Mark all named subscriptions which are ready (ie, we already called the\n // ready callback) as needing to be revived.\n // XXX We should also block reconnect quiescence until unnamed subscriptions\n // (eg, autopublish) are done re-publishing to avoid flicker!\n self._subsBeingRevived = {};\n _.each(self._subscriptions, function (sub, id) {\n if (sub.ready)\n self._subsBeingRevived[id] = true;\n });\n\n // Arrange for \"half-finished\" methods to have their callbacks run, and\n // track methods that were sent on this connection so that we don't\n // quiesce until they are all done.\n //\n // Start by clearing _methodsBlockingQuiescence: methods sent before\n // reconnect don't matter, and any \"wait\" methods sent on the new connection\n // that we drop here will be restored by the loop below.\n self._methodsBlockingQuiescence = {};\n if (self._resetStores) {\n _.each(self._methodInvokers, function (invoker) {\n if (invoker.gotResult()) {\n // This method already got its result, but it didn't call its callback\n // because its data didn't become visible. We did not resend the\n // method RPC. We'll call its callback when we get a full quiesce,\n // since that's as close as we'll get to \"data must be visible\".\n self._afterUpdateCallbacks.push(_.bind(invoker.dataVisible, invoker));\n } else if (invoker.sentMessage) {\n // This method has been sent on this connection (maybe as a resend\n // from the last connection, maybe from onReconnect, maybe just very\n // quickly before processing the connected message).\n //\n // We don't need to do anything special to ensure its callbacks get\n // called, but we'll count it as a method which is preventing\n // reconnect quiescence. (eg, it might be a login method that was run\n // from onReconnect, and we don't want to see flicker by seeing a\n // logged-out state.)\n self._methodsBlockingQuiescence[invoker.methodId] = true;\n }\n });\n }\n\n self._messagesBufferedUntilQuiescence = [];\n\n // If we're not waiting on any methods or subs, we can reset the stores and\n // call the callbacks immediately.\n if (!self._waitingForQuiescence()) {\n if (self._resetStores) {\n _.each(self._stores, function (s) {\n s.beginUpdate(0, true);\n s.endUpdate();\n });\n self._resetStores = false;\n }\n self._runAfterUpdateCallbacks();\n }\n },\n\n\n _processOneDataMessage: function (msg, updates) {\n var self = this;\n // Using underscore here so as not to need to capitalize.\n self['_process_' + msg.msg](msg, updates);\n },\n\n\n _livedata_data: function (msg) {\n var self = this;\n\n // collection name -> array of messages\n var updates = {};\n\n if (self._waitingForQuiescence()) {\n self._messagesBufferedUntilQuiescence.push(msg);\n\n if (msg.msg === \"nosub\")\n delete self._subsBeingRevived[msg.id];\n\n _.each(msg.subs || [], function (subId) {\n delete self._subsBeingRevived[subId];\n });\n _.each(msg.methods || [], function (methodId) {\n delete self._methodsBlockingQuiescence[methodId];\n });\n\n if (self._waitingForQuiescence())\n return;\n\n // No methods or subs are blocking quiescence!\n // We'll now process and all of our buffered messages, reset all stores,\n // and apply them all at once.\n _.each(self._messagesBufferedUntilQuiescence, function (bufferedMsg) {\n self._processOneDataMessage(bufferedMsg, updates);\n });\n self._messagesBufferedUntilQuiescence = [];\n } else {\n self._processOneDataMessage(msg, updates);\n }\n\n if (self._resetStores || !_.isEmpty(updates)) {\n // Begin a transactional update of each store.\n _.each(self._stores, function (s, storeName) {\n s.beginUpdate(_.has(updates, storeName) ? updates[storeName].length : 0,\n self._resetStores);\n });\n self._resetStores = false;\n\n _.each(updates, function (updateMessages, storeName) {\n var store = self._stores[storeName];\n if (store) {\n _.each(updateMessages, function (updateMessage) {\n store.update(updateMessage);\n });\n } else {\n // Nobody's listening for this data. Queue it up until\n // someone wants it.\n // XXX memory use will grow without bound if you forget to\n // create a collection or just don't care about it... going\n // to have to do something about that.\n if (!_.has(self._updatesForUnknownStores, storeName))\n self._updatesForUnknownStores[storeName] = [];\n Array.prototype.push.apply(self._updatesForUnknownStores[storeName],\n updateMessages);\n }\n });\n\n // End update transaction.\n _.each(self._stores, function (s) { s.endUpdate(); });\n }\n\n self._runAfterUpdateCallbacks();\n },\n\n // Call any callbacks deferred with _runWhenAllServerDocsAreFlushed whose\n // relevant docs have been flushed, as well as dataVisible callbacks at\n // reconnect-quiescence time.\n _runAfterUpdateCallbacks: function () {\n var self = this;\n var callbacks = self._afterUpdateCallbacks;\n self._afterUpdateCallbacks = [];\n _.each(callbacks, function (c) {\n c();\n });\n },\n\n _pushUpdate: function (updates, collection, msg) {\n var self = this;\n if (!_.has(updates, collection)) {\n updates[collection] = [];\n }\n updates[collection].push(msg);\n },\n\n _getServerDoc: function (collection, id) {\n var self = this;\n if (!_.has(self._serverDocuments, collection))\n return null;\n var serverDocsForCollection = self._serverDocuments[collection];\n return serverDocsForCollection.get(id) || null;\n },\n\n _process_added: function (msg, updates) {\n var self = this;\n var id = LocalCollection._idParse(msg.id);\n var serverDoc = self._getServerDoc(msg.collection, id);\n if (serverDoc) {\n // Some outstanding stub wrote here.\n if (serverDoc.document !== undefined)\n throw new Error(\"Server sent add for existing id: \" + msg.id);\n serverDoc.document = msg.fields || {};\n serverDoc.document._id = id;\n } else {\n self._pushUpdate(updates, msg.collection, msg);\n }\n },\n\n _process_changed: function (msg, updates) {\n var self = this;\n var serverDoc = self._getServerDoc(\n msg.collection, LocalCollection._idParse(msg.id));\n if (serverDoc) {\n if (serverDoc.document === undefined)\n throw new Error(\"Server sent changed for nonexisting id: \" + msg.id);\n LocalCollection._applyChanges(serverDoc.document, msg.fields);\n } else {\n self._pushUpdate(updates, msg.collection, msg);\n }\n },\n\n _process_removed: function (msg, updates) {\n var self = this;\n var serverDoc = self._getServerDoc(\n msg.collection, LocalCollection._idParse(msg.id));\n if (serverDoc) {\n // Some outstanding stub wrote here.\n if (serverDoc.document === undefined)\n throw new Error(\"Server sent removed for nonexisting id:\" + msg.id);\n serverDoc.document = undefined;\n } else {\n self._pushUpdate(updates, msg.collection, {\n msg: 'removed',\n collection: msg.collection,\n id: msg.id\n });\n }\n },\n\n _process_updated: function (msg, updates) {\n var self = this;\n // Process \"method done\" messages.\n _.each(msg.methods, function (methodId) {\n _.each(self._documentsWrittenByStub[methodId], function (written) {\n var serverDoc = self._getServerDoc(written.collection, written.id);\n if (!serverDoc)\n throw new Error(\"Lost serverDoc for \" + JSON.stringify(written));\n if (!serverDoc.writtenByStubs[methodId])\n throw new Error(\"Doc \" + JSON.stringify(written) +\n \" not written by method \" + methodId);\n delete serverDoc.writtenByStubs[methodId];\n if (_.isEmpty(serverDoc.writtenByStubs)) {\n // All methods whose stubs wrote this method have completed! We can\n // now copy the saved document to the database (reverting the stub's\n // change if the server did not write to this object, or applying the\n // server's writes if it did).\n\n // This is a fake ddp 'replace' message. It's just for talking\n // between livedata connections and minimongo. (We have to stringify\n // the ID because it's supposed to look like a wire message.)\n self._pushUpdate(updates, written.collection, {\n msg: 'replace',\n id: LocalCollection._idStringify(written.id),\n replace: serverDoc.document\n });\n // Call all flush callbacks.\n _.each(serverDoc.flushCallbacks, function (c) {\n c();\n });\n\n // Delete this completed serverDocument. Don't bother to GC empty\n // IdMaps inside self._serverDocuments, since there probably aren't\n // many collections and they'll be written repeatedly.\n self._serverDocuments[written.collection].remove(written.id);\n }\n });\n delete self._documentsWrittenByStub[methodId];\n\n // We want to call the data-written callback, but we can't do so until all\n // currently buffered messages are flushed.\n var callbackInvoker = self._methodInvokers[methodId];\n if (!callbackInvoker)\n throw new Error(\"No callback invoker for method \" + methodId);\n self._runWhenAllServerDocsAreFlushed(\n _.bind(callbackInvoker.dataVisible, callbackInvoker));\n });\n },\n\n _process_ready: function (msg, updates) {\n var self = this;\n // Process \"sub ready\" messages. \"sub ready\" messages don't take effect\n // until all current server documents have been flushed to the local\n // database. We can use a write fence to implement this.\n _.each(msg.subs, function (subId) {\n self._runWhenAllServerDocsAreFlushed(function () {\n var subRecord = self._subscriptions[subId];\n // Did we already unsubscribe?\n if (!subRecord)\n return;\n // Did we already receive a ready message? (Oops!)\n if (subRecord.ready)\n return;\n subRecord.readyCallback && subRecord.readyCallback();\n subRecord.ready = true;\n subRecord.readyDeps.changed();\n });\n });\n },\n\n // Ensures that \"f\" will be called after all documents currently in\n // _serverDocuments have been written to the local cache. f will not be called\n // if the connection is lost before then!\n _runWhenAllServerDocsAreFlushed: function (f) {\n var self = this;\n var runFAfterUpdates = function () {\n self._afterUpdateCallbacks.push(f);\n };\n var unflushedServerDocCount = 0;\n var onServerDocFlush = function () {\n --unflushedServerDocCount;\n if (unflushedServerDocCount === 0) {\n // This was the last doc to flush! Arrange to run f after the updates\n // have been applied.\n runFAfterUpdates();\n }\n };\n _.each(self._serverDocuments, function (collectionDocs) {\n collectionDocs.forEach(function (serverDoc) {\n var writtenByStubForAMethodWithSentMessage = _.any(\n serverDoc.writtenByStubs, function (dummy, methodId) {\n var invoker = self._methodInvokers[methodId];\n return invoker && invoker.sentMessage;\n });\n if (writtenByStubForAMethodWithSentMessage) {\n ++unflushedServerDocCount;\n serverDoc.flushCallbacks.push(onServerDocFlush);\n }\n });\n });\n if (unflushedServerDocCount === 0) {\n // There aren't any buffered docs --- we can call f as soon as the current\n // round of updates is applied!\n runFAfterUpdates();\n }\n },\n\n _livedata_nosub: function (msg) {\n var self = this;\n\n // First pass it through _livedata_data, which only uses it to help get\n // towards quiescence.\n self._livedata_data(msg);\n\n // Do the rest of our processing immediately, with no\n // buffering-until-quiescence.\n\n // we weren't subbed anyway, or we initiated the unsub.\n if (!_.has(self._subscriptions, msg.id))\n return;\n\n // XXX COMPAT WITH 1.0.3.1 #errorCallback\n var errorCallback = self._subscriptions[msg.id].errorCallback;\n var stopCallback = self._subscriptions[msg.id].stopCallback;\n\n self._subscriptions[msg.id].remove();\n\n var meteorErrorFromMsg = function (msgArg) {\n return msgArg && msgArg.error && new Meteor.Error(\n msgArg.error.error, msgArg.error.reason, msgArg.error.details);\n }\n\n // XXX COMPAT WITH 1.0.3.1 #errorCallback\n if (errorCallback && msg.error) {\n errorCallback(meteorErrorFromMsg(msg));\n }\n\n if (stopCallback) {\n stopCallback(meteorErrorFromMsg(msg));\n }\n },\n\n _process_nosub: function () {\n // This is called as part of the \"buffer until quiescence\" process, but\n // nosub's effect is always immediate. It only goes in the buffer at all\n // because it's possible for a nosub to be the thing that triggers\n // quiescence, if we were waiting for a sub to be revived and it dies\n // instead.\n },\n\n _livedata_result: function (msg) {\n // id, result or error. error has error (code), reason, details\n\n var self = this;\n\n // find the outstanding request\n // should be O(1) in nearly all realistic use cases\n if (_.isEmpty(self._outstandingMethodBlocks)) {\n Meteor._debug(\"Received method result but no methods outstanding\");\n return;\n }\n var currentMethodBlock = self._outstandingMethodBlocks[0].methods;\n var m;\n for (var i = 0; i < currentMethodBlock.length; i++) {\n m = currentMethodBlock[i];\n if (m.methodId === msg.id)\n break;\n }\n\n if (!m) {\n Meteor._debug(\"Can't match method response to original method call\", msg);\n return;\n }\n\n // Remove from current method block. This may leave the block empty, but we\n // don't move on to the next block until the callback has been delivered, in\n // _outstandingMethodFinished.\n currentMethodBlock.splice(i, 1);\n\n if (_.has(msg, 'error')) {\n m.receiveResult(new Meteor.Error(\n msg.error.error, msg.error.reason,\n msg.error.details));\n } else {\n // msg.result may be undefined if the method didn't return a\n // value\n m.receiveResult(undefined, msg.result);\n }\n },\n\n // Called by MethodInvoker after a method's callback is invoked. If this was\n // the last outstanding method in the current block, runs the next block. If\n // there are no more methods, consider accepting a hot code push.\n _outstandingMethodFinished: function () {\n var self = this;\n if (self._anyMethodsAreOutstanding())\n return;\n\n // No methods are outstanding. This should mean that the first block of\n // methods is empty. (Or it might not exist, if this was a method that\n // half-finished before disconnect/reconnect.)\n if (! _.isEmpty(self._outstandingMethodBlocks)) {\n var firstBlock = self._outstandingMethodBlocks.shift();\n if (! _.isEmpty(firstBlock.methods))\n throw new Error(\"No methods outstanding but nonempty block: \" +\n JSON.stringify(firstBlock));\n\n // Send the outstanding methods now in the first block.\n if (!_.isEmpty(self._outstandingMethodBlocks))\n self._sendOutstandingMethods();\n }\n\n // Maybe accept a hot code push.\n self._maybeMigrate();\n },\n\n // Sends messages for all the methods in the first block in\n // _outstandingMethodBlocks.\n _sendOutstandingMethods: function() {\n var self = this;\n if (_.isEmpty(self._outstandingMethodBlocks))\n return;\n _.each(self._outstandingMethodBlocks[0].methods, function (m) {\n m.sendMessage();\n });\n },\n\n _livedata_error: function (msg) {\n Meteor._debug(\"Received error from server: \", msg.reason);\n if (msg.offendingMessage)\n Meteor._debug(\"For: \", msg.offendingMessage);\n },\n\n _callOnReconnectAndSendAppropriateOutstandingMethods: function() {\n var self = this;\n var oldOutstandingMethodBlocks = self._outstandingMethodBlocks;\n self._outstandingMethodBlocks = [];\n\n self.onReconnect();\n\n if (_.isEmpty(oldOutstandingMethodBlocks))\n return;\n\n // We have at least one block worth of old outstanding methods to try\n // again. First: did onReconnect actually send anything? If not, we just\n // restore all outstanding methods and run the first block.\n if (_.isEmpty(self._outstandingMethodBlocks)) {\n self._outstandingMethodBlocks = oldOutstandingMethodBlocks;\n self._sendOutstandingMethods();\n return;\n }\n\n // OK, there are blocks on both sides. Special case: merge the last block of\n // the reconnect methods with the first block of the original methods, if\n // neither of them are \"wait\" blocks.\n if (!_.last(self._outstandingMethodBlocks).wait &&\n !oldOutstandingMethodBlocks[0].wait) {\n _.each(oldOutstandingMethodBlocks[0].methods, function (m) {\n _.last(self._outstandingMethodBlocks).methods.push(m);\n\n // If this \"last block\" is also the first block, send the message.\n if (self._outstandingMethodBlocks.length === 1)\n m.sendMessage();\n });\n\n oldOutstandingMethodBlocks.shift();\n }\n\n // Now add the rest of the original blocks on.\n _.each(oldOutstandingMethodBlocks, function (block) {\n self._outstandingMethodBlocks.push(block);\n });\n },\n\n // We can accept a hot code push if there are no methods in flight.\n _readyToMigrate: function() {\n var self = this;\n return _.isEmpty(self._methodInvokers);\n },\n\n // If we were blocking a migration, see if it's now possible to continue.\n // Call whenever the set of outstanding/blocked methods shrinks.\n _maybeMigrate: function () {\n var self = this;\n if (self._retryMigrate && self._readyToMigrate()) {\n self._retryMigrate();\n self._retryMigrate = null;\n }\n }\n});\n\nLivedataTest.Connection = Connection;\n\n// @param url {String} URL to Meteor app,\n// e.g.:\n// \"subdomain.meteor.com\",\n// \"http://subdomain.meteor.com\",\n// \"/\",\n// \"ddp+sockjs://ddp--****-foo.meteor.com/sockjs\"\n\n/**\n * @summary Connect to the server of a different Meteor application to subscribe to its document sets and invoke its remote methods.\n * @locus Anywhere\n * @param {String} url The URL of another Meteor application.\n */\nDDP.connect = function (url, options) {\n var ret = new Connection(url, options);\n allConnections.push(ret); // hack. see below.\n return ret;\n};\n\n// Hack for `spiderable` package: a way to see if the page is done\n// loading all the data it needs.\n//\nallConnections = [];\nDDP._allSubscriptionsReady = function () {\n return _.all(allConnections, function (conn) {\n return _.all(conn._subscriptions, function (sub) {\n return sub.ready;\n });\n });\n};\n","// Only create a server if we are in an environment with a HTTP server\n// (as opposed to, eg, a command-line tool).\n//\n// Note: this whole conditional is a total hack to get around the fact that this\n// package logically should be split into a ddp-client and ddp-server package;\n// see https://github.com/meteor/meteor/issues/3452\n//\n// Until we do that, this conditional (and the weak dependency on webapp that\n// should really be a strong dependency of the ddp-server package) allows you to\n// build projects which use `ddp` in Node without wanting to run a DDP server\n// (ie, allows you to act as if you were using the nonexistent `ddp-client`\n// server package).\nif (Package.webapp) {\n if (process.env.DDP_DEFAULT_CONNECTION_URL) {\n __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL =\n process.env.DDP_DEFAULT_CONNECTION_URL;\n }\n\n Meteor.server = new Server;\n\n Meteor.refresh = function (notification) {\n DDPServer._InvalidationCrossbar.fire(notification);\n };\n\n // Proxy the public methods of Meteor.server so they can\n // be called directly on Meteor.\n _.each(['publish', 'methods', 'call', 'apply', 'onConnection'],\n function (name) {\n Meteor[name] = _.bind(Meteor.server[name], Meteor.server);\n });\n} else {\n // No server? Make these empty/no-ops.\n Meteor.server = null;\n Meteor.refresh = function (notification) {\n };\n\n // Make these empty/no-ops too, so that non-webapp apps can still\n // depend on/use packages that use those functions.\n _.each(['publish', 'methods', 'onConnection'],\n function (name) {\n Meteor[name] = function () { };\n });\n}\n\n// Meteor.server used to be called Meteor.default_server. Provide\n// backcompat as a courtesy even though it was never documented.\n// XXX COMPAT WITH 0.6.4\nMeteor.default_server = Meteor.server;\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/deps.js b/web-app/.meteor/local/build/programs/server/packages/deps.js deleted file mode 100644 index 443ab79..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/deps.js +++ /dev/null @@ -1,22 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; - -/* Package-scope variables */ -var Tracker, Deps; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.deps = { - Tracker: Tracker, - Deps: Deps -}; - -})(); - -//# sourceMappingURL=deps.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/deps.js.map b/web-app/.meteor/local/build/programs/server/packages/deps.js.map deleted file mode 100644 index 2e8a49c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/deps.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;;;;;;","file":"/packages/deps.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/ejson.js b/web-app/.meteor/local/build/programs/server/packages/ejson.js deleted file mode 100644 index 3326785..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ejson.js +++ /dev/null @@ -1,679 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var Base64 = Package.base64.Base64; - -/* Package-scope variables */ -var EJSON, EJSONTest; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ejson/ejson.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/** // 1 - * @namespace // 2 - * @summary Namespace for EJSON functions // 3 - */ // 4 -EJSON = {}; // 5 -EJSONTest = {}; // 6 - // 7 - // 8 - // 9 -// Custom type interface definition // 10 -/** // 11 - * @class CustomType // 12 - * @instanceName customType // 13 - * @memberOf EJSON // 14 - * @summary The interface that a class must satisfy to be able to become an // 15 - * EJSON custom type via EJSON.addType. // 16 - */ // 17 - // 18 -/** // 19 - * @function typeName // 20 - * @memberOf EJSON.CustomType // 21 - * @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). - * @locus Anywhere // 23 - * @instance // 24 - */ // 25 - // 26 -/** // 27 - * @function toJSONValue // 28 - * @memberOf EJSON.CustomType // 29 - * @summary Serialize this instance into a JSON-compatible value. // 30 - * @locus Anywhere // 31 - * @instance // 32 - */ // 33 - // 34 -/** // 35 - * @function clone // 36 - * @memberOf EJSON.CustomType // 37 - * @summary Return a value `r` such that `this.equals(r)` is true, and modifications to `r` do not affect `this` and vice versa. - * @locus Anywhere // 39 - * @instance // 40 - */ // 41 - // 42 -/** // 43 - * @function equals // 44 - * @memberOf EJSON.CustomType // 45 - * @summary Return `true` if `other` has a value equal to `this`; `false` otherwise. // 46 - * @locus Anywhere // 47 - * @param {Object} other Another object to compare this to. // 48 - * @instance // 49 - */ // 50 - // 51 - // 52 -var customTypes = {}; // 53 -// Add a custom type, using a method of your choice to get to and // 54 -// from a basic JSON-able representation. The factory argument // 55 -// is a function of JSON-able --> your object // 56 -// The type you add must have: // 57 -// - A toJSONValue() method, so that Meteor can serialize it // 58 -// - a typeName() method, to show how to look it up in our type table. // 59 -// It is okay if these methods are monkey-patched on. // 60 -// EJSON.clone will use toJSONValue and the given factory to produce // 61 -// a clone, but you may specify a method clone() that will be // 62 -// used instead. // 63 -// Similarly, EJSON.equals will use toJSONValue to make comparisons, // 64 -// but you may provide a method equals() instead. // 65 -/** // 66 - * @summary Add a custom datatype to EJSON. // 67 - * @locus Anywhere // 68 - * @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. - * @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. - */ // 71 -EJSON.addType = function (name, factory) { // 72 - if (_.has(customTypes, name)) // 73 - throw new Error("Type " + name + " already present"); // 74 - customTypes[name] = factory; // 75 -}; // 76 - // 77 -var isInfOrNan = function (obj) { // 78 - return _.isNaN(obj) || obj === Infinity || obj === -Infinity; // 79 -}; // 80 - // 81 -var builtinConverters = [ // 82 - { // Date // 83 - matchJSONValue: function (obj) { // 84 - return _.has(obj, '$date') && _.size(obj) === 1; // 85 - }, // 86 - matchObject: function (obj) { // 87 - return obj instanceof Date; // 88 - }, // 89 - toJSONValue: function (obj) { // 90 - return {$date: obj.getTime()}; // 91 - }, // 92 - fromJSONValue: function (obj) { // 93 - return new Date(obj.$date); // 94 - } // 95 - }, // 96 - { // NaN, Inf, -Inf. (These are the only objects with typeof !== 'object' // 97 - // which we match.) // 98 - matchJSONValue: function (obj) { // 99 - return _.has(obj, '$InfNaN') && _.size(obj) === 1; // 100 - }, // 101 - matchObject: isInfOrNan, // 102 - toJSONValue: function (obj) { // 103 - var sign; // 104 - if (_.isNaN(obj)) // 105 - sign = 0; // 106 - else if (obj === Infinity) // 107 - sign = 1; // 108 - else // 109 - sign = -1; // 110 - return {$InfNaN: sign}; // 111 - }, // 112 - fromJSONValue: function (obj) { // 113 - return obj.$InfNaN/0; // 114 - } // 115 - }, // 116 - { // Binary // 117 - matchJSONValue: function (obj) { // 118 - return _.has(obj, '$binary') && _.size(obj) === 1; // 119 - }, // 120 - matchObject: function (obj) { // 121 - return typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array // 122 - || (obj && _.has(obj, '$Uint8ArrayPolyfill')); // 123 - }, // 124 - toJSONValue: function (obj) { // 125 - return {$binary: Base64.encode(obj)}; // 126 - }, // 127 - fromJSONValue: function (obj) { // 128 - return Base64.decode(obj.$binary); // 129 - } // 130 - }, // 131 - { // Escaping one level // 132 - matchJSONValue: function (obj) { // 133 - return _.has(obj, '$escape') && _.size(obj) === 1; // 134 - }, // 135 - matchObject: function (obj) { // 136 - if (_.isEmpty(obj) || _.size(obj) > 2) { // 137 - return false; // 138 - } // 139 - return _.any(builtinConverters, function (converter) { // 140 - return converter.matchJSONValue(obj); // 141 - }); // 142 - }, // 143 - toJSONValue: function (obj) { // 144 - var newObj = {}; // 145 - _.each(obj, function (value, key) { // 146 - newObj[key] = EJSON.toJSONValue(value); // 147 - }); // 148 - return {$escape: newObj}; // 149 - }, // 150 - fromJSONValue: function (obj) { // 151 - var newObj = {}; // 152 - _.each(obj.$escape, function (value, key) { // 153 - newObj[key] = EJSON.fromJSONValue(value); // 154 - }); // 155 - return newObj; // 156 - } // 157 - }, // 158 - { // Custom // 159 - matchJSONValue: function (obj) { // 160 - return _.has(obj, '$type') && _.has(obj, '$value') && _.size(obj) === 2; // 161 - }, // 162 - matchObject: function (obj) { // 163 - return EJSON._isCustomType(obj); // 164 - }, // 165 - toJSONValue: function (obj) { // 166 - var jsonValue = Meteor._noYieldsAllowed(function () { // 167 - return obj.toJSONValue(); // 168 - }); // 169 - return {$type: obj.typeName(), $value: jsonValue}; // 170 - }, // 171 - fromJSONValue: function (obj) { // 172 - var typeName = obj.$type; // 173 - if (!_.has(customTypes, typeName)) // 174 - throw new Error("Custom EJSON type " + typeName + " is not defined"); // 175 - var converter = customTypes[typeName]; // 176 - return Meteor._noYieldsAllowed(function () { // 177 - return converter(obj.$value); // 178 - }); // 179 - } // 180 - } // 181 -]; // 182 - // 183 -EJSON._isCustomType = function (obj) { // 184 - return obj && // 185 - typeof obj.toJSONValue === 'function' && // 186 - typeof obj.typeName === 'function' && // 187 - _.has(customTypes, obj.typeName()); // 188 -}; // 189 - // 190 - // 191 -// for both arrays and objects, in-place modification. // 192 -var adjustTypesToJSONValue = // 193 -EJSON._adjustTypesToJSONValue = function (obj) { // 194 - // Is it an atom that we need to adjust? // 195 - if (obj === null) // 196 - return null; // 197 - var maybeChanged = toJSONValueHelper(obj); // 198 - if (maybeChanged !== undefined) // 199 - return maybeChanged; // 200 - // 201 - // Other atoms are unchanged. // 202 - if (typeof obj !== 'object') // 203 - return obj; // 204 - // 205 - // Iterate over array or object structure. // 206 - _.each(obj, function (value, key) { // 207 - if (typeof value !== 'object' && value !== undefined && // 208 - !isInfOrNan(value)) // 209 - return; // continue // 210 - // 211 - var changed = toJSONValueHelper(value); // 212 - if (changed) { // 213 - obj[key] = changed; // 214 - return; // on to the next key // 215 - } // 216 - // if we get here, value is an object but not adjustable // 217 - // at this level. recurse. // 218 - adjustTypesToJSONValue(value); // 219 - }); // 220 - return obj; // 221 -}; // 222 - // 223 -// Either return the JSON-compatible version of the argument, or undefined (if // 224 -// the item isn't itself replaceable, but maybe some fields in it are) // 225 -var toJSONValueHelper = function (item) { // 226 - for (var i = 0; i < builtinConverters.length; i++) { // 227 - var converter = builtinConverters[i]; // 228 - if (converter.matchObject(item)) { // 229 - return converter.toJSONValue(item); // 230 - } // 231 - } // 232 - return undefined; // 233 -}; // 234 - // 235 -/** // 236 - * @summary Serialize an EJSON-compatible value into its plain JSON representation. // 237 - * @locus Anywhere // 238 - * @param {EJSON} val A value to serialize to plain JSON. // 239 - */ // 240 -EJSON.toJSONValue = function (item) { // 241 - var changed = toJSONValueHelper(item); // 242 - if (changed !== undefined) // 243 - return changed; // 244 - if (typeof item === 'object') { // 245 - item = EJSON.clone(item); // 246 - adjustTypesToJSONValue(item); // 247 - } // 248 - return item; // 249 -}; // 250 - // 251 -// for both arrays and objects. Tries its best to just // 252 -// use the object you hand it, but may return something // 253 -// different if the object you hand it itself needs changing. // 254 -// // 255 -var adjustTypesFromJSONValue = // 256 -EJSON._adjustTypesFromJSONValue = function (obj) { // 257 - if (obj === null) // 258 - return null; // 259 - var maybeChanged = fromJSONValueHelper(obj); // 260 - if (maybeChanged !== obj) // 261 - return maybeChanged; // 262 - // 263 - // Other atoms are unchanged. // 264 - if (typeof obj !== 'object') // 265 - return obj; // 266 - // 267 - _.each(obj, function (value, key) { // 268 - if (typeof value === 'object') { // 269 - var changed = fromJSONValueHelper(value); // 270 - if (value !== changed) { // 271 - obj[key] = changed; // 272 - return; // 273 - } // 274 - // if we get here, value is an object but not adjustable // 275 - // at this level. recurse. // 276 - adjustTypesFromJSONValue(value); // 277 - } // 278 - }); // 279 - return obj; // 280 -}; // 281 - // 282 -// Either return the argument changed to have the non-json // 283 -// rep of itself (the Object version) or the argument itself. // 284 - // 285 -// DOES NOT RECURSE. For actually getting the fully-changed value, use // 286 -// EJSON.fromJSONValue // 287 -var fromJSONValueHelper = function (value) { // 288 - if (typeof value === 'object' && value !== null) { // 289 - if (_.size(value) <= 2 // 290 - && _.all(value, function (v, k) { // 291 - return typeof k === 'string' && k.substr(0, 1) === '$'; // 292 - })) { // 293 - for (var i = 0; i < builtinConverters.length; i++) { // 294 - var converter = builtinConverters[i]; // 295 - if (converter.matchJSONValue(value)) { // 296 - return converter.fromJSONValue(value); // 297 - } // 298 - } // 299 - } // 300 - } // 301 - return value; // 302 -}; // 303 - // 304 -/** // 305 - * @summary Deserialize an EJSON value from its plain JSON representation. // 306 - * @locus Anywhere // 307 - * @param {JSONCompatible} val A value to deserialize into EJSON. // 308 - */ // 309 -EJSON.fromJSONValue = function (item) { // 310 - var changed = fromJSONValueHelper(item); // 311 - if (changed === item && typeof item === 'object') { // 312 - item = EJSON.clone(item); // 313 - adjustTypesFromJSONValue(item); // 314 - return item; // 315 - } else { // 316 - return changed; // 317 - } // 318 -}; // 319 - // 320 -/** // 321 - * @summary Serialize a value to a string. // 322 - // 323 -For EJSON values, the serialization fully represents the value. For non-EJSON values, serializes the same way as `JSON.stringify`. - * @locus Anywhere // 325 - * @param {EJSON} val A value to stringify. // 326 - * @param {Object} [options] // 327 - * @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. - * @param {Boolean} options.canonical When `true`, stringifies keys in an object in sorted order. // 329 - */ // 330 -EJSON.stringify = function (item, options) { // 331 - var json = EJSON.toJSONValue(item); // 332 - if (options && (options.canonical || options.indent)) { // 333 - return EJSON._canonicalStringify(json, options); // 334 - } else { // 335 - return JSON.stringify(json); // 336 - } // 337 -}; // 338 - // 339 -/** // 340 - * @summary Parse a string into an EJSON value. Throws an error if the string is not valid EJSON. // 341 - * @locus Anywhere // 342 - * @param {String} str A string to parse into an EJSON value. // 343 - */ // 344 -EJSON.parse = function (item) { // 345 - if (typeof item !== 'string') // 346 - throw new Error("EJSON.parse argument should be a string"); // 347 - return EJSON.fromJSONValue(JSON.parse(item)); // 348 -}; // 349 - // 350 -/** // 351 - * @summary Returns true if `x` is a buffer of binary data, as returned from [`EJSON.newBinary`](#ejson_new_binary). // 352 - * @param {Object} x The variable to check. // 353 - * @locus Anywhere // 354 - */ // 355 -EJSON.isBinary = function (obj) { // 356 - return !!((typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array) || // 357 - (obj && obj.$Uint8ArrayPolyfill)); // 358 -}; // 359 - // 360 -/** // 361 - * @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. - * @locus Anywhere // 363 - * @param {EJSON} a // 364 - * @param {EJSON} b // 365 - * @param {Object} [options] // 366 - * @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`. - */ // 368 -EJSON.equals = function (a, b, options) { // 369 - var i; // 370 - var keyOrderSensitive = !!(options && options.keyOrderSensitive); // 371 - if (a === b) // 372 - return true; // 373 - if (_.isNaN(a) && _.isNaN(b)) // 374 - return true; // This differs from the IEEE spec for NaN equality, b/c we don't want // 375 - // anything ever with a NaN to be poisoned from becoming equal to anything. // 376 - if (!a || !b) // if either one is falsy, they'd have to be === to be equal // 377 - return false; // 378 - if (!(typeof a === 'object' && typeof b === 'object')) // 379 - return false; // 380 - if (a instanceof Date && b instanceof Date) // 381 - return a.valueOf() === b.valueOf(); // 382 - if (EJSON.isBinary(a) && EJSON.isBinary(b)) { // 383 - if (a.length !== b.length) // 384 - return false; // 385 - for (i = 0; i < a.length; i++) { // 386 - if (a[i] !== b[i]) // 387 - return false; // 388 - } // 389 - return true; // 390 - } // 391 - if (typeof (a.equals) === 'function') // 392 - return a.equals(b, options); // 393 - if (typeof (b.equals) === 'function') // 394 - return b.equals(a, options); // 395 - if (a instanceof Array) { // 396 - if (!(b instanceof Array)) // 397 - return false; // 398 - if (a.length !== b.length) // 399 - return false; // 400 - for (i = 0; i < a.length; i++) { // 401 - if (!EJSON.equals(a[i], b[i], options)) // 402 - return false; // 403 - } // 404 - return true; // 405 - } // 406 - // fallback for custom types that don't implement their own equals // 407 - switch (EJSON._isCustomType(a) + EJSON._isCustomType(b)) { // 408 - case 1: return false; // 409 - case 2: return EJSON.equals(EJSON.toJSONValue(a), EJSON.toJSONValue(b)); // 410 - } // 411 - // fall back to structural equality of objects // 412 - var ret; // 413 - if (keyOrderSensitive) { // 414 - var bKeys = []; // 415 - _.each(b, function (val, x) { // 416 - bKeys.push(x); // 417 - }); // 418 - i = 0; // 419 - ret = _.all(a, function (val, x) { // 420 - if (i >= bKeys.length) { // 421 - return false; // 422 - } // 423 - if (x !== bKeys[i]) { // 424 - return false; // 425 - } // 426 - if (!EJSON.equals(val, b[bKeys[i]], options)) { // 427 - return false; // 428 - } // 429 - i++; // 430 - return true; // 431 - }); // 432 - return ret && i === bKeys.length; // 433 - } else { // 434 - i = 0; // 435 - ret = _.all(a, function (val, key) { // 436 - if (!_.has(b, key)) { // 437 - return false; // 438 - } // 439 - if (!EJSON.equals(val, b[key], options)) { // 440 - return false; // 441 - } // 442 - i++; // 443 - return true; // 444 - }); // 445 - return ret && _.size(b) === i; // 446 - } // 447 -}; // 448 - // 449 -/** // 450 - * @summary Return a deep copy of `val`. // 451 - * @locus Anywhere // 452 - * @param {EJSON} val A value to copy. // 453 - */ // 454 -EJSON.clone = function (v) { // 455 - var ret; // 456 - if (typeof v !== "object") // 457 - return v; // 458 - if (v === null) // 459 - return null; // null has typeof "object" // 460 - if (v instanceof Date) // 461 - return new Date(v.getTime()); // 462 - // RegExps are not really EJSON elements (eg we don't define a serialization // 463 - // for them), but they're immutable anyway, so we can support them in clone. // 464 - if (v instanceof RegExp) // 465 - return v; // 466 - if (EJSON.isBinary(v)) { // 467 - ret = EJSON.newBinary(v.length); // 468 - for (var i = 0; i < v.length; i++) { // 469 - ret[i] = v[i]; // 470 - } // 471 - return ret; // 472 - } // 473 - // XXX: Use something better than underscore's isArray // 474 - if (_.isArray(v) || _.isArguments(v)) { // 475 - // For some reason, _.map doesn't work in this context on Opera (weird test // 476 - // failures). // 477 - ret = []; // 478 - for (i = 0; i < v.length; i++) // 479 - ret[i] = EJSON.clone(v[i]); // 480 - return ret; // 481 - } // 482 - // handle general user-defined typed Objects if they have a clone method // 483 - if (typeof v.clone === 'function') { // 484 - return v.clone(); // 485 - } // 486 - // handle other custom types // 487 - if (EJSON._isCustomType(v)) { // 488 - return EJSON.fromJSONValue(EJSON.clone(EJSON.toJSONValue(v)), true); // 489 - } // 490 - // handle other objects // 491 - ret = {}; // 492 - _.each(v, function (value, key) { // 493 - ret[key] = EJSON.clone(value); // 494 - }); // 495 - return ret; // 496 -}; // 497 - // 498 -/** // 499 - * @summary Allocate a new buffer of binary data that EJSON can serialize. // 500 - * @locus Anywhere // 501 - * @param {Number} size The number of bytes of binary data to allocate. // 502 - */ // 503 -// EJSON.newBinary is the public documented API for this functionality, // 504 -// but the implementation is in the 'base64' package to avoid // 505 -// introducing a circular dependency. (If the implementation were here, // 506 -// then 'base64' would have to use EJSON.newBinary, and 'ejson' would // 507 -// also have to use 'base64'.) // 508 -EJSON.newBinary = Base64.newBinary; // 509 - // 510 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ejson/stringify.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Based on json2.js from https://github.com/douglascrockford/JSON-js // 1 -// // 2 -// json2.js // 3 -// 2012-10-08 // 4 -// // 5 -// Public Domain. // 6 -// // 7 -// NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. // 8 - // 9 -function quote(string) { // 10 - return JSON.stringify(string); // 11 -} // 12 - // 13 -var str = function (key, holder, singleIndent, outerIndent, canonical) { // 14 - // 15 - // Produce a string from holder[key]. // 16 - // 17 - var i; // The loop counter. // 18 - var k; // The member key. // 19 - var v; // The member value. // 20 - var length; // 21 - var innerIndent = outerIndent; // 22 - var partial; // 23 - var value = holder[key]; // 24 - // 25 - // What happens next depends on the value's type. // 26 - // 27 - switch (typeof value) { // 28 - case 'string': // 29 - return quote(value); // 30 - case 'number': // 31 - // JSON numbers must be finite. Encode non-finite numbers as null. // 32 - return isFinite(value) ? String(value) : 'null'; // 33 - case 'boolean': // 34 - return String(value); // 35 - // If the type is 'object', we might be dealing with an object or an array or // 36 - // null. // 37 - case 'object': // 38 - // Due to a specification blunder in ECMAScript, typeof null is 'object', // 39 - // so watch out for that case. // 40 - if (!value) { // 41 - return 'null'; // 42 - } // 43 - // Make an array to hold the partial results of stringifying this object value. // 44 - innerIndent = outerIndent + singleIndent; // 45 - partial = []; // 46 - // 47 - // Is the value an array? // 48 - if (_.isArray(value) || _.isArguments(value)) { // 49 - // 50 - // The value is an array. Stringify every element. Use null as a placeholder // 51 - // for non-JSON values. // 52 - // 53 - length = value.length; // 54 - for (i = 0; i < length; i += 1) { // 55 - partial[i] = str(i, value, singleIndent, innerIndent, canonical) || 'null'; // 56 - } // 57 - // 58 - // Join all of the elements together, separated with commas, and wrap them in // 59 - // brackets. // 60 - // 61 - if (partial.length === 0) { // 62 - v = '[]'; // 63 - } else if (innerIndent) { // 64 - v = '[\n' + innerIndent + partial.join(',\n' + innerIndent) + '\n' + outerIndent + ']'; // 65 - } else { // 66 - v = '[' + partial.join(',') + ']'; // 67 - } // 68 - return v; // 69 - } // 70 - // 71 - // 72 - // Iterate through all of the keys in the object. // 73 - var keys = _.keys(value); // 74 - if (canonical) // 75 - keys = keys.sort(); // 76 - _.each(keys, function (k) { // 77 - v = str(k, value, singleIndent, innerIndent, canonical); // 78 - if (v) { // 79 - partial.push(quote(k) + (innerIndent ? ': ' : ':') + v); // 80 - } // 81 - }); // 82 - // 83 - // 84 - // Join all of the member texts together, separated with commas, // 85 - // and wrap them in braces. // 86 - // 87 - if (partial.length === 0) { // 88 - v = '{}'; // 89 - } else if (innerIndent) { // 90 - v = '{\n' + innerIndent + partial.join(',\n' + innerIndent) + '\n' + outerIndent + '}'; // 91 - } else { // 92 - v = '{' + partial.join(',') + '}'; // 93 - } // 94 - return v; // 95 - } // 96 -} // 97 - // 98 -// If the JSON object does not yet have a stringify method, give it one. // 99 - // 100 -EJSON._canonicalStringify = function (value, options) { // 101 - // Make a fake root object containing our value under the key of ''. // 102 - // Return the result of stringifying the value. // 103 - options = _.extend({ // 104 - indent: "", // 105 - canonical: false // 106 - }, options); // 107 - if (options.indent === true) { // 108 - options.indent = " "; // 109 - } else if (typeof options.indent === 'number') { // 110 - var newIndent = ""; // 111 - for (var i = 0; i < options.indent; i++) { // 112 - newIndent += ' '; // 113 - } // 114 - options.indent = newIndent; // 115 - } // 116 - return str('', {'': value}, options.indent, "", options.canonical); // 117 -}; // 118 - // 119 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.ejson = { - EJSON: EJSON, - EJSONTest: EJSONTest -}; - -})(); - -//# sourceMappingURL=ejson.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/ejson.js.map b/web-app/.meteor/local/build/programs/server/packages/ejson.js.map deleted file mode 100644 index 21243a0..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ejson.js.map +++ /dev/null @@ -1 +0,0 @@ -{"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"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js b/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js deleted file mode 100644 index ddcec2c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js +++ /dev/null @@ -1,455 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - -/* Package-scope variables */ -var GeoJSON, module; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/geojson-utils/pre.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Define an object named exports. This will cause geojson-utils.js to put `gju` // 1 -// as a field on it, instead of in the global namespace. See also post.js. // 2 -module = {exports:{}}; // 3 - // 4 - // 5 -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/geojson-utils/geojson-utils.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -(function () { // 1 - var gju = {}; // 2 - // 3 - // Export the geojson object for **CommonJS** // 4 - if (typeof module !== 'undefined' && module.exports) { // 5 - module.exports = gju; // 6 - } // 7 - // 8 - // adapted from http://www.kevlindev.com/gui/math/intersection/Intersection.js // 9 - gju.lineStringsIntersect = function (l1, l2) { // 10 - var intersects = []; // 11 - for (var i = 0; i <= l1.coordinates.length - 2; ++i) { // 12 - for (var j = 0; j <= l2.coordinates.length - 2; ++j) { // 13 - var a1 = { // 14 - x: l1.coordinates[i][1], // 15 - y: l1.coordinates[i][0] // 16 - }, // 17 - a2 = { // 18 - x: l1.coordinates[i + 1][1], // 19 - y: l1.coordinates[i + 1][0] // 20 - }, // 21 - b1 = { // 22 - x: l2.coordinates[j][1], // 23 - y: l2.coordinates[j][0] // 24 - }, // 25 - b2 = { // 26 - x: l2.coordinates[j + 1][1], // 27 - y: l2.coordinates[j + 1][0] // 28 - }, // 29 - ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x), // 30 - ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x), // 31 - u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y); // 32 - if (u_b != 0) { // 33 - var ua = ua_t / u_b, // 34 - ub = ub_t / u_b; // 35 - if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) { // 36 - intersects.push({ // 37 - 'type': 'Point', // 38 - 'coordinates': [a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)] // 39 - }); // 40 - } // 41 - } // 42 - } // 43 - } // 44 - if (intersects.length == 0) intersects = false; // 45 - return intersects; // 46 - } // 47 - // 48 - // Bounding Box // 49 - // 50 - function boundingBoxAroundPolyCoords (coords) { // 51 - var xAll = [], yAll = [] // 52 - // 53 - for (var i = 0; i < coords[0].length; i++) { // 54 - xAll.push(coords[0][i][1]) // 55 - yAll.push(coords[0][i][0]) // 56 - } // 57 - // 58 - xAll = xAll.sort(function (a,b) { return a - b }) // 59 - yAll = yAll.sort(function (a,b) { return a - b }) // 60 - // 61 - return [ [xAll[0], yAll[0]], [xAll[xAll.length - 1], yAll[yAll.length - 1]] ] // 62 - } // 63 - // 64 - gju.pointInBoundingBox = function (point, bounds) { // 65 - return !(point.coordinates[1] < bounds[0][0] || point.coordinates[1] > bounds[1][0] || point.coordinates[0] < bounds[0][1] || point.coordinates[0] > bounds[1][1]) - } // 67 - // 68 - // Point in Polygon // 69 - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html#Listing the Vertices // 70 - // 71 - function pnpoly (x,y,coords) { // 72 - var vert = [ [0,0] ] // 73 - // 74 - for (var i = 0; i < coords.length; i++) { // 75 - for (var j = 0; j < coords[i].length; j++) { // 76 - vert.push(coords[i][j]) // 77 - } // 78 - vert.push([0,0]) // 79 - } // 80 - // 81 - var inside = false // 82 - for (var i = 0, j = vert.length - 1; i < vert.length; j = i++) { // 83 - if (((vert[i][0] > y) != (vert[j][0] > y)) && (x < (vert[j][1] - vert[i][1]) * (y - vert[i][0]) / (vert[j][0] - vert[i][0]) + vert[i][1])) inside = !inside - } // 85 - // 86 - return inside // 87 - } // 88 - // 89 - gju.pointInPolygon = function (p, poly) { // 90 - var coords = (poly.type == "Polygon") ? [ poly.coordinates ] : poly.coordinates // 91 - // 92 - var insideBox = false // 93 - for (var i = 0; i < coords.length; i++) { // 94 - if (gju.pointInBoundingBox(p, boundingBoxAroundPolyCoords(coords[i]))) insideBox = true // 95 - } // 96 - if (!insideBox) return false // 97 - // 98 - var insidePoly = false // 99 - for (var i = 0; i < coords.length; i++) { // 100 - if (pnpoly(p.coordinates[1], p.coordinates[0], coords[i])) insidePoly = true // 101 - } // 102 - // 103 - return insidePoly // 104 - } // 105 - // 106 - gju.numberToRadius = function (number) { // 107 - return number * Math.PI / 180; // 108 - } // 109 - // 110 - gju.numberToDegree = function (number) { // 111 - return number * 180 / Math.PI; // 112 - } // 113 - // 114 - // written with help from @tautologe // 115 - gju.drawCircle = function (radiusInMeters, centerPoint, steps) { // 116 - var center = [centerPoint.coordinates[1], centerPoint.coordinates[0]], // 117 - dist = (radiusInMeters / 1000) / 6371, // 118 - // convert meters to radiant // 119 - radCenter = [gju.numberToRadius(center[0]), gju.numberToRadius(center[1])], // 120 - steps = steps || 15, // 121 - // 15 sided circle // 122 - poly = [[center[0], center[1]]]; // 123 - for (var i = 0; i < steps; i++) { // 124 - var brng = 2 * Math.PI * i / steps; // 125 - var lat = Math.asin(Math.sin(radCenter[0]) * Math.cos(dist) // 126 - + Math.cos(radCenter[0]) * Math.sin(dist) * Math.cos(brng)); // 127 - var lng = radCenter[1] + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(radCenter[0]), // 128 - Math.cos(dist) - Math.sin(radCenter[0]) * Math.sin(lat)); // 129 - poly[i] = []; // 130 - poly[i][1] = gju.numberToDegree(lat); // 131 - poly[i][0] = gju.numberToDegree(lng); // 132 - } // 133 - return { // 134 - "type": "Polygon", // 135 - "coordinates": [poly] // 136 - }; // 137 - } // 138 - // 139 - // assumes rectangle starts at lower left point // 140 - gju.rectangleCentroid = function (rectangle) { // 141 - var bbox = rectangle.coordinates[0]; // 142 - var xmin = bbox[0][0], // 143 - ymin = bbox[0][1], // 144 - xmax = bbox[2][0], // 145 - ymax = bbox[2][1]; // 146 - var xwidth = xmax - xmin; // 147 - var ywidth = ymax - ymin; // 148 - return { // 149 - 'type': 'Point', // 150 - 'coordinates': [xmin + xwidth / 2, ymin + ywidth / 2] // 151 - }; // 152 - } // 153 - // 154 - // from http://www.movable-type.co.uk/scripts/latlong.html // 155 - gju.pointDistance = function (pt1, pt2) { // 156 - var lon1 = pt1.coordinates[0], // 157 - lat1 = pt1.coordinates[1], // 158 - lon2 = pt2.coordinates[0], // 159 - lat2 = pt2.coordinates[1], // 160 - dLat = gju.numberToRadius(lat2 - lat1), // 161 - dLon = gju.numberToRadius(lon2 - lon1), // 162 - a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(gju.numberToRadius(lat1)) // 163 - * Math.cos(gju.numberToRadius(lat2)) * Math.pow(Math.sin(dLon / 2), 2), // 164 - c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // 165 - // Earth radius is 6371 km // 166 - return (6371 * c) * 1000; // returns meters // 167 - }, // 168 - // 169 - // checks if geometry lies entirely within a circle // 170 - // works with Point, LineString, Polygon // 171 - gju.geometryWithinRadius = function (geometry, center, radius) { // 172 - if (geometry.type == 'Point') { // 173 - return gju.pointDistance(geometry, center) <= radius; // 174 - } else if (geometry.type == 'LineString' || geometry.type == 'Polygon') { // 175 - var point = {}; // 176 - var coordinates; // 177 - if (geometry.type == 'Polygon') { // 178 - // it's enough to check the exterior ring of the Polygon // 179 - coordinates = geometry.coordinates[0]; // 180 - } else { // 181 - coordinates = geometry.coordinates; // 182 - } // 183 - for (var i in coordinates) { // 184 - point.coordinates = coordinates[i]; // 185 - if (gju.pointDistance(point, center) > radius) { // 186 - return false; // 187 - } // 188 - } // 189 - } // 190 - return true; // 191 - } // 192 - // 193 - // adapted from http://paulbourke.net/geometry/polyarea/javascript.txt // 194 - gju.area = function (polygon) { // 195 - var area = 0; // 196 - // TODO: polygon holes at coordinates[1] // 197 - var points = polygon.coordinates[0]; // 198 - var j = points.length - 1; // 199 - var p1, p2; // 200 - // 201 - for (var i = 0; i < points.length; j = i++) { // 202 - var p1 = { // 203 - x: points[i][1], // 204 - y: points[i][0] // 205 - }; // 206 - var p2 = { // 207 - x: points[j][1], // 208 - y: points[j][0] // 209 - }; // 210 - area += p1.x * p2.y; // 211 - area -= p1.y * p2.x; // 212 - } // 213 - // 214 - area /= 2; // 215 - return area; // 216 - }, // 217 - // 218 - // adapted from http://paulbourke.net/geometry/polyarea/javascript.txt // 219 - gju.centroid = function (polygon) { // 220 - var f, x = 0, // 221 - y = 0; // 222 - // TODO: polygon holes at coordinates[1] // 223 - var points = polygon.coordinates[0]; // 224 - var j = points.length - 1; // 225 - var p1, p2; // 226 - // 227 - for (var i = 0; i < points.length; j = i++) { // 228 - var p1 = { // 229 - x: points[i][1], // 230 - y: points[i][0] // 231 - }; // 232 - var p2 = { // 233 - x: points[j][1], // 234 - y: points[j][0] // 235 - }; // 236 - f = p1.x * p2.y - p2.x * p1.y; // 237 - x += (p1.x + p2.x) * f; // 238 - y += (p1.y + p2.y) * f; // 239 - } // 240 - // 241 - f = gju.area(polygon) * 6; // 242 - return { // 243 - 'type': 'Point', // 244 - 'coordinates': [y / f, x / f] // 245 - }; // 246 - }, // 247 - // 248 - gju.simplify = function (source, kink) { /* source[] array of geojson points */ // 249 - /* kink in metres, kinks above this depth kept */ // 250 - /* kink depth is the height of the triangle abc where a-b and b-c are two consecutive line segments */ // 251 - kink = kink || 20; // 252 - source = source.map(function (o) { // 253 - return { // 254 - lng: o.coordinates[0], // 255 - lat: o.coordinates[1] // 256 - } // 257 - }); // 258 - // 259 - var n_source, n_stack, n_dest, start, end, i, sig; // 260 - var dev_sqr, max_dev_sqr, band_sqr; // 261 - var x12, y12, d12, x13, y13, d13, x23, y23, d23; // 262 - var F = (Math.PI / 180.0) * 0.5; // 263 - var index = new Array(); /* aray of indexes of source points to include in the reduced line */ // 264 - var sig_start = new Array(); /* indices of start & end of working section */ // 265 - var sig_end = new Array(); // 266 - // 267 - /* check for simple cases */ // 268 - // 269 - if (source.length < 3) return (source); /* one or two points */ // 270 - // 271 - /* more complex case. initialize stack */ // 272 - // 273 - n_source = source.length; // 274 - band_sqr = kink * 360.0 / (2.0 * Math.PI * 6378137.0); /* Now in degrees */ // 275 - band_sqr *= band_sqr; // 276 - n_dest = 0; // 277 - sig_start[0] = 0; // 278 - sig_end[0] = n_source - 1; // 279 - n_stack = 1; // 280 - // 281 - /* while the stack is not empty ... */ // 282 - while (n_stack > 0) { // 283 - // 284 - /* ... pop the top-most entries off the stacks */ // 285 - // 286 - start = sig_start[n_stack - 1]; // 287 - end = sig_end[n_stack - 1]; // 288 - n_stack--; // 289 - // 290 - if ((end - start) > 1) { /* any intermediate points ? */ // 291 - // 292 - /* ... yes, so find most deviant intermediate point to // 293 - either side of line joining start & end points */ // 294 - // 295 - x12 = (source[end].lng() - source[start].lng()); // 296 - y12 = (source[end].lat() - source[start].lat()); // 297 - if (Math.abs(x12) > 180.0) x12 = 360.0 - Math.abs(x12); // 298 - x12 *= Math.cos(F * (source[end].lat() + source[start].lat())); /* use avg lat to reduce lng */ // 299 - d12 = (x12 * x12) + (y12 * y12); // 300 - // 301 - for (i = start + 1, sig = start, max_dev_sqr = -1.0; i < end; i++) { // 302 - // 303 - x13 = source[i].lng() - source[start].lng(); // 304 - y13 = source[i].lat() - source[start].lat(); // 305 - if (Math.abs(x13) > 180.0) x13 = 360.0 - Math.abs(x13); // 306 - x13 *= Math.cos(F * (source[i].lat() + source[start].lat())); // 307 - d13 = (x13 * x13) + (y13 * y13); // 308 - // 309 - x23 = source[i].lng() - source[end].lng(); // 310 - y23 = source[i].lat() - source[end].lat(); // 311 - if (Math.abs(x23) > 180.0) x23 = 360.0 - Math.abs(x23); // 312 - x23 *= Math.cos(F * (source[i].lat() + source[end].lat())); // 313 - d23 = (x23 * x23) + (y23 * y23); // 314 - // 315 - if (d13 >= (d12 + d23)) dev_sqr = d23; // 316 - else if (d23 >= (d12 + d13)) dev_sqr = d13; // 317 - else dev_sqr = (x13 * y12 - y13 * x12) * (x13 * y12 - y13 * x12) / d12; // solve triangle // 318 - if (dev_sqr > max_dev_sqr) { // 319 - sig = i; // 320 - max_dev_sqr = dev_sqr; // 321 - } // 322 - } // 323 - // 324 - if (max_dev_sqr < band_sqr) { /* is there a sig. intermediate point ? */ // 325 - /* ... no, so transfer current start point */ // 326 - index[n_dest] = start; // 327 - n_dest++; // 328 - } else { /* ... yes, so push two sub-sections on stack for further processing */ // 329 - n_stack++; // 330 - sig_start[n_stack - 1] = sig; // 331 - sig_end[n_stack - 1] = end; // 332 - n_stack++; // 333 - sig_start[n_stack - 1] = start; // 334 - sig_end[n_stack - 1] = sig; // 335 - } // 336 - } else { /* ... no intermediate points, so transfer current start point */ // 337 - index[n_dest] = start; // 338 - n_dest++; // 339 - } // 340 - } // 341 - // 342 - /* transfer last point */ // 343 - index[n_dest] = n_source - 1; // 344 - n_dest++; // 345 - // 346 - /* make return array */ // 347 - var r = new Array(); // 348 - for (var i = 0; i < n_dest; i++) // 349 - r.push(source[index[i]]); // 350 - // 351 - return r.map(function (o) { // 352 - return { // 353 - type: "Point", // 354 - coordinates: [o.lng, o.lat] // 355 - } // 356 - }); // 357 - } // 358 - // 359 - // http://www.movable-type.co.uk/scripts/latlong.html#destPoint // 360 - gju.destinationPoint = function (pt, brng, dist) { // 361 - dist = dist/6371; // convert dist to angular distance in radians // 362 - brng = gju.numberToRadius(brng); // 363 - // 364 - var lat1 = gju.numberToRadius(pt.coordinates[0]); // 365 - var lon1 = gju.numberToRadius(pt.coordinates[1]); // 366 - // 367 - var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + // 368 - Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) ); // 369 - var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), // 370 - Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2)); // 371 - lon2 = (lon2+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º // 372 - // 373 - return { // 374 - 'type': 'Point', // 375 - 'coordinates': [gju.numberToDegree(lat2), gju.numberToDegree(lon2)] // 376 - }; // 377 - }; // 378 - // 379 -})(); // 380 - // 381 -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/geojson-utils/post.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// This exports object was created in pre.js. Now copy the `exports` object // 1 -// from it into the package-scope variable `GeoJSON`, which will get exported. // 2 -GeoJSON = module.exports; // 3 - // 4 - // 5 -///////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['geojson-utils'] = { - GeoJSON: GeoJSON -}; - -})(); - -//# sourceMappingURL=geojson-utils.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js.map b/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js.map deleted file mode 100644 index 7e9d955..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/geojson-utils.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["geojson-utils/pre.js","geojson-utils/geojson-utils.js","geojson-utils/post.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gF;AACA,2E;AACA,sB;;;;;;;;;;;;;;;;;;;;ACFA,c;AACA,e;;AAEA,+C;AACA,wD;AACA,yB;AACA,G;;AAEA,gF;AACA,gD;AACA,wB;AACA,0D;AACA,4D;AACA,kB;AACA,kC;AACA,iC;AACA,U;AACA,gB;AACA,wC;AACA,uC;AACA,Y;AACA,gB;AACA,oC;AACA,mC;AACA,Y;AACA,gB;AACA,wC;AACA,uC;AACA,Y;AACA,+E;AACA,+E;AACA,8E;AACA,uB;AACA,8B;AACA,4B;AACA,yD;AACA,6B;AACA,8B;AACA,mF;AACA,e;AACA,W;AACA,S;AACA,O;AACA,K;AACA,mD;AACA,sB;AACA,G;;AAEA,iB;;AAEA,iD;AACA,4B;;AAEA,gD;AACA,gC;AACA,gC;AACA,K;;AAEA,qD;AACA,qD;;AAEA,iF;AACA,G;;AAEA,qD;AACA,uK;AACA,G;;AAEA,qB;AACA,gG;;AAEA,gC;AACA,wB;;AAEA,6C;AACA,kD;AACA,+B;AACA,O;AACA,sB;AACA,K;;AAEA,sB;AACA,oE;AACA,iK;AACA,K;;AAEA,iB;AACA,G;;AAEA,2C;AACA,mF;;AAEA,yB;AACA,6C;AACA,6F;AACA,K;AACA,gC;;AAEA,0B;AACA,6C;AACA,kF;AACA,K;;AAEA,qB;AACA,G;;AAEA,0C;AACA,kC;AACA,G;;AAEA,0C;AACA,kC;AACA,G;;AAEA,sC;AACA,kE;AACA,0E;AACA,4C;AACA,kC;AACA,iF;AACA,0B;AACA,wB;AACA,sC;AACA,qC;AACA,yC;AACA,iE;AACA,0E;AACA,mG;AACA,mG;AACA,mB;AACA,2C;AACA,2C;AACA,K;AACA,Y;AACA,wB;AACA,2B;AACA,M;AACA,G;;AAEA,iD;AACA,gD;AACA,wC;AACA,0B;AACA,wB;AACA,wB;AACA,wB;AACA,6B;AACA,6B;AACA,Y;AACA,sB;AACA,2D;AACA,M;AACA,G;;AAEA,4D;AACA,2C;AACA,kC;AACA,gC;AACA,gC;AACA,gC;AACA,6C;AACA,6C;AACA,8E;AACA,+E;AACA,yD;AACA,8B;AACA,+C;AACA,I;;AAEA,qD;AACA,0C;AACA,kE;AACA,mC;AACA,2D;AACA,6E;AACA,qB;AACA,sB;AACA,uC;AACA,gE;AACA,8C;AACA,c;AACA,2C;AACA,O;AACA,kC;AACA,2C;AACA,wD;AACA,uB;AACA,S;AACA,O;AACA,K;AACA,gB;AACA,G;;AAEA,wE;AACA,iC;AACA,iB;AACA,4C;AACA,wC;AACA,8B;AACA,e;;AAEA,iD;AACA,gB;AACA,wB;AACA,uB;AACA,Q;AACA,gB;AACA,wB;AACA,uB;AACA,Q;AACA,0B;AACA,0B;AACA,K;;AAEA,c;AACA,gB;AACA,I;;AAEA,wE;AACA,qC;AACA,iB;AACA,Y;AACA,4C;AACA,wC;AACA,8B;AACA,e;;AAEA,iD;AACA,gB;AACA,wB;AACA,uB;AACA,Q;AACA,gB;AACA,wB;AACA,uB;AACA,Q;AACA,oC;AACA,6B;AACA,6B;AACA,K;;AAEA,8B;AACA,Y;AACA,sB;AACA,mC;AACA,M;AACA,I;;AAEA,iF;AACA,sD;AACA,0G;AACA,sB;AACA,sC;AACA,c;AACA,8B;AACA,6B;AACA,O;AACA,O;;AAEA,sD;AACA,uC;AACA,oD;AACA,oC;AACA,kG;AACA,gF;AACA,8B;;AAEA,gC;;AAEA,mE;;AAEA,6C;;AAEA,6B;AACA,+E;AACA,yB;AACA,e;AACA,qB;AACA,8B;AACA,gB;;AAEA,2C;AACA,yB;;AAEA,uD;;AAEA,qC;AACA,iC;AACA,gB;;AAEA,8D;;AAEA,8D;AACA,yD;;AAEA,wD;AACA,wD;AACA,+D;AACA,uG;AACA,wC;;AAEA,4E;;AAEA,sD;AACA,sD;AACA,iE;AACA,uE;AACA,0C;;AAEA,oD;AACA,oD;AACA,iE;AACA,qE;AACA,0C;;AAEA,gD;AACA,qD;AACA,mG;AACA,sC;AACA,oB;AACA,kC;AACA,W;AACA,S;;AAEA,gF;AACA,uD;AACA,gC;AACA,mB;AACA,wF;AACA,oB;AACA,uC;AACA,qC;AACA,oB;AACA,yC;AACA,qC;AACA,S;AACA,gF;AACA,8B;AACA,iB;AACA,O;AACA,K;;AAEA,6B;AACA,iC;AACA,a;;AAEA,2B;AACA,wB;AACA,oC;AACA,+B;;AAEA,+B;AACA,c;AACA,sB;AACA,mC;AACA,O;AACA,O;AACA,G;;AAEA,iE;AACA,oD;AACA,qE;AACA,oC;;AAEA,qD;AACA,qD;;AAEA,yD;AACA,yE;AACA,8E;AACA,+E;AACA,iF;;AAEA,Y;AACA,sB;AACA,yE;AACA,M;AACA,I;;AAEA,K;;;;;;;;;;;;;;;;;;;AC3XA,4E;AACA,8E;AACA,yB","file":"/packages/geojson-utils.js","sourcesContent":["// Define an object named exports. This will cause geojson-utils.js to put `gju`\n// as a field on it, instead of in the global namespace. See also post.js.\nmodule = {exports:{}};\n\n","(function () {\n var gju = {};\n\n // Export the geojson object for **CommonJS**\n if (typeof module !== 'undefined' && module.exports) {\n module.exports = gju;\n }\n\n // adapted from http://www.kevlindev.com/gui/math/intersection/Intersection.js\n gju.lineStringsIntersect = function (l1, l2) {\n var intersects = [];\n for (var i = 0; i <= l1.coordinates.length - 2; ++i) {\n for (var j = 0; j <= l2.coordinates.length - 2; ++j) {\n var a1 = {\n x: l1.coordinates[i][1],\n y: l1.coordinates[i][0]\n },\n a2 = {\n x: l1.coordinates[i + 1][1],\n y: l1.coordinates[i + 1][0]\n },\n b1 = {\n x: l2.coordinates[j][1],\n y: l2.coordinates[j][0]\n },\n b2 = {\n x: l2.coordinates[j + 1][1],\n y: l2.coordinates[j + 1][0]\n },\n ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),\n ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),\n u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);\n if (u_b != 0) {\n var ua = ua_t / u_b,\n ub = ub_t / u_b;\n if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n intersects.push({\n 'type': 'Point',\n 'coordinates': [a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)]\n });\n }\n }\n }\n }\n if (intersects.length == 0) intersects = false;\n return intersects;\n }\n\n // Bounding Box\n\n function boundingBoxAroundPolyCoords (coords) {\n var xAll = [], yAll = []\n\n for (var i = 0; i < coords[0].length; i++) {\n xAll.push(coords[0][i][1])\n yAll.push(coords[0][i][0])\n }\n\n xAll = xAll.sort(function (a,b) { return a - b })\n yAll = yAll.sort(function (a,b) { return a - b })\n\n return [ [xAll[0], yAll[0]], [xAll[xAll.length - 1], yAll[yAll.length - 1]] ]\n }\n\n gju.pointInBoundingBox = function (point, bounds) {\n return !(point.coordinates[1] < bounds[0][0] || point.coordinates[1] > bounds[1][0] || point.coordinates[0] < bounds[0][1] || point.coordinates[0] > bounds[1][1]) \n }\n\n // Point in Polygon\n // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html#Listing the Vertices\n\n function pnpoly (x,y,coords) {\n var vert = [ [0,0] ]\n\n for (var i = 0; i < coords.length; i++) {\n for (var j = 0; j < coords[i].length; j++) {\n vert.push(coords[i][j])\n }\n vert.push([0,0])\n }\n\n var inside = false\n for (var i = 0, j = vert.length - 1; i < vert.length; j = i++) {\n if (((vert[i][0] > y) != (vert[j][0] > y)) && (x < (vert[j][1] - vert[i][1]) * (y - vert[i][0]) / (vert[j][0] - vert[i][0]) + vert[i][1])) inside = !inside\n }\n\n return inside\n }\n\n gju.pointInPolygon = function (p, poly) {\n var coords = (poly.type == \"Polygon\") ? [ poly.coordinates ] : poly.coordinates\n\n var insideBox = false\n for (var i = 0; i < coords.length; i++) {\n if (gju.pointInBoundingBox(p, boundingBoxAroundPolyCoords(coords[i]))) insideBox = true\n }\n if (!insideBox) return false\n\n var insidePoly = false\n for (var i = 0; i < coords.length; i++) {\n if (pnpoly(p.coordinates[1], p.coordinates[0], coords[i])) insidePoly = true\n }\n\n return insidePoly\n }\n\n gju.numberToRadius = function (number) {\n return number * Math.PI / 180;\n }\n\n gju.numberToDegree = function (number) {\n return number * 180 / Math.PI;\n }\n\n // written with help from @tautologe\n gju.drawCircle = function (radiusInMeters, centerPoint, steps) {\n var center = [centerPoint.coordinates[1], centerPoint.coordinates[0]],\n dist = (radiusInMeters / 1000) / 6371,\n // convert meters to radiant\n radCenter = [gju.numberToRadius(center[0]), gju.numberToRadius(center[1])],\n steps = steps || 15,\n // 15 sided circle\n poly = [[center[0], center[1]]];\n for (var i = 0; i < steps; i++) {\n var brng = 2 * Math.PI * i / steps;\n var lat = Math.asin(Math.sin(radCenter[0]) * Math.cos(dist)\n + Math.cos(radCenter[0]) * Math.sin(dist) * Math.cos(brng));\n var lng = radCenter[1] + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(radCenter[0]),\n Math.cos(dist) - Math.sin(radCenter[0]) * Math.sin(lat));\n poly[i] = [];\n poly[i][1] = gju.numberToDegree(lat);\n poly[i][0] = gju.numberToDegree(lng);\n }\n return {\n \"type\": \"Polygon\",\n \"coordinates\": [poly]\n };\n }\n\n // assumes rectangle starts at lower left point\n gju.rectangleCentroid = function (rectangle) {\n var bbox = rectangle.coordinates[0];\n var xmin = bbox[0][0],\n ymin = bbox[0][1],\n xmax = bbox[2][0],\n ymax = bbox[2][1];\n var xwidth = xmax - xmin;\n var ywidth = ymax - ymin;\n return {\n 'type': 'Point',\n 'coordinates': [xmin + xwidth / 2, ymin + ywidth / 2]\n };\n }\n\n // from http://www.movable-type.co.uk/scripts/latlong.html\n gju.pointDistance = function (pt1, pt2) {\n var lon1 = pt1.coordinates[0],\n lat1 = pt1.coordinates[1],\n lon2 = pt2.coordinates[0],\n lat2 = pt2.coordinates[1],\n dLat = gju.numberToRadius(lat2 - lat1),\n dLon = gju.numberToRadius(lon2 - lon1),\n a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(gju.numberToRadius(lat1))\n * Math.cos(gju.numberToRadius(lat2)) * Math.pow(Math.sin(dLon / 2), 2),\n c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n // Earth radius is 6371 km\n return (6371 * c) * 1000; // returns meters\n },\n\n // checks if geometry lies entirely within a circle\n // works with Point, LineString, Polygon\n gju.geometryWithinRadius = function (geometry, center, radius) {\n if (geometry.type == 'Point') {\n return gju.pointDistance(geometry, center) <= radius;\n } else if (geometry.type == 'LineString' || geometry.type == 'Polygon') {\n var point = {};\n var coordinates;\n if (geometry.type == 'Polygon') {\n // it's enough to check the exterior ring of the Polygon\n coordinates = geometry.coordinates[0];\n } else {\n coordinates = geometry.coordinates;\n }\n for (var i in coordinates) {\n point.coordinates = coordinates[i];\n if (gju.pointDistance(point, center) > radius) {\n return false;\n }\n }\n }\n return true;\n }\n\n // adapted from http://paulbourke.net/geometry/polyarea/javascript.txt\n gju.area = function (polygon) {\n var area = 0;\n // TODO: polygon holes at coordinates[1]\n var points = polygon.coordinates[0];\n var j = points.length - 1;\n var p1, p2;\n\n for (var i = 0; i < points.length; j = i++) {\n var p1 = {\n x: points[i][1],\n y: points[i][0]\n };\n var p2 = {\n x: points[j][1],\n y: points[j][0]\n };\n area += p1.x * p2.y;\n area -= p1.y * p2.x;\n }\n\n area /= 2;\n return area;\n },\n\n // adapted from http://paulbourke.net/geometry/polyarea/javascript.txt\n gju.centroid = function (polygon) {\n var f, x = 0,\n y = 0;\n // TODO: polygon holes at coordinates[1]\n var points = polygon.coordinates[0];\n var j = points.length - 1;\n var p1, p2;\n\n for (var i = 0; i < points.length; j = i++) {\n var p1 = {\n x: points[i][1],\n y: points[i][0]\n };\n var p2 = {\n x: points[j][1],\n y: points[j][0]\n };\n f = p1.x * p2.y - p2.x * p1.y;\n x += (p1.x + p2.x) * f;\n y += (p1.y + p2.y) * f;\n }\n\n f = gju.area(polygon) * 6;\n return {\n 'type': 'Point',\n 'coordinates': [y / f, x / f]\n };\n },\n\n gju.simplify = function (source, kink) { /* source[] array of geojson points */\n /* kink\tin metres, kinks above this depth kept */\n /* kink depth is the height of the triangle abc where a-b and b-c are two consecutive line segments */\n kink = kink || 20;\n source = source.map(function (o) {\n return {\n lng: o.coordinates[0],\n lat: o.coordinates[1]\n }\n });\n\n var n_source, n_stack, n_dest, start, end, i, sig;\n var dev_sqr, max_dev_sqr, band_sqr;\n var x12, y12, d12, x13, y13, d13, x23, y23, d23;\n var F = (Math.PI / 180.0) * 0.5;\n var index = new Array(); /* aray of indexes of source points to include in the reduced line */\n var sig_start = new Array(); /* indices of start & end of working section */\n var sig_end = new Array();\n\n /* check for simple cases */\n\n if (source.length < 3) return (source); /* one or two points */\n\n /* more complex case. initialize stack */\n\n n_source = source.length;\n band_sqr = kink * 360.0 / (2.0 * Math.PI * 6378137.0); /* Now in degrees */\n band_sqr *= band_sqr;\n n_dest = 0;\n sig_start[0] = 0;\n sig_end[0] = n_source - 1;\n n_stack = 1;\n\n /* while the stack is not empty ... */\n while (n_stack > 0) {\n\n /* ... pop the top-most entries off the stacks */\n\n start = sig_start[n_stack - 1];\n end = sig_end[n_stack - 1];\n n_stack--;\n\n if ((end - start) > 1) { /* any intermediate points ? */\n\n /* ... yes, so find most deviant intermediate point to\n either side of line joining start & end points */\n\n x12 = (source[end].lng() - source[start].lng());\n y12 = (source[end].lat() - source[start].lat());\n if (Math.abs(x12) > 180.0) x12 = 360.0 - Math.abs(x12);\n x12 *= Math.cos(F * (source[end].lat() + source[start].lat())); /* use avg lat to reduce lng */\n d12 = (x12 * x12) + (y12 * y12);\n\n for (i = start + 1, sig = start, max_dev_sqr = -1.0; i < end; i++) {\n\n x13 = source[i].lng() - source[start].lng();\n y13 = source[i].lat() - source[start].lat();\n if (Math.abs(x13) > 180.0) x13 = 360.0 - Math.abs(x13);\n x13 *= Math.cos(F * (source[i].lat() + source[start].lat()));\n d13 = (x13 * x13) + (y13 * y13);\n\n x23 = source[i].lng() - source[end].lng();\n y23 = source[i].lat() - source[end].lat();\n if (Math.abs(x23) > 180.0) x23 = 360.0 - Math.abs(x23);\n x23 *= Math.cos(F * (source[i].lat() + source[end].lat()));\n d23 = (x23 * x23) + (y23 * y23);\n\n if (d13 >= (d12 + d23)) dev_sqr = d23;\n else if (d23 >= (d12 + d13)) dev_sqr = d13;\n else dev_sqr = (x13 * y12 - y13 * x12) * (x13 * y12 - y13 * x12) / d12; // solve triangle\n if (dev_sqr > max_dev_sqr) {\n sig = i;\n max_dev_sqr = dev_sqr;\n }\n }\n\n if (max_dev_sqr < band_sqr) { /* is there a sig. intermediate point ? */\n /* ... no, so transfer current start point */\n index[n_dest] = start;\n n_dest++;\n } else { /* ... yes, so push two sub-sections on stack for further processing */\n n_stack++;\n sig_start[n_stack - 1] = sig;\n sig_end[n_stack - 1] = end;\n n_stack++;\n sig_start[n_stack - 1] = start;\n sig_end[n_stack - 1] = sig;\n }\n } else { /* ... no intermediate points, so transfer current start point */\n index[n_dest] = start;\n n_dest++;\n }\n }\n\n /* transfer last point */\n index[n_dest] = n_source - 1;\n n_dest++;\n\n /* make return array */\n var r = new Array();\n for (var i = 0; i < n_dest; i++)\n r.push(source[index[i]]);\n\n return r.map(function (o) {\n return {\n type: \"Point\",\n coordinates: [o.lng, o.lat]\n }\n });\n }\n\n // http://www.movable-type.co.uk/scripts/latlong.html#destPoint\n gju.destinationPoint = function (pt, brng, dist) {\n dist = dist/6371; // convert dist to angular distance in radians\n brng = gju.numberToRadius(brng);\n\n var lat1 = gju.numberToRadius(pt.coordinates[0]);\n var lon1 = gju.numberToRadius(pt.coordinates[1]);\n\n var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) +\n Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) );\n var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1),\n Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));\n lon2 = (lon2+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º\n\n return {\n 'type': 'Point',\n 'coordinates': [gju.numberToDegree(lat2), gju.numberToDegree(lon2)]\n };\n };\n\n})();\n","// This exports object was created in pre.js. Now copy the `exports` object\n// from it into the package-scope variable `GeoJSON`, which will get exported.\nGeoJSON = module.exports;\n\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/global-imports.js b/web-app/.meteor/local/build/programs/server/packages/global-imports.js deleted file mode 100644 index 5297b26..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/global-imports.js +++ /dev/null @@ -1,28 +0,0 @@ -/* Imports for global scope */ - -moment = Package['momentjs:moment'].moment; -lodash = Package['stevezhu:lodash'].lodash; -_ = Package.underscore._; -numeral = Package['numeral:numeral'].numeral; -topojson = Package['mrt:topojson'].topojson; -Meteor = Package.meteor.Meteor; -WebApp = Package.webapp.WebApp; -main = Package.webapp.main; -WebAppInternals = Package.webapp.WebAppInternals; -Log = Package.logging.Log; -Tracker = Package.deps.Tracker; -Deps = Package.deps.Deps; -DDP = Package.livedata.DDP; -DDPServer = Package.livedata.DDPServer; -MongoInternals = Package.mongo.MongoInternals; -Mongo = Package.mongo.Mongo; -Blaze = Package.ui.Blaze; -UI = Package.ui.UI; -Handlebars = Package.ui.Handlebars; -Spacebars = Package.spacebars.Spacebars; -check = Package.check.check; -Match = Package.check.Match; -Random = Package.random.Random; -EJSON = Package.ejson.EJSON; -HTML = Package.htmljs.HTML; - diff --git a/web-app/.meteor/local/build/programs/server/packages/html-tools.js b/web-app/.meteor/local/build/programs/server/packages/html-tools.js deleted file mode 100644 index b50a396..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/html-tools.js +++ /dev/null @@ -1,3566 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var HTML = Package.htmljs.HTML; - -/* Package-scope variables */ -var HTMLTools, Scanner, makeRegexMatcher, getCharacterReference, getComment, getDoctype, getHTMLToken, getTagToken, TEMPLATE_TAG_POSITION, isLookingAtEndTag, codePointToString, getContent, getRCData; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/html-tools/utils.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // - // 1 -HTMLTools = {}; // 2 -HTMLTools.Parse = {}; // 3 - // 4 -var asciiLowerCase = HTMLTools.asciiLowerCase = function (str) { // 5 - return str.replace(/[A-Z]/g, function (c) { // 6 - return String.fromCharCode(c.charCodeAt(0) + 32); // 7 - }); // 8 -}; // 9 - // 10 -var svgCamelCaseAttributes = 'attributeName attributeType baseFrequency baseProfile calcMode clipPathUnits contentScriptType contentStyleType diffuseConstant edgeMode externalResourcesRequired filterRes filterUnits glyphRef glyphRef gradientTransform gradientTransform gradientUnits gradientUnits kernelMatrix kernelUnitLength kernelUnitLength kernelUnitLength keyPoints keySplines keyTimes lengthAdjust limitingConeAngle markerHeight markerUnits markerWidth maskContentUnits maskUnits numOctaves pathLength patternContentUnits patternTransform patternUnits pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits refX refY repeatCount repeatDur requiredExtensions requiredFeatures specularConstant specularExponent specularExponent spreadMethod spreadMethod startOffset stdDeviation stitchTiles surfaceScale surfaceScale systemLanguage tableValues targetX targetY textLength textLength viewBox viewTarget xChannelSelector yChannelSelector zoomAndPan'.split(' '); - // 12 -var properAttributeCaseMap = (function (map) { // 13 - for (var i = 0; i < svgCamelCaseAttributes.length; i++) { // 14 - var a = svgCamelCaseAttributes[i]; // 15 - map[asciiLowerCase(a)] = a; // 16 - } // 17 - return map; // 18 -})({}); // 19 - // 20 -var properTagCaseMap = (function (map) { // 21 - var knownElements = HTML.knownElementNames; // 22 - for (var i = 0; i < knownElements.length; i++) { // 23 - var a = knownElements[i]; // 24 - map[asciiLowerCase(a)] = a; // 25 - } // 26 - return map; // 27 -})({}); // 28 - // 29 -// Take a tag name in any case and make it the proper case for HTML. // 30 -// // 31 -// Modern browsers let you embed SVG in HTML, but SVG elements are special // 32 -// in that they have a case-sensitive DOM API (nodeName, getAttribute, // 33 -// setAttribute). For example, it has to be `setAttribute("viewBox")`, // 34 -// not `"viewbox"`. However, the browser's HTML parser is NOT case sensitive // 35 -// and will fix the case for you, so if you write `` // 36 -// you actually get a `"viewBox"` attribute. Any HTML-parsing toolchain // 37 -// must do the same. // 38 -HTMLTools.properCaseTagName = function (name) { // 39 - var lowered = asciiLowerCase(name); // 40 - return properTagCaseMap.hasOwnProperty(lowered) ? // 41 - properTagCaseMap[lowered] : lowered; // 42 -}; // 43 - // 44 -// See docs for properCaseTagName. // 45 -HTMLTools.properCaseAttributeName = function (name) { // 46 - var lowered = asciiLowerCase(name); // 47 - return properAttributeCaseMap.hasOwnProperty(lowered) ? // 48 - properAttributeCaseMap[lowered] : lowered; // 49 -}; // 50 - // 51 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/html-tools/scanner.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// This is a Scanner class suitable for any parser/lexer/tokenizer. // 1 -// // 2 -// A Scanner has an immutable source document (string) `input` and a current // 3 -// position `pos`, an index into the string, which can be set at will. // 4 -// // 5 -// * `new Scanner(input)` - constructs a Scanner with source string `input` // 6 -// * `scanner.rest()` - returns the rest of the input after `pos` // 7 -// * `scanner.peek()` - returns the character at `pos` // 8 -// * `scanner.isEOF()` - true if `pos` is at or beyond the end of `input` // 9 -// * `scanner.fatal(msg)` - throw an error indicating a problem at `pos` // 10 - // 11 -Scanner = HTMLTools.Scanner = function (input) { // 12 - this.input = input; // public, read-only // 13 - this.pos = 0; // public, read-write // 14 -}; // 15 - // 16 -Scanner.prototype.rest = function () { // 17 - // Slicing a string is O(1) in modern JavaScript VMs (including old IE). // 18 - return this.input.slice(this.pos); // 19 -}; // 20 - // 21 -Scanner.prototype.isEOF = function () { // 22 - return this.pos >= this.input.length; // 23 -}; // 24 - // 25 -Scanner.prototype.fatal = function (msg) { // 26 - // despite this default, you should always provide a message! // 27 - msg = (msg || "Parse error"); // 28 - // 29 - var CONTEXT_AMOUNT = 20; // 30 - // 31 - var input = this.input; // 32 - var pos = this.pos; // 33 - var pastInput = input.substring(pos - CONTEXT_AMOUNT - 1, pos); // 34 - if (pastInput.length > CONTEXT_AMOUNT) // 35 - pastInput = '...' + pastInput.substring(-CONTEXT_AMOUNT); // 36 - // 37 - var upcomingInput = input.substring(pos, pos + CONTEXT_AMOUNT + 1); // 38 - if (upcomingInput.length > CONTEXT_AMOUNT) // 39 - upcomingInput = upcomingInput.substring(0, CONTEXT_AMOUNT) + '...'; // 40 - // 41 - var positionDisplay = ((pastInput + upcomingInput).replace(/\n/g, ' ') + '\n' + // 42 - (new Array(pastInput.length + 1).join(' ')) + "^"); // 43 - // 44 - var e = new Error(msg + "\n" + positionDisplay); // 45 - // 46 - e.offset = pos; // 47 - var allPastInput = input.substring(0, pos); // 48 - e.line = (1 + (allPastInput.match(/\n/g) || []).length); // 49 - e.col = (1 + pos - allPastInput.lastIndexOf('\n')); // 50 - e.scanner = this; // 51 - // 52 - throw e; // 53 -}; // 54 - // 55 -// Peek at the next character. // 56 -// // 57 -// If `isEOF`, returns an empty string. // 58 -Scanner.prototype.peek = function () { // 59 - return this.input.charAt(this.pos); // 60 -}; // 61 - // 62 -// Constructs a `getFoo` function where `foo` is specified with a regex. // 63 -// The regex should start with `^`. The constructed function will return // 64 -// match group 1, if it exists and matches a non-empty string, or else // 65 -// the entire matched string (or null if there is no match). // 66 -// // 67 -// A `getFoo` function tries to match and consume a foo. If it succeeds, // 68 -// the current position of the scanner is advanced. If it fails, the // 69 -// current position is not advanced and a falsy value (typically null) // 70 -// is returned. // 71 -makeRegexMatcher = function (regex) { // 72 - return function (scanner) { // 73 - var match = regex.exec(scanner.rest()); // 74 - // 75 - if (! match) // 76 - return null; // 77 - // 78 - scanner.pos += match[0].length; // 79 - return match[1] || match[0]; // 80 - }; // 81 -}; // 82 - // 83 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/html-tools/charref.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // - // 1 -// http://www.whatwg.org/specs/web-apps/current-work/multipage/entities.json // 2 - // 3 - // 4 -// Note that some entities don't have a final semicolon! These are used to // 5 -// make `<` (for example) with no semicolon a parse error but `&abcde` not. // 6 - // 7 -var ENTITIES = { // 8 - "Á": { "codepoints": [193], "characters": "\u00C1" }, // 9 - "Á": { "codepoints": [193], "characters": "\u00C1" }, // 10 - "á": { "codepoints": [225], "characters": "\u00E1" }, // 11 - "á": { "codepoints": [225], "characters": "\u00E1" }, // 12 - "Ă": { "codepoints": [258], "characters": "\u0102" }, // 13 - "ă": { "codepoints": [259], "characters": "\u0103" }, // 14 - "∾": { "codepoints": [8766], "characters": "\u223E" }, // 15 - "∿": { "codepoints": [8767], "characters": "\u223F" }, // 16 - "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" }, // 17 - "Â": { "codepoints": [194], "characters": "\u00C2" }, // 18 - "Â": { "codepoints": [194], "characters": "\u00C2" }, // 19 - "â": { "codepoints": [226], "characters": "\u00E2" }, // 20 - "â": { "codepoints": [226], "characters": "\u00E2" }, // 21 - "´": { "codepoints": [180], "characters": "\u00B4" }, // 22 - "´": { "codepoints": [180], "characters": "\u00B4" }, // 23 - "А": { "codepoints": [1040], "characters": "\u0410" }, // 24 - "а": { "codepoints": [1072], "characters": "\u0430" }, // 25 - "Æ": { "codepoints": [198], "characters": "\u00C6" }, // 26 - "Æ": { "codepoints": [198], "characters": "\u00C6" }, // 27 - "æ": { "codepoints": [230], "characters": "\u00E6" }, // 28 - "æ": { "codepoints": [230], "characters": "\u00E6" }, // 29 - "⁡": { "codepoints": [8289], "characters": "\u2061" }, // 30 - "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" }, // 31 - "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" }, // 32 - "À": { "codepoints": [192], "characters": "\u00C0" }, // 33 - "À": { "codepoints": [192], "characters": "\u00C0" }, // 34 - "à": { "codepoints": [224], "characters": "\u00E0" }, // 35 - "à": { "codepoints": [224], "characters": "\u00E0" }, // 36 - "ℵ": { "codepoints": [8501], "characters": "\u2135" }, // 37 - "ℵ": { "codepoints": [8501], "characters": "\u2135" }, // 38 - "Α": { "codepoints": [913], "characters": "\u0391" }, // 39 - "α": { "codepoints": [945], "characters": "\u03B1" }, // 40 - "Ā": { "codepoints": [256], "characters": "\u0100" }, // 41 - "ā": { "codepoints": [257], "characters": "\u0101" }, // 42 - "⨿": { "codepoints": [10815], "characters": "\u2A3F" }, // 43 - "&": { "codepoints": [38], "characters": "\u0026" }, // 44 - "&": { "codepoints": [38], "characters": "\u0026" }, // 45 - "&": { "codepoints": [38], "characters": "\u0026" }, // 46 - "&": { "codepoints": [38], "characters": "\u0026" }, // 47 - "⩕": { "codepoints": [10837], "characters": "\u2A55" }, // 48 - "⩓": { "codepoints": [10835], "characters": "\u2A53" }, // 49 - "∧": { "codepoints": [8743], "characters": "\u2227" }, // 50 - "⩜": { "codepoints": [10844], "characters": "\u2A5C" }, // 51 - "⩘": { "codepoints": [10840], "characters": "\u2A58" }, // 52 - "⩚": { "codepoints": [10842], "characters": "\u2A5A" }, // 53 - "∠": { "codepoints": [8736], "characters": "\u2220" }, // 54 - "⦤": { "codepoints": [10660], "characters": "\u29A4" }, // 55 - "∠": { "codepoints": [8736], "characters": "\u2220" }, // 56 - "⦨": { "codepoints": [10664], "characters": "\u29A8" }, // 57 - "⦩": { "codepoints": [10665], "characters": "\u29A9" }, // 58 - "⦪": { "codepoints": [10666], "characters": "\u29AA" }, // 59 - "⦫": { "codepoints": [10667], "characters": "\u29AB" }, // 60 - "⦬": { "codepoints": [10668], "characters": "\u29AC" }, // 61 - "⦭": { "codepoints": [10669], "characters": "\u29AD" }, // 62 - "⦮": { "codepoints": [10670], "characters": "\u29AE" }, // 63 - "⦯": { "codepoints": [10671], "characters": "\u29AF" }, // 64 - "∡": { "codepoints": [8737], "characters": "\u2221" }, // 65 - "∟": { "codepoints": [8735], "characters": "\u221F" }, // 66 - "⊾": { "codepoints": [8894], "characters": "\u22BE" }, // 67 - "⦝": { "codepoints": [10653], "characters": "\u299D" }, // 68 - "∢": { "codepoints": [8738], "characters": "\u2222" }, // 69 - "Å": { "codepoints": [197], "characters": "\u00C5" }, // 70 - "⍼": { "codepoints": [9084], "characters": "\u237C" }, // 71 - "Ą": { "codepoints": [260], "characters": "\u0104" }, // 72 - "ą": { "codepoints": [261], "characters": "\u0105" }, // 73 - "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" }, // 74 - "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" }, // 75 - "⩯": { "codepoints": [10863], "characters": "\u2A6F" }, // 76 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 77 - "⩰": { "codepoints": [10864], "characters": "\u2A70" }, // 78 - "≊": { "codepoints": [8778], "characters": "\u224A" }, // 79 - "≋": { "codepoints": [8779], "characters": "\u224B" }, // 80 - "'": { "codepoints": [39], "characters": "\u0027" }, // 81 - "⁡": { "codepoints": [8289], "characters": "\u2061" }, // 82 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 83 - "≊": { "codepoints": [8778], "characters": "\u224A" }, // 84 - "Å": { "codepoints": [197], "characters": "\u00C5" }, // 85 - "Å": { "codepoints": [197], "characters": "\u00C5" }, // 86 - "å": { "codepoints": [229], "characters": "\u00E5" }, // 87 - "å": { "codepoints": [229], "characters": "\u00E5" }, // 88 - "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" }, // 89 - "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" }, // 90 - "≔": { "codepoints": [8788], "characters": "\u2254" }, // 91 - "*": { "codepoints": [42], "characters": "\u002A" }, // 92 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 93 - "≍": { "codepoints": [8781], "characters": "\u224D" }, // 94 - "Ã": { "codepoints": [195], "characters": "\u00C3" }, // 95 - "Ã": { "codepoints": [195], "characters": "\u00C3" }, // 96 - "ã": { "codepoints": [227], "characters": "\u00E3" }, // 97 - "ã": { "codepoints": [227], "characters": "\u00E3" }, // 98 - "Ä": { "codepoints": [196], "characters": "\u00C4" }, // 99 - "Ä": { "codepoints": [196], "characters": "\u00C4" }, // 100 - "ä": { "codepoints": [228], "characters": "\u00E4" }, // 101 - "ä": { "codepoints": [228], "characters": "\u00E4" }, // 102 - "∳": { "codepoints": [8755], "characters": "\u2233" }, // 103 - "⨑": { "codepoints": [10769], "characters": "\u2A11" }, // 104 - "≌": { "codepoints": [8780], "characters": "\u224C" }, // 105 - "϶": { "codepoints": [1014], "characters": "\u03F6" }, // 106 - "‵": { "codepoints": [8245], "characters": "\u2035" }, // 107 - "∽": { "codepoints": [8765], "characters": "\u223D" }, // 108 - "⋍": { "codepoints": [8909], "characters": "\u22CD" }, // 109 - "∖": { "codepoints": [8726], "characters": "\u2216" }, // 110 - "⫧": { "codepoints": [10983], "characters": "\u2AE7" }, // 111 - "⊽": { "codepoints": [8893], "characters": "\u22BD" }, // 112 - "⌅": { "codepoints": [8965], "characters": "\u2305" }, // 113 - "⌆": { "codepoints": [8966], "characters": "\u2306" }, // 114 - "⌅": { "codepoints": [8965], "characters": "\u2305" }, // 115 - "⎵": { "codepoints": [9141], "characters": "\u23B5" }, // 116 - "⎶": { "codepoints": [9142], "characters": "\u23B6" }, // 117 - "≌": { "codepoints": [8780], "characters": "\u224C" }, // 118 - "Б": { "codepoints": [1041], "characters": "\u0411" }, // 119 - "б": { "codepoints": [1073], "characters": "\u0431" }, // 120 - "„": { "codepoints": [8222], "characters": "\u201E" }, // 121 - "∵": { "codepoints": [8757], "characters": "\u2235" }, // 122 - "∵": { "codepoints": [8757], "characters": "\u2235" }, // 123 - "∵": { "codepoints": [8757], "characters": "\u2235" }, // 124 - "⦰": { "codepoints": [10672], "characters": "\u29B0" }, // 125 - "϶": { "codepoints": [1014], "characters": "\u03F6" }, // 126 - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, // 127 - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, // 128 - "Β": { "codepoints": [914], "characters": "\u0392" }, // 129 - "β": { "codepoints": [946], "characters": "\u03B2" }, // 130 - "ℶ": { "codepoints": [8502], "characters": "\u2136" }, // 131 - "≬": { "codepoints": [8812], "characters": "\u226C" }, // 132 - "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" }, // 133 - "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" }, // 134 - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, // 135 - "◯": { "codepoints": [9711], "characters": "\u25EF" }, // 136 - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, // 137 - "⨀": { "codepoints": [10752], "characters": "\u2A00" }, // 138 - "⨁": { "codepoints": [10753], "characters": "\u2A01" }, // 139 - "⨂": { "codepoints": [10754], "characters": "\u2A02" }, // 140 - "⨆": { "codepoints": [10758], "characters": "\u2A06" }, // 141 - "★": { "codepoints": [9733], "characters": "\u2605" }, // 142 - "▽": { "codepoints": [9661], "characters": "\u25BD" }, // 143 - "△": { "codepoints": [9651], "characters": "\u25B3" }, // 144 - "⨄": { "codepoints": [10756], "characters": "\u2A04" }, // 145 - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, // 146 - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, // 147 - "⤍": { "codepoints": [10509], "characters": "\u290D" }, // 148 - "⧫": { "codepoints": [10731], "characters": "\u29EB" }, // 149 - "▪": { "codepoints": [9642], "characters": "\u25AA" }, // 150 - "▴": { "codepoints": [9652], "characters": "\u25B4" }, // 151 - "▾": { "codepoints": [9662], "characters": "\u25BE" }, // 152 - "◂": { "codepoints": [9666], "characters": "\u25C2" }, // 153 - "▸": { "codepoints": [9656], "characters": "\u25B8" }, // 154 - "␣": { "codepoints": [9251], "characters": "\u2423" }, // 155 - "▒": { "codepoints": [9618], "characters": "\u2592" }, // 156 - "░": { "codepoints": [9617], "characters": "\u2591" }, // 157 - "▓": { "codepoints": [9619], "characters": "\u2593" }, // 158 - "█": { "codepoints": [9608], "characters": "\u2588" }, // 159 - "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" }, // 160 - "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" }, // 161 - "⫭": { "codepoints": [10989], "characters": "\u2AED" }, // 162 - "⌐": { "codepoints": [8976], "characters": "\u2310" }, // 163 - "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" }, // 164 - "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" }, // 165 - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, // 166 - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, // 167 - "⋈": { "codepoints": [8904], "characters": "\u22C8" }, // 168 - "⧉": { "codepoints": [10697], "characters": "\u29C9" }, // 169 - "┐": { "codepoints": [9488], "characters": "\u2510" }, // 170 - "╕": { "codepoints": [9557], "characters": "\u2555" }, // 171 - "╖": { "codepoints": [9558], "characters": "\u2556" }, // 172 - "╗": { "codepoints": [9559], "characters": "\u2557" }, // 173 - "┌": { "codepoints": [9484], "characters": "\u250C" }, // 174 - "╒": { "codepoints": [9554], "characters": "\u2552" }, // 175 - "╓": { "codepoints": [9555], "characters": "\u2553" }, // 176 - "╔": { "codepoints": [9556], "characters": "\u2554" }, // 177 - "─": { "codepoints": [9472], "characters": "\u2500" }, // 178 - "═": { "codepoints": [9552], "characters": "\u2550" }, // 179 - "┬": { "codepoints": [9516], "characters": "\u252C" }, // 180 - "╤": { "codepoints": [9572], "characters": "\u2564" }, // 181 - "╥": { "codepoints": [9573], "characters": "\u2565" }, // 182 - "╦": { "codepoints": [9574], "characters": "\u2566" }, // 183 - "┴": { "codepoints": [9524], "characters": "\u2534" }, // 184 - "╧": { "codepoints": [9575], "characters": "\u2567" }, // 185 - "╨": { "codepoints": [9576], "characters": "\u2568" }, // 186 - "╩": { "codepoints": [9577], "characters": "\u2569" }, // 187 - "⊟": { "codepoints": [8863], "characters": "\u229F" }, // 188 - "⊞": { "codepoints": [8862], "characters": "\u229E" }, // 189 - "⊠": { "codepoints": [8864], "characters": "\u22A0" }, // 190 - "┘": { "codepoints": [9496], "characters": "\u2518" }, // 191 - "╛": { "codepoints": [9563], "characters": "\u255B" }, // 192 - "╜": { "codepoints": [9564], "characters": "\u255C" }, // 193 - "╝": { "codepoints": [9565], "characters": "\u255D" }, // 194 - "└": { "codepoints": [9492], "characters": "\u2514" }, // 195 - "╘": { "codepoints": [9560], "characters": "\u2558" }, // 196 - "╙": { "codepoints": [9561], "characters": "\u2559" }, // 197 - "╚": { "codepoints": [9562], "characters": "\u255A" }, // 198 - "│": { "codepoints": [9474], "characters": "\u2502" }, // 199 - "║": { "codepoints": [9553], "characters": "\u2551" }, // 200 - "┼": { "codepoints": [9532], "characters": "\u253C" }, // 201 - "╪": { "codepoints": [9578], "characters": "\u256A" }, // 202 - "╫": { "codepoints": [9579], "characters": "\u256B" }, // 203 - "╬": { "codepoints": [9580], "characters": "\u256C" }, // 204 - "┤": { "codepoints": [9508], "characters": "\u2524" }, // 205 - "╡": { "codepoints": [9569], "characters": "\u2561" }, // 206 - "╢": { "codepoints": [9570], "characters": "\u2562" }, // 207 - "╣": { "codepoints": [9571], "characters": "\u2563" }, // 208 - "├": { "codepoints": [9500], "characters": "\u251C" }, // 209 - "╞": { "codepoints": [9566], "characters": "\u255E" }, // 210 - "╟": { "codepoints": [9567], "characters": "\u255F" }, // 211 - "╠": { "codepoints": [9568], "characters": "\u2560" }, // 212 - "‵": { "codepoints": [8245], "characters": "\u2035" }, // 213 - "˘": { "codepoints": [728], "characters": "\u02D8" }, // 214 - "˘": { "codepoints": [728], "characters": "\u02D8" }, // 215 - "¦": { "codepoints": [166], "characters": "\u00A6" }, // 216 - "¦": { "codepoints": [166], "characters": "\u00A6" }, // 217 - "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" }, // 218 - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, // 219 - "⁏": { "codepoints": [8271], "characters": "\u204F" }, // 220 - "∽": { "codepoints": [8765], "characters": "\u223D" }, // 221 - "⋍": { "codepoints": [8909], "characters": "\u22CD" }, // 222 - "⧅": { "codepoints": [10693], "characters": "\u29C5" }, // 223 - "\": { "codepoints": [92], "characters": "\u005C" }, // 224 - "⟈": { "codepoints": [10184], "characters": "\u27C8" }, // 225 - "•": { "codepoints": [8226], "characters": "\u2022" }, // 226 - "•": { "codepoints": [8226], "characters": "\u2022" }, // 227 - "≎": { "codepoints": [8782], "characters": "\u224E" }, // 228 - "⪮": { "codepoints": [10926], "characters": "\u2AAE" }, // 229 - "≏": { "codepoints": [8783], "characters": "\u224F" }, // 230 - "≎": { "codepoints": [8782], "characters": "\u224E" }, // 231 - "≏": { "codepoints": [8783], "characters": "\u224F" }, // 232 - "Ć": { "codepoints": [262], "characters": "\u0106" }, // 233 - "ć": { "codepoints": [263], "characters": "\u0107" }, // 234 - "⩄": { "codepoints": [10820], "characters": "\u2A44" }, // 235 - "⩉": { "codepoints": [10825], "characters": "\u2A49" }, // 236 - "⩋": { "codepoints": [10827], "characters": "\u2A4B" }, // 237 - "∩": { "codepoints": [8745], "characters": "\u2229" }, // 238 - "⋒": { "codepoints": [8914], "characters": "\u22D2" }, // 239 - "⩇": { "codepoints": [10823], "characters": "\u2A47" }, // 240 - "⩀": { "codepoints": [10816], "characters": "\u2A40" }, // 241 - "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, // 242 - "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" }, // 243 - "⁁": { "codepoints": [8257], "characters": "\u2041" }, // 244 - "ˇ": { "codepoints": [711], "characters": "\u02C7" }, // 245 - "ℭ": { "codepoints": [8493], "characters": "\u212D" }, // 246 - "⩍": { "codepoints": [10829], "characters": "\u2A4D" }, // 247 - "Č": { "codepoints": [268], "characters": "\u010C" }, // 248 - "č": { "codepoints": [269], "characters": "\u010D" }, // 249 - "Ç": { "codepoints": [199], "characters": "\u00C7" }, // 250 - "Ç": { "codepoints": [199], "characters": "\u00C7" }, // 251 - "ç": { "codepoints": [231], "characters": "\u00E7" }, // 252 - "ç": { "codepoints": [231], "characters": "\u00E7" }, // 253 - "Ĉ": { "codepoints": [264], "characters": "\u0108" }, // 254 - "ĉ": { "codepoints": [265], "characters": "\u0109" }, // 255 - "∰": { "codepoints": [8752], "characters": "\u2230" }, // 256 - "⩌": { "codepoints": [10828], "characters": "\u2A4C" }, // 257 - "⩐": { "codepoints": [10832], "characters": "\u2A50" }, // 258 - "Ċ": { "codepoints": [266], "characters": "\u010A" }, // 259 - "ċ": { "codepoints": [267], "characters": "\u010B" }, // 260 - "¸": { "codepoints": [184], "characters": "\u00B8" }, // 261 - "¸": { "codepoints": [184], "characters": "\u00B8" }, // 262 - "¸": { "codepoints": [184], "characters": "\u00B8" }, // 263 - "⦲": { "codepoints": [10674], "characters": "\u29B2" }, // 264 - "¢": { "codepoints": [162], "characters": "\u00A2" }, // 265 - "¢": { "codepoints": [162], "characters": "\u00A2" }, // 266 - "·": { "codepoints": [183], "characters": "\u00B7" }, // 267 - "·": { "codepoints": [183], "characters": "\u00B7" }, // 268 - "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" }, // 269 - "ℭ": { "codepoints": [8493], "characters": "\u212D" }, // 270 - "Ч": { "codepoints": [1063], "characters": "\u0427" }, // 271 - "ч": { "codepoints": [1095], "characters": "\u0447" }, // 272 - "✓": { "codepoints": [10003], "characters": "\u2713" }, // 273 - "✓": { "codepoints": [10003], "characters": "\u2713" }, // 274 - "Χ": { "codepoints": [935], "characters": "\u03A7" }, // 275 - "χ": { "codepoints": [967], "characters": "\u03C7" }, // 276 - "ˆ": { "codepoints": [710], "characters": "\u02C6" }, // 277 - "≗": { "codepoints": [8791], "characters": "\u2257" }, // 278 - "↺": { "codepoints": [8634], "characters": "\u21BA" }, // 279 - "↻": { "codepoints": [8635], "characters": "\u21BB" }, // 280 - "⊛": { "codepoints": [8859], "characters": "\u229B" }, // 281 - "⊚": { "codepoints": [8858], "characters": "\u229A" }, // 282 - "⊝": { "codepoints": [8861], "characters": "\u229D" }, // 283 - "⊙": { "codepoints": [8857], "characters": "\u2299" }, // 284 - "®": { "codepoints": [174], "characters": "\u00AE" }, // 285 - "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, // 286 - "⊖": { "codepoints": [8854], "characters": "\u2296" }, // 287 - "⊕": { "codepoints": [8853], "characters": "\u2295" }, // 288 - "⊗": { "codepoints": [8855], "characters": "\u2297" }, // 289 - "○": { "codepoints": [9675], "characters": "\u25CB" }, // 290 - "⧃": { "codepoints": [10691], "characters": "\u29C3" }, // 291 - "≗": { "codepoints": [8791], "characters": "\u2257" }, // 292 - "⨐": { "codepoints": [10768], "characters": "\u2A10" }, // 293 - "⫯": { "codepoints": [10991], "characters": "\u2AEF" }, // 294 - "⧂": { "codepoints": [10690], "characters": "\u29C2" }, // 295 - "∲": { "codepoints": [8754], "characters": "\u2232" }, // 296 - "”": { "codepoints": [8221], "characters": "\u201D" }, // 297 - "’": { "codepoints": [8217], "characters": "\u2019" }, // 298 - "♣": { "codepoints": [9827], "characters": "\u2663" }, // 299 - "♣": { "codepoints": [9827], "characters": "\u2663" }, // 300 - ":": { "codepoints": [58], "characters": "\u003A" }, // 301 - "∷": { "codepoints": [8759], "characters": "\u2237" }, // 302 - "⩴": { "codepoints": [10868], "characters": "\u2A74" }, // 303 - "≔": { "codepoints": [8788], "characters": "\u2254" }, // 304 - "≔": { "codepoints": [8788], "characters": "\u2254" }, // 305 - ",": { "codepoints": [44], "characters": "\u002C" }, // 306 - "@": { "codepoints": [64], "characters": "\u0040" }, // 307 - "∁": { "codepoints": [8705], "characters": "\u2201" }, // 308 - "∘": { "codepoints": [8728], "characters": "\u2218" }, // 309 - "∁": { "codepoints": [8705], "characters": "\u2201" }, // 310 - "ℂ": { "codepoints": [8450], "characters": "\u2102" }, // 311 - "≅": { "codepoints": [8773], "characters": "\u2245" }, // 312 - "⩭": { "codepoints": [10861], "characters": "\u2A6D" }, // 313 - "≡": { "codepoints": [8801], "characters": "\u2261" }, // 314 - "∮": { "codepoints": [8750], "characters": "\u222E" }, // 315 - "∯": { "codepoints": [8751], "characters": "\u222F" }, // 316 - "∮": { "codepoints": [8750], "characters": "\u222E" }, // 317 - "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" }, // 318 - "ℂ": { "codepoints": [8450], "characters": "\u2102" }, // 319 - "∐": { "codepoints": [8720], "characters": "\u2210" }, // 320 - "∐": { "codepoints": [8720], "characters": "\u2210" }, // 321 - "©": { "codepoints": [169], "characters": "\u00A9" }, // 322 - "©": { "codepoints": [169], "characters": "\u00A9" }, // 323 - "©": { "codepoints": [169], "characters": "\u00A9" }, // 324 - "©": { "codepoints": [169], "characters": "\u00A9" }, // 325 - "℗": { "codepoints": [8471], "characters": "\u2117" }, // 326 - "∳": { "codepoints": [8755], "characters": "\u2233" }, // 327 - "↵": { "codepoints": [8629], "characters": "\u21B5" }, // 328 - "✗": { "codepoints": [10007], "characters": "\u2717" }, // 329 - "⨯": { "codepoints": [10799], "characters": "\u2A2F" }, // 330 - "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" }, // 331 - "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" }, // 332 - "⫏": { "codepoints": [10959], "characters": "\u2ACF" }, // 333 - "⫑": { "codepoints": [10961], "characters": "\u2AD1" }, // 334 - "⫐": { "codepoints": [10960], "characters": "\u2AD0" }, // 335 - "⫒": { "codepoints": [10962], "characters": "\u2AD2" }, // 336 - "⋯": { "codepoints": [8943], "characters": "\u22EF" }, // 337 - "⤸": { "codepoints": [10552], "characters": "\u2938" }, // 338 - "⤵": { "codepoints": [10549], "characters": "\u2935" }, // 339 - "⋞": { "codepoints": [8926], "characters": "\u22DE" }, // 340 - "⋟": { "codepoints": [8927], "characters": "\u22DF" }, // 341 - "↶": { "codepoints": [8630], "characters": "\u21B6" }, // 342 - "⤽": { "codepoints": [10557], "characters": "\u293D" }, // 343 - "⩈": { "codepoints": [10824], "characters": "\u2A48" }, // 344 - "⩆": { "codepoints": [10822], "characters": "\u2A46" }, // 345 - "≍": { "codepoints": [8781], "characters": "\u224D" }, // 346 - "∪": { "codepoints": [8746], "characters": "\u222A" }, // 347 - "⋓": { "codepoints": [8915], "characters": "\u22D3" }, // 348 - "⩊": { "codepoints": [10826], "characters": "\u2A4A" }, // 349 - "⊍": { "codepoints": [8845], "characters": "\u228D" }, // 350 - "⩅": { "codepoints": [10821], "characters": "\u2A45" }, // 351 - "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" }, // 352 - "↷": { "codepoints": [8631], "characters": "\u21B7" }, // 353 - "⤼": { "codepoints": [10556], "characters": "\u293C" }, // 354 - "⋞": { "codepoints": [8926], "characters": "\u22DE" }, // 355 - "⋟": { "codepoints": [8927], "characters": "\u22DF" }, // 356 - "⋎": { "codepoints": [8910], "characters": "\u22CE" }, // 357 - "⋏": { "codepoints": [8911], "characters": "\u22CF" }, // 358 - "¤": { "codepoints": [164], "characters": "\u00A4" }, // 359 - "¤": { "codepoints": [164], "characters": "\u00A4" }, // 360 - "↶": { "codepoints": [8630], "characters": "\u21B6" }, // 361 - "↷": { "codepoints": [8631], "characters": "\u21B7" }, // 362 - "⋎": { "codepoints": [8910], "characters": "\u22CE" }, // 363 - "⋏": { "codepoints": [8911], "characters": "\u22CF" }, // 364 - "∲": { "codepoints": [8754], "characters": "\u2232" }, // 365 - "∱": { "codepoints": [8753], "characters": "\u2231" }, // 366 - "⌭": { "codepoints": [9005], "characters": "\u232D" }, // 367 - "†": { "codepoints": [8224], "characters": "\u2020" }, // 368 - "‡": { "codepoints": [8225], "characters": "\u2021" }, // 369 - "ℸ": { "codepoints": [8504], "characters": "\u2138" }, // 370 - "↓": { "codepoints": [8595], "characters": "\u2193" }, // 371 - "↡": { "codepoints": [8609], "characters": "\u21A1" }, // 372 - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, // 373 - "‐": { "codepoints": [8208], "characters": "\u2010" }, // 374 - "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, // 375 - "⊣": { "codepoints": [8867], "characters": "\u22A3" }, // 376 - "⤏": { "codepoints": [10511], "characters": "\u290F" }, // 377 - "˝": { "codepoints": [733], "characters": "\u02DD" }, // 378 - "Ď": { "codepoints": [270], "characters": "\u010E" }, // 379 - "ď": { "codepoints": [271], "characters": "\u010F" }, // 380 - "Д": { "codepoints": [1044], "characters": "\u0414" }, // 381 - "д": { "codepoints": [1076], "characters": "\u0434" }, // 382 - "‡": { "codepoints": [8225], "characters": "\u2021" }, // 383 - "⇊": { "codepoints": [8650], "characters": "\u21CA" }, // 384 - "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, // 385 - "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, // 386 - "⤑": { "codepoints": [10513], "characters": "\u2911" }, // 387 - "⩷": { "codepoints": [10871], "characters": "\u2A77" }, // 388 - "°": { "codepoints": [176], "characters": "\u00B0" }, // 389 - "°": { "codepoints": [176], "characters": "\u00B0" }, // 390 - "∇": { "codepoints": [8711], "characters": "\u2207" }, // 391 - "Δ": { "codepoints": [916], "characters": "\u0394" }, // 392 - "δ": { "codepoints": [948], "characters": "\u03B4" }, // 393 - "⦱": { "codepoints": [10673], "characters": "\u29B1" }, // 394 - "⥿": { "codepoints": [10623], "characters": "\u297F" }, // 395 - "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" }, // 396 - "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" }, // 397 - "⥥": { "codepoints": [10597], "characters": "\u2965" }, // 398 - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, // 399 - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, // 400 - "´": { "codepoints": [180], "characters": "\u00B4" }, // 401 - "˙": { "codepoints": [729], "characters": "\u02D9" }, // 402 - "˝": { "codepoints": [733], "characters": "\u02DD" }, // 403 - "`": { "codepoints": [96], "characters": "\u0060" }, // 404 - "˜": { "codepoints": [732], "characters": "\u02DC" }, // 405 - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, // 406 - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, // 407 - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, // 408 - "♦": { "codepoints": [9830], "characters": "\u2666" }, // 409 - "♦": { "codepoints": [9830], "characters": "\u2666" }, // 410 - "¨": { "codepoints": [168], "characters": "\u00A8" }, // 411 - "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, // 412 - "ϝ": { "codepoints": [989], "characters": "\u03DD" }, // 413 - "⋲": { "codepoints": [8946], "characters": "\u22F2" }, // 414 - "÷": { "codepoints": [247], "characters": "\u00F7" }, // 415 - "÷": { "codepoints": [247], "characters": "\u00F7" }, // 416 - "÷": { "codepoints": [247], "characters": "\u00F7" }, // 417 - "⋇": { "codepoints": [8903], "characters": "\u22C7" }, // 418 - "⋇": { "codepoints": [8903], "characters": "\u22C7" }, // 419 - "Ђ": { "codepoints": [1026], "characters": "\u0402" }, // 420 - "ђ": { "codepoints": [1106], "characters": "\u0452" }, // 421 - "⌞": { "codepoints": [8990], "characters": "\u231E" }, // 422 - "⌍": { "codepoints": [8973], "characters": "\u230D" }, // 423 - "$": { "codepoints": [36], "characters": "\u0024" }, // 424 - "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" }, // 425 - "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" }, // 426 - "¨": { "codepoints": [168], "characters": "\u00A8" }, // 427 - "˙": { "codepoints": [729], "characters": "\u02D9" }, // 428 - "⃜": { "codepoints": [8412], "characters": "\u20DC" }, // 429 - "≐": { "codepoints": [8784], "characters": "\u2250" }, // 430 - "≑": { "codepoints": [8785], "characters": "\u2251" }, // 431 - "≐": { "codepoints": [8784], "characters": "\u2250" }, // 432 - "∸": { "codepoints": [8760], "characters": "\u2238" }, // 433 - "∔": { "codepoints": [8724], "characters": "\u2214" }, // 434 - "⊡": { "codepoints": [8865], "characters": "\u22A1" }, // 435 - "⌆": { "codepoints": [8966], "characters": "\u2306" }, // 436 - "∯": { "codepoints": [8751], "characters": "\u222F" }, // 437 - "¨": { "codepoints": [168], "characters": "\u00A8" }, // 438 - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, // 439 - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, // 440 - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, // 441 - "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, // 442 - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, // 443 - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, // 444 - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, // 445 - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, // 446 - "⊨": { "codepoints": [8872], "characters": "\u22A8" }, // 447 - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, // 448 - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, // 449 - "∥": { "codepoints": [8741], "characters": "\u2225" }, // 450 - "⤓": { "codepoints": [10515], "characters": "\u2913" }, // 451 - "↓": { "codepoints": [8595], "characters": "\u2193" }, // 452 - "↓": { "codepoints": [8595], "characters": "\u2193" }, // 453 - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, // 454 - "⇵": { "codepoints": [8693], "characters": "\u21F5" }, // 455 - "̑": { "codepoints": [785], "characters": "\u0311" }, // 456 - "⇊": { "codepoints": [8650], "characters": "\u21CA" }, // 457 - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, // 458 - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, // 459 - "⥐": { "codepoints": [10576], "characters": "\u2950" }, // 460 - "⥞": { "codepoints": [10590], "characters": "\u295E" }, // 461 - "⥖": { "codepoints": [10582], "characters": "\u2956" }, // 462 - "↽": { "codepoints": [8637], "characters": "\u21BD" }, // 463 - "⥟": { "codepoints": [10591], "characters": "\u295F" }, // 464 - "⥗": { "codepoints": [10583], "characters": "\u2957" }, // 465 - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, // 466 - "↧": { "codepoints": [8615], "characters": "\u21A7" }, // 467 - "⊤": { "codepoints": [8868], "characters": "\u22A4" }, // 468 - "⤐": { "codepoints": [10512], "characters": "\u2910" }, // 469 - "⌟": { "codepoints": [8991], "characters": "\u231F" }, // 470 - "⌌": { "codepoints": [8972], "characters": "\u230C" }, // 471 - "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" }, // 472 - "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" }, // 473 - "Ѕ": { "codepoints": [1029], "characters": "\u0405" }, // 474 - "ѕ": { "codepoints": [1109], "characters": "\u0455" }, // 475 - "⧶": { "codepoints": [10742], "characters": "\u29F6" }, // 476 - "Đ": { "codepoints": [272], "characters": "\u0110" }, // 477 - "đ": { "codepoints": [273], "characters": "\u0111" }, // 478 - "⋱": { "codepoints": [8945], "characters": "\u22F1" }, // 479 - "▿": { "codepoints": [9663], "characters": "\u25BF" }, // 480 - "▾": { "codepoints": [9662], "characters": "\u25BE" }, // 481 - "⇵": { "codepoints": [8693], "characters": "\u21F5" }, // 482 - "⥯": { "codepoints": [10607], "characters": "\u296F" }, // 483 - "⦦": { "codepoints": [10662], "characters": "\u29A6" }, // 484 - "Џ": { "codepoints": [1039], "characters": "\u040F" }, // 485 - "џ": { "codepoints": [1119], "characters": "\u045F" }, // 486 - "⟿": { "codepoints": [10239], "characters": "\u27FF" }, // 487 - "É": { "codepoints": [201], "characters": "\u00C9" }, // 488 - "É": { "codepoints": [201], "characters": "\u00C9" }, // 489 - "é": { "codepoints": [233], "characters": "\u00E9" }, // 490 - "é": { "codepoints": [233], "characters": "\u00E9" }, // 491 - "⩮": { "codepoints": [10862], "characters": "\u2A6E" }, // 492 - "Ě": { "codepoints": [282], "characters": "\u011A" }, // 493 - "ě": { "codepoints": [283], "characters": "\u011B" }, // 494 - "Ê": { "codepoints": [202], "characters": "\u00CA" }, // 495 - "Ê": { "codepoints": [202], "characters": "\u00CA" }, // 496 - "ê": { "codepoints": [234], "characters": "\u00EA" }, // 497 - "ê": { "codepoints": [234], "characters": "\u00EA" }, // 498 - "≖": { "codepoints": [8790], "characters": "\u2256" }, // 499 - "≕": { "codepoints": [8789], "characters": "\u2255" }, // 500 - "Э": { "codepoints": [1069], "characters": "\u042D" }, // 501 - "э": { "codepoints": [1101], "characters": "\u044D" }, // 502 - "⩷": { "codepoints": [10871], "characters": "\u2A77" }, // 503 - "Ė": { "codepoints": [278], "characters": "\u0116" }, // 504 - "ė": { "codepoints": [279], "characters": "\u0117" }, // 505 - "≑": { "codepoints": [8785], "characters": "\u2251" }, // 506 - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, // 507 - "≒": { "codepoints": [8786], "characters": "\u2252" }, // 508 - "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" }, // 509 - "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" }, // 510 - "⪚": { "codepoints": [10906], "characters": "\u2A9A" }, // 511 - "È": { "codepoints": [200], "characters": "\u00C8" }, // 512 - "È": { "codepoints": [200], "characters": "\u00C8" }, // 513 - "è": { "codepoints": [232], "characters": "\u00E8" }, // 514 - "è": { "codepoints": [232], "characters": "\u00E8" }, // 515 - "⪖": { "codepoints": [10902], "characters": "\u2A96" }, // 516 - "⪘": { "codepoints": [10904], "characters": "\u2A98" }, // 517 - "⪙": { "codepoints": [10905], "characters": "\u2A99" }, // 518 - "∈": { "codepoints": [8712], "characters": "\u2208" }, // 519 - "⏧": { "codepoints": [9191], "characters": "\u23E7" }, // 520 - "ℓ": { "codepoints": [8467], "characters": "\u2113" }, // 521 - "⪕": { "codepoints": [10901], "characters": "\u2A95" }, // 522 - "⪗": { "codepoints": [10903], "characters": "\u2A97" }, // 523 - "Ē": { "codepoints": [274], "characters": "\u0112" }, // 524 - "ē": { "codepoints": [275], "characters": "\u0113" }, // 525 - "∅": { "codepoints": [8709], "characters": "\u2205" }, // 526 - "∅": { "codepoints": [8709], "characters": "\u2205" }, // 527 - "◻": { "codepoints": [9723], "characters": "\u25FB" }, // 528 - "∅": { "codepoints": [8709], "characters": "\u2205" }, // 529 - "▫": { "codepoints": [9643], "characters": "\u25AB" }, // 530 - " ": { "codepoints": [8196], "characters": "\u2004" }, // 531 - " ": { "codepoints": [8197], "characters": "\u2005" }, // 532 - " ": { "codepoints": [8195], "characters": "\u2003" }, // 533 - "Ŋ": { "codepoints": [330], "characters": "\u014A" }, // 534 - "ŋ": { "codepoints": [331], "characters": "\u014B" }, // 535 - " ": { "codepoints": [8194], "characters": "\u2002" }, // 536 - "Ę": { "codepoints": [280], "characters": "\u0118" }, // 537 - "ę": { "codepoints": [281], "characters": "\u0119" }, // 538 - "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" }, // 539 - "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" }, // 540 - "⋕": { "codepoints": [8917], "characters": "\u22D5" }, // 541 - "⧣": { "codepoints": [10723], "characters": "\u29E3" }, // 542 - "⩱": { "codepoints": [10865], "characters": "\u2A71" }, // 543 - "ε": { "codepoints": [949], "characters": "\u03B5" }, // 544 - "Ε": { "codepoints": [917], "characters": "\u0395" }, // 545 - "ε": { "codepoints": [949], "characters": "\u03B5" }, // 546 - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, // 547 - "≖": { "codepoints": [8790], "characters": "\u2256" }, // 548 - "≕": { "codepoints": [8789], "characters": "\u2255" }, // 549 - "≂": { "codepoints": [8770], "characters": "\u2242" }, // 550 - "⪖": { "codepoints": [10902], "characters": "\u2A96" }, // 551 - "⪕": { "codepoints": [10901], "characters": "\u2A95" }, // 552 - "⩵": { "codepoints": [10869], "characters": "\u2A75" }, // 553 - "=": { "codepoints": [61], "characters": "\u003D" }, // 554 - "≂": { "codepoints": [8770], "characters": "\u2242" }, // 555 - "≟": { "codepoints": [8799], "characters": "\u225F" }, // 556 - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, // 557 - "≡": { "codepoints": [8801], "characters": "\u2261" }, // 558 - "⩸": { "codepoints": [10872], "characters": "\u2A78" }, // 559 - "⧥": { "codepoints": [10725], "characters": "\u29E5" }, // 560 - "⥱": { "codepoints": [10609], "characters": "\u2971" }, // 561 - "≓": { "codepoints": [8787], "characters": "\u2253" }, // 562 - "ℯ": { "codepoints": [8495], "characters": "\u212F" }, // 563 - "ℰ": { "codepoints": [8496], "characters": "\u2130" }, // 564 - "≐": { "codepoints": [8784], "characters": "\u2250" }, // 565 - "⩳": { "codepoints": [10867], "characters": "\u2A73" }, // 566 - "≂": { "codepoints": [8770], "characters": "\u2242" }, // 567 - "Η": { "codepoints": [919], "characters": "\u0397" }, // 568 - "η": { "codepoints": [951], "characters": "\u03B7" }, // 569 - "Ð": { "codepoints": [208], "characters": "\u00D0" }, // 570 - "Ð": { "codepoints": [208], "characters": "\u00D0" }, // 571 - "ð": { "codepoints": [240], "characters": "\u00F0" }, // 572 - "ð": { "codepoints": [240], "characters": "\u00F0" }, // 573 - "Ë": { "codepoints": [203], "characters": "\u00CB" }, // 574 - "Ë": { "codepoints": [203], "characters": "\u00CB" }, // 575 - "ë": { "codepoints": [235], "characters": "\u00EB" }, // 576 - "ë": { "codepoints": [235], "characters": "\u00EB" }, // 577 - "€": { "codepoints": [8364], "characters": "\u20AC" }, // 578 - "!": { "codepoints": [33], "characters": "\u0021" }, // 579 - "∃": { "codepoints": [8707], "characters": "\u2203" }, // 580 - "∃": { "codepoints": [8707], "characters": "\u2203" }, // 581 - "ℰ": { "codepoints": [8496], "characters": "\u2130" }, // 582 - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, // 583 - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, // 584 - "≒": { "codepoints": [8786], "characters": "\u2252" }, // 585 - "Ф": { "codepoints": [1060], "characters": "\u0424" }, // 586 - "ф": { "codepoints": [1092], "characters": "\u0444" }, // 587 - "♀": { "codepoints": [9792], "characters": "\u2640" }, // 588 - "ffi": { "codepoints": [64259], "characters": "\uFB03" }, // 589 - "ff": { "codepoints": [64256], "characters": "\uFB00" }, // 590 - "ffl": { "codepoints": [64260], "characters": "\uFB04" }, // 591 - "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" }, // 592 - "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" }, // 593 - "fi": { "codepoints": [64257], "characters": "\uFB01" }, // 594 - "◼": { "codepoints": [9724], "characters": "\u25FC" }, // 595 - "▪": { "codepoints": [9642], "characters": "\u25AA" }, // 596 - "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" }, // 597 - "♭": { "codepoints": [9837], "characters": "\u266D" }, // 598 - "fl": { "codepoints": [64258], "characters": "\uFB02" }, // 599 - "▱": { "codepoints": [9649], "characters": "\u25B1" }, // 600 - "ƒ": { "codepoints": [402], "characters": "\u0192" }, // 601 - "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" }, // 602 - "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" }, // 603 - "∀": { "codepoints": [8704], "characters": "\u2200" }, // 604 - "∀": { "codepoints": [8704], "characters": "\u2200" }, // 605 - "⋔": { "codepoints": [8916], "characters": "\u22D4" }, // 606 - "⫙": { "codepoints": [10969], "characters": "\u2AD9" }, // 607 - "ℱ": { "codepoints": [8497], "characters": "\u2131" }, // 608 - "⨍": { "codepoints": [10765], "characters": "\u2A0D" }, // 609 - "½": { "codepoints": [189], "characters": "\u00BD" }, // 610 - "½": { "codepoints": [189], "characters": "\u00BD" }, // 611 - "⅓": { "codepoints": [8531], "characters": "\u2153" }, // 612 - "¼": { "codepoints": [188], "characters": "\u00BC" }, // 613 - "¼": { "codepoints": [188], "characters": "\u00BC" }, // 614 - "⅕": { "codepoints": [8533], "characters": "\u2155" }, // 615 - "⅙": { "codepoints": [8537], "characters": "\u2159" }, // 616 - "⅛": { "codepoints": [8539], "characters": "\u215B" }, // 617 - "⅔": { "codepoints": [8532], "characters": "\u2154" }, // 618 - "⅖": { "codepoints": [8534], "characters": "\u2156" }, // 619 - "¾": { "codepoints": [190], "characters": "\u00BE" }, // 620 - "¾": { "codepoints": [190], "characters": "\u00BE" }, // 621 - "⅗": { "codepoints": [8535], "characters": "\u2157" }, // 622 - "⅜": { "codepoints": [8540], "characters": "\u215C" }, // 623 - "⅘": { "codepoints": [8536], "characters": "\u2158" }, // 624 - "⅚": { "codepoints": [8538], "characters": "\u215A" }, // 625 - "⅝": { "codepoints": [8541], "characters": "\u215D" }, // 626 - "⅞": { "codepoints": [8542], "characters": "\u215E" }, // 627 - "⁄": { "codepoints": [8260], "characters": "\u2044" }, // 628 - "⌢": { "codepoints": [8994], "characters": "\u2322" }, // 629 - "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" }, // 630 - "ℱ": { "codepoints": [8497], "characters": "\u2131" }, // 631 - "ǵ": { "codepoints": [501], "characters": "\u01F5" }, // 632 - "Γ": { "codepoints": [915], "characters": "\u0393" }, // 633 - "γ": { "codepoints": [947], "characters": "\u03B3" }, // 634 - "Ϝ": { "codepoints": [988], "characters": "\u03DC" }, // 635 - "ϝ": { "codepoints": [989], "characters": "\u03DD" }, // 636 - "⪆": { "codepoints": [10886], "characters": "\u2A86" }, // 637 - "Ğ": { "codepoints": [286], "characters": "\u011E" }, // 638 - "ğ": { "codepoints": [287], "characters": "\u011F" }, // 639 - "Ģ": { "codepoints": [290], "characters": "\u0122" }, // 640 - "Ĝ": { "codepoints": [284], "characters": "\u011C" }, // 641 - "ĝ": { "codepoints": [285], "characters": "\u011D" }, // 642 - "Г": { "codepoints": [1043], "characters": "\u0413" }, // 643 - "г": { "codepoints": [1075], "characters": "\u0433" }, // 644 - "Ġ": { "codepoints": [288], "characters": "\u0120" }, // 645 - "ġ": { "codepoints": [289], "characters": "\u0121" }, // 646 - "≥": { "codepoints": [8805], "characters": "\u2265" }, // 647 - "≧": { "codepoints": [8807], "characters": "\u2267" }, // 648 - "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, // 649 - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, // 650 - "≥": { "codepoints": [8805], "characters": "\u2265" }, // 651 - "≧": { "codepoints": [8807], "characters": "\u2267" }, // 652 - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, // 653 - "⪩": { "codepoints": [10921], "characters": "\u2AA9" }, // 654 - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, // 655 - "⪀": { "codepoints": [10880], "characters": "\u2A80" }, // 656 - "⪂": { "codepoints": [10882], "characters": "\u2A82" }, // 657 - "⪄": { "codepoints": [10884], "characters": "\u2A84" }, // 658 - "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" }, // 659 - "⪔": { "codepoints": [10900], "characters": "\u2A94" }, // 660 - "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" }, // 661 - "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" }, // 662 - "≫": { "codepoints": [8811], "characters": "\u226B" }, // 663 - "⋙": { "codepoints": [8921], "characters": "\u22D9" }, // 664 - "⋙": { "codepoints": [8921], "characters": "\u22D9" }, // 665 - "ℷ": { "codepoints": [8503], "characters": "\u2137" }, // 666 - "Ѓ": { "codepoints": [1027], "characters": "\u0403" }, // 667 - "ѓ": { "codepoints": [1107], "characters": "\u0453" }, // 668 - "⪥": { "codepoints": [10917], "characters": "\u2AA5" }, // 669 - "≷": { "codepoints": [8823], "characters": "\u2277" }, // 670 - "⪒": { "codepoints": [10898], "characters": "\u2A92" }, // 671 - "⪤": { "codepoints": [10916], "characters": "\u2AA4" }, // 672 - "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, // 673 - "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, // 674 - "⪈": { "codepoints": [10888], "characters": "\u2A88" }, // 675 - "≩": { "codepoints": [8809], "characters": "\u2269" }, // 676 - "⪈": { "codepoints": [10888], "characters": "\u2A88" }, // 677 - "≩": { "codepoints": [8809], "characters": "\u2269" }, // 678 - "⋧": { "codepoints": [8935], "characters": "\u22E7" }, // 679 - "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" }, // 680 - "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" }, // 681 - "`": { "codepoints": [96], "characters": "\u0060" }, // 682 - "≥": { "codepoints": [8805], "characters": "\u2265" }, // 683 - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, // 684 - "≧": { "codepoints": [8807], "characters": "\u2267" }, // 685 - "⪢": { "codepoints": [10914], "characters": "\u2AA2" }, // 686 - "≷": { "codepoints": [8823], "characters": "\u2277" }, // 687 - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, // 688 - "≳": { "codepoints": [8819], "characters": "\u2273" }, // 689 - "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" }, // 690 - "ℊ": { "codepoints": [8458], "characters": "\u210A" }, // 691 - "≳": { "codepoints": [8819], "characters": "\u2273" }, // 692 - "⪎": { "codepoints": [10894], "characters": "\u2A8E" }, // 693 - "⪐": { "codepoints": [10896], "characters": "\u2A90" }, // 694 - "⪧": { "codepoints": [10919], "characters": "\u2AA7" }, // 695 - "⩺": { "codepoints": [10874], "characters": "\u2A7A" }, // 696 - ">": { "codepoints": [62], "characters": "\u003E" }, // 697 - ">": { "codepoints": [62], "characters": "\u003E" }, // 698 - ">": { "codepoints": [62], "characters": "\u003E" }, // 699 - ">": { "codepoints": [62], "characters": "\u003E" }, // 700 - "≫": { "codepoints": [8811], "characters": "\u226B" }, // 701 - "⋗": { "codepoints": [8919], "characters": "\u22D7" }, // 702 - "⦕": { "codepoints": [10645], "characters": "\u2995" }, // 703 - "⩼": { "codepoints": [10876], "characters": "\u2A7C" }, // 704 - "⪆": { "codepoints": [10886], "characters": "\u2A86" }, // 705 - "⥸": { "codepoints": [10616], "characters": "\u2978" }, // 706 - "⋗": { "codepoints": [8919], "characters": "\u22D7" }, // 707 - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, // 708 - "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, // 709 - "≷": { "codepoints": [8823], "characters": "\u2277" }, // 710 - "≳": { "codepoints": [8819], "characters": "\u2273" }, // 711 - "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, // 712 - "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, // 713 - "ˇ": { "codepoints": [711], "characters": "\u02C7" }, // 714 - " ": { "codepoints": [8202], "characters": "\u200A" }, // 715 - "½": { "codepoints": [189], "characters": "\u00BD" }, // 716 - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, // 717 - "Ъ": { "codepoints": [1066], "characters": "\u042A" }, // 718 - "ъ": { "codepoints": [1098], "characters": "\u044A" }, // 719 - "⥈": { "codepoints": [10568], "characters": "\u2948" }, // 720 - "↔": { "codepoints": [8596], "characters": "\u2194" }, // 721 - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, // 722 - "↭": { "codepoints": [8621], "characters": "\u21AD" }, // 723 - "^": { "codepoints": [94], "characters": "\u005E" }, // 724 - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, // 725 - "Ĥ": { "codepoints": [292], "characters": "\u0124" }, // 726 - "ĥ": { "codepoints": [293], "characters": "\u0125" }, // 727 - "♥": { "codepoints": [9829], "characters": "\u2665" }, // 728 - "♥": { "codepoints": [9829], "characters": "\u2665" }, // 729 - "…": { "codepoints": [8230], "characters": "\u2026" }, // 730 - "⊹": { "codepoints": [8889], "characters": "\u22B9" }, // 731 - "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" }, // 732 - "ℌ": { "codepoints": [8460], "characters": "\u210C" }, // 733 - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, // 734 - "⤥": { "codepoints": [10533], "characters": "\u2925" }, // 735 - "⤦": { "codepoints": [10534], "characters": "\u2926" }, // 736 - "⇿": { "codepoints": [8703], "characters": "\u21FF" }, // 737 - "∻": { "codepoints": [8763], "characters": "\u223B" }, // 738 - "↩": { "codepoints": [8617], "characters": "\u21A9" }, // 739 - "↪": { "codepoints": [8618], "characters": "\u21AA" }, // 740 - "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" }, // 741 - "ℍ": { "codepoints": [8461], "characters": "\u210D" }, // 742 - "―": { "codepoints": [8213], "characters": "\u2015" }, // 743 - "─": { "codepoints": [9472], "characters": "\u2500" }, // 744 - "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" }, // 745 - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, // 746 - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, // 747 - "Ħ": { "codepoints": [294], "characters": "\u0126" }, // 748 - "ħ": { "codepoints": [295], "characters": "\u0127" }, // 749 - "≎": { "codepoints": [8782], "characters": "\u224E" }, // 750 - "≏": { "codepoints": [8783], "characters": "\u224F" }, // 751 - "⁃": { "codepoints": [8259], "characters": "\u2043" }, // 752 - "‐": { "codepoints": [8208], "characters": "\u2010" }, // 753 - "Í": { "codepoints": [205], "characters": "\u00CD" }, // 754 - "Í": { "codepoints": [205], "characters": "\u00CD" }, // 755 - "í": { "codepoints": [237], "characters": "\u00ED" }, // 756 - "í": { "codepoints": [237], "characters": "\u00ED" }, // 757 - "⁣": { "codepoints": [8291], "characters": "\u2063" }, // 758 - "Î": { "codepoints": [206], "characters": "\u00CE" }, // 759 - "Î": { "codepoints": [206], "characters": "\u00CE" }, // 760 - "î": { "codepoints": [238], "characters": "\u00EE" }, // 761 - "î": { "codepoints": [238], "characters": "\u00EE" }, // 762 - "И": { "codepoints": [1048], "characters": "\u0418" }, // 763 - "и": { "codepoints": [1080], "characters": "\u0438" }, // 764 - "İ": { "codepoints": [304], "characters": "\u0130" }, // 765 - "Е": { "codepoints": [1045], "characters": "\u0415" }, // 766 - "е": { "codepoints": [1077], "characters": "\u0435" }, // 767 - "¡": { "codepoints": [161], "characters": "\u00A1" }, // 768 - "¡": { "codepoints": [161], "characters": "\u00A1" }, // 769 - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, // 770 - "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" }, // 771 - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, // 772 - "Ì": { "codepoints": [204], "characters": "\u00CC" }, // 773 - "Ì": { "codepoints": [204], "characters": "\u00CC" }, // 774 - "ì": { "codepoints": [236], "characters": "\u00EC" }, // 775 - "ì": { "codepoints": [236], "characters": "\u00EC" }, // 776 - "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, // 777 - "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, // 778 - "∭": { "codepoints": [8749], "characters": "\u222D" }, // 779 - "⧜": { "codepoints": [10716], "characters": "\u29DC" }, // 780 - "℩": { "codepoints": [8489], "characters": "\u2129" }, // 781 - "IJ": { "codepoints": [306], "characters": "\u0132" }, // 782 - "ij": { "codepoints": [307], "characters": "\u0133" }, // 783 - "Ī": { "codepoints": [298], "characters": "\u012A" }, // 784 - "ī": { "codepoints": [299], "characters": "\u012B" }, // 785 - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, // 786 - "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, // 787 - "ℐ": { "codepoints": [8464], "characters": "\u2110" }, // 788 - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, // 789 - "ı": { "codepoints": [305], "characters": "\u0131" }, // 790 - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, // 791 - "⊷": { "codepoints": [8887], "characters": "\u22B7" }, // 792 - "Ƶ": { "codepoints": [437], "characters": "\u01B5" }, // 793 - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, // 794 - "℅": { "codepoints": [8453], "characters": "\u2105" }, // 795 - "∈": { "codepoints": [8712], "characters": "\u2208" }, // 796 - "∞": { "codepoints": [8734], "characters": "\u221E" }, // 797 - "⧝": { "codepoints": [10717], "characters": "\u29DD" }, // 798 - "ı": { "codepoints": [305], "characters": "\u0131" }, // 799 - "⊺": { "codepoints": [8890], "characters": "\u22BA" }, // 800 - "∫": { "codepoints": [8747], "characters": "\u222B" }, // 801 - "∬": { "codepoints": [8748], "characters": "\u222C" }, // 802 - "ℤ": { "codepoints": [8484], "characters": "\u2124" }, // 803 - "∫": { "codepoints": [8747], "characters": "\u222B" }, // 804 - "⊺": { "codepoints": [8890], "characters": "\u22BA" }, // 805 - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, // 806 - "⨗": { "codepoints": [10775], "characters": "\u2A17" }, // 807 - "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, // 808 - "⁣": { "codepoints": [8291], "characters": "\u2063" }, // 809 - "⁢": { "codepoints": [8290], "characters": "\u2062" }, // 810 - "Ё": { "codepoints": [1025], "characters": "\u0401" }, // 811 - "ё": { "codepoints": [1105], "characters": "\u0451" }, // 812 - "Į": { "codepoints": [302], "characters": "\u012E" }, // 813 - "į": { "codepoints": [303], "characters": "\u012F" }, // 814 - "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" }, // 815 - "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" }, // 816 - "Ι": { "codepoints": [921], "characters": "\u0399" }, // 817 - "ι": { "codepoints": [953], "characters": "\u03B9" }, // 818 - "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, // 819 - "¿": { "codepoints": [191], "characters": "\u00BF" }, // 820 - "¿": { "codepoints": [191], "characters": "\u00BF" }, // 821 - "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" }, // 822 - "ℐ": { "codepoints": [8464], "characters": "\u2110" }, // 823 - "∈": { "codepoints": [8712], "characters": "\u2208" }, // 824 - "⋵": { "codepoints": [8949], "characters": "\u22F5" }, // 825 - "⋹": { "codepoints": [8953], "characters": "\u22F9" }, // 826 - "⋴": { "codepoints": [8948], "characters": "\u22F4" }, // 827 - "⋳": { "codepoints": [8947], "characters": "\u22F3" }, // 828 - "∈": { "codepoints": [8712], "characters": "\u2208" }, // 829 - "⁢": { "codepoints": [8290], "characters": "\u2062" }, // 830 - "Ĩ": { "codepoints": [296], "characters": "\u0128" }, // 831 - "ĩ": { "codepoints": [297], "characters": "\u0129" }, // 832 - "І": { "codepoints": [1030], "characters": "\u0406" }, // 833 - "і": { "codepoints": [1110], "characters": "\u0456" }, // 834 - "Ï": { "codepoints": [207], "characters": "\u00CF" }, // 835 - "Ï": { "codepoints": [207], "characters": "\u00CF" }, // 836 - "ï": { "codepoints": [239], "characters": "\u00EF" }, // 837 - "ï": { "codepoints": [239], "characters": "\u00EF" }, // 838 - "Ĵ": { "codepoints": [308], "characters": "\u0134" }, // 839 - "ĵ": { "codepoints": [309], "characters": "\u0135" }, // 840 - "Й": { "codepoints": [1049], "characters": "\u0419" }, // 841 - "й": { "codepoints": [1081], "characters": "\u0439" }, // 842 - "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" }, // 843 - "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" }, // 844 - "ȷ": { "codepoints": [567], "characters": "\u0237" }, // 845 - "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" }, // 846 - "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" }, // 847 - "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" }, // 848 - "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" }, // 849 - "Ј": { "codepoints": [1032], "characters": "\u0408" }, // 850 - "ј": { "codepoints": [1112], "characters": "\u0458" }, // 851 - "Є": { "codepoints": [1028], "characters": "\u0404" }, // 852 - "є": { "codepoints": [1108], "characters": "\u0454" }, // 853 - "Κ": { "codepoints": [922], "characters": "\u039A" }, // 854 - "κ": { "codepoints": [954], "characters": "\u03BA" }, // 855 - "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, // 856 - "Ķ": { "codepoints": [310], "characters": "\u0136" }, // 857 - "ķ": { "codepoints": [311], "characters": "\u0137" }, // 858 - "К": { "codepoints": [1050], "characters": "\u041A" }, // 859 - "к": { "codepoints": [1082], "characters": "\u043A" }, // 860 - "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" }, // 861 - "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" }, // 862 - "ĸ": { "codepoints": [312], "characters": "\u0138" }, // 863 - "Х": { "codepoints": [1061], "characters": "\u0425" }, // 864 - "х": { "codepoints": [1093], "characters": "\u0445" }, // 865 - "Ќ": { "codepoints": [1036], "characters": "\u040C" }, // 866 - "ќ": { "codepoints": [1116], "characters": "\u045C" }, // 867 - "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" }, // 868 - "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" }, // 869 - "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" }, // 870 - "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" }, // 871 - "⇚": { "codepoints": [8666], "characters": "\u21DA" }, // 872 - "Ĺ": { "codepoints": [313], "characters": "\u0139" }, // 873 - "ĺ": { "codepoints": [314], "characters": "\u013A" }, // 874 - "⦴": { "codepoints": [10676], "characters": "\u29B4" }, // 875 - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, // 876 - "Λ": { "codepoints": [923], "characters": "\u039B" }, // 877 - "λ": { "codepoints": [955], "characters": "\u03BB" }, // 878 - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, // 879 - "⟪": { "codepoints": [10218], "characters": "\u27EA" }, // 880 - "⦑": { "codepoints": [10641], "characters": "\u2991" }, // 881 - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, // 882 - "⪅": { "codepoints": [10885], "characters": "\u2A85" }, // 883 - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, // 884 - "«": { "codepoints": [171], "characters": "\u00AB" }, // 885 - "«": { "codepoints": [171], "characters": "\u00AB" }, // 886 - "⇤": { "codepoints": [8676], "characters": "\u21E4" }, // 887 - "⤟": { "codepoints": [10527], "characters": "\u291F" }, // 888 - "←": { "codepoints": [8592], "characters": "\u2190" }, // 889 - "↞": { "codepoints": [8606], "characters": "\u219E" }, // 890 - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, // 891 - "⤝": { "codepoints": [10525], "characters": "\u291D" }, // 892 - "↩": { "codepoints": [8617], "characters": "\u21A9" }, // 893 - "↫": { "codepoints": [8619], "characters": "\u21AB" }, // 894 - "⤹": { "codepoints": [10553], "characters": "\u2939" }, // 895 - "⥳": { "codepoints": [10611], "characters": "\u2973" }, // 896 - "↢": { "codepoints": [8610], "characters": "\u21A2" }, // 897 - "⤙": { "codepoints": [10521], "characters": "\u2919" }, // 898 - "⤛": { "codepoints": [10523], "characters": "\u291B" }, // 899 - "⪫": { "codepoints": [10923], "characters": "\u2AAB" }, // 900 - "⪭": { "codepoints": [10925], "characters": "\u2AAD" }, // 901 - "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" }, // 902 - "⤌": { "codepoints": [10508], "characters": "\u290C" }, // 903 - "⤎": { "codepoints": [10510], "characters": "\u290E" }, // 904 - "❲": { "codepoints": [10098], "characters": "\u2772" }, // 905 - "{": { "codepoints": [123], "characters": "\u007B" }, // 906 - "[": { "codepoints": [91], "characters": "\u005B" }, // 907 - "⦋": { "codepoints": [10635], "characters": "\u298B" }, // 908 - "⦏": { "codepoints": [10639], "characters": "\u298F" }, // 909 - "⦍": { "codepoints": [10637], "characters": "\u298D" }, // 910 - "Ľ": { "codepoints": [317], "characters": "\u013D" }, // 911 - "ľ": { "codepoints": [318], "characters": "\u013E" }, // 912 - "Ļ": { "codepoints": [315], "characters": "\u013B" }, // 913 - "ļ": { "codepoints": [316], "characters": "\u013C" }, // 914 - "⌈": { "codepoints": [8968], "characters": "\u2308" }, // 915 - "{": { "codepoints": [123], "characters": "\u007B" }, // 916 - "Л": { "codepoints": [1051], "characters": "\u041B" }, // 917 - "л": { "codepoints": [1083], "characters": "\u043B" }, // 918 - "⤶": { "codepoints": [10550], "characters": "\u2936" }, // 919 - "“": { "codepoints": [8220], "characters": "\u201C" }, // 920 - "„": { "codepoints": [8222], "characters": "\u201E" }, // 921 - "⥧": { "codepoints": [10599], "characters": "\u2967" }, // 922 - "⥋": { "codepoints": [10571], "characters": "\u294B" }, // 923 - "↲": { "codepoints": [8626], "characters": "\u21B2" }, // 924 - "≤": { "codepoints": [8804], "characters": "\u2264" }, // 925 - "≦": { "codepoints": [8806], "characters": "\u2266" }, // 926 - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, // 927 - "⇤": { "codepoints": [8676], "characters": "\u21E4" }, // 928 - "←": { "codepoints": [8592], "characters": "\u2190" }, // 929 - "←": { "codepoints": [8592], "characters": "\u2190" }, // 930 - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, // 931 - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, // 932 - "↢": { "codepoints": [8610], "characters": "\u21A2" }, // 933 - "⌈": { "codepoints": [8968], "characters": "\u2308" }, // 934 - "⟦": { "codepoints": [10214], "characters": "\u27E6" }, // 935 - "⥡": { "codepoints": [10593], "characters": "\u2961" }, // 936 - "⥙": { "codepoints": [10585], "characters": "\u2959" }, // 937 - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, // 938 - "⌊": { "codepoints": [8970], "characters": "\u230A" }, // 939 - "↽": { "codepoints": [8637], "characters": "\u21BD" }, // 940 - "↼": { "codepoints": [8636], "characters": "\u21BC" }, // 941 - "⇇": { "codepoints": [8647], "characters": "\u21C7" }, // 942 - "↔": { "codepoints": [8596], "characters": "\u2194" }, // 943 - "↔": { "codepoints": [8596], "characters": "\u2194" }, // 944 - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, // 945 - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, // 946 - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, // 947 - "↭": { "codepoints": [8621], "characters": "\u21AD" }, // 948 - "⥎": { "codepoints": [10574], "characters": "\u294E" }, // 949 - "↤": { "codepoints": [8612], "characters": "\u21A4" }, // 950 - "⊣": { "codepoints": [8867], "characters": "\u22A3" }, // 951 - "⥚": { "codepoints": [10586], "characters": "\u295A" }, // 952 - "⋋": { "codepoints": [8907], "characters": "\u22CB" }, // 953 - "⧏": { "codepoints": [10703], "characters": "\u29CF" }, // 954 - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, // 955 - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, // 956 - "⥑": { "codepoints": [10577], "characters": "\u2951" }, // 957 - "⥠": { "codepoints": [10592], "characters": "\u2960" }, // 958 - "⥘": { "codepoints": [10584], "characters": "\u2958" }, // 959 - "↿": { "codepoints": [8639], "characters": "\u21BF" }, // 960 - "⥒": { "codepoints": [10578], "characters": "\u2952" }, // 961 - "↼": { "codepoints": [8636], "characters": "\u21BC" }, // 962 - "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, // 963 - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, // 964 - "≤": { "codepoints": [8804], "characters": "\u2264" }, // 965 - "≦": { "codepoints": [8806], "characters": "\u2266" }, // 966 - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, // 967 - "⪨": { "codepoints": [10920], "characters": "\u2AA8" }, // 968 - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, // 969 - "⩿": { "codepoints": [10879], "characters": "\u2A7F" }, // 970 - "⪁": { "codepoints": [10881], "characters": "\u2A81" }, // 971 - "⪃": { "codepoints": [10883], "characters": "\u2A83" }, // 972 - "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" }, // 973 - "⪓": { "codepoints": [10899], "characters": "\u2A93" }, // 974 - "⪅": { "codepoints": [10885], "characters": "\u2A85" }, // 975 - "⋖": { "codepoints": [8918], "characters": "\u22D6" }, // 976 - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, // 977 - "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, // 978 - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, // 979 - "≦": { "codepoints": [8806], "characters": "\u2266" }, // 980 - "≶": { "codepoints": [8822], "characters": "\u2276" }, // 981 - "≶": { "codepoints": [8822], "characters": "\u2276" }, // 982 - "⪡": { "codepoints": [10913], "characters": "\u2AA1" }, // 983 - "≲": { "codepoints": [8818], "characters": "\u2272" }, // 984 - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, // 985 - "≲": { "codepoints": [8818], "characters": "\u2272" }, // 986 - "⥼": { "codepoints": [10620], "characters": "\u297C" }, // 987 - "⌊": { "codepoints": [8970], "characters": "\u230A" }, // 988 - "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" }, // 989 - "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" }, // 990 - "≶": { "codepoints": [8822], "characters": "\u2276" }, // 991 - "⪑": { "codepoints": [10897], "characters": "\u2A91" }, // 992 - "⥢": { "codepoints": [10594], "characters": "\u2962" }, // 993 - "↽": { "codepoints": [8637], "characters": "\u21BD" }, // 994 - "↼": { "codepoints": [8636], "characters": "\u21BC" }, // 995 - "⥪": { "codepoints": [10602], "characters": "\u296A" }, // 996 - "▄": { "codepoints": [9604], "characters": "\u2584" }, // 997 - "Љ": { "codepoints": [1033], "characters": "\u0409" }, // 998 - "љ": { "codepoints": [1113], "characters": "\u0459" }, // 999 - "⇇": { "codepoints": [8647], "characters": "\u21C7" }, // 1000 - "≪": { "codepoints": [8810], "characters": "\u226A" }, // 1001 - "⋘": { "codepoints": [8920], "characters": "\u22D8" }, // 1002 - "⌞": { "codepoints": [8990], "characters": "\u231E" }, // 1003 - "⇚": { "codepoints": [8666], "characters": "\u21DA" }, // 1004 - "⥫": { "codepoints": [10603], "characters": "\u296B" }, // 1005 - "◺": { "codepoints": [9722], "characters": "\u25FA" }, // 1006 - "Ŀ": { "codepoints": [319], "characters": "\u013F" }, // 1007 - "ŀ": { "codepoints": [320], "characters": "\u0140" }, // 1008 - "⎰": { "codepoints": [9136], "characters": "\u23B0" }, // 1009 - "⎰": { "codepoints": [9136], "characters": "\u23B0" }, // 1010 - "⪉": { "codepoints": [10889], "characters": "\u2A89" }, // 1011 - "⪉": { "codepoints": [10889], "characters": "\u2A89" }, // 1012 - "⪇": { "codepoints": [10887], "characters": "\u2A87" }, // 1013 - "≨": { "codepoints": [8808], "characters": "\u2268" }, // 1014 - "⪇": { "codepoints": [10887], "characters": "\u2A87" }, // 1015 - "≨": { "codepoints": [8808], "characters": "\u2268" }, // 1016 - "⋦": { "codepoints": [8934], "characters": "\u22E6" }, // 1017 - "⟬": { "codepoints": [10220], "characters": "\u27EC" }, // 1018 - "⇽": { "codepoints": [8701], "characters": "\u21FD" }, // 1019 - "⟦": { "codepoints": [10214], "characters": "\u27E6" }, // 1020 - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, // 1021 - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, // 1022 - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, // 1023 - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, // 1024 - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, // 1025 - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, // 1026 - "⟼": { "codepoints": [10236], "characters": "\u27FC" }, // 1027 - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, // 1028 - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, // 1029 - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, // 1030 - "↫": { "codepoints": [8619], "characters": "\u21AB" }, // 1031 - "↬": { "codepoints": [8620], "characters": "\u21AC" }, // 1032 - "⦅": { "codepoints": [10629], "characters": "\u2985" }, // 1033 - "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" }, // 1034 - "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" }, // 1035 - "⨭": { "codepoints": [10797], "characters": "\u2A2D" }, // 1036 - "⨴": { "codepoints": [10804], "characters": "\u2A34" }, // 1037 - "∗": { "codepoints": [8727], "characters": "\u2217" }, // 1038 - "_": { "codepoints": [95], "characters": "\u005F" }, // 1039 - "↙": { "codepoints": [8601], "characters": "\u2199" }, // 1040 - "↘": { "codepoints": [8600], "characters": "\u2198" }, // 1041 - "◊": { "codepoints": [9674], "characters": "\u25CA" }, // 1042 - "◊": { "codepoints": [9674], "characters": "\u25CA" }, // 1043 - "⧫": { "codepoints": [10731], "characters": "\u29EB" }, // 1044 - "(": { "codepoints": [40], "characters": "\u0028" }, // 1045 - "⦓": { "codepoints": [10643], "characters": "\u2993" }, // 1046 - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, // 1047 - "⌟": { "codepoints": [8991], "characters": "\u231F" }, // 1048 - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, // 1049 - "⥭": { "codepoints": [10605], "characters": "\u296D" }, // 1050 - "‎": { "codepoints": [8206], "characters": "\u200E" }, // 1051 - "⊿": { "codepoints": [8895], "characters": "\u22BF" }, // 1052 - "‹": { "codepoints": [8249], "characters": "\u2039" }, // 1053 - "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" }, // 1054 - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, // 1055 - "↰": { "codepoints": [8624], "characters": "\u21B0" }, // 1056 - "↰": { "codepoints": [8624], "characters": "\u21B0" }, // 1057 - "≲": { "codepoints": [8818], "characters": "\u2272" }, // 1058 - "⪍": { "codepoints": [10893], "characters": "\u2A8D" }, // 1059 - "⪏": { "codepoints": [10895], "characters": "\u2A8F" }, // 1060 - "[": { "codepoints": [91], "characters": "\u005B" }, // 1061 - "‘": { "codepoints": [8216], "characters": "\u2018" }, // 1062 - "‚": { "codepoints": [8218], "characters": "\u201A" }, // 1063 - "Ł": { "codepoints": [321], "characters": "\u0141" }, // 1064 - "ł": { "codepoints": [322], "characters": "\u0142" }, // 1065 - "⪦": { "codepoints": [10918], "characters": "\u2AA6" }, // 1066 - "⩹": { "codepoints": [10873], "characters": "\u2A79" }, // 1067 - "<": { "codepoints": [60], "characters": "\u003C" }, // 1068 - "<": { "codepoints": [60], "characters": "\u003C" }, // 1069 - "<": { "codepoints": [60], "characters": "\u003C" }, // 1070 - "<": { "codepoints": [60], "characters": "\u003C" }, // 1071 - "≪": { "codepoints": [8810], "characters": "\u226A" }, // 1072 - "⋖": { "codepoints": [8918], "characters": "\u22D6" }, // 1073 - "⋋": { "codepoints": [8907], "characters": "\u22CB" }, // 1074 - "⋉": { "codepoints": [8905], "characters": "\u22C9" }, // 1075 - "⥶": { "codepoints": [10614], "characters": "\u2976" }, // 1076 - "⩻": { "codepoints": [10875], "characters": "\u2A7B" }, // 1077 - "◃": { "codepoints": [9667], "characters": "\u25C3" }, // 1078 - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, // 1079 - "◂": { "codepoints": [9666], "characters": "\u25C2" }, // 1080 - "⦖": { "codepoints": [10646], "characters": "\u2996" }, // 1081 - "⥊": { "codepoints": [10570], "characters": "\u294A" }, // 1082 - "⥦": { "codepoints": [10598], "characters": "\u2966" }, // 1083 - "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, // 1084 - "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, // 1085 - "¯": { "codepoints": [175], "characters": "\u00AF" }, // 1086 - "¯": { "codepoints": [175], "characters": "\u00AF" }, // 1087 - "♂": { "codepoints": [9794], "characters": "\u2642" }, // 1088 - "✠": { "codepoints": [10016], "characters": "\u2720" }, // 1089 - "✠": { "codepoints": [10016], "characters": "\u2720" }, // 1090 - "⤅": { "codepoints": [10501], "characters": "\u2905" }, // 1091 - "↦": { "codepoints": [8614], "characters": "\u21A6" }, // 1092 - "↦": { "codepoints": [8614], "characters": "\u21A6" }, // 1093 - "↧": { "codepoints": [8615], "characters": "\u21A7" }, // 1094 - "↤": { "codepoints": [8612], "characters": "\u21A4" }, // 1095 - "↥": { "codepoints": [8613], "characters": "\u21A5" }, // 1096 - "▮": { "codepoints": [9646], "characters": "\u25AE" }, // 1097 - "⨩": { "codepoints": [10793], "characters": "\u2A29" }, // 1098 - "М": { "codepoints": [1052], "characters": "\u041C" }, // 1099 - "м": { "codepoints": [1084], "characters": "\u043C" }, // 1100 - "—": { "codepoints": [8212], "characters": "\u2014" }, // 1101 - "∺": { "codepoints": [8762], "characters": "\u223A" }, // 1102 - "∡": { "codepoints": [8737], "characters": "\u2221" }, // 1103 - " ": { "codepoints": [8287], "characters": "\u205F" }, // 1104 - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, // 1105 - "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" }, // 1106 - "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" }, // 1107 - "℧": { "codepoints": [8487], "characters": "\u2127" }, // 1108 - "µ": { "codepoints": [181], "characters": "\u00B5" }, // 1109 - "µ": { "codepoints": [181], "characters": "\u00B5" }, // 1110 - "*": { "codepoints": [42], "characters": "\u002A" }, // 1111 - "⫰": { "codepoints": [10992], "characters": "\u2AF0" }, // 1112 - "∣": { "codepoints": [8739], "characters": "\u2223" }, // 1113 - "·": { "codepoints": [183], "characters": "\u00B7" }, // 1114 - "·": { "codepoints": [183], "characters": "\u00B7" }, // 1115 - "⊟": { "codepoints": [8863], "characters": "\u229F" }, // 1116 - "−": { "codepoints": [8722], "characters": "\u2212" }, // 1117 - "∸": { "codepoints": [8760], "characters": "\u2238" }, // 1118 - "⨪": { "codepoints": [10794], "characters": "\u2A2A" }, // 1119 - "∓": { "codepoints": [8723], "characters": "\u2213" }, // 1120 - "⫛": { "codepoints": [10971], "characters": "\u2ADB" }, // 1121 - "…": { "codepoints": [8230], "characters": "\u2026" }, // 1122 - "∓": { "codepoints": [8723], "characters": "\u2213" }, // 1123 - "⊧": { "codepoints": [8871], "characters": "\u22A7" }, // 1124 - "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" }, // 1125 - "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" }, // 1126 - "∓": { "codepoints": [8723], "characters": "\u2213" }, // 1127 - "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" }, // 1128 - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, // 1129 - "∾": { "codepoints": [8766], "characters": "\u223E" }, // 1130 - "Μ": { "codepoints": [924], "characters": "\u039C" }, // 1131 - "μ": { "codepoints": [956], "characters": "\u03BC" }, // 1132 - "⊸": { "codepoints": [8888], "characters": "\u22B8" }, // 1133 - "⊸": { "codepoints": [8888], "characters": "\u22B8" }, // 1134 - "∇": { "codepoints": [8711], "characters": "\u2207" }, // 1135 - "Ń": { "codepoints": [323], "characters": "\u0143" }, // 1136 - "ń": { "codepoints": [324], "characters": "\u0144" }, // 1137 - "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" }, // 1138 - "≉": { "codepoints": [8777], "characters": "\u2249" }, // 1139 - "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" }, // 1140 - "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" }, // 1141 - "ʼn": { "codepoints": [329], "characters": "\u0149" }, // 1142 - "≉": { "codepoints": [8777], "characters": "\u2249" }, // 1143 - "♮": { "codepoints": [9838], "characters": "\u266E" }, // 1144 - "ℕ": { "codepoints": [8469], "characters": "\u2115" }, // 1145 - "♮": { "codepoints": [9838], "characters": "\u266E" }, // 1146 - " ": { "codepoints": [160], "characters": "\u00A0" }, // 1147 - " ": { "codepoints": [160], "characters": "\u00A0" }, // 1148 - "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, // 1149 - "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, // 1150 - "⩃": { "codepoints": [10819], "characters": "\u2A43" }, // 1151 - "Ň": { "codepoints": [327], "characters": "\u0147" }, // 1152 - "ň": { "codepoints": [328], "characters": "\u0148" }, // 1153 - "Ņ": { "codepoints": [325], "characters": "\u0145" }, // 1154 - "ņ": { "codepoints": [326], "characters": "\u0146" }, // 1155 - "≇": { "codepoints": [8775], "characters": "\u2247" }, // 1156 - "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" }, // 1157 - "⩂": { "codepoints": [10818], "characters": "\u2A42" }, // 1158 - "Н": { "codepoints": [1053], "characters": "\u041D" }, // 1159 - "н": { "codepoints": [1085], "characters": "\u043D" }, // 1160 - "–": { "codepoints": [8211], "characters": "\u2013" }, // 1161 - "⤤": { "codepoints": [10532], "characters": "\u2924" }, // 1162 - "↗": { "codepoints": [8599], "characters": "\u2197" }, // 1163 - "⇗": { "codepoints": [8663], "characters": "\u21D7" }, // 1164 - "↗": { "codepoints": [8599], "characters": "\u2197" }, // 1165 - "≠": { "codepoints": [8800], "characters": "\u2260" }, // 1166 - "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" }, // 1167 - "​": { "codepoints": [8203], "characters": "\u200B" }, // 1168 - "​": { "codepoints": [8203], "characters": "\u200B" }, // 1169 - "​": { "codepoints": [8203], "characters": "\u200B" }, // 1170 - "​": { "codepoints": [8203], "characters": "\u200B" }, // 1171 - "≢": { "codepoints": [8802], "characters": "\u2262" }, // 1172 - "⤨": { "codepoints": [10536], "characters": "\u2928" }, // 1173 - "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, // 1174 - "≫": { "codepoints": [8811], "characters": "\u226B" }, // 1175 - "≪": { "codepoints": [8810], "characters": "\u226A" }, // 1176 - " ": { "codepoints": [10], "characters": "\u000A" }, // 1177 - "∄": { "codepoints": [8708], "characters": "\u2204" }, // 1178 - "∄": { "codepoints": [8708], "characters": "\u2204" }, // 1179 - "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" }, // 1180 - "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" }, // 1181 - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, // 1182 - "≱": { "codepoints": [8817], "characters": "\u2271" }, // 1183 - "≱": { "codepoints": [8817], "characters": "\u2271" }, // 1184 - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, // 1185 - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, // 1186 - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, // 1187 - "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" }, // 1188 - "≵": { "codepoints": [8821], "characters": "\u2275" }, // 1189 - "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" }, // 1190 - "≯": { "codepoints": [8815], "characters": "\u226F" }, // 1191 - "≯": { "codepoints": [8815], "characters": "\u226F" }, // 1192 - "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, // 1193 - "↮": { "codepoints": [8622], "characters": "\u21AE" }, // 1194 - "⇎": { "codepoints": [8654], "characters": "\u21CE" }, // 1195 - "⫲": { "codepoints": [10994], "characters": "\u2AF2" }, // 1196 - "∋": { "codepoints": [8715], "characters": "\u220B" }, // 1197 - "⋼": { "codepoints": [8956], "characters": "\u22FC" }, // 1198 - "⋺": { "codepoints": [8954], "characters": "\u22FA" }, // 1199 - "∋": { "codepoints": [8715], "characters": "\u220B" }, // 1200 - "Њ": { "codepoints": [1034], "characters": "\u040A" }, // 1201 - "њ": { "codepoints": [1114], "characters": "\u045A" }, // 1202 - "↚": { "codepoints": [8602], "characters": "\u219A" }, // 1203 - "⇍": { "codepoints": [8653], "characters": "\u21CD" }, // 1204 - "‥": { "codepoints": [8229], "characters": "\u2025" }, // 1205 - "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, // 1206 - "≰": { "codepoints": [8816], "characters": "\u2270" }, // 1207 - "↚": { "codepoints": [8602], "characters": "\u219A" }, // 1208 - "⇍": { "codepoints": [8653], "characters": "\u21CD" }, // 1209 - "↮": { "codepoints": [8622], "characters": "\u21AE" }, // 1210 - "⇎": { "codepoints": [8654], "characters": "\u21CE" }, // 1211 - "≰": { "codepoints": [8816], "characters": "\u2270" }, // 1212 - "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, // 1213 - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, // 1214 - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, // 1215 - "≮": { "codepoints": [8814], "characters": "\u226E" }, // 1216 - "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" }, // 1217 - "≴": { "codepoints": [8820], "characters": "\u2274" }, // 1218 - "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" }, // 1219 - "≮": { "codepoints": [8814], "characters": "\u226E" }, // 1220 - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, // 1221 - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, // 1222 - "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, // 1223 - "∤": { "codepoints": [8740], "characters": "\u2224" }, // 1224 - "⁠": { "codepoints": [8288], "characters": "\u2060" }, // 1225 - " ": { "codepoints": [160], "characters": "\u00A0" }, // 1226 - "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" }, // 1227 - "ℕ": { "codepoints": [8469], "characters": "\u2115" }, // 1228 - "⫬": { "codepoints": [10988], "characters": "\u2AEC" }, // 1229 - "¬": { "codepoints": [172], "characters": "\u00AC" }, // 1230 - "¬": { "codepoints": [172], "characters": "\u00AC" }, // 1231 - "≢": { "codepoints": [8802], "characters": "\u2262" }, // 1232 - "≭": { "codepoints": [8813], "characters": "\u226D" }, // 1233 - "∦": { "codepoints": [8742], "characters": "\u2226" }, // 1234 - "∉": { "codepoints": [8713], "characters": "\u2209" }, // 1235 - "≠": { "codepoints": [8800], "characters": "\u2260" }, // 1236 - "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, // 1237 - "∄": { "codepoints": [8708], "characters": "\u2204" }, // 1238 - "≯": { "codepoints": [8815], "characters": "\u226F" }, // 1239 - "≱": { "codepoints": [8817], "characters": "\u2271" }, // 1240 - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, // 1241 - "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, // 1242 - "≹": { "codepoints": [8825], "characters": "\u2279" }, // 1243 - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, // 1244 - "≵": { "codepoints": [8821], "characters": "\u2275" }, // 1245 - "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, // 1246 - "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, // 1247 - "∉": { "codepoints": [8713], "characters": "\u2209" }, // 1248 - "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" }, // 1249 - "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" }, // 1250 - "∉": { "codepoints": [8713], "characters": "\u2209" }, // 1251 - "⋷": { "codepoints": [8951], "characters": "\u22F7" }, // 1252 - "⋶": { "codepoints": [8950], "characters": "\u22F6" }, // 1253 - "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" }, // 1254 - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, // 1255 - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, // 1256 - "≮": { "codepoints": [8814], "characters": "\u226E" }, // 1257 - "≰": { "codepoints": [8816], "characters": "\u2270" }, // 1258 - "≸": { "codepoints": [8824], "characters": "\u2278" }, // 1259 - "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, // 1260 - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, // 1261 - "≴": { "codepoints": [8820], "characters": "\u2274" }, // 1262 - "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" }, // 1263 - "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" }, // 1264 - "∌": { "codepoints": [8716], "characters": "\u220C" }, // 1265 - "∌": { "codepoints": [8716], "characters": "\u220C" }, // 1266 - "⋾": { "codepoints": [8958], "characters": "\u22FE" }, // 1267 - "⋽": { "codepoints": [8957], "characters": "\u22FD" }, // 1268 - "⊀": { "codepoints": [8832], "characters": "\u2280" }, // 1269 - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, // 1270 - "⋠": { "codepoints": [8928], "characters": "\u22E0" }, // 1271 - "∌": { "codepoints": [8716], "characters": "\u220C" }, // 1272 - "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" }, // 1273 - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, // 1274 - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, // 1275 - "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" }, // 1276 - "⋢": { "codepoints": [8930], "characters": "\u22E2" }, // 1277 - "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" }, // 1278 - "⋣": { "codepoints": [8931], "characters": "\u22E3" }, // 1279 - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, // 1280 - "⊈": { "codepoints": [8840], "characters": "\u2288" }, // 1281 - "⊁": { "codepoints": [8833], "characters": "\u2281" }, // 1282 - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, // 1283 - "⋡": { "codepoints": [8929], "characters": "\u22E1" }, // 1284 - "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" }, // 1285 - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, // 1286 - "⊉": { "codepoints": [8841], "characters": "\u2289" }, // 1287 - "≁": { "codepoints": [8769], "characters": "\u2241" }, // 1288 - "≄": { "codepoints": [8772], "characters": "\u2244" }, // 1289 - "≇": { "codepoints": [8775], "characters": "\u2247" }, // 1290 - "≉": { "codepoints": [8777], "characters": "\u2249" }, // 1291 - "∤": { "codepoints": [8740], "characters": "\u2224" }, // 1292 - "∦": { "codepoints": [8742], "characters": "\u2226" }, // 1293 - "∦": { "codepoints": [8742], "characters": "\u2226" }, // 1294 - "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" }, // 1295 - "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" }, // 1296 - "⨔": { "codepoints": [10772], "characters": "\u2A14" }, // 1297 - "⊀": { "codepoints": [8832], "characters": "\u2280" }, // 1298 - "⋠": { "codepoints": [8928], "characters": "\u22E0" }, // 1299 - "⊀": { "codepoints": [8832], "characters": "\u2280" }, // 1300 - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, // 1301 - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, // 1302 - "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" }, // 1303 - "↛": { "codepoints": [8603], "characters": "\u219B" }, // 1304 - "⇏": { "codepoints": [8655], "characters": "\u21CF" }, // 1305 - "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" }, // 1306 - "↛": { "codepoints": [8603], "characters": "\u219B" }, // 1307 - "⇏": { "codepoints": [8655], "characters": "\u21CF" }, // 1308 - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, // 1309 - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, // 1310 - "⊁": { "codepoints": [8833], "characters": "\u2281" }, // 1311 - "⋡": { "codepoints": [8929], "characters": "\u22E1" }, // 1312 - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, // 1313 - "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" }, // 1314 - "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" }, // 1315 - "∤": { "codepoints": [8740], "characters": "\u2224" }, // 1316 - "∦": { "codepoints": [8742], "characters": "\u2226" }, // 1317 - "≁": { "codepoints": [8769], "characters": "\u2241" }, // 1318 - "≄": { "codepoints": [8772], "characters": "\u2244" }, // 1319 - "≄": { "codepoints": [8772], "characters": "\u2244" }, // 1320 - "∤": { "codepoints": [8740], "characters": "\u2224" }, // 1321 - "∦": { "codepoints": [8742], "characters": "\u2226" }, // 1322 - "⋢": { "codepoints": [8930], "characters": "\u22E2" }, // 1323 - "⋣": { "codepoints": [8931], "characters": "\u22E3" }, // 1324 - "⊄": { "codepoints": [8836], "characters": "\u2284" }, // 1325 - "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, // 1326 - "⊈": { "codepoints": [8840], "characters": "\u2288" }, // 1327 - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, // 1328 - "⊈": { "codepoints": [8840], "characters": "\u2288" }, // 1329 - "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, // 1330 - "⊁": { "codepoints": [8833], "characters": "\u2281" }, // 1331 - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, // 1332 - "⊅": { "codepoints": [8837], "characters": "\u2285" }, // 1333 - "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, // 1334 - "⊉": { "codepoints": [8841], "characters": "\u2289" }, // 1335 - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, // 1336 - "⊉": { "codepoints": [8841], "characters": "\u2289" }, // 1337 - "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, // 1338 - "≹": { "codepoints": [8825], "characters": "\u2279" }, // 1339 - "Ñ": { "codepoints": [209], "characters": "\u00D1" }, // 1340 - "Ñ": { "codepoints": [209], "characters": "\u00D1" }, // 1341 - "ñ": { "codepoints": [241], "characters": "\u00F1" }, // 1342 - "ñ": { "codepoints": [241], "characters": "\u00F1" }, // 1343 - "≸": { "codepoints": [8824], "characters": "\u2278" }, // 1344 - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, // 1345 - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, // 1346 - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, // 1347 - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, // 1348 - "Ν": { "codepoints": [925], "characters": "\u039D" }, // 1349 - "ν": { "codepoints": [957], "characters": "\u03BD" }, // 1350 - "#": { "codepoints": [35], "characters": "\u0023" }, // 1351 - "№": { "codepoints": [8470], "characters": "\u2116" }, // 1352 - " ": { "codepoints": [8199], "characters": "\u2007" }, // 1353 - "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" }, // 1354 - "⊬": { "codepoints": [8876], "characters": "\u22AC" }, // 1355 - "⊭": { "codepoints": [8877], "characters": "\u22AD" }, // 1356 - "⊮": { "codepoints": [8878], "characters": "\u22AE" }, // 1357 - "⊯": { "codepoints": [8879], "characters": "\u22AF" }, // 1358 - "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" }, // 1359 - ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" }, // 1360 - "⤄": { "codepoints": [10500], "characters": "\u2904" }, // 1361 - "⧞": { "codepoints": [10718], "characters": "\u29DE" }, // 1362 - "⤂": { "codepoints": [10498], "characters": "\u2902" }, // 1363 - "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" }, // 1364 - "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" }, // 1365 - "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" }, // 1366 - "⤃": { "codepoints": [10499], "characters": "\u2903" }, // 1367 - "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" }, // 1368 - "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" }, // 1369 - "⤣": { "codepoints": [10531], "characters": "\u2923" }, // 1370 - "↖": { "codepoints": [8598], "characters": "\u2196" }, // 1371 - "⇖": { "codepoints": [8662], "characters": "\u21D6" }, // 1372 - "↖": { "codepoints": [8598], "characters": "\u2196" }, // 1373 - "⤧": { "codepoints": [10535], "characters": "\u2927" }, // 1374 - "Ó": { "codepoints": [211], "characters": "\u00D3" }, // 1375 - "Ó": { "codepoints": [211], "characters": "\u00D3" }, // 1376 - "ó": { "codepoints": [243], "characters": "\u00F3" }, // 1377 - "ó": { "codepoints": [243], "characters": "\u00F3" }, // 1378 - "⊛": { "codepoints": [8859], "characters": "\u229B" }, // 1379 - "Ô": { "codepoints": [212], "characters": "\u00D4" }, // 1380 - "Ô": { "codepoints": [212], "characters": "\u00D4" }, // 1381 - "ô": { "codepoints": [244], "characters": "\u00F4" }, // 1382 - "ô": { "codepoints": [244], "characters": "\u00F4" }, // 1383 - "⊚": { "codepoints": [8858], "characters": "\u229A" }, // 1384 - "О": { "codepoints": [1054], "characters": "\u041E" }, // 1385 - "о": { "codepoints": [1086], "characters": "\u043E" }, // 1386 - "⊝": { "codepoints": [8861], "characters": "\u229D" }, // 1387 - "Ő": { "codepoints": [336], "characters": "\u0150" }, // 1388 - "ő": { "codepoints": [337], "characters": "\u0151" }, // 1389 - "⨸": { "codepoints": [10808], "characters": "\u2A38" }, // 1390 - "⊙": { "codepoints": [8857], "characters": "\u2299" }, // 1391 - "⦼": { "codepoints": [10684], "characters": "\u29BC" }, // 1392 - "Œ": { "codepoints": [338], "characters": "\u0152" }, // 1393 - "œ": { "codepoints": [339], "characters": "\u0153" }, // 1394 - "⦿": { "codepoints": [10687], "characters": "\u29BF" }, // 1395 - "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" }, // 1396 - "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" }, // 1397 - "˛": { "codepoints": [731], "characters": "\u02DB" }, // 1398 - "Ò": { "codepoints": [210], "characters": "\u00D2" }, // 1399 - "Ò": { "codepoints": [210], "characters": "\u00D2" }, // 1400 - "ò": { "codepoints": [242], "characters": "\u00F2" }, // 1401 - "ò": { "codepoints": [242], "characters": "\u00F2" }, // 1402 - "⧁": { "codepoints": [10689], "characters": "\u29C1" }, // 1403 - "⦵": { "codepoints": [10677], "characters": "\u29B5" }, // 1404 - "Ω": { "codepoints": [937], "characters": "\u03A9" }, // 1405 - "∮": { "codepoints": [8750], "characters": "\u222E" }, // 1406 - "↺": { "codepoints": [8634], "characters": "\u21BA" }, // 1407 - "⦾": { "codepoints": [10686], "characters": "\u29BE" }, // 1408 - "⦻": { "codepoints": [10683], "characters": "\u29BB" }, // 1409 - "‾": { "codepoints": [8254], "characters": "\u203E" }, // 1410 - "⧀": { "codepoints": [10688], "characters": "\u29C0" }, // 1411 - "Ō": { "codepoints": [332], "characters": "\u014C" }, // 1412 - "ō": { "codepoints": [333], "characters": "\u014D" }, // 1413 - "Ω": { "codepoints": [937], "characters": "\u03A9" }, // 1414 - "ω": { "codepoints": [969], "characters": "\u03C9" }, // 1415 - "Ο": { "codepoints": [927], "characters": "\u039F" }, // 1416 - "ο": { "codepoints": [959], "characters": "\u03BF" }, // 1417 - "⦶": { "codepoints": [10678], "characters": "\u29B6" }, // 1418 - "⊖": { "codepoints": [8854], "characters": "\u2296" }, // 1419 - "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" }, // 1420 - "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" }, // 1421 - "⦷": { "codepoints": [10679], "characters": "\u29B7" }, // 1422 - "“": { "codepoints": [8220], "characters": "\u201C" }, // 1423 - "‘": { "codepoints": [8216], "characters": "\u2018" }, // 1424 - "⦹": { "codepoints": [10681], "characters": "\u29B9" }, // 1425 - "⊕": { "codepoints": [8853], "characters": "\u2295" }, // 1426 - "↻": { "codepoints": [8635], "characters": "\u21BB" }, // 1427 - "⩔": { "codepoints": [10836], "characters": "\u2A54" }, // 1428 - "∨": { "codepoints": [8744], "characters": "\u2228" }, // 1429 - "⩝": { "codepoints": [10845], "characters": "\u2A5D" }, // 1430 - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, // 1431 - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, // 1432 - "ª": { "codepoints": [170], "characters": "\u00AA" }, // 1433 - "ª": { "codepoints": [170], "characters": "\u00AA" }, // 1434 - "º": { "codepoints": [186], "characters": "\u00BA" }, // 1435 - "º": { "codepoints": [186], "characters": "\u00BA" }, // 1436 - "⊶": { "codepoints": [8886], "characters": "\u22B6" }, // 1437 - "⩖": { "codepoints": [10838], "characters": "\u2A56" }, // 1438 - "⩗": { "codepoints": [10839], "characters": "\u2A57" }, // 1439 - "⩛": { "codepoints": [10843], "characters": "\u2A5B" }, // 1440 - "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, // 1441 - "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" }, // 1442 - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, // 1443 - "Ø": { "codepoints": [216], "characters": "\u00D8" }, // 1444 - "Ø": { "codepoints": [216], "characters": "\u00D8" }, // 1445 - "ø": { "codepoints": [248], "characters": "\u00F8" }, // 1446 - "ø": { "codepoints": [248], "characters": "\u00F8" }, // 1447 - "⊘": { "codepoints": [8856], "characters": "\u2298" }, // 1448 - "Õ": { "codepoints": [213], "characters": "\u00D5" }, // 1449 - "Õ": { "codepoints": [213], "characters": "\u00D5" }, // 1450 - "õ": { "codepoints": [245], "characters": "\u00F5" }, // 1451 - "õ": { "codepoints": [245], "characters": "\u00F5" }, // 1452 - "⨶": { "codepoints": [10806], "characters": "\u2A36" }, // 1453 - "⨷": { "codepoints": [10807], "characters": "\u2A37" }, // 1454 - "⊗": { "codepoints": [8855], "characters": "\u2297" }, // 1455 - "Ö": { "codepoints": [214], "characters": "\u00D6" }, // 1456 - "Ö": { "codepoints": [214], "characters": "\u00D6" }, // 1457 - "ö": { "codepoints": [246], "characters": "\u00F6" }, // 1458 - "ö": { "codepoints": [246], "characters": "\u00F6" }, // 1459 - "⌽": { "codepoints": [9021], "characters": "\u233D" }, // 1460 - "‾": { "codepoints": [8254], "characters": "\u203E" }, // 1461 - "⏞": { "codepoints": [9182], "characters": "\u23DE" }, // 1462 - "⎴": { "codepoints": [9140], "characters": "\u23B4" }, // 1463 - "⏜": { "codepoints": [9180], "characters": "\u23DC" }, // 1464 - "¶": { "codepoints": [182], "characters": "\u00B6" }, // 1465 - "¶": { "codepoints": [182], "characters": "\u00B6" }, // 1466 - "∥": { "codepoints": [8741], "characters": "\u2225" }, // 1467 - "∥": { "codepoints": [8741], "characters": "\u2225" }, // 1468 - "⫳": { "codepoints": [10995], "characters": "\u2AF3" }, // 1469 - "⫽": { "codepoints": [11005], "characters": "\u2AFD" }, // 1470 - "∂": { "codepoints": [8706], "characters": "\u2202" }, // 1471 - "∂": { "codepoints": [8706], "characters": "\u2202" }, // 1472 - "П": { "codepoints": [1055], "characters": "\u041F" }, // 1473 - "п": { "codepoints": [1087], "characters": "\u043F" }, // 1474 - "%": { "codepoints": [37], "characters": "\u0025" }, // 1475 - ".": { "codepoints": [46], "characters": "\u002E" }, // 1476 - "‰": { "codepoints": [8240], "characters": "\u2030" }, // 1477 - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, // 1478 - "‱": { "codepoints": [8241], "characters": "\u2031" }, // 1479 - "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" }, // 1480 - "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" }, // 1481 - "Φ": { "codepoints": [934], "characters": "\u03A6" }, // 1482 - "φ": { "codepoints": [966], "characters": "\u03C6" }, // 1483 - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, // 1484 - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, // 1485 - "☎": { "codepoints": [9742], "characters": "\u260E" }, // 1486 - "Π": { "codepoints": [928], "characters": "\u03A0" }, // 1487 - "π": { "codepoints": [960], "characters": "\u03C0" }, // 1488 - "⋔": { "codepoints": [8916], "characters": "\u22D4" }, // 1489 - "ϖ": { "codepoints": [982], "characters": "\u03D6" }, // 1490 - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, // 1491 - "ℎ": { "codepoints": [8462], "characters": "\u210E" }, // 1492 - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, // 1493 - "⨣": { "codepoints": [10787], "characters": "\u2A23" }, // 1494 - "⊞": { "codepoints": [8862], "characters": "\u229E" }, // 1495 - "⨢": { "codepoints": [10786], "characters": "\u2A22" }, // 1496 - "+": { "codepoints": [43], "characters": "\u002B" }, // 1497 - "∔": { "codepoints": [8724], "characters": "\u2214" }, // 1498 - "⨥": { "codepoints": [10789], "characters": "\u2A25" }, // 1499 - "⩲": { "codepoints": [10866], "characters": "\u2A72" }, // 1500 - "±": { "codepoints": [177], "characters": "\u00B1" }, // 1501 - "±": { "codepoints": [177], "characters": "\u00B1" }, // 1502 - "±": { "codepoints": [177], "characters": "\u00B1" }, // 1503 - "⨦": { "codepoints": [10790], "characters": "\u2A26" }, // 1504 - "⨧": { "codepoints": [10791], "characters": "\u2A27" }, // 1505 - "±": { "codepoints": [177], "characters": "\u00B1" }, // 1506 - "ℌ": { "codepoints": [8460], "characters": "\u210C" }, // 1507 - "⨕": { "codepoints": [10773], "characters": "\u2A15" }, // 1508 - "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" }, // 1509 - "ℙ": { "codepoints": [8473], "characters": "\u2119" }, // 1510 - "£": { "codepoints": [163], "characters": "\u00A3" }, // 1511 - "£": { "codepoints": [163], "characters": "\u00A3" }, // 1512 - "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, // 1513 - "⪻": { "codepoints": [10939], "characters": "\u2ABB" }, // 1514 - "≺": { "codepoints": [8826], "characters": "\u227A" }, // 1515 - "≼": { "codepoints": [8828], "characters": "\u227C" }, // 1516 - "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, // 1517 - "≺": { "codepoints": [8826], "characters": "\u227A" }, // 1518 - "≼": { "codepoints": [8828], "characters": "\u227C" }, // 1519 - "≺": { "codepoints": [8826], "characters": "\u227A" }, // 1520 - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, // 1521 - "≼": { "codepoints": [8828], "characters": "\u227C" }, // 1522 - "≾": { "codepoints": [8830], "characters": "\u227E" }, // 1523 - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, // 1524 - "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, // 1525 - "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, // 1526 - "⋨": { "codepoints": [8936], "characters": "\u22E8" }, // 1527 - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, // 1528 - "⪳": { "codepoints": [10931], "characters": "\u2AB3" }, // 1529 - "≾": { "codepoints": [8830], "characters": "\u227E" }, // 1530 - "′": { "codepoints": [8242], "characters": "\u2032" }, // 1531 - "″": { "codepoints": [8243], "characters": "\u2033" }, // 1532 - "ℙ": { "codepoints": [8473], "characters": "\u2119" }, // 1533 - "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, // 1534 - "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, // 1535 - "⋨": { "codepoints": [8936], "characters": "\u22E8" }, // 1536 - "∏": { "codepoints": [8719], "characters": "\u220F" }, // 1537 - "∏": { "codepoints": [8719], "characters": "\u220F" }, // 1538 - "⌮": { "codepoints": [9006], "characters": "\u232E" }, // 1539 - "⌒": { "codepoints": [8978], "characters": "\u2312" }, // 1540 - "⌓": { "codepoints": [8979], "characters": "\u2313" }, // 1541 - "∝": { "codepoints": [8733], "characters": "\u221D" }, // 1542 - "∝": { "codepoints": [8733], "characters": "\u221D" }, // 1543 - "∷": { "codepoints": [8759], "characters": "\u2237" }, // 1544 - "∝": { "codepoints": [8733], "characters": "\u221D" }, // 1545 - "≾": { "codepoints": [8830], "characters": "\u227E" }, // 1546 - "⊰": { "codepoints": [8880], "characters": "\u22B0" }, // 1547 - "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" }, // 1548 - "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" }, // 1549 - "Ψ": { "codepoints": [936], "characters": "\u03A8" }, // 1550 - "ψ": { "codepoints": [968], "characters": "\u03C8" }, // 1551 - " ": { "codepoints": [8200], "characters": "\u2008" }, // 1552 - "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" }, // 1553 - "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" }, // 1554 - "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, // 1555 - "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" }, // 1556 - "ℚ": { "codepoints": [8474], "characters": "\u211A" }, // 1557 - "⁗": { "codepoints": [8279], "characters": "\u2057" }, // 1558 - "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" }, // 1559 - "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" }, // 1560 - "ℍ": { "codepoints": [8461], "characters": "\u210D" }, // 1561 - "⨖": { "codepoints": [10774], "characters": "\u2A16" }, // 1562 - "?": { "codepoints": [63], "characters": "\u003F" }, // 1563 - "≟": { "codepoints": [8799], "characters": "\u225F" }, // 1564 - """: { "codepoints": [34], "characters": "\u0022" }, // 1565 - """: { "codepoints": [34], "characters": "\u0022" }, // 1566 - """: { "codepoints": [34], "characters": "\u0022" }, // 1567 - """: { "codepoints": [34], "characters": "\u0022" }, // 1568 - "⇛": { "codepoints": [8667], "characters": "\u21DB" }, // 1569 - "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" }, // 1570 - "Ŕ": { "codepoints": [340], "characters": "\u0154" }, // 1571 - "ŕ": { "codepoints": [341], "characters": "\u0155" }, // 1572 - "√": { "codepoints": [8730], "characters": "\u221A" }, // 1573 - "⦳": { "codepoints": [10675], "characters": "\u29B3" }, // 1574 - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, // 1575 - "⟫": { "codepoints": [10219], "characters": "\u27EB" }, // 1576 - "⦒": { "codepoints": [10642], "characters": "\u2992" }, // 1577 - "⦥": { "codepoints": [10661], "characters": "\u29A5" }, // 1578 - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, // 1579 - "»": { "codepoints": [187], "characters": "\u00BB" }, // 1580 - "»": { "codepoints": [187], "characters": "\u00BB" }, // 1581 - "⥵": { "codepoints": [10613], "characters": "\u2975" }, // 1582 - "⇥": { "codepoints": [8677], "characters": "\u21E5" }, // 1583 - "⤠": { "codepoints": [10528], "characters": "\u2920" }, // 1584 - "⤳": { "codepoints": [10547], "characters": "\u2933" }, // 1585 - "→": { "codepoints": [8594], "characters": "\u2192" }, // 1586 - "↠": { "codepoints": [8608], "characters": "\u21A0" }, // 1587 - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, // 1588 - "⤞": { "codepoints": [10526], "characters": "\u291E" }, // 1589 - "↪": { "codepoints": [8618], "characters": "\u21AA" }, // 1590 - "↬": { "codepoints": [8620], "characters": "\u21AC" }, // 1591 - "⥅": { "codepoints": [10565], "characters": "\u2945" }, // 1592 - "⥴": { "codepoints": [10612], "characters": "\u2974" }, // 1593 - "⤖": { "codepoints": [10518], "characters": "\u2916" }, // 1594 - "↣": { "codepoints": [8611], "characters": "\u21A3" }, // 1595 - "↝": { "codepoints": [8605], "characters": "\u219D" }, // 1596 - "⤚": { "codepoints": [10522], "characters": "\u291A" }, // 1597 - "⤜": { "codepoints": [10524], "characters": "\u291C" }, // 1598 - "∶": { "codepoints": [8758], "characters": "\u2236" }, // 1599 - "ℚ": { "codepoints": [8474], "characters": "\u211A" }, // 1600 - "⤍": { "codepoints": [10509], "characters": "\u290D" }, // 1601 - "⤏": { "codepoints": [10511], "characters": "\u290F" }, // 1602 - "⤐": { "codepoints": [10512], "characters": "\u2910" }, // 1603 - "❳": { "codepoints": [10099], "characters": "\u2773" }, // 1604 - "}": { "codepoints": [125], "characters": "\u007D" }, // 1605 - "]": { "codepoints": [93], "characters": "\u005D" }, // 1606 - "⦌": { "codepoints": [10636], "characters": "\u298C" }, // 1607 - "⦎": { "codepoints": [10638], "characters": "\u298E" }, // 1608 - "⦐": { "codepoints": [10640], "characters": "\u2990" }, // 1609 - "Ř": { "codepoints": [344], "characters": "\u0158" }, // 1610 - "ř": { "codepoints": [345], "characters": "\u0159" }, // 1611 - "Ŗ": { "codepoints": [342], "characters": "\u0156" }, // 1612 - "ŗ": { "codepoints": [343], "characters": "\u0157" }, // 1613 - "⌉": { "codepoints": [8969], "characters": "\u2309" }, // 1614 - "}": { "codepoints": [125], "characters": "\u007D" }, // 1615 - "Р": { "codepoints": [1056], "characters": "\u0420" }, // 1616 - "р": { "codepoints": [1088], "characters": "\u0440" }, // 1617 - "⤷": { "codepoints": [10551], "characters": "\u2937" }, // 1618 - "⥩": { "codepoints": [10601], "characters": "\u2969" }, // 1619 - "”": { "codepoints": [8221], "characters": "\u201D" }, // 1620 - "”": { "codepoints": [8221], "characters": "\u201D" }, // 1621 - "↳": { "codepoints": [8627], "characters": "\u21B3" }, // 1622 - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, // 1623 - "ℛ": { "codepoints": [8475], "characters": "\u211B" }, // 1624 - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, // 1625 - "ℝ": { "codepoints": [8477], "characters": "\u211D" }, // 1626 - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, // 1627 - "▭": { "codepoints": [9645], "characters": "\u25AD" }, // 1628 - "®": { "codepoints": [174], "characters": "\u00AE" }, // 1629 - "®": { "codepoints": [174], "characters": "\u00AE" }, // 1630 - "®": { "codepoints": [174], "characters": "\u00AE" }, // 1631 - "®": { "codepoints": [174], "characters": "\u00AE" }, // 1632 - "∋": { "codepoints": [8715], "characters": "\u220B" }, // 1633 - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, // 1634 - "⥯": { "codepoints": [10607], "characters": "\u296F" }, // 1635 - "⥽": { "codepoints": [10621], "characters": "\u297D" }, // 1636 - "⌋": { "codepoints": [8971], "characters": "\u230B" }, // 1637 - "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" }, // 1638 - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, // 1639 - "⥤": { "codepoints": [10596], "characters": "\u2964" }, // 1640 - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, // 1641 - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, // 1642 - "⥬": { "codepoints": [10604], "characters": "\u296C" }, // 1643 - "Ρ": { "codepoints": [929], "characters": "\u03A1" }, // 1644 - "ρ": { "codepoints": [961], "characters": "\u03C1" }, // 1645 - "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, // 1646 - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, // 1647 - "⇥": { "codepoints": [8677], "characters": "\u21E5" }, // 1648 - "→": { "codepoints": [8594], "characters": "\u2192" }, // 1649 - "→": { "codepoints": [8594], "characters": "\u2192" }, // 1650 - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, // 1651 - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, // 1652 - "↣": { "codepoints": [8611], "characters": "\u21A3" }, // 1653 - "⌉": { "codepoints": [8969], "characters": "\u2309" }, // 1654 - "⟧": { "codepoints": [10215], "characters": "\u27E7" }, // 1655 - "⥝": { "codepoints": [10589], "characters": "\u295D" }, // 1656 - "⥕": { "codepoints": [10581], "characters": "\u2955" }, // 1657 - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, // 1658 - "⌋": { "codepoints": [8971], "characters": "\u230B" }, // 1659 - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, // 1660 - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, // 1661 - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, // 1662 - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, // 1663 - "⇉": { "codepoints": [8649], "characters": "\u21C9" }, // 1664 - "↝": { "codepoints": [8605], "characters": "\u219D" }, // 1665 - "↦": { "codepoints": [8614], "characters": "\u21A6" }, // 1666 - "⊢": { "codepoints": [8866], "characters": "\u22A2" }, // 1667 - "⥛": { "codepoints": [10587], "characters": "\u295B" }, // 1668 - "⋌": { "codepoints": [8908], "characters": "\u22CC" }, // 1669 - "⧐": { "codepoints": [10704], "characters": "\u29D0" }, // 1670 - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, // 1671 - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, // 1672 - "⥏": { "codepoints": [10575], "characters": "\u294F" }, // 1673 - "⥜": { "codepoints": [10588], "characters": "\u295C" }, // 1674 - "⥔": { "codepoints": [10580], "characters": "\u2954" }, // 1675 - "↾": { "codepoints": [8638], "characters": "\u21BE" }, // 1676 - "⥓": { "codepoints": [10579], "characters": "\u2953" }, // 1677 - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, // 1678 - "˚": { "codepoints": [730], "characters": "\u02DA" }, // 1679 - "≓": { "codepoints": [8787], "characters": "\u2253" }, // 1680 - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, // 1681 - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, // 1682 - "‏": { "codepoints": [8207], "characters": "\u200F" }, // 1683 - "⎱": { "codepoints": [9137], "characters": "\u23B1" }, // 1684 - "⎱": { "codepoints": [9137], "characters": "\u23B1" }, // 1685 - "⫮": { "codepoints": [10990], "characters": "\u2AEE" }, // 1686 - "⟭": { "codepoints": [10221], "characters": "\u27ED" }, // 1687 - "⇾": { "codepoints": [8702], "characters": "\u21FE" }, // 1688 - "⟧": { "codepoints": [10215], "characters": "\u27E7" }, // 1689 - "⦆": { "codepoints": [10630], "characters": "\u2986" }, // 1690 - "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" }, // 1691 - "ℝ": { "codepoints": [8477], "characters": "\u211D" }, // 1692 - "⨮": { "codepoints": [10798], "characters": "\u2A2E" }, // 1693 - "⨵": { "codepoints": [10805], "characters": "\u2A35" }, // 1694 - "⥰": { "codepoints": [10608], "characters": "\u2970" }, // 1695 - ")": { "codepoints": [41], "characters": "\u0029" }, // 1696 - "⦔": { "codepoints": [10644], "characters": "\u2994" }, // 1697 - "⨒": { "codepoints": [10770], "characters": "\u2A12" }, // 1698 - "⇉": { "codepoints": [8649], "characters": "\u21C9" }, // 1699 - "⇛": { "codepoints": [8667], "characters": "\u21DB" }, // 1700 - "›": { "codepoints": [8250], "characters": "\u203A" }, // 1701 - "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" }, // 1702 - "ℛ": { "codepoints": [8475], "characters": "\u211B" }, // 1703 - "↱": { "codepoints": [8625], "characters": "\u21B1" }, // 1704 - "↱": { "codepoints": [8625], "characters": "\u21B1" }, // 1705 - "]": { "codepoints": [93], "characters": "\u005D" }, // 1706 - "’": { "codepoints": [8217], "characters": "\u2019" }, // 1707 - "’": { "codepoints": [8217], "characters": "\u2019" }, // 1708 - "⋌": { "codepoints": [8908], "characters": "\u22CC" }, // 1709 - "⋊": { "codepoints": [8906], "characters": "\u22CA" }, // 1710 - "▹": { "codepoints": [9657], "characters": "\u25B9" }, // 1711 - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, // 1712 - "▸": { "codepoints": [9656], "characters": "\u25B8" }, // 1713 - "⧎": { "codepoints": [10702], "characters": "\u29CE" }, // 1714 - "⧴": { "codepoints": [10740], "characters": "\u29F4" }, // 1715 - "⥨": { "codepoints": [10600], "characters": "\u2968" }, // 1716 - "℞": { "codepoints": [8478], "characters": "\u211E" }, // 1717 - "Ś": { "codepoints": [346], "characters": "\u015A" }, // 1718 - "ś": { "codepoints": [347], "characters": "\u015B" }, // 1719 - "‚": { "codepoints": [8218], "characters": "\u201A" }, // 1720 - "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, // 1721 - "Š": { "codepoints": [352], "characters": "\u0160" }, // 1722 - "š": { "codepoints": [353], "characters": "\u0161" }, // 1723 - "⪼": { "codepoints": [10940], "characters": "\u2ABC" }, // 1724 - "≻": { "codepoints": [8827], "characters": "\u227B" }, // 1725 - "≽": { "codepoints": [8829], "characters": "\u227D" }, // 1726 - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, // 1727 - "⪴": { "codepoints": [10932], "characters": "\u2AB4" }, // 1728 - "Ş": { "codepoints": [350], "characters": "\u015E" }, // 1729 - "ş": { "codepoints": [351], "characters": "\u015F" }, // 1730 - "Ŝ": { "codepoints": [348], "characters": "\u015C" }, // 1731 - "ŝ": { "codepoints": [349], "characters": "\u015D" }, // 1732 - "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, // 1733 - "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, // 1734 - "⋩": { "codepoints": [8937], "characters": "\u22E9" }, // 1735 - "⨓": { "codepoints": [10771], "characters": "\u2A13" }, // 1736 - "≿": { "codepoints": [8831], "characters": "\u227F" }, // 1737 - "С": { "codepoints": [1057], "characters": "\u0421" }, // 1738 - "с": { "codepoints": [1089], "characters": "\u0441" }, // 1739 - "⊡": { "codepoints": [8865], "characters": "\u22A1" }, // 1740 - "⋅": { "codepoints": [8901], "characters": "\u22C5" }, // 1741 - "⩦": { "codepoints": [10854], "characters": "\u2A66" }, // 1742 - "⤥": { "codepoints": [10533], "characters": "\u2925" }, // 1743 - "↘": { "codepoints": [8600], "characters": "\u2198" }, // 1744 - "⇘": { "codepoints": [8664], "characters": "\u21D8" }, // 1745 - "↘": { "codepoints": [8600], "characters": "\u2198" }, // 1746 - "§": { "codepoints": [167], "characters": "\u00A7" }, // 1747 - "§": { "codepoints": [167], "characters": "\u00A7" }, // 1748 - ";": { "codepoints": [59], "characters": "\u003B" }, // 1749 - "⤩": { "codepoints": [10537], "characters": "\u2929" }, // 1750 - "∖": { "codepoints": [8726], "characters": "\u2216" }, // 1751 - "∖": { "codepoints": [8726], "characters": "\u2216" }, // 1752 - "✶": { "codepoints": [10038], "characters": "\u2736" }, // 1753 - "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" }, // 1754 - "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" }, // 1755 - "⌢": { "codepoints": [8994], "characters": "\u2322" }, // 1756 - "♯": { "codepoints": [9839], "characters": "\u266F" }, // 1757 - "Щ": { "codepoints": [1065], "characters": "\u0429" }, // 1758 - "щ": { "codepoints": [1097], "characters": "\u0449" }, // 1759 - "Ш": { "codepoints": [1064], "characters": "\u0428" }, // 1760 - "ш": { "codepoints": [1096], "characters": "\u0448" }, // 1761 - "↓": { "codepoints": [8595], "characters": "\u2193" }, // 1762 - "←": { "codepoints": [8592], "characters": "\u2190" }, // 1763 - "∣": { "codepoints": [8739], "characters": "\u2223" }, // 1764 - "∥": { "codepoints": [8741], "characters": "\u2225" }, // 1765 - "→": { "codepoints": [8594], "characters": "\u2192" }, // 1766 - "↑": { "codepoints": [8593], "characters": "\u2191" }, // 1767 - "­": { "codepoints": [173], "characters": "\u00AD" }, // 1768 - "­": { "codepoints": [173], "characters": "\u00AD" }, // 1769 - "Σ": { "codepoints": [931], "characters": "\u03A3" }, // 1770 - "σ": { "codepoints": [963], "characters": "\u03C3" }, // 1771 - "ς": { "codepoints": [962], "characters": "\u03C2" }, // 1772 - "ς": { "codepoints": [962], "characters": "\u03C2" }, // 1773 - "∼": { "codepoints": [8764], "characters": "\u223C" }, // 1774 - "⩪": { "codepoints": [10858], "characters": "\u2A6A" }, // 1775 - "≃": { "codepoints": [8771], "characters": "\u2243" }, // 1776 - "≃": { "codepoints": [8771], "characters": "\u2243" }, // 1777 - "⪞": { "codepoints": [10910], "characters": "\u2A9E" }, // 1778 - "⪠": { "codepoints": [10912], "characters": "\u2AA0" }, // 1779 - "⪝": { "codepoints": [10909], "characters": "\u2A9D" }, // 1780 - "⪟": { "codepoints": [10911], "characters": "\u2A9F" }, // 1781 - "≆": { "codepoints": [8774], "characters": "\u2246" }, // 1782 - "⨤": { "codepoints": [10788], "characters": "\u2A24" }, // 1783 - "⥲": { "codepoints": [10610], "characters": "\u2972" }, // 1784 - "←": { "codepoints": [8592], "characters": "\u2190" }, // 1785 - "∘": { "codepoints": [8728], "characters": "\u2218" }, // 1786 - "∖": { "codepoints": [8726], "characters": "\u2216" }, // 1787 - "⨳": { "codepoints": [10803], "characters": "\u2A33" }, // 1788 - "⧤": { "codepoints": [10724], "characters": "\u29E4" }, // 1789 - "∣": { "codepoints": [8739], "characters": "\u2223" }, // 1790 - "⌣": { "codepoints": [8995], "characters": "\u2323" }, // 1791 - "⪪": { "codepoints": [10922], "characters": "\u2AAA" }, // 1792 - "⪬": { "codepoints": [10924], "characters": "\u2AAC" }, // 1793 - "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" }, // 1794 - "Ь": { "codepoints": [1068], "characters": "\u042C" }, // 1795 - "ь": { "codepoints": [1100], "characters": "\u044C" }, // 1796 - "⌿": { "codepoints": [9023], "characters": "\u233F" }, // 1797 - "⧄": { "codepoints": [10692], "characters": "\u29C4" }, // 1798 - "/": { "codepoints": [47], "characters": "\u002F" }, // 1799 - "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" }, // 1800 - "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" }, // 1801 - "♠": { "codepoints": [9824], "characters": "\u2660" }, // 1802 - "♠": { "codepoints": [9824], "characters": "\u2660" }, // 1803 - "∥": { "codepoints": [8741], "characters": "\u2225" }, // 1804 - "⊓": { "codepoints": [8851], "characters": "\u2293" }, // 1805 - "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" }, // 1806 - "⊔": { "codepoints": [8852], "characters": "\u2294" }, // 1807 - "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" }, // 1808 - "√": { "codepoints": [8730], "characters": "\u221A" }, // 1809 - "⊏": { "codepoints": [8847], "characters": "\u228F" }, // 1810 - "⊑": { "codepoints": [8849], "characters": "\u2291" }, // 1811 - "⊏": { "codepoints": [8847], "characters": "\u228F" }, // 1812 - "⊑": { "codepoints": [8849], "characters": "\u2291" }, // 1813 - "⊐": { "codepoints": [8848], "characters": "\u2290" }, // 1814 - "⊒": { "codepoints": [8850], "characters": "\u2292" }, // 1815 - "⊐": { "codepoints": [8848], "characters": "\u2290" }, // 1816 - "⊒": { "codepoints": [8850], "characters": "\u2292" }, // 1817 - "□": { "codepoints": [9633], "characters": "\u25A1" }, // 1818 - "□": { "codepoints": [9633], "characters": "\u25A1" }, // 1819 - "⊓": { "codepoints": [8851], "characters": "\u2293" }, // 1820 - "⊏": { "codepoints": [8847], "characters": "\u228F" }, // 1821 - "⊑": { "codepoints": [8849], "characters": "\u2291" }, // 1822 - "⊐": { "codepoints": [8848], "characters": "\u2290" }, // 1823 - "⊒": { "codepoints": [8850], "characters": "\u2292" }, // 1824 - "⊔": { "codepoints": [8852], "characters": "\u2294" }, // 1825 - "▪": { "codepoints": [9642], "characters": "\u25AA" }, // 1826 - "□": { "codepoints": [9633], "characters": "\u25A1" }, // 1827 - "▪": { "codepoints": [9642], "characters": "\u25AA" }, // 1828 - "→": { "codepoints": [8594], "characters": "\u2192" }, // 1829 - "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" }, // 1830 - "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" }, // 1831 - "∖": { "codepoints": [8726], "characters": "\u2216" }, // 1832 - "⌣": { "codepoints": [8995], "characters": "\u2323" }, // 1833 - "⋆": { "codepoints": [8902], "characters": "\u22C6" }, // 1834 - "⋆": { "codepoints": [8902], "characters": "\u22C6" }, // 1835 - "☆": { "codepoints": [9734], "characters": "\u2606" }, // 1836 - "★": { "codepoints": [9733], "characters": "\u2605" }, // 1837 - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, // 1838 - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, // 1839 - "¯": { "codepoints": [175], "characters": "\u00AF" }, // 1840 - "⊂": { "codepoints": [8834], "characters": "\u2282" }, // 1841 - "⋐": { "codepoints": [8912], "characters": "\u22D0" }, // 1842 - "⪽": { "codepoints": [10941], "characters": "\u2ABD" }, // 1843 - "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, // 1844 - "⊆": { "codepoints": [8838], "characters": "\u2286" }, // 1845 - "⫃": { "codepoints": [10947], "characters": "\u2AC3" }, // 1846 - "⫁": { "codepoints": [10945], "characters": "\u2AC1" }, // 1847 - "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, // 1848 - "⊊": { "codepoints": [8842], "characters": "\u228A" }, // 1849 - "⪿": { "codepoints": [10943], "characters": "\u2ABF" }, // 1850 - "⥹": { "codepoints": [10617], "characters": "\u2979" }, // 1851 - "⊂": { "codepoints": [8834], "characters": "\u2282" }, // 1852 - "⋐": { "codepoints": [8912], "characters": "\u22D0" }, // 1853 - "⊆": { "codepoints": [8838], "characters": "\u2286" }, // 1854 - "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, // 1855 - "⊆": { "codepoints": [8838], "characters": "\u2286" }, // 1856 - "⊊": { "codepoints": [8842], "characters": "\u228A" }, // 1857 - "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, // 1858 - "⫇": { "codepoints": [10951], "characters": "\u2AC7" }, // 1859 - "⫕": { "codepoints": [10965], "characters": "\u2AD5" }, // 1860 - "⫓": { "codepoints": [10963], "characters": "\u2AD3" }, // 1861 - "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, // 1862 - "≻": { "codepoints": [8827], "characters": "\u227B" }, // 1863 - "≽": { "codepoints": [8829], "characters": "\u227D" }, // 1864 - "≻": { "codepoints": [8827], "characters": "\u227B" }, // 1865 - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, // 1866 - "≽": { "codepoints": [8829], "characters": "\u227D" }, // 1867 - "≿": { "codepoints": [8831], "characters": "\u227F" }, // 1868 - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, // 1869 - "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, // 1870 - "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, // 1871 - "⋩": { "codepoints": [8937], "characters": "\u22E9" }, // 1872 - "≿": { "codepoints": [8831], "characters": "\u227F" }, // 1873 - "∋": { "codepoints": [8715], "characters": "\u220B" }, // 1874 - "∑": { "codepoints": [8721], "characters": "\u2211" }, // 1875 - "∑": { "codepoints": [8721], "characters": "\u2211" }, // 1876 - "♪": { "codepoints": [9834], "characters": "\u266A" }, // 1877 - "¹": { "codepoints": [185], "characters": "\u00B9" }, // 1878 - "¹": { "codepoints": [185], "characters": "\u00B9" }, // 1879 - "²": { "codepoints": [178], "characters": "\u00B2" }, // 1880 - "²": { "codepoints": [178], "characters": "\u00B2" }, // 1881 - "³": { "codepoints": [179], "characters": "\u00B3" }, // 1882 - "³": { "codepoints": [179], "characters": "\u00B3" }, // 1883 - "⊃": { "codepoints": [8835], "characters": "\u2283" }, // 1884 - "⋑": { "codepoints": [8913], "characters": "\u22D1" }, // 1885 - "⪾": { "codepoints": [10942], "characters": "\u2ABE" }, // 1886 - "⫘": { "codepoints": [10968], "characters": "\u2AD8" }, // 1887 - "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, // 1888 - "⊇": { "codepoints": [8839], "characters": "\u2287" }, // 1889 - "⫄": { "codepoints": [10948], "characters": "\u2AC4" }, // 1890 - "⊃": { "codepoints": [8835], "characters": "\u2283" }, // 1891 - "⊇": { "codepoints": [8839], "characters": "\u2287" }, // 1892 - "⟉": { "codepoints": [10185], "characters": "\u27C9" }, // 1893 - "⫗": { "codepoints": [10967], "characters": "\u2AD7" }, // 1894 - "⥻": { "codepoints": [10619], "characters": "\u297B" }, // 1895 - "⫂": { "codepoints": [10946], "characters": "\u2AC2" }, // 1896 - "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, // 1897 - "⊋": { "codepoints": [8843], "characters": "\u228B" }, // 1898 - "⫀": { "codepoints": [10944], "characters": "\u2AC0" }, // 1899 - "⊃": { "codepoints": [8835], "characters": "\u2283" }, // 1900 - "⋑": { "codepoints": [8913], "characters": "\u22D1" }, // 1901 - "⊇": { "codepoints": [8839], "characters": "\u2287" }, // 1902 - "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, // 1903 - "⊋": { "codepoints": [8843], "characters": "\u228B" }, // 1904 - "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, // 1905 - "⫈": { "codepoints": [10952], "characters": "\u2AC8" }, // 1906 - "⫔": { "codepoints": [10964], "characters": "\u2AD4" }, // 1907 - "⫖": { "codepoints": [10966], "characters": "\u2AD6" }, // 1908 - "⤦": { "codepoints": [10534], "characters": "\u2926" }, // 1909 - "↙": { "codepoints": [8601], "characters": "\u2199" }, // 1910 - "⇙": { "codepoints": [8665], "characters": "\u21D9" }, // 1911 - "↙": { "codepoints": [8601], "characters": "\u2199" }, // 1912 - "⤪": { "codepoints": [10538], "characters": "\u292A" }, // 1913 - "ß": { "codepoints": [223], "characters": "\u00DF" }, // 1914 - "ß": { "codepoints": [223], "characters": "\u00DF" }, // 1915 - " ": { "codepoints": [9], "characters": "\u0009" }, // 1916 - "⌖": { "codepoints": [8982], "characters": "\u2316" }, // 1917 - "Τ": { "codepoints": [932], "characters": "\u03A4" }, // 1918 - "τ": { "codepoints": [964], "characters": "\u03C4" }, // 1919 - "⎴": { "codepoints": [9140], "characters": "\u23B4" }, // 1920 - "Ť": { "codepoints": [356], "characters": "\u0164" }, // 1921 - "ť": { "codepoints": [357], "characters": "\u0165" }, // 1922 - "Ţ": { "codepoints": [354], "characters": "\u0162" }, // 1923 - "ţ": { "codepoints": [355], "characters": "\u0163" }, // 1924 - "Т": { "codepoints": [1058], "characters": "\u0422" }, // 1925 - "т": { "codepoints": [1090], "characters": "\u0442" }, // 1926 - "⃛": { "codepoints": [8411], "characters": "\u20DB" }, // 1927 - "⌕": { "codepoints": [8981], "characters": "\u2315" }, // 1928 - "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" }, // 1929 - "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" }, // 1930 - "∴": { "codepoints": [8756], "characters": "\u2234" }, // 1931 - "∴": { "codepoints": [8756], "characters": "\u2234" }, // 1932 - "∴": { "codepoints": [8756], "characters": "\u2234" }, // 1933 - "Θ": { "codepoints": [920], "characters": "\u0398" }, // 1934 - "θ": { "codepoints": [952], "characters": "\u03B8" }, // 1935 - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, // 1936 - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, // 1937 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 1938 - "∼": { "codepoints": [8764], "characters": "\u223C" }, // 1939 - "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" }, // 1940 - " ": { "codepoints": [8201], "characters": "\u2009" }, // 1941 - " ": { "codepoints": [8201], "characters": "\u2009" }, // 1942 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 1943 - "∼": { "codepoints": [8764], "characters": "\u223C" }, // 1944 - "Þ": { "codepoints": [222], "characters": "\u00DE" }, // 1945 - "Þ": { "codepoints": [222], "characters": "\u00DE" }, // 1946 - "þ": { "codepoints": [254], "characters": "\u00FE" }, // 1947 - "þ": { "codepoints": [254], "characters": "\u00FE" }, // 1948 - "˜": { "codepoints": [732], "characters": "\u02DC" }, // 1949 - "∼": { "codepoints": [8764], "characters": "\u223C" }, // 1950 - "≃": { "codepoints": [8771], "characters": "\u2243" }, // 1951 - "≅": { "codepoints": [8773], "characters": "\u2245" }, // 1952 - "≈": { "codepoints": [8776], "characters": "\u2248" }, // 1953 - "⨱": { "codepoints": [10801], "characters": "\u2A31" }, // 1954 - "⊠": { "codepoints": [8864], "characters": "\u22A0" }, // 1955 - "×": { "codepoints": [215], "characters": "\u00D7" }, // 1956 - "×": { "codepoints": [215], "characters": "\u00D7" }, // 1957 - "⨰": { "codepoints": [10800], "characters": "\u2A30" }, // 1958 - "∭": { "codepoints": [8749], "characters": "\u222D" }, // 1959 - "⤨": { "codepoints": [10536], "characters": "\u2928" }, // 1960 - "⌶": { "codepoints": [9014], "characters": "\u2336" }, // 1961 - "⫱": { "codepoints": [10993], "characters": "\u2AF1" }, // 1962 - "⊤": { "codepoints": [8868], "characters": "\u22A4" }, // 1963 - "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" }, // 1964 - "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" }, // 1965 - "⫚": { "codepoints": [10970], "characters": "\u2ADA" }, // 1966 - "⤩": { "codepoints": [10537], "characters": "\u2929" }, // 1967 - "‴": { "codepoints": [8244], "characters": "\u2034" }, // 1968 - "™": { "codepoints": [8482], "characters": "\u2122" }, // 1969 - "™": { "codepoints": [8482], "characters": "\u2122" }, // 1970 - "▵": { "codepoints": [9653], "characters": "\u25B5" }, // 1971 - "▿": { "codepoints": [9663], "characters": "\u25BF" }, // 1972 - "◃": { "codepoints": [9667], "characters": "\u25C3" }, // 1973 - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, // 1974 - "≜": { "codepoints": [8796], "characters": "\u225C" }, // 1975 - "▹": { "codepoints": [9657], "characters": "\u25B9" }, // 1976 - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, // 1977 - "◬": { "codepoints": [9708], "characters": "\u25EC" }, // 1978 - "≜": { "codepoints": [8796], "characters": "\u225C" }, // 1979 - "⨺": { "codepoints": [10810], "characters": "\u2A3A" }, // 1980 - "⃛": { "codepoints": [8411], "characters": "\u20DB" }, // 1981 - "⨹": { "codepoints": [10809], "characters": "\u2A39" }, // 1982 - "⧍": { "codepoints": [10701], "characters": "\u29CD" }, // 1983 - "⨻": { "codepoints": [10811], "characters": "\u2A3B" }, // 1984 - "⏢": { "codepoints": [9186], "characters": "\u23E2" }, // 1985 - "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" }, // 1986 - "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" }, // 1987 - "Ц": { "codepoints": [1062], "characters": "\u0426" }, // 1988 - "ц": { "codepoints": [1094], "characters": "\u0446" }, // 1989 - "Ћ": { "codepoints": [1035], "characters": "\u040B" }, // 1990 - "ћ": { "codepoints": [1115], "characters": "\u045B" }, // 1991 - "Ŧ": { "codepoints": [358], "characters": "\u0166" }, // 1992 - "ŧ": { "codepoints": [359], "characters": "\u0167" }, // 1993 - "≬": { "codepoints": [8812], "characters": "\u226C" }, // 1994 - "↞": { "codepoints": [8606], "characters": "\u219E" }, // 1995 - "↠": { "codepoints": [8608], "characters": "\u21A0" }, // 1996 - "Ú": { "codepoints": [218], "characters": "\u00DA" }, // 1997 - "Ú": { "codepoints": [218], "characters": "\u00DA" }, // 1998 - "ú": { "codepoints": [250], "characters": "\u00FA" }, // 1999 - "ú": { "codepoints": [250], "characters": "\u00FA" }, // 2000 - "↑": { "codepoints": [8593], "characters": "\u2191" }, // 2001 - "↟": { "codepoints": [8607], "characters": "\u219F" }, // 2002 - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, // 2003 - "⥉": { "codepoints": [10569], "characters": "\u2949" }, // 2004 - "Ў": { "codepoints": [1038], "characters": "\u040E" }, // 2005 - "ў": { "codepoints": [1118], "characters": "\u045E" }, // 2006 - "Ŭ": { "codepoints": [364], "characters": "\u016C" }, // 2007 - "ŭ": { "codepoints": [365], "characters": "\u016D" }, // 2008 - "Û": { "codepoints": [219], "characters": "\u00DB" }, // 2009 - "Û": { "codepoints": [219], "characters": "\u00DB" }, // 2010 - "û": { "codepoints": [251], "characters": "\u00FB" }, // 2011 - "û": { "codepoints": [251], "characters": "\u00FB" }, // 2012 - "У": { "codepoints": [1059], "characters": "\u0423" }, // 2013 - "у": { "codepoints": [1091], "characters": "\u0443" }, // 2014 - "⇅": { "codepoints": [8645], "characters": "\u21C5" }, // 2015 - "Ű": { "codepoints": [368], "characters": "\u0170" }, // 2016 - "ű": { "codepoints": [369], "characters": "\u0171" }, // 2017 - "⥮": { "codepoints": [10606], "characters": "\u296E" }, // 2018 - "⥾": { "codepoints": [10622], "characters": "\u297E" }, // 2019 - "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" }, // 2020 - "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" }, // 2021 - "Ù": { "codepoints": [217], "characters": "\u00D9" }, // 2022 - "Ù": { "codepoints": [217], "characters": "\u00D9" }, // 2023 - "ù": { "codepoints": [249], "characters": "\u00F9" }, // 2024 - "ù": { "codepoints": [249], "characters": "\u00F9" }, // 2025 - "⥣": { "codepoints": [10595], "characters": "\u2963" }, // 2026 - "↿": { "codepoints": [8639], "characters": "\u21BF" }, // 2027 - "↾": { "codepoints": [8638], "characters": "\u21BE" }, // 2028 - "▀": { "codepoints": [9600], "characters": "\u2580" }, // 2029 - "⌜": { "codepoints": [8988], "characters": "\u231C" }, // 2030 - "⌜": { "codepoints": [8988], "characters": "\u231C" }, // 2031 - "⌏": { "codepoints": [8975], "characters": "\u230F" }, // 2032 - "◸": { "codepoints": [9720], "characters": "\u25F8" }, // 2033 - "Ū": { "codepoints": [362], "characters": "\u016A" }, // 2034 - "ū": { "codepoints": [363], "characters": "\u016B" }, // 2035 - "¨": { "codepoints": [168], "characters": "\u00A8" }, // 2036 - "¨": { "codepoints": [168], "characters": "\u00A8" }, // 2037 - "_": { "codepoints": [95], "characters": "\u005F" }, // 2038 - "⏟": { "codepoints": [9183], "characters": "\u23DF" }, // 2039 - "⎵": { "codepoints": [9141], "characters": "\u23B5" }, // 2040 - "⏝": { "codepoints": [9181], "characters": "\u23DD" }, // 2041 - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, // 2042 - "⊎": { "codepoints": [8846], "characters": "\u228E" }, // 2043 - "Ų": { "codepoints": [370], "characters": "\u0172" }, // 2044 - "ų": { "codepoints": [371], "characters": "\u0173" }, // 2045 - "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" }, // 2046 - "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" }, // 2047 - "⤒": { "codepoints": [10514], "characters": "\u2912" }, // 2048 - "↑": { "codepoints": [8593], "characters": "\u2191" }, // 2049 - "↑": { "codepoints": [8593], "characters": "\u2191" }, // 2050 - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, // 2051 - "⇅": { "codepoints": [8645], "characters": "\u21C5" }, // 2052 - "↕": { "codepoints": [8597], "characters": "\u2195" }, // 2053 - "↕": { "codepoints": [8597], "characters": "\u2195" }, // 2054 - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, // 2055 - "⥮": { "codepoints": [10606], "characters": "\u296E" }, // 2056 - "↿": { "codepoints": [8639], "characters": "\u21BF" }, // 2057 - "↾": { "codepoints": [8638], "characters": "\u21BE" }, // 2058 - "⊎": { "codepoints": [8846], "characters": "\u228E" }, // 2059 - "↖": { "codepoints": [8598], "characters": "\u2196" }, // 2060 - "↗": { "codepoints": [8599], "characters": "\u2197" }, // 2061 - "υ": { "codepoints": [965], "characters": "\u03C5" }, // 2062 - "ϒ": { "codepoints": [978], "characters": "\u03D2" }, // 2063 - "ϒ": { "codepoints": [978], "characters": "\u03D2" }, // 2064 - "Υ": { "codepoints": [933], "characters": "\u03A5" }, // 2065 - "υ": { "codepoints": [965], "characters": "\u03C5" }, // 2066 - "↥": { "codepoints": [8613], "characters": "\u21A5" }, // 2067 - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, // 2068 - "⇈": { "codepoints": [8648], "characters": "\u21C8" }, // 2069 - "⌝": { "codepoints": [8989], "characters": "\u231D" }, // 2070 - "⌝": { "codepoints": [8989], "characters": "\u231D" }, // 2071 - "⌎": { "codepoints": [8974], "characters": "\u230E" }, // 2072 - "Ů": { "codepoints": [366], "characters": "\u016E" }, // 2073 - "ů": { "codepoints": [367], "characters": "\u016F" }, // 2074 - "◹": { "codepoints": [9721], "characters": "\u25F9" }, // 2075 - "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" }, // 2076 - "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" }, // 2077 - "⋰": { "codepoints": [8944], "characters": "\u22F0" }, // 2078 - "Ũ": { "codepoints": [360], "characters": "\u0168" }, // 2079 - "ũ": { "codepoints": [361], "characters": "\u0169" }, // 2080 - "▵": { "codepoints": [9653], "characters": "\u25B5" }, // 2081 - "▴": { "codepoints": [9652], "characters": "\u25B4" }, // 2082 - "⇈": { "codepoints": [8648], "characters": "\u21C8" }, // 2083 - "Ü": { "codepoints": [220], "characters": "\u00DC" }, // 2084 - "Ü": { "codepoints": [220], "characters": "\u00DC" }, // 2085 - "ü": { "codepoints": [252], "characters": "\u00FC" }, // 2086 - "ü": { "codepoints": [252], "characters": "\u00FC" }, // 2087 - "⦧": { "codepoints": [10663], "characters": "\u29A7" }, // 2088 - "⦜": { "codepoints": [10652], "characters": "\u299C" }, // 2089 - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, // 2090 - "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, // 2091 - "∅": { "codepoints": [8709], "characters": "\u2205" }, // 2092 - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, // 2093 - "ϖ": { "codepoints": [982], "characters": "\u03D6" }, // 2094 - "∝": { "codepoints": [8733], "characters": "\u221D" }, // 2095 - "↕": { "codepoints": [8597], "characters": "\u2195" }, // 2096 - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, // 2097 - "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, // 2098 - "ς": { "codepoints": [962], "characters": "\u03C2" }, // 2099 - "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, // 2100 - "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, // 2101 - "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, // 2102 - "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, // 2103 - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, // 2104 - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, // 2105 - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, // 2106 - "⫨": { "codepoints": [10984], "characters": "\u2AE8" }, // 2107 - "⫫": { "codepoints": [10987], "characters": "\u2AEB" }, // 2108 - "⫩": { "codepoints": [10985], "characters": "\u2AE9" }, // 2109 - "В": { "codepoints": [1042], "characters": "\u0412" }, // 2110 - "в": { "codepoints": [1074], "characters": "\u0432" }, // 2111 - "⊢": { "codepoints": [8866], "characters": "\u22A2" }, // 2112 - "⊨": { "codepoints": [8872], "characters": "\u22A8" }, // 2113 - "⊩": { "codepoints": [8873], "characters": "\u22A9" }, // 2114 - "⊫": { "codepoints": [8875], "characters": "\u22AB" }, // 2115 - "⫦": { "codepoints": [10982], "characters": "\u2AE6" }, // 2116 - "⊻": { "codepoints": [8891], "characters": "\u22BB" }, // 2117 - "∨": { "codepoints": [8744], "characters": "\u2228" }, // 2118 - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, // 2119 - "≚": { "codepoints": [8794], "characters": "\u225A" }, // 2120 - "⋮": { "codepoints": [8942], "characters": "\u22EE" }, // 2121 - "|": { "codepoints": [124], "characters": "\u007C" }, // 2122 - "‖": { "codepoints": [8214], "characters": "\u2016" }, // 2123 - "|": { "codepoints": [124], "characters": "\u007C" }, // 2124 - "‖": { "codepoints": [8214], "characters": "\u2016" }, // 2125 - "∣": { "codepoints": [8739], "characters": "\u2223" }, // 2126 - "|": { "codepoints": [124], "characters": "\u007C" }, // 2127 - "❘": { "codepoints": [10072], "characters": "\u2758" }, // 2128 - "≀": { "codepoints": [8768], "characters": "\u2240" }, // 2129 - " ": { "codepoints": [8202], "characters": "\u200A" }, // 2130 - "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" }, // 2131 - "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" }, // 2132 - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, // 2133 - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, // 2134 - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, // 2135 - "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" }, // 2136 - "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" }, // 2137 - "∝": { "codepoints": [8733], "characters": "\u221D" }, // 2138 - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, // 2139 - "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" }, // 2140 - "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" }, // 2141 - "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, // 2142 - "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, // 2143 - "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, // 2144 - "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, // 2145 - "⊪": { "codepoints": [8874], "characters": "\u22AA" }, // 2146 - "⦚": { "codepoints": [10650], "characters": "\u299A" }, // 2147 - "Ŵ": { "codepoints": [372], "characters": "\u0174" }, // 2148 - "ŵ": { "codepoints": [373], "characters": "\u0175" }, // 2149 - "⩟": { "codepoints": [10847], "characters": "\u2A5F" }, // 2150 - "∧": { "codepoints": [8743], "characters": "\u2227" }, // 2151 - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, // 2152 - "≙": { "codepoints": [8793], "characters": "\u2259" }, // 2153 - "℘": { "codepoints": [8472], "characters": "\u2118" }, // 2154 - "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" }, // 2155 - "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" }, // 2156 - "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" }, // 2157 - "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" }, // 2158 - "℘": { "codepoints": [8472], "characters": "\u2118" }, // 2159 - "≀": { "codepoints": [8768], "characters": "\u2240" }, // 2160 - "≀": { "codepoints": [8768], "characters": "\u2240" }, // 2161 - "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" }, // 2162 - "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" }, // 2163 - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, // 2164 - "◯": { "codepoints": [9711], "characters": "\u25EF" }, // 2165 - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, // 2166 - "▽": { "codepoints": [9661], "characters": "\u25BD" }, // 2167 - "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" }, // 2168 - "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" }, // 2169 - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, // 2170 - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, // 2171 - "Ξ": { "codepoints": [926], "characters": "\u039E" }, // 2172 - "ξ": { "codepoints": [958], "characters": "\u03BE" }, // 2173 - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, // 2174 - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, // 2175 - "⟼": { "codepoints": [10236], "characters": "\u27FC" }, // 2176 - "⋻": { "codepoints": [8955], "characters": "\u22FB" }, // 2177 - "⨀": { "codepoints": [10752], "characters": "\u2A00" }, // 2178 - "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" }, // 2179 - "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" }, // 2180 - "⨁": { "codepoints": [10753], "characters": "\u2A01" }, // 2181 - "⨂": { "codepoints": [10754], "characters": "\u2A02" }, // 2182 - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, // 2183 - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, // 2184 - "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" }, // 2185 - "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" }, // 2186 - "⨆": { "codepoints": [10758], "characters": "\u2A06" }, // 2187 - "⨄": { "codepoints": [10756], "characters": "\u2A04" }, // 2188 - "△": { "codepoints": [9651], "characters": "\u25B3" }, // 2189 - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, // 2190 - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, // 2191 - "Ý": { "codepoints": [221], "characters": "\u00DD" }, // 2192 - "Ý": { "codepoints": [221], "characters": "\u00DD" }, // 2193 - "ý": { "codepoints": [253], "characters": "\u00FD" }, // 2194 - "ý": { "codepoints": [253], "characters": "\u00FD" }, // 2195 - "Я": { "codepoints": [1071], "characters": "\u042F" }, // 2196 - "я": { "codepoints": [1103], "characters": "\u044F" }, // 2197 - "Ŷ": { "codepoints": [374], "characters": "\u0176" }, // 2198 - "ŷ": { "codepoints": [375], "characters": "\u0177" }, // 2199 - "Ы": { "codepoints": [1067], "characters": "\u042B" }, // 2200 - "ы": { "codepoints": [1099], "characters": "\u044B" }, // 2201 - "¥": { "codepoints": [165], "characters": "\u00A5" }, // 2202 - "¥": { "codepoints": [165], "characters": "\u00A5" }, // 2203 - "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" }, // 2204 - "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" }, // 2205 - "Ї": { "codepoints": [1031], "characters": "\u0407" }, // 2206 - "ї": { "codepoints": [1111], "characters": "\u0457" }, // 2207 - "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" }, // 2208 - "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" }, // 2209 - "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" }, // 2210 - "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" }, // 2211 - "Ю": { "codepoints": [1070], "characters": "\u042E" }, // 2212 - "ю": { "codepoints": [1102], "characters": "\u044E" }, // 2213 - "ÿ": { "codepoints": [255], "characters": "\u00FF" }, // 2214 - "ÿ": { "codepoints": [255], "characters": "\u00FF" }, // 2215 - "Ÿ": { "codepoints": [376], "characters": "\u0178" }, // 2216 - "Ź": { "codepoints": [377], "characters": "\u0179" }, // 2217 - "ź": { "codepoints": [378], "characters": "\u017A" }, // 2218 - "Ž": { "codepoints": [381], "characters": "\u017D" }, // 2219 - "ž": { "codepoints": [382], "characters": "\u017E" }, // 2220 - "З": { "codepoints": [1047], "characters": "\u0417" }, // 2221 - "з": { "codepoints": [1079], "characters": "\u0437" }, // 2222 - "Ż": { "codepoints": [379], "characters": "\u017B" }, // 2223 - "ż": { "codepoints": [380], "characters": "\u017C" }, // 2224 - "ℨ": { "codepoints": [8488], "characters": "\u2128" }, // 2225 - "​": { "codepoints": [8203], "characters": "\u200B" }, // 2226 - "Ζ": { "codepoints": [918], "characters": "\u0396" }, // 2227 - "ζ": { "codepoints": [950], "characters": "\u03B6" }, // 2228 - "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" }, // 2229 - "ℨ": { "codepoints": [8488], "characters": "\u2128" }, // 2230 - "Ж": { "codepoints": [1046], "characters": "\u0416" }, // 2231 - "ж": { "codepoints": [1078], "characters": "\u0436" }, // 2232 - "⇝": { "codepoints": [8669], "characters": "\u21DD" }, // 2233 - "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" }, // 2234 - "ℤ": { "codepoints": [8484], "characters": "\u2124" }, // 2235 - "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" }, // 2236 - "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" }, // 2237 - "‍": { "codepoints": [8205], "characters": "\u200D" }, // 2238 - "‌": { "codepoints": [8204], "characters": "\u200C" } // 2239 -}; // 2240 - // 2241 -var ALPHANUMERIC = /^[a-zA-Z0-9]/; // 2242 -var getPossibleNamedEntityStart = makeRegexMatcher(/^&[a-zA-Z0-9]/); // 2243 -var getApparentNamedEntity = makeRegexMatcher(/^&[a-zA-Z0-9]+;/); // 2244 - // 2245 -var getNamedEntityByFirstChar = {}; // 2246 -(function () { // 2247 - var namedEntitiesByFirstChar = {}; // 2248 - for (var ent in ENTITIES) { // 2249 - var chr = ent.charAt(1); // 2250 - namedEntitiesByFirstChar[chr] = (namedEntitiesByFirstChar[chr] || []); // 2251 - namedEntitiesByFirstChar[chr].push(ent.slice(2)); // 2252 - } // 2253 - for (var chr in namedEntitiesByFirstChar) { // 2254 - getNamedEntityByFirstChar[chr] = makeRegexMatcher( // 2255 - new RegExp('^&' + chr + '(?:' + // 2256 - namedEntitiesByFirstChar[chr].join('|') + ')')); // 2257 - } // 2258 -})(); // 2259 - // 2260 -// Run a provided "matcher" function but reset the current position afterwards. // 2261 -// Fatal failure of the matcher is not suppressed. // 2262 -var peekMatcher = function (scanner, matcher) { // 2263 - var start = scanner.pos; // 2264 - var result = matcher(scanner); // 2265 - scanner.pos = start; // 2266 - return result; // 2267 -}; // 2268 - // 2269 -// Returns a string like "&" or a falsy value if no match. Fails fatally // 2270 -// if something looks like a named entity but isn't. // 2271 -var getNamedCharRef = function (scanner, inAttribute) { // 2272 - // look for `&` followed by alphanumeric // 2273 - if (! peekMatcher(scanner, getPossibleNamedEntityStart)) // 2274 - return null; // 2275 - // 2276 - var matcher = getNamedEntityByFirstChar[scanner.rest().charAt(1)]; // 2277 - var entity = null; // 2278 - if (matcher) // 2279 - entity = peekMatcher(scanner, matcher); // 2280 - // 2281 - if (entity) { // 2282 - if (entity.slice(-1) !== ';') { // 2283 - // Certain character references with no semi are an error, like `<`. // 2284 - // In attribute values, however, this is not fatal if the next character // 2285 - // is alphanumeric. // 2286 - // // 2287 - // This rule affects href attributes, for example, deeming "/?foo=bar<c=abc" // 2288 - // to be ok but "/?foo=bar<=abc" to not be. // 2289 - if (inAttribute && ALPHANUMERIC.test(scanner.rest().charAt(entity.length))) // 2290 - return null; // 2291 - scanner.fatal("Character reference requires semicolon: " + entity); // 2292 - } else { // 2293 - scanner.pos += entity.length; // 2294 - return entity; // 2295 - } // 2296 - } else { // 2297 - // we couldn't match any real entity, so see if this is a bad entity // 2298 - // or something we can overlook. // 2299 - var badEntity = peekMatcher(scanner, getApparentNamedEntity); // 2300 - if (badEntity) // 2301 - scanner.fatal("Invalid character reference: " + badEntity); // 2302 - // `&aaaa` is ok with no semicolon // 2303 - return null; // 2304 - } // 2305 -}; // 2306 - // 2307 -// Returns the sequence of one or two codepoints making up an entity as an array. // 2308 -// Codepoints in the array are integers and may be out of the single-char JavaScript // 2309 -// range. // 2310 -var getCodePoints = function (namedEntity) { // 2311 - return ENTITIES[namedEntity].codepoints; // 2312 -}; // 2313 - // 2314 -var ALLOWED_AFTER_AMP = /^[\u0009\u000a\u000c <&]/; // 2315 - // 2316 -var getCharRefNumber = makeRegexMatcher(/^(?:[xX][0-9a-fA-F]+|[0-9]+);/); // 2317 - // 2318 -var BIG_BAD_CODEPOINTS = (function (obj) { // 2319 - var list = [0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, // 2320 - 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, // 2321 - 0x7FFFE, 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, // 2322 - 0xAFFFE, 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, // 2323 - 0xDFFFE, 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, // 2324 - 0x10FFFE, 0x10FFFF]; // 2325 - for (var i = 0; i < list.length; i++) // 2326 - obj[list[i]] = true; // 2327 - // 2328 - return obj; // 2329 -})({}); // 2330 - // 2331 -var isLegalCodepoint = function (cp) { // 2332 - if ((cp === 0) || // 2333 - (cp >= 0x80 && cp <= 0x9f) || // 2334 - (cp >= 0xd800 && cp <= 0xdfff) || // 2335 - (cp >= 0x10ffff) || // 2336 - (cp >= 0x1 && cp <= 0x8) || // 2337 - (cp === 0xb) || // 2338 - (cp >= 0xd && cp <= 0x1f) || // 2339 - (cp >= 0x7f && cp <= 0x9f) || // 2340 - (cp >= 0xfdd0 && cp <= 0xfdef) || // 2341 - (cp === 0xfffe) || // 2342 - (cp === 0xffff) || // 2343 - (cp >= 0x10000 && BIG_BAD_CODEPOINTS[cp])) // 2344 - return false; // 2345 - // 2346 - return true; // 2347 -}; // 2348 - // 2349 -// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference // 2350 -// // 2351 -// Matches a character reference if possible, including the initial `&`. // 2352 -// Fails fatally in error cases (assuming an initial `&` is matched), like a disallowed codepoint // 2353 -// number or a bad named character reference. // 2354 -// // 2355 -// `inAttribute` is truthy if we are in an attribute value. // 2356 -// // 2357 -// `allowedChar` is an optional character that, // 2358 -// if found after the initial `&`, aborts parsing silently rather than failing fatally. In real use it is // 2359 -// either `"`, `'`, or `>` and is supplied when parsing attribute values. NOTE: In the current spec, the // 2360 -// value of `allowedChar` doesn't actually seem to end up mattering, but there is still some debate about // 2361 -// the right approach to ampersands. // 2362 -getCharacterReference = HTMLTools.Parse.getCharacterReference = function (scanner, inAttribute, allowedChar) { // 2363 - if (scanner.peek() !== '&') // 2364 - // no ampersand // 2365 - return null; // 2366 - // 2367 - var afterAmp = scanner.rest().charAt(1); // 2368 - // 2369 - if (afterAmp === '#') { // 2370 - scanner.pos += 2; // 2371 - // refNumber includes possible initial `x` and final semicolon // 2372 - var refNumber = getCharRefNumber(scanner); // 2373 - // At this point we've consumed the input, so we're committed to returning // 2374 - // something or failing fatally. // 2375 - if (! refNumber) // 2376 - scanner.fatal("Invalid numerical character reference starting with &#"); // 2377 - var codepoint; // 2378 - if (refNumber.charAt(0) === 'x' || refNumber.charAt(0) === 'X') { // 2379 - // hex // 2380 - var hex = refNumber.slice(1, -1); // 2381 - while (hex.charAt(0) === '0') // 2382 - hex = hex.slice(1); // 2383 - if (hex.length > 6) // 2384 - scanner.fatal("Numerical character reference too large: 0x" + hex); // 2385 - codepoint = parseInt(hex || "0", 16); // 2386 - } else { // 2387 - var dec = refNumber.slice(0, -1); // 2388 - while (dec.charAt(0) === '0') // 2389 - dec = dec.slice(1); // 2390 - if (dec.length > 7) // 2391 - scanner.fatal("Numerical character reference too large: " + dec); // 2392 - codepoint = parseInt(dec || "0", 10); // 2393 - } // 2394 - if (! isLegalCodepoint(codepoint)) // 2395 - scanner.fatal("Illegal codepoint in numerical character reference: &#" + refNumber); // 2396 - return { t: 'CharRef', // 2397 - v: '&#' + refNumber, // 2398 - cp: [codepoint] }; // 2399 - } else if ((! afterAmp) // EOF // 2400 - || (allowedChar && afterAmp === allowedChar) // 2401 - || ALLOWED_AFTER_AMP.test(afterAmp)) { // 2402 - return null; // 2403 - } else { // 2404 - var namedEntity = getNamedCharRef(scanner, inAttribute); // 2405 - if (namedEntity) { // 2406 - return { t: 'CharRef', // 2407 - v: namedEntity, // 2408 - cp: getCodePoints(namedEntity) }; // 2409 - } else { // 2410 - return null; // 2411 - } // 2412 - } // 2413 -}; // 2414 - // 2415 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/html-tools/tokenize.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Token types: // 1 -// // 2 -// { t: 'Doctype', // 3 -// v: String (entire Doctype declaration from the source), // 4 -// name: String, // 5 -// systemId: String (optional), // 6 -// publicId: String (optional) // 7 -// } // 8 -// // 9 -// { t: 'Comment', // 10 -// v: String (not including "") // 11 -// } // 12 -// // 13 -// { t: 'Chars', // 14 -// v: String (pure text like you might pass to document.createTextNode, // 15 -// no character references) // 16 -// } // 17 -// // 18 -// { t: 'Tag', // 19 -// isEnd: Boolean (optional), // 20 -// isSelfClosing: Boolean (optional), // 21 -// n: String (tag name, in lowercase or camel case), // 22 -// attrs: dictionary of { String: [tokens] } // 23 -// OR [{ String: [tokens] }, TemplateTag tokens...] // 24 -// (only for start tags; required) // 25 -// } // 26 -// // 27 -// { t: 'CharRef', // 28 -// v: String (entire character reference from the source, e.g. "&"), // 29 -// cp: [Integer] (array of Unicode code point numbers it expands to) // 30 -// } // 31 -// // 32 -// We keep around both the original form of the character reference and its // 33 -// expansion so that subsequent processing steps have the option to // 34 -// re-emit it (if they are generating HTML) or interpret it. Named and // 35 -// numerical code points may be more than 16 bits, in which case they // 36 -// need to passed through codePointToString to make a JavaScript string. // 37 -// Most named entities and all numeric character references are one codepoint // 38 -// (e.g. "&" is [38]), but a few are two codepoints. // 39 -// // 40 -// { t: 'TemplateTag', // 41 -// v: HTMLTools.TemplateTag // 42 -// } // 43 - // 44 -// The HTML tokenization spec says to preprocess the input stream to replace // 45 -// CR(LF)? with LF. However, preprocessing `scanner` would complicate things // 46 -// by making indexes not match the input (e.g. for error messages), so we just // 47 -// keep in mind as we go along that an LF might be represented by CRLF or CR. // 48 -// In most cases, it doesn't actually matter what combination of whitespace // 49 -// characters are present (e.g. inside tags). // 50 -var HTML_SPACE = /^[\f\n\r\t ]/; // 51 - // 52 -var convertCRLF = function (str) { // 53 - return str.replace(/\r\n?/g, '\n'); // 54 -}; // 55 - // 56 -getComment = HTMLTools.Parse.getComment = function (scanner) { // 57 - if (scanner.rest().slice(0, 4) !== ''); // 69 - if (closePos < 0) // 70 - scanner.fatal("Unclosed HTML comment"); // 71 - // 72 - var commentContents = rest.slice(0, closePos); // 73 - if (commentContents.slice(-1) === '-') // 74 - scanner.fatal("HTML comment must end at first `--`"); // 75 - if (commentContents.indexOf("--") >= 0) // 76 - scanner.fatal("HTML comment cannot contain `--` anywhere"); // 77 - if (commentContents.indexOf('\u0000') >= 0) // 78 - scanner.fatal("HTML comment cannot contain NULL"); // 79 - // 80 - scanner.pos += closePos + 3; // 81 - // 82 - return { t: 'Comment', // 83 - v: convertCRLF(commentContents) }; // 84 -}; // 85 - // 86 -var skipSpaces = function (scanner) { // 87 - while (HTML_SPACE.test(scanner.peek())) // 88 - scanner.pos++; // 89 -}; // 90 - // 91 -var requireSpaces = function (scanner) { // 92 - if (! HTML_SPACE.test(scanner.peek())) // 93 - scanner.fatal("Expected space"); // 94 - skipSpaces(scanner); // 95 -}; // 96 - // 97 -var getDoctypeQuotedString = function (scanner) { // 98 - var quote = scanner.peek(); // 99 - if (! (quote === '"' || quote === "'")) // 100 - scanner.fatal("Expected single or double quote in DOCTYPE"); // 101 - scanner.pos++; // 102 - // 103 - if (scanner.peek() === quote) // 104 - // prevent a falsy return value (empty string) // 105 - scanner.fatal("Malformed DOCTYPE"); // 106 - // 107 - var str = ''; // 108 - var ch; // 109 - while ((ch = scanner.peek()), ch !== quote) { // 110 - if ((! ch) || (ch === '\u0000') || (ch === '>')) // 111 - scanner.fatal("Malformed DOCTYPE"); // 112 - str += ch; // 113 - scanner.pos++; // 114 - } // 115 - // 116 - scanner.pos++; // 117 - // 118 - return str; // 119 -}; // 120 - // 121 -// See http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#the-doctype. // 122 -// // 123 -// If `getDocType` sees "') || (ch === '\u0000')) // 134 - scanner.fatal('Malformed DOCTYPE'); // 135 - var name = ch; // 136 - scanner.pos++; // 137 - // 138 - while ((ch = scanner.peek()), ! (HTML_SPACE.test(ch) || ch === '>')) { // 139 - if ((! ch) || (ch === '\u0000')) // 140 - scanner.fatal('Malformed DOCTYPE'); // 141 - name += ch; // 142 - scanner.pos++; // 143 - } // 144 - name = HTMLTools.asciiLowerCase(name); // 145 - // 146 - // Now we're looking at a space or a `>`. // 147 - skipSpaces(scanner); // 148 - // 149 - var systemId = null; // 150 - var publicId = null; // 151 - // 152 - if (scanner.peek() !== '>') { // 153 - // Now we're essentially in the "After DOCTYPE name state" of the tokenizer, // 154 - // but we're not looking at space or `>`. // 155 - // 156 - // this should be "public" or "system". // 157 - var publicOrSystem = HTMLTools.asciiLowerCase(scanner.rest().slice(0, 6)); // 158 - // 159 - if (publicOrSystem === 'system') { // 160 - scanner.pos += 6; // 161 - requireSpaces(scanner); // 162 - systemId = getDoctypeQuotedString(scanner); // 163 - skipSpaces(scanner); // 164 - if (scanner.peek() !== '>') // 165 - scanner.fatal("Malformed DOCTYPE"); // 166 - } else if (publicOrSystem === 'public') { // 167 - scanner.pos += 6; // 168 - requireSpaces(scanner); // 169 - publicId = getDoctypeQuotedString(scanner); // 170 - if (scanner.peek() !== '>') { // 171 - requireSpaces(scanner); // 172 - if (scanner.peek() !== '>') { // 173 - systemId = getDoctypeQuotedString(scanner); // 174 - skipSpaces(scanner); // 175 - if (scanner.peek() !== '>') // 176 - scanner.fatal("Malformed DOCTYPE"); // 177 - } // 178 - } // 179 - } else { // 180 - scanner.fatal("Expected PUBLIC or SYSTEM in DOCTYPE"); // 181 - } // 182 - } // 183 - // 184 - // looking at `>` // 185 - scanner.pos++; // 186 - var result = { t: 'Doctype', // 187 - v: scanner.input.slice(start, scanner.pos), // 188 - name: name }; // 189 - // 190 - if (systemId) // 191 - result.systemId = systemId; // 192 - if (publicId) // 193 - result.publicId = publicId; // 194 - // 195 - return result; // 196 -}; // 197 - // 198 -// The special character `{` is only allowed as the first character // 199 -// of a Chars, so that we have a chance to detect template tags. // 200 -var getChars = makeRegexMatcher(/^[^&<\u0000][^&<\u0000{]*/); // 201 - // 202 -var assertIsTemplateTag = function (x) { // 203 - if (! (x instanceof HTMLTools.TemplateTag)) // 204 - throw new Error("Expected an instance of HTMLTools.TemplateTag"); // 205 - return x; // 206 -}; // 207 - // 208 -// Returns the next HTML token, or `null` if we reach EOF. // 209 -// // 210 -// Note that if we have a `getTemplateTag` function that sometimes // 211 -// consumes characters and emits nothing (e.g. in the case of template // 212 -// comments), we may go from not-at-EOF to at-EOF and return `null`, // 213 -// while otherwise we always find some token to return. // 214 -getHTMLToken = HTMLTools.Parse.getHTMLToken = function (scanner, dataMode) { // 215 - var result = null; // 216 - if (scanner.getTemplateTag) { // 217 - // Try to parse a template tag by calling out to the provided // 218 - // `getTemplateTag` function. If the function returns `null` but // 219 - // consumes characters, it must have parsed a comment or something, // 220 - // so we loop and try it again. If it ever returns `null` without // 221 - // consuming anything, that means it didn't see anything interesting // 222 - // so we look for a normal token. If it returns a truthy value, // 223 - // the value must be instanceof HTMLTools.TemplateTag. We wrap it // 224 - // in a Special token. // 225 - var lastPos = scanner.pos; // 226 - result = scanner.getTemplateTag( // 227 - scanner, // 228 - (dataMode === 'rcdata' ? TEMPLATE_TAG_POSITION.IN_RCDATA : // 229 - (dataMode === 'rawtext' ? TEMPLATE_TAG_POSITION.IN_RAWTEXT : // 230 - TEMPLATE_TAG_POSITION.ELEMENT))); // 231 - // 232 - if (result) // 233 - return { t: 'TemplateTag', v: assertIsTemplateTag(result) }; // 234 - else if (scanner.pos > lastPos) // 235 - return null; // 236 - } // 237 - // 238 - var chars = getChars(scanner); // 239 - if (chars) // 240 - return { t: 'Chars', // 241 - v: convertCRLF(chars) }; // 242 - // 243 - var ch = scanner.peek(); // 244 - if (! ch) // 245 - return null; // EOF // 246 - // 247 - if (ch === '\u0000') // 248 - scanner.fatal("Illegal NULL character"); // 249 - // 250 - if (ch === '&') { // 251 - if (dataMode !== 'rawtext') { // 252 - var charRef = getCharacterReference(scanner); // 253 - if (charRef) // 254 - return charRef; // 255 - } // 256 - // 257 - scanner.pos++; // 258 - return { t: 'Chars', // 259 - v: '&' }; // 260 - } // 261 - // 262 - // If we're here, we're looking at `<`. // 263 - // 264 - if (scanner.peek() === '<' && dataMode) { // 265 - // don't interpret tags // 266 - scanner.pos++; // 267 - return { t: 'Chars', // 268 - v: '<' }; // 269 - } // 270 - // 271 - // `getTag` will claim anything starting with `<` not followed by `!`. // 272 - // `getComment` takes `\")\n// }\n//\n// { t: 'Chars',\n// v: String (pure text like you might pass to document.createTextNode,\n// no character references)\n// }\n//\n// { t: 'Tag',\n// isEnd: Boolean (optional),\n// isSelfClosing: Boolean (optional),\n// n: String (tag name, in lowercase or camel case),\n// attrs: dictionary of { String: [tokens] }\n// OR [{ String: [tokens] }, TemplateTag tokens...]\n// (only for start tags; required)\n// }\n//\n// { t: 'CharRef',\n// v: String (entire character reference from the source, e.g. \"&\"),\n// cp: [Integer] (array of Unicode code point numbers it expands to)\n// }\n//\n// We keep around both the original form of the character reference and its\n// expansion so that subsequent processing steps have the option to\n// re-emit it (if they are generating HTML) or interpret it. Named and\n// numerical code points may be more than 16 bits, in which case they\n// need to passed through codePointToString to make a JavaScript string.\n// Most named entities and all numeric character references are one codepoint\n// (e.g. \"&\" is [38]), but a few are two codepoints.\n//\n// { t: 'TemplateTag',\n// v: HTMLTools.TemplateTag\n// }\n\n// The HTML tokenization spec says to preprocess the input stream to replace\n// CR(LF)? with LF. However, preprocessing `scanner` would complicate things\n// by making indexes not match the input (e.g. for error messages), so we just\n// keep in mind as we go along that an LF might be represented by CRLF or CR.\n// In most cases, it doesn't actually matter what combination of whitespace\n// characters are present (e.g. inside tags).\nvar HTML_SPACE = /^[\\f\\n\\r\\t ]/;\n\nvar convertCRLF = function (str) {\n return str.replace(/\\r\\n?/g, '\\n');\n};\n\ngetComment = HTMLTools.Parse.getComment = function (scanner) {\n if (scanner.rest().slice(0, 4) !== '');\n if (closePos < 0)\n scanner.fatal(\"Unclosed HTML comment\");\n\n var commentContents = rest.slice(0, closePos);\n if (commentContents.slice(-1) === '-')\n scanner.fatal(\"HTML comment must end at first `--`\");\n if (commentContents.indexOf(\"--\") >= 0)\n scanner.fatal(\"HTML comment cannot contain `--` anywhere\");\n if (commentContents.indexOf('\\u0000') >= 0)\n scanner.fatal(\"HTML comment cannot contain NULL\");\n\n scanner.pos += closePos + 3;\n\n return { t: 'Comment',\n v: convertCRLF(commentContents) };\n};\n\nvar skipSpaces = function (scanner) {\n while (HTML_SPACE.test(scanner.peek()))\n scanner.pos++;\n};\n\nvar requireSpaces = function (scanner) {\n if (! HTML_SPACE.test(scanner.peek()))\n scanner.fatal(\"Expected space\");\n skipSpaces(scanner);\n};\n\nvar getDoctypeQuotedString = function (scanner) {\n var quote = scanner.peek();\n if (! (quote === '\"' || quote === \"'\"))\n scanner.fatal(\"Expected single or double quote in DOCTYPE\");\n scanner.pos++;\n\n if (scanner.peek() === quote)\n // prevent a falsy return value (empty string)\n scanner.fatal(\"Malformed DOCTYPE\");\n\n var str = '';\n var ch;\n while ((ch = scanner.peek()), ch !== quote) {\n if ((! ch) || (ch === '\\u0000') || (ch === '>'))\n scanner.fatal(\"Malformed DOCTYPE\");\n str += ch;\n scanner.pos++;\n }\n\n scanner.pos++;\n\n return str;\n};\n\n// See http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#the-doctype.\n//\n// If `getDocType` sees \"') || (ch === '\\u0000'))\n scanner.fatal('Malformed DOCTYPE');\n var name = ch;\n scanner.pos++;\n\n while ((ch = scanner.peek()), ! (HTML_SPACE.test(ch) || ch === '>')) {\n if ((! ch) || (ch === '\\u0000'))\n scanner.fatal('Malformed DOCTYPE');\n name += ch;\n scanner.pos++;\n }\n name = HTMLTools.asciiLowerCase(name);\n\n // Now we're looking at a space or a `>`.\n skipSpaces(scanner);\n\n var systemId = null;\n var publicId = null;\n\n if (scanner.peek() !== '>') {\n // Now we're essentially in the \"After DOCTYPE name state\" of the tokenizer,\n // but we're not looking at space or `>`.\n\n // this should be \"public\" or \"system\".\n var publicOrSystem = HTMLTools.asciiLowerCase(scanner.rest().slice(0, 6));\n\n if (publicOrSystem === 'system') {\n scanner.pos += 6;\n requireSpaces(scanner);\n systemId = getDoctypeQuotedString(scanner);\n skipSpaces(scanner);\n if (scanner.peek() !== '>')\n scanner.fatal(\"Malformed DOCTYPE\");\n } else if (publicOrSystem === 'public') {\n scanner.pos += 6;\n requireSpaces(scanner);\n publicId = getDoctypeQuotedString(scanner);\n if (scanner.peek() !== '>') {\n requireSpaces(scanner);\n if (scanner.peek() !== '>') {\n systemId = getDoctypeQuotedString(scanner);\n skipSpaces(scanner);\n if (scanner.peek() !== '>')\n scanner.fatal(\"Malformed DOCTYPE\");\n }\n }\n } else {\n scanner.fatal(\"Expected PUBLIC or SYSTEM in DOCTYPE\");\n }\n }\n\n // looking at `>`\n scanner.pos++;\n var result = { t: 'Doctype',\n v: scanner.input.slice(start, scanner.pos),\n name: name };\n\n if (systemId)\n result.systemId = systemId;\n if (publicId)\n result.publicId = publicId;\n\n return result;\n};\n\n// The special character `{` is only allowed as the first character\n// of a Chars, so that we have a chance to detect template tags.\nvar getChars = makeRegexMatcher(/^[^&<\\u0000][^&<\\u0000{]*/);\n\nvar assertIsTemplateTag = function (x) {\n if (! (x instanceof HTMLTools.TemplateTag))\n throw new Error(\"Expected an instance of HTMLTools.TemplateTag\");\n return x;\n};\n\n// Returns the next HTML token, or `null` if we reach EOF.\n//\n// Note that if we have a `getTemplateTag` function that sometimes\n// consumes characters and emits nothing (e.g. in the case of template\n// comments), we may go from not-at-EOF to at-EOF and return `null`,\n// while otherwise we always find some token to return.\ngetHTMLToken = HTMLTools.Parse.getHTMLToken = function (scanner, dataMode) {\n var result = null;\n if (scanner.getTemplateTag) {\n // Try to parse a template tag by calling out to the provided\n // `getTemplateTag` function. If the function returns `null` but\n // consumes characters, it must have parsed a comment or something,\n // so we loop and try it again. If it ever returns `null` without\n // consuming anything, that means it didn't see anything interesting\n // so we look for a normal token. If it returns a truthy value,\n // the value must be instanceof HTMLTools.TemplateTag. We wrap it\n // in a Special token.\n var lastPos = scanner.pos;\n result = scanner.getTemplateTag(\n scanner,\n (dataMode === 'rcdata' ? TEMPLATE_TAG_POSITION.IN_RCDATA :\n (dataMode === 'rawtext' ? TEMPLATE_TAG_POSITION.IN_RAWTEXT :\n TEMPLATE_TAG_POSITION.ELEMENT)));\n\n if (result)\n return { t: 'TemplateTag', v: assertIsTemplateTag(result) };\n else if (scanner.pos > lastPos)\n return null;\n }\n\n var chars = getChars(scanner);\n if (chars)\n return { t: 'Chars',\n v: convertCRLF(chars) };\n\n var ch = scanner.peek();\n if (! ch)\n return null; // EOF\n\n if (ch === '\\u0000')\n scanner.fatal(\"Illegal NULL character\");\n\n if (ch === '&') {\n if (dataMode !== 'rawtext') {\n var charRef = getCharacterReference(scanner);\n if (charRef)\n return charRef;\n }\n\n scanner.pos++;\n return { t: 'Chars',\n v: '&' };\n }\n\n // If we're here, we're looking at `<`.\n\n if (scanner.peek() === '<' && dataMode) {\n // don't interpret tags\n scanner.pos++;\n return { t: 'Chars',\n v: '<' };\n }\n\n // `getTag` will claim anything starting with `<` not followed by `!`.\n // `getComment` takes `'; // 265 - }, // 266 - visitCharRef: function (charRef) { // 267 - return charRef.html; // 268 - }, // 269 - visitRaw: function (raw) { // 270 - return raw.value; // 271 - }, // 272 - visitTag: function (tag) { // 273 - var attrStrs = []; // 274 - // 275 - var tagName = tag.tagName; // 276 - var children = tag.children; // 277 - // 278 - var attrs = tag.attrs; // 279 - if (attrs) { // 280 - attrs = HTML.flattenAttributes(attrs); // 281 - for (var k in attrs) { // 282 - if (k === 'value' && tagName === 'textarea') { // 283 - children = [attrs[k], children]; // 284 - } else { // 285 - var v = this.toText(attrs[k], HTML.TEXTMODE.ATTRIBUTE); // 286 - attrStrs.push(' ' + k + '="' + v + '"'); // 287 - } // 288 - } // 289 - } // 290 - // 291 - var startTag = '<' + tagName + attrStrs.join('') + '>'; // 292 - // 293 - var childStrs = []; // 294 - var content; // 295 - if (tagName === 'textarea') { // 296 - // 297 - for (var i = 0; i < children.length; i++) // 298 - childStrs.push(this.toText(children[i], HTML.TEXTMODE.RCDATA)); // 299 - // 300 - content = childStrs.join(''); // 301 - if (content.slice(0, 1) === '\n') // 302 - // TEXTAREA will absorb a newline, so if we see one, add // 303 - // another one. // 304 - content = '\n' + content; // 305 - // 306 - } else { // 307 - for (var i = 0; i < children.length; i++) // 308 - childStrs.push(this.visit(children[i])); // 309 - // 310 - content = childStrs.join(''); // 311 - } // 312 - // 313 - var result = startTag + content; // 314 - // 315 - if (children.length || ! HTML.isVoidElement(tagName)) { // 316 - // "Void" elements like BR are the only ones that don't get a close // 317 - // tag in HTML5. They shouldn't have contents, either, so we could // 318 - // throw an error upon seeing contents here. // 319 - result += ''; // 320 - } // 321 - // 322 - return result; // 323 - }, // 324 - visitObject: function (x) { // 325 - throw new Error("Unexpected object in htmljs in toHTML: " + x); // 326 - }, // 327 - toText: function (node, textMode) { // 328 - return HTML.toText(node, textMode); // 329 - } // 330 -}); // 331 - // 332 -//////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/htmljs/html.js // -// // -//////////////////////////////////////////////////////////////////////////////////////// - // - // 1 - // 2 -HTML.Tag = function () {}; // 3 -HTML.Tag.prototype.tagName = ''; // this will be set per Tag subclass // 4 -HTML.Tag.prototype.attrs = null; // 5 -HTML.Tag.prototype.children = Object.freeze ? Object.freeze([]) : []; // 6 -HTML.Tag.prototype.htmljsType = HTML.Tag.htmljsType = ['Tag']; // 7 - // 8 -// Given "p" create the function `HTML.P`. // 9 -var makeTagConstructor = function (tagName) { // 10 - // HTMLTag is the per-tagName constructor of a HTML.Tag subclass // 11 - var HTMLTag = function (/*arguments*/) { // 12 - // Work with or without `new`. If not called with `new`, // 13 - // perform instantiation by recursively calling this constructor. // 14 - // We can't pass varargs, so pass no args. // 15 - var instance = (this instanceof HTML.Tag) ? this : new HTMLTag; // 16 - // 17 - var i = 0; // 18 - var attrs = arguments.length && arguments[0]; // 19 - if (attrs && (typeof attrs === 'object')) { // 20 - // Treat vanilla JS object as an attributes dictionary. // 21 - if (! HTML.isConstructedObject(attrs)) { // 22 - instance.attrs = attrs; // 23 - i++; // 24 - } else if (attrs instanceof HTML.Attrs) { // 25 - var array = attrs.value; // 26 - if (array.length === 1) { // 27 - instance.attrs = array[0]; // 28 - } else if (array.length > 1) { // 29 - instance.attrs = array; // 30 - } // 31 - i++; // 32 - } // 33 - } // 34 - // 35 - // 36 - // If no children, don't create an array at all, use the prototype's // 37 - // (frozen, empty) array. This way we don't create an empty array // 38 - // every time someone creates a tag without `new` and this constructor // 39 - // calls itself with no arguments (above). // 40 - if (i < arguments.length) // 41 - instance.children = SLICE.call(arguments, i); // 42 - // 43 - return instance; // 44 - }; // 45 - HTMLTag.prototype = new HTML.Tag; // 46 - HTMLTag.prototype.constructor = HTMLTag; // 47 - HTMLTag.prototype.tagName = tagName; // 48 - // 49 - return HTMLTag; // 50 -}; // 51 - // 52 -// Not an HTMLjs node, but a wrapper to pass multiple attrs dictionaries // 53 -// to a tag (for the purpose of implementing dynamic attributes). // 54 -var Attrs = HTML.Attrs = function (/*attrs dictionaries*/) { // 55 - // Work with or without `new`. If not called with `new`, // 56 - // perform instantiation by recursively calling this constructor. // 57 - // We can't pass varargs, so pass no args. // 58 - var instance = (this instanceof Attrs) ? this : new Attrs; // 59 - // 60 - instance.value = SLICE.call(arguments); // 61 - // 62 - return instance; // 63 -}; // 64 - // 65 -////////////////////////////// KNOWN ELEMENTS // 66 - // 67 -HTML.getTag = function (tagName) { // 68 - var symbolName = HTML.getSymbolName(tagName); // 69 - if (symbolName === tagName) // all-caps tagName // 70 - throw new Error("Use the lowercase or camelCase form of '" + tagName + "' here"); // 71 - // 72 - if (! HTML[symbolName]) // 73 - HTML[symbolName] = makeTagConstructor(tagName); // 74 - // 75 - return HTML[symbolName]; // 76 -}; // 77 - // 78 -HTML.ensureTag = function (tagName) { // 79 - HTML.getTag(tagName); // don't return it // 80 -}; // 81 - // 82 -HTML.isTagEnsured = function (tagName) { // 83 - return HTML.isKnownElement(tagName); // 84 -}; // 85 - // 86 -HTML.getSymbolName = function (tagName) { // 87 - // "foo-bar" -> "FOO_BAR" // 88 - return tagName.toUpperCase().replace(/-/g, '_'); // 89 -}; // 90 - // 91 -HTML.knownElementNames = 'a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption center cite code col colgroup command data datagrid datalist dd del details dfn dir div dl dt em embed eventsource fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins isindex kbd keygen label legend li link main map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr'.split(' '); -// (we add the SVG ones below) // 93 - // 94 -HTML.knownSVGElementNames = 'altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform circle clipPath color-profile cursor defs desc ellipse feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter font font-face font-face-format font-face-name font-face-src font-face-uri foreignObject g glyph glyphRef hkern image line linearGradient marker mask metadata missing-glyph path pattern polygon polyline radialGradient rect script set stop style svg switch symbol text textPath title tref tspan use view vkern'.split(' '); -// Append SVG element names to list of known element names // 96 -HTML.knownElementNames = HTML.knownElementNames.concat(HTML.knownSVGElementNames); // 97 - // 98 -HTML.voidElementNames = 'area base br col command embed hr img input keygen link meta param source track wbr'.split(' '); - // 100 -// Speed up search through lists of known elements by creating internal "sets" // 101 -// of strings. // 102 -var YES = {yes:true}; // 103 -var makeSet = function (array) { // 104 - var set = {}; // 105 - for (var i = 0; i < array.length; i++) // 106 - set[array[i]] = YES; // 107 - return set; // 108 -}; // 109 -var voidElementSet = makeSet(HTML.voidElementNames); // 110 -var knownElementSet = makeSet(HTML.knownElementNames); // 111 -var knownSVGElementSet = makeSet(HTML.knownSVGElementNames); // 112 - // 113 -HTML.isKnownElement = function (tagName) { // 114 - return knownElementSet[tagName] === YES; // 115 -}; // 116 - // 117 -HTML.isKnownSVGElement = function (tagName) { // 118 - return knownSVGElementSet[tagName] === YES; // 119 -}; // 120 - // 121 -HTML.isVoidElement = function (tagName) { // 122 - return voidElementSet[tagName] === YES; // 123 -}; // 124 - // 125 - // 126 -// Ensure tags for all known elements // 127 -for (var i = 0; i < HTML.knownElementNames.length; i++) // 128 - HTML.ensureTag(HTML.knownElementNames[i]); // 129 - // 130 - // 131 -var CharRef = HTML.CharRef = function (attrs) { // 132 - if (! (this instanceof CharRef)) // 133 - // called without `new` // 134 - return new CharRef(attrs); // 135 - // 136 - if (! (attrs && attrs.html && attrs.str)) // 137 - throw new Error( // 138 - "HTML.CharRef must be constructed with ({html:..., str:...})"); // 139 - // 140 - this.html = attrs.html; // 141 - this.str = attrs.str; // 142 -}; // 143 -CharRef.prototype.htmljsType = CharRef.htmljsType = ['CharRef']; // 144 - // 145 -var Comment = HTML.Comment = function (value) { // 146 - if (! (this instanceof Comment)) // 147 - // called without `new` // 148 - return new Comment(value); // 149 - // 150 - if (typeof value !== 'string') // 151 - throw new Error('HTML.Comment must be constructed with a string'); // 152 - // 153 - this.value = value; // 154 - // Kill illegal hyphens in comment value (no way to escape them in HTML) // 155 - this.sanitizedValue = value.replace(/^-|--+|-$/g, ''); // 156 -}; // 157 -Comment.prototype.htmljsType = Comment.htmljsType = ['Comment']; // 158 - // 159 -var Raw = HTML.Raw = function (value) { // 160 - if (! (this instanceof Raw)) // 161 - // called without `new` // 162 - return new Raw(value); // 163 - // 164 - if (typeof value !== 'string') // 165 - throw new Error('HTML.Raw must be constructed with a string'); // 166 - // 167 - this.value = value; // 168 -}; // 169 -Raw.prototype.htmljsType = Raw.htmljsType = ['Raw']; // 170 - // 171 - // 172 -HTML.isArray = function (x) { // 173 - // could change this to use the more convoluted Object.prototype.toString // 174 - // approach that works when objects are passed between frames, but does // 175 - // it matter? // 176 - return (x instanceof Array); // 177 -}; // 178 - // 179 -HTML.isConstructedObject = function (x) { // 180 - return (x && (typeof x === 'object') && // 181 - (x.constructor !== Object) && // 182 - (! Object.prototype.hasOwnProperty.call(x, 'constructor'))); // 183 -}; // 184 - // 185 -HTML.isNully = function (node) { // 186 - if (node == null) // 187 - // null or undefined // 188 - return true; // 189 - // 190 - if (HTML.isArray(node)) { // 191 - // is it an empty array or an array of all nully items? // 192 - for (var i = 0; i < node.length; i++) // 193 - if (! HTML.isNully(node[i])) // 194 - return false; // 195 - return true; // 196 - } // 197 - // 198 - return false; // 199 -}; // 200 - // 201 -HTML.isValidAttributeName = function (name) { // 202 - return /^[:_A-Za-z][:_A-Za-z0-9.\-]*/.test(name); // 203 -}; // 204 - // 205 -// If `attrs` is an array of attributes dictionaries, combines them // 206 -// into one. Removes attributes that are "nully." // 207 -HTML.flattenAttributes = function (attrs) { // 208 - if (! attrs) // 209 - return attrs; // 210 - // 211 - var isArray = HTML.isArray(attrs); // 212 - if (isArray && attrs.length === 0) // 213 - return null; // 214 - // 215 - var result = {}; // 216 - for (var i = 0, N = (isArray ? attrs.length : 1); i < N; i++) { // 217 - var oneAttrs = (isArray ? attrs[i] : attrs); // 218 - if ((typeof oneAttrs !== 'object') || // 219 - HTML.isConstructedObject(oneAttrs)) // 220 - throw new Error("Expected plain JS object as attrs, found: " + oneAttrs); // 221 - for (var name in oneAttrs) { // 222 - if (! HTML.isValidAttributeName(name)) // 223 - throw new Error("Illegal HTML attribute name: " + name); // 224 - var value = oneAttrs[name]; // 225 - if (! HTML.isNully(value)) // 226 - result[name] = value; // 227 - } // 228 - } // 229 - // 230 - return result; // 231 -}; // 232 - // 233 - // 234 - // 235 -////////////////////////////// TOHTML // 236 - // 237 -HTML.toHTML = function (content) { // 238 - return (new HTML.ToHTMLVisitor).visit(content); // 239 -}; // 240 - // 241 -// Escaping modes for outputting text when generating HTML. // 242 -HTML.TEXTMODE = { // 243 - STRING: 1, // 244 - RCDATA: 2, // 245 - ATTRIBUTE: 3 // 246 -}; // 247 - // 248 - // 249 -HTML.toText = function (content, textMode) { // 250 - if (! textMode) // 251 - throw new Error("textMode required for HTML.toText"); // 252 - if (! (textMode === HTML.TEXTMODE.STRING || // 253 - textMode === HTML.TEXTMODE.RCDATA || // 254 - textMode === HTML.TEXTMODE.ATTRIBUTE)) // 255 - throw new Error("Unknown textMode: " + textMode); // 256 - // 257 - var visitor = new HTML.ToTextVisitor({textMode: textMode});; // 258 - return visitor.visit(content); // 259 -}; // 260 - // 261 -//////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.htmljs = { - HTML: HTML -}; - -})(); - -//# sourceMappingURL=htmljs.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/htmljs.js.map b/web-app/.meteor/local/build/programs/server/packages/htmljs.js.map deleted file mode 100644 index 4cc8543..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/htmljs.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["htmljs/preamble.js","htmljs/visitors.js","htmljs/html.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,U;;AAEA,sC;AACA,8B;;;;;;;;;;;;;;;;;;;ACHA,uC;;AAEA,0D;AACA,4D;AACA,O;AACA,sD;AACA,mC;AACA,sB;AACA,qC;AACA,sB;AACA,G;AACA,a;AACA,E;;AAEA,iC;AACA,uB;AACA,E;;AAEA,uC;AACA,mC;AACA,E;;AAEA,0C;AACA,qB;AACA,4D;AACA,wC;AACA,I;AACA,kC;AACA,kC;AACA,4B;AACA,c;AACA,wC;AACA,iB;AACA,E;;AAEA,kB;AACA,sC;AACA,wB;AACA,2B;AACA,mD;;AAEA,sC;AACA,+B;AACA,qC;AACA,iC;AACA,sD;AACA,qC;AACA,0D;AACA,qC;AACA,0D;AACA,iC;AACA,sD;AACA,gB;AACA,wE;AACA,S;AACA,O;;AAEA,gC;AACA,sD;;AAEA,qD;;AAEA,+C;AACA,gD;AACA,+C;AACA,wD;;AAEA,+C;AACA,uD;AACA,K;;AAEA,+D;;AAEA,I;AACA,oD;AACA,+D;AACA,2C;AACA,+C;AACA,+C;AACA,uC;AACA,uC;AACA,wC;AACA,2D;AACA,I;AACA,0C;AACA,6D;AACA,G;AACA,G;;AAEA,iD;AACA,8B;AACA,sB;AACA,2B;AACA,yC;AACA,yC;AACA,uB;AACA,4C;AACA,6B;AACA,4B;AACA,qD;AACA,gC;AACA,gC;AACA,6B;AACA,iC;AACA,4B;AACA,O;AACA,K;AACA,kB;AACA,I;AACA,yB;AACA,yB;AACA,qB;AACA,wB;AACA,0B;AACA,qC;AACA,mC;AACA,yC;AACA,8B;AACA,+D;;AAEA,6B;AACA,2B;AACA,8D;;AAEA,6D;AACA,iB;;AAEA,mE;AACA,4B;AACA,kB;AACA,I;AACA,+C;AACA,kD;AACA,I;AACA,yE;AACA,yD;AACA,qB;AACA,8C;AACA,8B;AACA,2C;AACA,yB;AACA,8C;AACA,+B;AACA,8B;AACA,iE;AACA,kC;AACA,0B;AACA,+B;AACA,mC;AACA,8B;AACA,S;AACA,O;AACA,oB;AACA,K;;AAEA,mD;AACA,8E;AACA,0E;AACA,wD;AACA,K;;AAEA,yB;AACA,4B;AACA,mB;AACA,kC;AACA,+C;AACA,+B;AACA,mC;AACA,wB;AACA,+B;AACA,iE;AACA,oC;AACA,0B;AACA,oC;AACA,6C;AACA,iC;AACA,S;AACA,O;AACA,K;;AAEA,oB;AACA,I;AACA,0D;AACA,2B;AACA,wD;AACA,wC;AACA,oB;AACA,wC;AACA,G;AACA,G;;;AAGA,2C;AACA,wB;AACA,yC;AACA,c;AACA,I;AACA,oD;AACA,4C;AACA,iD;AACA,8D;AACA,2D;AACA,sD;AACA,gE;AACA,Y;AACA,iB;AACA,K;AACA,I;AACA,gC;AACA,mB;AACA,0C;AACA,uC;AACA,0B;AACA,I;AACA,oC;AACA,iD;AACA,I;AACA,oC;AACA,iD;AACA,oD;AACA,0B;AACA,Y;AACA,yB;AACA,K;AACA,I;AACA,4B;AACA,qB;AACA,I;AACA,4B;AACA,iE;AACA,4D;AACA,sE;AACA,kE;AACA,uE;AACA,iE;AACA,0D;AACA,wC;AACA,I;AACA,6B;AACA,mE;AACA,I;AACA,2B;AACA,6B;AACA,G;AACA,G;;;;AAIA,2C;AACA,wB;AACA,yC;AACA,c;AACA,I;AACA,oD;AACA,4C;AACA,4D;AACA,I;AACA,gC;AACA,mB;AACA,0C;AACA,uC;AACA,0B;AACA,I;AACA,oC;AACA,mD;AACA,I;AACA,oC;AACA,wB;AACA,I;AACA,4B;AACA,qB;AACA,I;AACA,4B;AACA,sB;;AAEA,8B;AACA,gC;;AAEA,0B;AACA,gB;AACA,4C;AACA,4B;AACA,sD;AACA,0C;AACA,gB;AACA,iE;AACA,kD;AACA,S;AACA,O;AACA,K;;AAEA,2D;;AAEA,uB;AACA,gB;AACA,iC;;AAEA,+C;AACA,uE;;AAEA,mC;AACA,uC;AACA,gE;AACA,uB;AACA,iC;;AAEA,Y;AACA,+C;AACA,gD;;AAEA,mC;AACA,K;;AAEA,oC;;AAEA,2D;AACA,yE;AACA,yE;AACA,kD;AACA,qC;AACA,K;;AAEA,kB;AACA,I;AACA,6B;AACA,mE;AACA,I;AACA,qC;AACA,uC;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;;;ACxUA,0B;AACA,qE;AACA,gC;AACA,qE;AACA,8D;;AAEA,0C;AACA,6C;AACA,kE;AACA,0C;AACA,6D;AACA,qE;AACA,8C;AACA,mE;;AAEA,c;AACA,iD;AACA,+C;AACA,6D;AACA,8C;AACA,+B;AACA,Y;AACA,+C;AACA,gC;AACA,iC;AACA,oC;AACA,sC;AACA,iC;AACA,S;AACA,Y;AACA,O;AACA,K;;;AAGA,wE;AACA,sE;AACA,0E;AACA,8C;AACA,6B;AACA,mD;;AAEA,oB;AACA,I;AACA,mC;AACA,0C;AACA,sC;;AAEA,iB;AACA,E;;AAEA,wE;AACA,iE;AACA,4D;AACA,2D;AACA,mE;AACA,4C;AACA,4D;;AAEA,yC;;AAEA,kB;AACA,E;;AAEA,6C;;AAEA,kC;AACA,+C;AACA,iD;AACA,qF;;AAEA,yB;AACA,mD;;AAEA,0B;AACA,E;;AAEA,qC;AACA,0C;AACA,E;;AAEA,wC;AACA,sC;AACA,E;;AAEA,yC;AACA,2B;AACA,kD;AACA,E;;AAEA,utB;AACA,8B;;AAEA,qxB;AACA,0D;AACA,kF;;AAEA,yH;;AAEA,8E;AACA,c;AACA,qB;AACA,gC;AACA,e;AACA,wC;AACA,wB;AACA,a;AACA,E;AACA,oD;AACA,sD;AACA,4D;;AAEA,0C;AACA,0C;AACA,E;;AAEA,6C;AACA,6C;AACA,E;;AAEA,yC;AACA,yC;AACA,E;;;AAGA,qC;AACA,uD;AACA,4C;;;AAGA,+C;AACA,kC;AACA,2B;AACA,8B;;AAEA,2C;AACA,oB;AACA,qE;;AAEA,yB;AACA,uB;AACA,E;AACA,gE;;AAEA,+C;AACA,kC;AACA,2B;AACA,8B;;AAEA,gC;AACA,sE;;AAEA,qB;AACA,0E;AACA,wD;AACA,E;AACA,gE;;AAEA,uC;AACA,8B;AACA,2B;AACA,0B;;AAEA,gC;AACA,kE;;AAEA,qB;AACA,E;AACA,oD;;;AAGA,6B;AACA,2E;AACA,yE;AACA,e;AACA,8B;AACA,E;;AAEA,yC;AACA,yC;AACA,uC;AACA,sE;AACA,E;;AAEA,gC;AACA,mB;AACA,wB;AACA,gB;;AAEA,2B;AACA,2D;AACA,yC;AACA,kC;AACA,qB;AACA,gB;AACA,G;;AAEA,e;AACA,E;;AAEA,6C;AACA,mD;AACA,E;;AAEA,mE;AACA,kD;AACA,2C;AACA,c;AACA,iB;;AAEA,oC;AACA,oC;AACA,gB;;AAEA,kB;AACA,iE;AACA,gD;AACA,yC;AACA,2C;AACA,+E;AACA,gC;AACA,4C;AACA,gE;AACA,iC;AACA,gC;AACA,6B;AACA,K;AACA,G;;AAEA,gB;AACA,E;;;;AAIA,qC;;AAEA,kC;AACA,iD;AACA,E;;AAEA,2D;AACA,iB;AACA,Y;AACA,Y;AACA,c;AACA,E;;;AAGA,4C;AACA,iB;AACA,yD;AACA,6C;AACA,6C;AACA,+C;AACA,qD;;AAEA,8D;AACA,gC;AACA,E","file":"/packages/htmljs.js","sourcesContent":["HTML = {};\n\nIDENTITY = function (x) { return x; };\nSLICE = Array.prototype.slice;\n","////////////////////////////// VISITORS\n\n// _assign is like _.extend or the upcoming Object.assign.\n// Copy src's own, enumerable properties onto tgt and return\n// tgt.\nvar _hasOwnProperty = Object.prototype.hasOwnProperty;\nvar _assign = function (tgt, src) {\n for (var k in src) {\n if (_hasOwnProperty.call(src, k))\n tgt[k] = src[k];\n }\n return tgt;\n};\n\nHTML.Visitor = function (props) {\n _assign(this, props);\n};\n\nHTML.Visitor.def = function (options) {\n _assign(this.prototype, options);\n};\n\nHTML.Visitor.extend = function (options) {\n var curType = this;\n var subType = function HTMLVisitorSubtype(/*arguments*/) {\n HTML.Visitor.apply(this, arguments);\n };\n subType.prototype = new curType;\n subType.extend = curType.extend;\n subType.def = curType.def;\n if (options)\n _assign(subType.prototype, options);\n return subType;\n};\n\nHTML.Visitor.def({\n visit: function (content/*, ...*/) {\n if (content == null)\n // null or undefined.\n return this.visitNull.apply(this, arguments);\n\n if (typeof content === 'object') {\n if (content.htmljsType) {\n switch (content.htmljsType) {\n case HTML.Tag.htmljsType:\n return this.visitTag.apply(this, arguments);\n case HTML.CharRef.htmljsType:\n return this.visitCharRef.apply(this, arguments);\n case HTML.Comment.htmljsType:\n return this.visitComment.apply(this, arguments);\n case HTML.Raw.htmljsType:\n return this.visitRaw.apply(this, arguments);\n default:\n throw new Error(\"Unknown htmljs type: \" + content.htmljsType);\n }\n }\n\n if (HTML.isArray(content))\n return this.visitArray.apply(this, arguments);\n\n return this.visitObject.apply(this, arguments);\n\n } else if ((typeof content === 'string') ||\n (typeof content === 'boolean') ||\n (typeof content === 'number')) {\n return this.visitPrimitive.apply(this, arguments);\n\n } else if (typeof content === 'function') {\n return this.visitFunction.apply(this, arguments);\n }\n\n throw new Error(\"Unexpected object in htmljs: \" + content);\n\n },\n visitNull: function (nullOrUndefined/*, ...*/) {},\n visitPrimitive: function (stringBooleanOrNumber/*, ...*/) {},\n visitArray: function (array/*, ...*/) {},\n visitComment: function (comment/*, ...*/) {},\n visitCharRef: function (charRef/*, ...*/) {},\n visitRaw: function (raw/*, ...*/) {},\n visitTag: function (tag/*, ...*/) {},\n visitObject: function (obj/*, ...*/) {\n throw new Error(\"Unexpected object in htmljs: \" + obj);\n },\n visitFunction: function (obj/*, ...*/) {\n throw new Error(\"Unexpected function in htmljs: \" + obj);\n }\n});\n\nHTML.TransformingVisitor = HTML.Visitor.extend();\nHTML.TransformingVisitor.def({\n visitNull: IDENTITY,\n visitPrimitive: IDENTITY,\n visitArray: function (array/*, ...*/) {\n var argsCopy = SLICE.call(arguments);\n var result = array;\n for (var i = 0; i < array.length; i++) {\n var oldItem = array[i];\n argsCopy[0] = oldItem;\n var newItem = this.visit.apply(this, argsCopy);\n if (newItem !== oldItem) {\n // copy `array` on write\n if (result === array)\n result = array.slice();\n result[i] = newItem;\n }\n }\n return result;\n },\n visitComment: IDENTITY,\n visitCharRef: IDENTITY,\n visitRaw: IDENTITY,\n visitObject: IDENTITY,\n visitFunction: IDENTITY,\n visitTag: function (tag/*, ...*/) {\n var oldChildren = tag.children;\n var argsCopy = SLICE.call(arguments);\n argsCopy[0] = oldChildren;\n var newChildren = this.visitChildren.apply(this, argsCopy);\n\n var oldAttrs = tag.attrs;\n argsCopy[0] = oldAttrs;\n var newAttrs = this.visitAttributes.apply(this, argsCopy);\n\n if (newAttrs === oldAttrs && newChildren === oldChildren)\n return tag;\n\n var newTag = HTML.getTag(tag.tagName).apply(null, newChildren);\n newTag.attrs = newAttrs;\n return newTag;\n },\n visitChildren: function (children/*, ...*/) {\n return this.visitArray.apply(this, arguments);\n },\n // Transform the `.attrs` property of a tag, which may be a dictionary,\n // an array, or in some uses, a foreign object (such as\n // a template tag).\n visitAttributes: function (attrs/*, ...*/) {\n if (HTML.isArray(attrs)) {\n var argsCopy = SLICE.call(arguments);\n var result = attrs;\n for (var i = 0; i < attrs.length; i++) {\n var oldItem = attrs[i];\n argsCopy[0] = oldItem;\n var newItem = this.visitAttributes.apply(this, argsCopy);\n if (newItem !== oldItem) {\n // copy on write\n if (result === attrs)\n result = attrs.slice();\n result[i] = newItem;\n }\n }\n return result;\n }\n\n if (attrs && HTML.isConstructedObject(attrs)) {\n throw new Error(\"The basic HTML.TransformingVisitor does not support \" +\n \"foreign objects in attributes. Define a custom \" +\n \"visitAttributes for this case.\");\n }\n\n var oldAttrs = attrs;\n var newAttrs = oldAttrs;\n if (oldAttrs) {\n var attrArgs = [null, null];\n attrArgs.push.apply(attrArgs, arguments);\n for (var k in oldAttrs) {\n var oldValue = oldAttrs[k];\n attrArgs[0] = k;\n attrArgs[1] = oldValue;\n var newValue = this.visitAttribute.apply(this, attrArgs);\n if (newValue !== oldValue) {\n // copy on write\n if (newAttrs === oldAttrs)\n newAttrs = _assign({}, oldAttrs);\n newAttrs[k] = newValue;\n }\n }\n }\n\n return newAttrs;\n },\n // Transform the value of one attribute name/value in an\n // attributes dictionary.\n visitAttribute: function (name, value, tag/*, ...*/) {\n var args = SLICE.call(arguments, 2);\n args[0] = value;\n return this.visit.apply(this, args);\n }\n});\n\n\nHTML.ToTextVisitor = HTML.Visitor.extend();\nHTML.ToTextVisitor.def({\n visitNull: function (nullOrUndefined) {\n return '';\n },\n visitPrimitive: function (stringBooleanOrNumber) {\n var str = String(stringBooleanOrNumber);\n if (this.textMode === HTML.TEXTMODE.RCDATA) {\n return str.replace(/&/g, '&').replace(/`), we hackishly support HTML tags in markdown\n // in templates by parsing them and stringifying them.\n return this.visit(this.toHTML(tag));\n },\n visitObject: function (x) {\n throw new Error(\"Unexpected object in htmljs in toText: \" + x);\n },\n toHTML: function (node) {\n return HTML.toHTML(node);\n }\n});\n\n\n\nHTML.ToHTMLVisitor = HTML.Visitor.extend();\nHTML.ToHTMLVisitor.def({\n visitNull: function (nullOrUndefined) {\n return '';\n },\n visitPrimitive: function (stringBooleanOrNumber) {\n var str = String(stringBooleanOrNumber);\n return str.replace(/&/g, '&').replace(/';\n },\n visitCharRef: function (charRef) {\n return charRef.html;\n },\n visitRaw: function (raw) {\n return raw.value;\n },\n visitTag: function (tag) {\n var attrStrs = [];\n\n var tagName = tag.tagName;\n var children = tag.children;\n\n var attrs = tag.attrs;\n if (attrs) {\n attrs = HTML.flattenAttributes(attrs);\n for (var k in attrs) {\n if (k === 'value' && tagName === 'textarea') {\n children = [attrs[k], children];\n } else {\n var v = this.toText(attrs[k], HTML.TEXTMODE.ATTRIBUTE);\n attrStrs.push(' ' + k + '=\"' + v + '\"');\n }\n }\n }\n\n var startTag = '<' + tagName + attrStrs.join('') + '>';\n\n var childStrs = [];\n var content;\n if (tagName === 'textarea') {\n\n for (var i = 0; i < children.length; i++)\n childStrs.push(this.toText(children[i], HTML.TEXTMODE.RCDATA));\n\n content = childStrs.join('');\n if (content.slice(0, 1) === '\\n')\n // TEXTAREA will absorb a newline, so if we see one, add\n // another one.\n content = '\\n' + content;\n\n } else {\n for (var i = 0; i < children.length; i++)\n childStrs.push(this.visit(children[i]));\n\n content = childStrs.join('');\n }\n\n var result = startTag + content;\n\n if (children.length || ! HTML.isVoidElement(tagName)) {\n // \"Void\" elements like BR are the only ones that don't get a close\n // tag in HTML5. They shouldn't have contents, either, so we could\n // throw an error upon seeing contents here.\n result += '';\n }\n\n return result;\n },\n visitObject: function (x) {\n throw new Error(\"Unexpected object in htmljs in toHTML: \" + x);\n },\n toText: function (node, textMode) {\n return HTML.toText(node, textMode);\n }\n});\n","\n\nHTML.Tag = function () {};\nHTML.Tag.prototype.tagName = ''; // this will be set per Tag subclass\nHTML.Tag.prototype.attrs = null;\nHTML.Tag.prototype.children = Object.freeze ? Object.freeze([]) : [];\nHTML.Tag.prototype.htmljsType = HTML.Tag.htmljsType = ['Tag'];\n\n// Given \"p\" create the function `HTML.P`.\nvar makeTagConstructor = function (tagName) {\n // HTMLTag is the per-tagName constructor of a HTML.Tag subclass\n var HTMLTag = function (/*arguments*/) {\n // Work with or without `new`. If not called with `new`,\n // perform instantiation by recursively calling this constructor.\n // We can't pass varargs, so pass no args.\n var instance = (this instanceof HTML.Tag) ? this : new HTMLTag;\n\n var i = 0;\n var attrs = arguments.length && arguments[0];\n if (attrs && (typeof attrs === 'object')) {\n // Treat vanilla JS object as an attributes dictionary.\n if (! HTML.isConstructedObject(attrs)) {\n instance.attrs = attrs;\n i++;\n } else if (attrs instanceof HTML.Attrs) {\n var array = attrs.value;\n if (array.length === 1) {\n instance.attrs = array[0];\n } else if (array.length > 1) {\n instance.attrs = array;\n }\n i++;\n }\n }\n\n\n // If no children, don't create an array at all, use the prototype's\n // (frozen, empty) array. This way we don't create an empty array\n // every time someone creates a tag without `new` and this constructor\n // calls itself with no arguments (above).\n if (i < arguments.length)\n instance.children = SLICE.call(arguments, i);\n\n return instance;\n };\n HTMLTag.prototype = new HTML.Tag;\n HTMLTag.prototype.constructor = HTMLTag;\n HTMLTag.prototype.tagName = tagName;\n\n return HTMLTag;\n};\n\n// Not an HTMLjs node, but a wrapper to pass multiple attrs dictionaries\n// to a tag (for the purpose of implementing dynamic attributes).\nvar Attrs = HTML.Attrs = function (/*attrs dictionaries*/) {\n // Work with or without `new`. If not called with `new`,\n // perform instantiation by recursively calling this constructor.\n // We can't pass varargs, so pass no args.\n var instance = (this instanceof Attrs) ? this : new Attrs;\n\n instance.value = SLICE.call(arguments);\n\n return instance;\n};\n\n////////////////////////////// KNOWN ELEMENTS\n\nHTML.getTag = function (tagName) {\n var symbolName = HTML.getSymbolName(tagName);\n if (symbolName === tagName) // all-caps tagName\n throw new Error(\"Use the lowercase or camelCase form of '\" + tagName + \"' here\");\n\n if (! HTML[symbolName])\n HTML[symbolName] = makeTagConstructor(tagName);\n\n return HTML[symbolName];\n};\n\nHTML.ensureTag = function (tagName) {\n HTML.getTag(tagName); // don't return it\n};\n\nHTML.isTagEnsured = function (tagName) {\n return HTML.isKnownElement(tagName);\n};\n\nHTML.getSymbolName = function (tagName) {\n // \"foo-bar\" -> \"FOO_BAR\"\n return tagName.toUpperCase().replace(/-/g, '_');\n};\n\nHTML.knownElementNames = 'a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption center cite code col colgroup command data datagrid datalist dd del details dfn dir div dl dt em embed eventsource fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins isindex kbd keygen label legend li link main map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr'.split(' ');\n// (we add the SVG ones below)\n\nHTML.knownSVGElementNames = 'altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform circle clipPath color-profile cursor defs desc ellipse feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter font font-face font-face-format font-face-name font-face-src font-face-uri foreignObject g glyph glyphRef hkern image line linearGradient marker mask metadata missing-glyph path pattern polygon polyline radialGradient rect script set stop style svg switch symbol text textPath title tref tspan use view vkern'.split(' ');\n// Append SVG element names to list of known element names\nHTML.knownElementNames = HTML.knownElementNames.concat(HTML.knownSVGElementNames);\n\nHTML.voidElementNames = 'area base br col command embed hr img input keygen link meta param source track wbr'.split(' ');\n\n// Speed up search through lists of known elements by creating internal \"sets\"\n// of strings.\nvar YES = {yes:true};\nvar makeSet = function (array) {\n var set = {};\n for (var i = 0; i < array.length; i++)\n set[array[i]] = YES;\n return set;\n};\nvar voidElementSet = makeSet(HTML.voidElementNames);\nvar knownElementSet = makeSet(HTML.knownElementNames);\nvar knownSVGElementSet = makeSet(HTML.knownSVGElementNames);\n\nHTML.isKnownElement = function (tagName) {\n return knownElementSet[tagName] === YES;\n};\n\nHTML.isKnownSVGElement = function (tagName) {\n return knownSVGElementSet[tagName] === YES;\n};\n\nHTML.isVoidElement = function (tagName) {\n return voidElementSet[tagName] === YES;\n};\n\n\n// Ensure tags for all known elements\nfor (var i = 0; i < HTML.knownElementNames.length; i++)\n HTML.ensureTag(HTML.knownElementNames[i]);\n\n\nvar CharRef = HTML.CharRef = function (attrs) {\n if (! (this instanceof CharRef))\n // called without `new`\n return new CharRef(attrs);\n\n if (! (attrs && attrs.html && attrs.str))\n throw new Error(\n \"HTML.CharRef must be constructed with ({html:..., str:...})\");\n\n this.html = attrs.html;\n this.str = attrs.str;\n};\nCharRef.prototype.htmljsType = CharRef.htmljsType = ['CharRef'];\n\nvar Comment = HTML.Comment = function (value) {\n if (! (this instanceof Comment))\n // called without `new`\n return new Comment(value);\n\n if (typeof value !== 'string')\n throw new Error('HTML.Comment must be constructed with a string');\n\n this.value = value;\n // Kill illegal hyphens in comment value (no way to escape them in HTML)\n this.sanitizedValue = value.replace(/^-|--+|-$/g, '');\n};\nComment.prototype.htmljsType = Comment.htmljsType = ['Comment'];\n\nvar Raw = HTML.Raw = function (value) {\n if (! (this instanceof Raw))\n // called without `new`\n return new Raw(value);\n\n if (typeof value !== 'string')\n throw new Error('HTML.Raw must be constructed with a string');\n\n this.value = value;\n};\nRaw.prototype.htmljsType = Raw.htmljsType = ['Raw'];\n\n\nHTML.isArray = function (x) {\n // could change this to use the more convoluted Object.prototype.toString\n // approach that works when objects are passed between frames, but does\n // it matter?\n return (x instanceof Array);\n};\n\nHTML.isConstructedObject = function (x) {\n return (x && (typeof x === 'object') &&\n (x.constructor !== Object) &&\n (! Object.prototype.hasOwnProperty.call(x, 'constructor')));\n};\n\nHTML.isNully = function (node) {\n if (node == null)\n // null or undefined\n return true;\n\n if (HTML.isArray(node)) {\n // is it an empty array or an array of all nully items?\n for (var i = 0; i < node.length; i++)\n if (! HTML.isNully(node[i]))\n return false;\n return true;\n }\n\n return false;\n};\n\nHTML.isValidAttributeName = function (name) {\n return /^[:_A-Za-z][:_A-Za-z0-9.\\-]*/.test(name);\n};\n\n// If `attrs` is an array of attributes dictionaries, combines them\n// into one. Removes attributes that are \"nully.\"\nHTML.flattenAttributes = function (attrs) {\n if (! attrs)\n return attrs;\n\n var isArray = HTML.isArray(attrs);\n if (isArray && attrs.length === 0)\n return null;\n\n var result = {};\n for (var i = 0, N = (isArray ? attrs.length : 1); i < N; i++) {\n var oneAttrs = (isArray ? attrs[i] : attrs);\n if ((typeof oneAttrs !== 'object') ||\n HTML.isConstructedObject(oneAttrs))\n throw new Error(\"Expected plain JS object as attrs, found: \" + oneAttrs);\n for (var name in oneAttrs) {\n if (! HTML.isValidAttributeName(name))\n throw new Error(\"Illegal HTML attribute name: \" + name);\n var value = oneAttrs[name];\n if (! HTML.isNully(value))\n result[name] = value;\n }\n }\n\n return result;\n};\n\n\n\n////////////////////////////// TOHTML\n\nHTML.toHTML = function (content) {\n return (new HTML.ToHTMLVisitor).visit(content);\n};\n\n// Escaping modes for outputting text when generating HTML.\nHTML.TEXTMODE = {\n STRING: 1,\n RCDATA: 2,\n ATTRIBUTE: 3\n};\n\n\nHTML.toText = function (content, textMode) {\n if (! textMode)\n throw new Error(\"textMode required for HTML.toText\");\n if (! (textMode === HTML.TEXTMODE.STRING ||\n textMode === HTML.TEXTMODE.RCDATA ||\n textMode === HTML.TEXTMODE.ATTRIBUTE))\n throw new Error(\"Unknown textMode: \" + textMode);\n\n var visitor = new HTML.ToTextVisitor({textMode: textMode});;\n return visitor.visit(content);\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/id-map.js b/web-app/.meteor/local/build/programs/server/packages/id-map.js deleted file mode 100644 index 1824ba6..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/id-map.js +++ /dev/null @@ -1,110 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var EJSON = Package.ejson.EJSON; - -/* Package-scope variables */ -var IdMap; - -(function () { - -//////////////////////////////////////////////////////////////////////////////// -// // -// packages/id-map/id-map.js // -// // -//////////////////////////////////////////////////////////////////////////////// - // -IdMap = function (idStringify, idParse) { // 1 - var self = this; // 2 - self._map = {}; // 3 - self._idStringify = idStringify || JSON.stringify; // 4 - self._idParse = idParse || JSON.parse; // 5 -}; // 6 - // 7 -// Some of these methods are designed to match methods on OrderedDict, since // 8 -// (eg) ObserveMultiplex and _CachingChangeObserver use them interchangeably. // 9 -// (Conceivably, this should be replaced with "UnorderedDict" with a specific // 10 -// set of methods that overlap between the two.) // 11 - // 12 -_.extend(IdMap.prototype, { // 13 - get: function (id) { // 14 - var self = this; // 15 - var key = self._idStringify(id); // 16 - return self._map[key]; // 17 - }, // 18 - set: function (id, value) { // 19 - var self = this; // 20 - var key = self._idStringify(id); // 21 - self._map[key] = value; // 22 - }, // 23 - remove: function (id) { // 24 - var self = this; // 25 - var key = self._idStringify(id); // 26 - delete self._map[key]; // 27 - }, // 28 - has: function (id) { // 29 - var self = this; // 30 - var key = self._idStringify(id); // 31 - return _.has(self._map, key); // 32 - }, // 33 - empty: function () { // 34 - var self = this; // 35 - return _.isEmpty(self._map); // 36 - }, // 37 - clear: function () { // 38 - var self = this; // 39 - self._map = {}; // 40 - }, // 41 - // Iterates over the items in the map. Return `false` to break the loop. // 42 - forEach: function (iterator) { // 43 - var self = this; // 44 - // don't use _.each, because we can't break out of it. // 45 - var keys = _.keys(self._map); // 46 - for (var i = 0; i < keys.length; i++) { // 47 - var breakIfFalse = iterator.call(null, self._map[keys[i]], // 48 - self._idParse(keys[i])); // 49 - if (breakIfFalse === false) // 50 - return; // 51 - } // 52 - }, // 53 - size: function () { // 54 - var self = this; // 55 - return _.size(self._map); // 56 - }, // 57 - setDefault: function (id, def) { // 58 - var self = this; // 59 - var key = self._idStringify(id); // 60 - if (_.has(self._map, key)) // 61 - return self._map[key]; // 62 - self._map[key] = def; // 63 - return def; // 64 - }, // 65 - // Assumes that values are EJSON-cloneable, and that we don't need to clone // 66 - // IDs (ie, that nobody is going to mutate an ObjectId). // 67 - clone: function () { // 68 - var self = this; // 69 - var clone = new IdMap(self._idStringify, self._idParse); // 70 - self.forEach(function (value, id) { // 71 - clone.set(id, EJSON.clone(value)); // 72 - }); // 73 - return clone; // 74 - } // 75 -}); // 76 - // 77 - // 78 -//////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['id-map'] = { - IdMap: IdMap -}; - -})(); - -//# sourceMappingURL=id-map.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/id-map.js.map b/web-app/.meteor/local/build/programs/server/packages/id-map.js.map deleted file mode 100644 index f19b0cc..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/id-map.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["id-map/id-map.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,yC;AACA,kB;AACA,iB;AACA,oD;AACA,wC;AACA,E;;AAEA,4E;AACA,6E;AACA,6E;AACA,gD;;AAEA,2B;AACA,sB;AACA,oB;AACA,oC;AACA,0B;AACA,I;AACA,6B;AACA,oB;AACA,oC;AACA,2B;AACA,I;AACA,yB;AACA,oB;AACA,oC;AACA,0B;AACA,I;AACA,sB;AACA,oB;AACA,oC;AACA,iC;AACA,I;AACA,sB;AACA,oB;AACA,gC;AACA,I;AACA,sB;AACA,oB;AACA,mB;AACA,I;AACA,0E;AACA,gC;AACA,oB;AACA,0D;AACA,iC;AACA,2C;AACA,gE;AACA,+D;AACA,iC;AACA,e;AACA,K;AACA,I;AACA,qB;AACA,oB;AACA,6B;AACA,I;AACA,kC;AACA,oB;AACA,oC;AACA,8B;AACA,4B;AACA,yB;AACA,e;AACA,I;AACA,6E;AACA,0D;AACA,sB;AACA,oB;AACA,4D;AACA,uC;AACA,wC;AACA,O;AACA,iB;AACA,G;AACA,G","file":"/packages/id-map.js","sourcesContent":["IdMap = function (idStringify, idParse) {\n var self = this;\n self._map = {};\n self._idStringify = idStringify || JSON.stringify;\n self._idParse = idParse || JSON.parse;\n};\n\n// Some of these methods are designed to match methods on OrderedDict, since\n// (eg) ObserveMultiplex and _CachingChangeObserver use them interchangeably.\n// (Conceivably, this should be replaced with \"UnorderedDict\" with a specific\n// set of methods that overlap between the two.)\n\n_.extend(IdMap.prototype, {\n get: function (id) {\n var self = this;\n var key = self._idStringify(id);\n return self._map[key];\n },\n set: function (id, value) {\n var self = this;\n var key = self._idStringify(id);\n self._map[key] = value;\n },\n remove: function (id) {\n var self = this;\n var key = self._idStringify(id);\n delete self._map[key];\n },\n has: function (id) {\n var self = this;\n var key = self._idStringify(id);\n return _.has(self._map, key);\n },\n empty: function () {\n var self = this;\n return _.isEmpty(self._map);\n },\n clear: function () {\n var self = this;\n self._map = {};\n },\n // Iterates over the items in the map. Return `false` to break the loop.\n forEach: function (iterator) {\n var self = this;\n // don't use _.each, because we can't break out of it.\n var keys = _.keys(self._map);\n for (var i = 0; i < keys.length; i++) {\n var breakIfFalse = iterator.call(null, self._map[keys[i]],\n self._idParse(keys[i]));\n if (breakIfFalse === false)\n return;\n }\n },\n size: function () {\n var self = this;\n return _.size(self._map);\n },\n setDefault: function (id, def) {\n var self = this;\n var key = self._idStringify(id);\n if (_.has(self._map, key))\n return self._map[key];\n self._map[key] = def;\n return def;\n },\n // Assumes that values are EJSON-cloneable, and that we don't need to clone\n // IDs (ie, that nobody is going to mutate an ObjectId).\n clone: function () {\n var self = this;\n var clone = new IdMap(self._idStringify, self._idParse);\n self.forEach(function (value, id) {\n clone.set(id, EJSON.clone(value));\n });\n return clone;\n }\n});\n\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/insecure.js b/web-app/.meteor/local/build/programs/server/packages/insecure.js deleted file mode 100644 index 6de6589..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/insecure.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.insecure = {}; - -})(); - -//# sourceMappingURL=insecure.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/insecure.js.map b/web-app/.meteor/local/build/programs/server/packages/insecure.js.map deleted file mode 100644 index 43a5d73..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/insecure.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/insecure.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/jquery.js b/web-app/.meteor/local/build/programs/server/packages/jquery.js deleted file mode 100644 index 53c857b..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/jquery.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.jquery = {}; - -})(); - -//# sourceMappingURL=jquery.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/jquery.js.map b/web-app/.meteor/local/build/programs/server/packages/jquery.js.map deleted file mode 100644 index 836bfe9..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/jquery.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/jquery.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/json.js b/web-app/.meteor/local/build/programs/server/packages/json.js deleted file mode 100644 index c3e6ca4..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/json.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.json = {}; - -})(); - -//# sourceMappingURL=json.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/json.js.map b/web-app/.meteor/local/build/programs/server/packages/json.js.map deleted file mode 100644 index 667dff1..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/json.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/json.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/livedata.js b/web-app/.meteor/local/build/programs/server/packages/livedata.js deleted file mode 100644 index c4a848e..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/livedata.js +++ /dev/null @@ -1,23 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var DDP = Package.ddp.DDP; -var DDPServer = Package.ddp.DDPServer; - -/* Package-scope variables */ -var DDP, DDPServer, LivedataTest; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.livedata = { - DDP: DDP, - DDPServer: DDPServer, - LivedataTest: LivedataTest -}; - -})(); - -//# sourceMappingURL=livedata.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/livedata.js.map b/web-app/.meteor/local/build/programs/server/packages/livedata.js.map deleted file mode 100644 index e7a872f..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/livedata.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;;;;;;","file":"/packages/livedata.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/logging.js b/web-app/.meteor/local/build/programs/server/packages/logging.js deleted file mode 100644 index 62caca2..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/logging.js +++ /dev/null @@ -1,309 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var EJSON = Package.ejson.EJSON; - -/* Package-scope variables */ -var Log; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/logging/logging.js // -// // -///////////////////////////////////////////////////////////////////////////////////////// - // -Log = function () { // 1 - return Log.info.apply(this, arguments); // 2 -}; // 3 - // 4 -/// FOR TESTING // 5 -var intercept = 0; // 6 -var interceptedLines = []; // 7 -var suppress = 0; // 8 - // 9 -// Intercept the next 'count' calls to a Log function. The actual // 10 -// lines printed to the console can be cleared and read by calling // 11 -// Log._intercepted(). // 12 -Log._intercept = function (count) { // 13 - intercept += count; // 14 -}; // 15 - // 16 -// Suppress the next 'count' calls to a Log function. Use this to stop // 17 -// tests from spamming the console, especially with red errors that // 18 -// might look like a failing test. // 19 -Log._suppress = function (count) { // 20 - suppress += count; // 21 -}; // 22 - // 23 -// Returns intercepted lines and resets the intercept counter. // 24 -Log._intercepted = function () { // 25 - var lines = interceptedLines; // 26 - interceptedLines = []; // 27 - intercept = 0; // 28 - return lines; // 29 -}; // 30 - // 31 -// Either 'json' or 'colored-text'. // 32 -// // 33 -// When this is set to 'json', print JSON documents that are parsed by another // 34 -// process ('satellite' or 'meteor run'). This other process should call // 35 -// 'Log.format' for nice output. // 36 -// // 37 -// When this is set to 'colored-text', call 'Log.format' before printing. // 38 -// This should be used for logging from within satellite, since there is no // 39 -// other process that will be reading its standard output. // 40 -Log.outputFormat = 'json'; // 41 - // 42 -var LEVEL_COLORS = { // 43 - debug: 'green', // 44 - // leave info as the default color // 45 - warn: 'magenta', // 46 - error: 'red' // 47 -}; // 48 - // 49 -var META_COLOR = 'blue'; // 50 - // 51 -// XXX package // 52 -var RESTRICTED_KEYS = ['time', 'timeInexact', 'level', 'file', 'line', // 53 - 'program', 'originApp', 'satellite', 'stderr']; // 54 - // 55 -var FORMATTED_KEYS = RESTRICTED_KEYS.concat(['app', 'message']); // 56 - // 57 -var logInBrowser = function (obj) { // 58 - var str = Log.format(obj); // 59 - // 60 - // XXX Some levels should be probably be sent to the server // 61 - var level = obj.level; // 62 - // 63 - if ((typeof console !== 'undefined') && console[level]) { // 64 - console[level](str); // 65 - } else { // 66 - // XXX Uses of Meteor._debug should probably be replaced by Log.debug or // 67 - // Log.info, and we should have another name for "do your best to // 68 - // call call console.log". // 69 - Meteor._debug(str); // 70 - } // 71 -}; // 72 - // 73 -// @returns {Object: { line: Number, file: String }} // 74 -Log._getCallerDetails = function () { // 75 - var getStack = function () { // 76 - // We do NOT use Error.prepareStackTrace here (a V8 extension that gets us a // 77 - // pre-parsed stack) since it's impossible to compose it with the use of // 78 - // Error.prepareStackTrace used on the server for source maps. // 79 - var err = new Error; // 80 - var stack = err.stack; // 81 - return stack; // 82 - }; // 83 - // 84 - var stack = getStack(); // 85 - // 86 - if (!stack) return {}; // 87 - // 88 - var lines = stack.split('\n'); // 89 - // 90 - // looking for the first line outside the logging package (or an // 91 - // eval if we find that first) // 92 - var line; // 93 - for (var i = 1; i < lines.length; ++i) { // 94 - line = lines[i]; // 95 - if (line.match(/^\s*at eval \(eval/)) { // 96 - return {file: "eval"}; // 97 - } // 98 - // 99 - if (!line.match(/packages\/(?:local-test:)?logging(?:\/|\.js)/)) // 100 - break; // 101 - } // 102 - // 103 - var details = {}; // 104 - // 105 - // The format for FF is 'functionName@filePath:lineNumber' // 106 - // The format for V8 is 'functionName (packages/logging/logging.js:81)' or // 107 - // 'packages/logging/logging.js:81' // 108 - var match = /(?:[@(]| at )([^(]+?):([0-9:]+)(?:\)|$)/.exec(line); // 109 - if (!match) // 110 - return details; // 111 - // in case the matched block here is line:column // 112 - details.line = match[2].split(':')[0]; // 113 - // 114 - // Possible format: https://foo.bar.com/scripts/file.js?random=foobar // 115 - // XXX: if you can write the following in better way, please do it // 116 - // XXX: what about evals? // 117 - details.file = match[1].split('/').slice(-1)[0].split('?')[0]; // 118 - // 119 - return details; // 120 -}; // 121 - // 122 -_.each(['debug', 'info', 'warn', 'error'], function (level) { // 123 - // @param arg {String|Object} // 124 - Log[level] = function (arg) { // 125 - if (suppress) { // 126 - suppress--; // 127 - return; // 128 - } // 129 - // 130 - var intercepted = false; // 131 - if (intercept) { // 132 - intercept--; // 133 - intercepted = true; // 134 - } // 135 - // 136 - var obj = (_.isObject(arg) && !_.isRegExp(arg) && !_.isDate(arg) ) ? // 137 - arg : {message: new String(arg).toString() }; // 138 - // 139 - _.each(RESTRICTED_KEYS, function (key) { // 140 - if (obj[key]) // 141 - throw new Error("Can't set '" + key + "' in log message"); // 142 - }); // 143 - // 144 - if (_.has(obj, 'message') && !_.isString(obj.message)) // 145 - throw new Error("The 'message' field in log objects must be a string"); // 146 - if (!obj.omitCallerDetails) // 147 - obj = _.extend(Log._getCallerDetails(), obj); // 148 - obj.time = new Date(); // 149 - obj.level = level; // 150 - // 151 - // XXX allow you to enable 'debug', probably per-package // 152 - if (level === 'debug') // 153 - return; // 154 - // 155 - if (intercepted) { // 156 - interceptedLines.push(EJSON.stringify(obj)); // 157 - } else if (Meteor.isServer) { // 158 - if (Log.outputFormat === 'colored-text') { // 159 - console.log(Log.format(obj, {color: true})); // 160 - } else if (Log.outputFormat === 'json') { // 161 - console.log(EJSON.stringify(obj)); // 162 - } else { // 163 - throw new Error("Unknown logging output format: " + Log.outputFormat); // 164 - } // 165 - } else { // 166 - logInBrowser(obj); // 167 - } // 168 - }; // 169 -}); // 170 - // 171 -// tries to parse line as EJSON. returns object if parse is successful, or null if not // 172 -Log.parse = function (line) { // 173 - var obj = null; // 174 - if (line && line.charAt(0) === '{') { // might be json generated from calling 'Log' // 175 - try { obj = EJSON.parse(line); } catch (e) {} // 176 - } // 177 - // 178 - // XXX should probably check fields other than 'time' // 179 - if (obj && obj.time && (obj.time instanceof Date)) // 180 - return obj; // 181 - else // 182 - return null; // 183 -}; // 184 - // 185 -// formats a log object into colored human and machine-readable text // 186 -Log.format = function (obj, options) { // 187 - obj = EJSON.clone(obj); // don't mutate the argument // 188 - options = options || {}; // 189 - // 190 - var time = obj.time; // 191 - if (!(time instanceof Date)) // 192 - throw new Error("'time' must be a Date object"); // 193 - var timeInexact = obj.timeInexact; // 194 - // 195 - // store fields that are in FORMATTED_KEYS since we strip them // 196 - var level = obj.level || 'info'; // 197 - var file = obj.file; // 198 - var lineNumber = obj.line; // 199 - var appName = obj.app || ''; // 200 - var originApp = obj.originApp; // 201 - var message = obj.message || ''; // 202 - var program = obj.program || ''; // 203 - var satellite = obj.satellite; // 204 - var stderr = obj.stderr || ''; // 205 - // 206 - _.each(FORMATTED_KEYS, function(key) { // 207 - delete obj[key]; // 208 - }); // 209 - // 210 - if (!_.isEmpty(obj)) { // 211 - if (message) message += " "; // 212 - message += EJSON.stringify(obj); // 213 - } // 214 - // 215 - var pad2 = function(n) { return n < 10 ? '0' + n : n.toString(); }; // 216 - var pad3 = function(n) { return n < 100 ? '0' + pad2(n) : n.toString(); }; // 217 - // 218 - var dateStamp = time.getFullYear().toString() + // 219 - pad2(time.getMonth() + 1 /*0-based*/) + // 220 - pad2(time.getDate()); // 221 - var timeStamp = pad2(time.getHours()) + // 222 - ':' + // 223 - pad2(time.getMinutes()) + // 224 - ':' + // 225 - pad2(time.getSeconds()) + // 226 - '.' + // 227 - pad3(time.getMilliseconds()); // 228 - // 229 - // eg in San Francisco in June this will be '(-7)' // 230 - var utcOffsetStr = '(' + (-(new Date().getTimezoneOffset() / 60)) + ')'; // 231 - // 232 - var appInfo = ''; // 233 - if (appName) appInfo += appName; // 234 - if (originApp && originApp !== appName) appInfo += ' via ' + originApp; // 235 - if (appInfo) appInfo = '[' + appInfo + '] '; // 236 - // 237 - var sourceInfoParts = []; // 238 - if (program) sourceInfoParts.push(program); // 239 - if (file) sourceInfoParts.push(file); // 240 - if (lineNumber) sourceInfoParts.push(lineNumber); // 241 - var sourceInfo = _.isEmpty(sourceInfoParts) ? // 242 - '' : '(' + sourceInfoParts.join(':') + ') '; // 243 - // 244 - if (satellite) // 245 - sourceInfo += ['[', satellite, ']'].join(''); // 246 - // 247 - var stderrIndicator = stderr ? '(STDERR) ' : ''; // 248 - // 249 - var metaPrefix = [ // 250 - level.charAt(0).toUpperCase(), // 251 - dateStamp, // 252 - '-', // 253 - timeStamp, // 254 - utcOffsetStr, // 255 - timeInexact ? '? ' : ' ', // 256 - appInfo, // 257 - sourceInfo, // 258 - stderrIndicator].join(''); // 259 - // 260 - var prettify = function (line, color) { // 261 - return (options.color && Meteor.isServer && color) ? // 262 - Npm.require('cli-color')[color](line) : line; // 263 - }; // 264 - // 265 - return prettify(metaPrefix, options.metaColor || META_COLOR) + // 266 - prettify(message, LEVEL_COLORS[level]); // 267 -}; // 268 - // 269 -// Turn a line of text into a loggable object. // 270 -// @param line {String} // 271 -// @param override {Object} // 272 -Log.objFromText = function (line, override) { // 273 - var obj = {message: line, level: "info", time: new Date(), timeInexact: true}; // 274 - return _.extend(obj, override); // 275 -}; // 276 - // 277 -///////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.logging = { - Log: Log -}; - -})(); - -//# sourceMappingURL=logging.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/logging.js.map b/web-app/.meteor/local/build/programs/server/packages/logging.js.map deleted file mode 100644 index 7f8f783..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/logging.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["logging/logging.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,mB;AACA,yC;AACA,E;;AAEA,e;AACA,kB;AACA,0B;AACA,iB;;AAEA,iE;AACA,kE;AACA,sB;AACA,mC;AACA,qB;AACA,E;;AAEA,sE;AACA,mE;AACA,kC;AACA,kC;AACA,oB;AACA,E;;AAEA,8D;AACA,gC;AACA,+B;AACA,wB;AACA,gB;AACA,e;AACA,E;;AAEA,mC;AACA,E;AACA,8E;AACA,wE;AACA,gC;AACA,E;AACA,yE;AACA,2E;AACA,0D;AACA,0B;;AAEA,oB;AACA,iB;AACA,oC;AACA,kB;AACA,c;AACA,E;;AAEA,wB;;AAEA,c;AACA,sE;AACA,uE;;AAEA,gE;;AAEA,mC;AACA,4B;;AAEA,6D;AACA,wB;;AAEA,2D;AACA,wB;AACA,U;AACA,4E;AACA,yE;AACA,kC;AACA,uB;AACA,G;AACA,E;;AAEA,oD;AACA,qC;AACA,8B;AACA,gF;AACA,4E;AACA,kE;AACA,wB;AACA,0B;AACA,iB;AACA,I;;AAEA,yB;;AAEA,wB;;AAEA,gC;;AAEA,kE;AACA,gC;AACA,W;AACA,0C;AACA,oB;AACA,2C;AACA,4B;AACA,K;;AAEA,oE;AACA,Y;AACA,G;;AAEA,mB;;AAEA,4D;AACA,4E;AACA,0D;AACA,mE;AACA,a;AACA,mB;AACA,kD;AACA,wC;;AAEA,uE;AACA,oE;AACA,2B;AACA,gE;;AAEA,iB;AACA,E;;AAEA,6D;AACA,+B;AACA,+B;AACA,mB;AACA,iB;AACA,a;AACA,K;;AAEA,4B;AACA,oB;AACA,kB;AACA,yB;AACA,K;;AAEA,wE;AACA,2D;;AAEA,4C;AACA,mB;AACA,kE;AACA,O;;AAEA,0D;AACA,6E;AACA,+B;AACA,mD;AACA,0B;AACA,sB;;AAEA,4D;AACA,0B;AACA,a;;AAEA,sB;AACA,kD;AACA,iC;AACA,gD;AACA,oD;AACA,+C;AACA,0C;AACA,c;AACA,8E;AACA,O;AACA,Y;AACA,wB;AACA,K;AACA,I;AACA,G;;AAEA,sF;AACA,6B;AACA,iB;AACA,qF;AACA,iD;AACA,G;;AAEA,uD;AACA,oD;AACA,e;AACA,M;AACA,gB;AACA,E;;AAEA,oE;AACA,sC;AACA,sD;AACA,0B;;AAEA,sB;AACA,8B;AACA,oD;AACA,oC;;AAEA,gE;AACA,kC;AACA,sB;AACA,4B;AACA,8B;AACA,gC;AACA,kC;AACA,kC;AACA,gC;AACA,gC;;AAEA,wC;AACA,oB;AACA,K;;AAEA,wB;AACA,gC;AACA,oC;AACA,G;;AAEA,qE;AACA,4E;;AAEA,iD;AACA,2C;AACA,yB;AACA,yC;AACA,a;AACA,iC;AACA,a;AACA,iC;AACA,a;AACA,qC;;AAEA,oD;AACA,0E;;AAEA,mB;AACA,kC;AACA,yE;AACA,8C;;AAEA,2B;AACA,6C;AACA,uC;AACA,mD;AACA,+C;AACA,gD;;AAEA,gB;AACA,iD;;AAEA,kD;;AAEA,oB;AACA,kC;AACA,c;AACA,Q;AACA,c;AACA,iB;AACA,6B;AACA,Y;AACA,e;AACA,8B;;AAEA,yC;AACA,wD;AACA,mD;AACA,I;;AAEA,gE;AACA,2C;AACA,E;;AAEA,8C;AACA,uB;AACA,2B;AACA,6C;AACA,gF;AACA,iC;AACA,E","file":"/packages/logging.js","sourcesContent":["Log = function () {\n return Log.info.apply(this, arguments);\n};\n\n/// FOR TESTING\nvar intercept = 0;\nvar interceptedLines = [];\nvar suppress = 0;\n\n// Intercept the next 'count' calls to a Log function. The actual\n// lines printed to the console can be cleared and read by calling\n// Log._intercepted().\nLog._intercept = function (count) {\n intercept += count;\n};\n\n// Suppress the next 'count' calls to a Log function. Use this to stop\n// tests from spamming the console, especially with red errors that\n// might look like a failing test.\nLog._suppress = function (count) {\n suppress += count;\n};\n\n// Returns intercepted lines and resets the intercept counter.\nLog._intercepted = function () {\n var lines = interceptedLines;\n interceptedLines = [];\n intercept = 0;\n return lines;\n};\n\n// Either 'json' or 'colored-text'.\n//\n// When this is set to 'json', print JSON documents that are parsed by another\n// process ('satellite' or 'meteor run'). This other process should call\n// 'Log.format' for nice output.\n//\n// When this is set to 'colored-text', call 'Log.format' before printing.\n// This should be used for logging from within satellite, since there is no\n// other process that will be reading its standard output.\nLog.outputFormat = 'json';\n\nvar LEVEL_COLORS = {\n debug: 'green',\n // leave info as the default color\n warn: 'magenta',\n error: 'red'\n};\n\nvar META_COLOR = 'blue';\n\n// XXX package\nvar RESTRICTED_KEYS = ['time', 'timeInexact', 'level', 'file', 'line',\n 'program', 'originApp', 'satellite', 'stderr'];\n\nvar FORMATTED_KEYS = RESTRICTED_KEYS.concat(['app', 'message']);\n\nvar logInBrowser = function (obj) {\n var str = Log.format(obj);\n\n // XXX Some levels should be probably be sent to the server\n var level = obj.level;\n\n if ((typeof console !== 'undefined') && console[level]) {\n console[level](str);\n } else {\n // XXX Uses of Meteor._debug should probably be replaced by Log.debug or\n // Log.info, and we should have another name for \"do your best to\n // call call console.log\".\n Meteor._debug(str);\n }\n};\n\n// @returns {Object: { line: Number, file: String }}\nLog._getCallerDetails = function () {\n var getStack = function () {\n // We do NOT use Error.prepareStackTrace here (a V8 extension that gets us a\n // pre-parsed stack) since it's impossible to compose it with the use of\n // Error.prepareStackTrace used on the server for source maps.\n var err = new Error;\n var stack = err.stack;\n return stack;\n };\n\n var stack = getStack();\n\n if (!stack) return {};\n\n var lines = stack.split('\\n');\n\n // looking for the first line outside the logging package (or an\n // eval if we find that first)\n var line;\n for (var i = 1; i < lines.length; ++i) {\n line = lines[i];\n if (line.match(/^\\s*at eval \\(eval/)) {\n return {file: \"eval\"};\n }\n\n if (!line.match(/packages\\/(?:local-test:)?logging(?:\\/|\\.js)/))\n break;\n }\n\n var details = {};\n\n // The format for FF is 'functionName@filePath:lineNumber'\n // The format for V8 is 'functionName (packages/logging/logging.js:81)' or\n // 'packages/logging/logging.js:81'\n var match = /(?:[@(]| at )([^(]+?):([0-9:]+)(?:\\)|$)/.exec(line);\n if (!match)\n return details;\n // in case the matched block here is line:column\n details.line = match[2].split(':')[0];\n\n // Possible format: https://foo.bar.com/scripts/file.js?random=foobar\n // XXX: if you can write the following in better way, please do it\n // XXX: what about evals?\n details.file = match[1].split('/').slice(-1)[0].split('?')[0];\n\n return details;\n};\n\n_.each(['debug', 'info', 'warn', 'error'], function (level) {\n // @param arg {String|Object}\n Log[level] = function (arg) {\n if (suppress) {\n suppress--;\n return;\n }\n\n var intercepted = false;\n if (intercept) {\n intercept--;\n intercepted = true;\n }\n\n var obj = (_.isObject(arg) && !_.isRegExp(arg) && !_.isDate(arg) ) ?\n arg : {message: new String(arg).toString() };\n\n _.each(RESTRICTED_KEYS, function (key) {\n if (obj[key])\n throw new Error(\"Can't set '\" + key + \"' in log message\");\n });\n\n if (_.has(obj, 'message') && !_.isString(obj.message))\n throw new Error(\"The 'message' field in log objects must be a string\");\n if (!obj.omitCallerDetails)\n obj = _.extend(Log._getCallerDetails(), obj);\n obj.time = new Date();\n obj.level = level;\n\n // XXX allow you to enable 'debug', probably per-package\n if (level === 'debug')\n return;\n\n if (intercepted) {\n interceptedLines.push(EJSON.stringify(obj));\n } else if (Meteor.isServer) {\n if (Log.outputFormat === 'colored-text') {\n console.log(Log.format(obj, {color: true}));\n } else if (Log.outputFormat === 'json') {\n console.log(EJSON.stringify(obj));\n } else {\n throw new Error(\"Unknown logging output format: \" + Log.outputFormat);\n }\n } else {\n logInBrowser(obj);\n }\n };\n});\n\n// tries to parse line as EJSON. returns object if parse is successful, or null if not\nLog.parse = function (line) {\n var obj = null;\n if (line && line.charAt(0) === '{') { // might be json generated from calling 'Log'\n try { obj = EJSON.parse(line); } catch (e) {}\n }\n\n // XXX should probably check fields other than 'time'\n if (obj && obj.time && (obj.time instanceof Date))\n return obj;\n else\n return null;\n};\n\n// formats a log object into colored human and machine-readable text\nLog.format = function (obj, options) {\n obj = EJSON.clone(obj); // don't mutate the argument\n options = options || {};\n\n var time = obj.time;\n if (!(time instanceof Date))\n throw new Error(\"'time' must be a Date object\");\n var timeInexact = obj.timeInexact;\n\n // store fields that are in FORMATTED_KEYS since we strip them\n var level = obj.level || 'info';\n var file = obj.file;\n var lineNumber = obj.line;\n var appName = obj.app || '';\n var originApp = obj.originApp;\n var message = obj.message || '';\n var program = obj.program || '';\n var satellite = obj.satellite;\n var stderr = obj.stderr || '';\n\n _.each(FORMATTED_KEYS, function(key) {\n delete obj[key];\n });\n\n if (!_.isEmpty(obj)) {\n if (message) message += \" \";\n message += EJSON.stringify(obj);\n }\n\n var pad2 = function(n) { return n < 10 ? '0' + n : n.toString(); };\n var pad3 = function(n) { return n < 100 ? '0' + pad2(n) : n.toString(); };\n\n var dateStamp = time.getFullYear().toString() +\n pad2(time.getMonth() + 1 /*0-based*/) +\n pad2(time.getDate());\n var timeStamp = pad2(time.getHours()) +\n ':' +\n pad2(time.getMinutes()) +\n ':' +\n pad2(time.getSeconds()) +\n '.' +\n pad3(time.getMilliseconds());\n\n // eg in San Francisco in June this will be '(-7)'\n var utcOffsetStr = '(' + (-(new Date().getTimezoneOffset() / 60)) + ')';\n\n var appInfo = '';\n if (appName) appInfo += appName;\n if (originApp && originApp !== appName) appInfo += ' via ' + originApp;\n if (appInfo) appInfo = '[' + appInfo + '] ';\n\n var sourceInfoParts = [];\n if (program) sourceInfoParts.push(program);\n if (file) sourceInfoParts.push(file);\n if (lineNumber) sourceInfoParts.push(lineNumber);\n var sourceInfo = _.isEmpty(sourceInfoParts) ?\n '' : '(' + sourceInfoParts.join(':') + ') ';\n\n if (satellite)\n sourceInfo += ['[', satellite, ']'].join('');\n\n var stderrIndicator = stderr ? '(STDERR) ' : '';\n\n var metaPrefix = [\n level.charAt(0).toUpperCase(),\n dateStamp,\n '-',\n timeStamp,\n utcOffsetStr,\n timeInexact ? '? ' : ' ',\n appInfo,\n sourceInfo,\n stderrIndicator].join('');\n\n var prettify = function (line, color) {\n return (options.color && Meteor.isServer && color) ?\n Npm.require('cli-color')[color](line) : line;\n };\n\n return prettify(metaPrefix, options.metaColor || META_COLOR) +\n prettify(message, LEVEL_COLORS[level]);\n};\n\n// Turn a line of text into a loggable object.\n// @param line {String}\n// @param override {Object}\nLog.objFromText = function (line, override) {\n var obj = {message: line, level: \"info\", time: new Date(), timeInexact: true};\n return _.extend(obj, override);\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js b/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js deleted file mode 100644 index 68a0ca2..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js +++ /dev/null @@ -1,15 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Autoupdate = Package.autoupdate.Autoupdate; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['meteor-platform'] = {}; - -})(); - -//# sourceMappingURL=meteor-platform.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js.map b/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js.map deleted file mode 100644 index ccd0ffa..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/meteor-platform.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;;","file":"/packages/meteor-platform.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/meteor.js b/web-app/.meteor/local/build/programs/server/packages/meteor.js deleted file mode 100644 index dbb4531..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/meteor.js +++ /dev/null @@ -1,1242 +0,0 @@ -(function () { - -/* Imports */ -var _ = Package.underscore._; - -/* Package-scope variables */ -var Meteor; - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/server_environment.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -Meteor = { // 1 - isClient: false, // 2 - isServer: true, // 3 - isCordova: false // 4 -}; // 5 - // 6 -Meteor.settings = {}; // 7 - // 8 -if (process.env.METEOR_SETTINGS) { // 9 - try { // 10 - Meteor.settings = JSON.parse(process.env.METEOR_SETTINGS); // 11 - } catch (e) { // 12 - throw new Error("METEOR_SETTINGS are not valid JSON: " + process.env.METEOR_SETTINGS); // 13 - } // 14 -} // 15 - // 16 -// Push a subset of settings to the client. // 17 -if (Meteor.settings && Meteor.settings.public && // 18 - typeof __meteor_runtime_config__ === "object") { // 19 - __meteor_runtime_config__.PUBLIC_SETTINGS = Meteor.settings.public; // 20 -} // 21 - // 22 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/helpers.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -if (Meteor.isServer) // 1 - var Future = Npm.require('fibers/future'); // 2 - // 3 -if (typeof __meteor_runtime_config__ === 'object' && // 4 - __meteor_runtime_config__.meteorRelease) { // 5 - /** // 6 - * @summary `Meteor.release` is a string containing the name of the [release](#meteorupdate) with which the project was built (for example, `"1.2.3"`). It is `undefined` if the project was built using a git checkout of Meteor. - * @locus Anywhere // 8 - * @type {String} // 9 - */ // 10 - Meteor.release = __meteor_runtime_config__.meteorRelease; // 11 -} // 12 - // 13 -// XXX find a better home for these? Ideally they would be _.get, // 14 -// _.ensure, _.delete.. // 15 - // 16 -_.extend(Meteor, { // 17 - // _get(a,b,c,d) returns a[b][c][d], or else undefined if a[b] or // 18 - // a[b][c] doesn't exist. // 19 - // // 20 - _get: function (obj /*, arguments */) { // 21 - for (var i = 1; i < arguments.length; i++) { // 22 - if (!(arguments[i] in obj)) // 23 - return undefined; // 24 - obj = obj[arguments[i]]; // 25 - } // 26 - return obj; // 27 - }, // 28 - // 29 - // _ensure(a,b,c,d) ensures that a[b][c][d] exists. If it does not, // 30 - // it is created and set to {}. Either way, it is returned. // 31 - // // 32 - _ensure: function (obj /*, arguments */) { // 33 - for (var i = 1; i < arguments.length; i++) { // 34 - var key = arguments[i]; // 35 - if (!(key in obj)) // 36 - obj[key] = {}; // 37 - obj = obj[key]; // 38 - } // 39 - // 40 - return obj; // 41 - }, // 42 - // 43 - // _delete(a, b, c, d) deletes a[b][c][d], then a[b][c] unless it // 44 - // isn't empty, then a[b] unless it isn't empty. // 45 - // // 46 - _delete: function (obj /*, arguments */) { // 47 - var stack = [obj]; // 48 - var leaf = true; // 49 - for (var i = 1; i < arguments.length - 1; i++) { // 50 - var key = arguments[i]; // 51 - if (!(key in obj)) { // 52 - leaf = false; // 53 - break; // 54 - } // 55 - obj = obj[key]; // 56 - if (typeof obj !== "object") // 57 - break; // 58 - stack.push(obj); // 59 - } // 60 - // 61 - for (var i = stack.length - 1; i >= 0; i--) { // 62 - var key = arguments[i+1]; // 63 - // 64 - if (leaf) // 65 - leaf = false; // 66 - else // 67 - for (var other in stack[i][key]) // 68 - return; // not empty -- we're done // 69 - // 70 - delete stack[i][key]; // 71 - } // 72 - }, // 73 - // 74 - // wrapAsync can wrap any function that takes some number of arguments that // 75 - // can't be undefined, followed by some optional arguments, where the callback // 76 - // is the last optional argument. // 77 - // e.g. fs.readFile(pathname, [callback]), // 78 - // fs.open(pathname, flags, [mode], [callback]) // 79 - // For maximum effectiveness and least confusion, wrapAsync should be used on // 80 - // functions where the callback is the only argument of type Function. // 81 - // 82 - /** // 83 - * @memberOf Meteor // 84 - * @summary Wrap a function that takes a callback function as its final parameter. On the server, the wrapped function can be used either synchronously (without passing a callback) or asynchronously (when a callback is passed). On the client, a callback is always required; errors will be logged if there is no callback. If a callback is provided, the environment captured when the original function was called will be restored in the callback. - * @locus Anywhere // 86 - * @param {Function} func A function that takes a callback as its final parameter // 87 - * @param {Object} [context] Optional `this` object against which the original function will be invoked // 88 - */ // 89 - wrapAsync: function (fn, context) { // 90 - return function (/* arguments */) { // 91 - var self = context || this; // 92 - var newArgs = _.toArray(arguments); // 93 - var callback; // 94 - // 95 - for (var i = newArgs.length - 1; i >= 0; --i) { // 96 - var arg = newArgs[i]; // 97 - var type = typeof arg; // 98 - if (type !== "undefined") { // 99 - if (type === "function") { // 100 - callback = arg; // 101 - } // 102 - break; // 103 - } // 104 - } // 105 - // 106 - if (! callback) { // 107 - if (Meteor.isClient) { // 108 - callback = logErr; // 109 - } else { // 110 - var fut = new Future(); // 111 - callback = fut.resolver(); // 112 - } // 113 - ++i; // Insert the callback just after arg. // 114 - } // 115 - // 116 - newArgs[i] = Meteor.bindEnvironment(callback); // 117 - var result = fn.apply(self, newArgs); // 118 - return fut ? fut.wait() : result; // 119 - }; // 120 - }, // 121 - // 122 - // Sets child's prototype to a new object whose prototype is parent's // 123 - // prototype. Used as: // 124 - // Meteor._inherits(ClassB, ClassA). // 125 - // _.extend(ClassB.prototype, { ... }) // 126 - // Inspired by CoffeeScript's `extend` and Google Closure's `goog.inherits`. // 127 - _inherits: function (Child, Parent) { // 128 - // copy Parent static properties // 129 - for (var key in Parent) { // 130 - // make sure we only copy hasOwnProperty properties vs. prototype // 131 - // properties // 132 - if (_.has(Parent, key)) // 133 - Child[key] = Parent[key]; // 134 - } // 135 - // 136 - // a middle member of prototype chain: takes the prototype from the Parent // 137 - var Middle = function () { // 138 - this.constructor = Child; // 139 - }; // 140 - Middle.prototype = Parent.prototype; // 141 - Child.prototype = new Middle(); // 142 - Child.__super__ = Parent.prototype; // 143 - return Child; // 144 - } // 145 -}); // 146 - // 147 -var warnedAboutWrapAsync = false; // 148 - // 149 -/** // 150 - * @deprecated in 0.9.3 // 151 - */ // 152 -Meteor._wrapAsync = function(fn, context) { // 153 - if (! warnedAboutWrapAsync) { // 154 - Meteor._debug("Meteor._wrapAsync has been renamed to Meteor.wrapAsync"); // 155 - warnedAboutWrapAsync = true; // 156 - } // 157 - return Meteor.wrapAsync.apply(Meteor, arguments); // 158 -}; // 159 - // 160 -function logErr(err) { // 161 - if (err) { // 162 - return Meteor._debug( // 163 - "Exception in callback of async function", // 164 - err.stack ? err.stack : err // 165 - ); // 166 - } // 167 -} // 168 - // 169 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/setimmediate.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Chooses one of three setImmediate implementations: // 1 -// // 2 -// * Native setImmediate (IE 10, Node 0.9+) // 3 -// // 4 -// * postMessage (many browsers) // 5 -// // 6 -// * setTimeout (fallback) // 7 -// // 8 -// The postMessage implementation is based on // 9 -// https://github.com/NobleJS/setImmediate/tree/1.0.1 // 10 -// // 11 -// Don't use `nextTick` for Node since it runs its callbacks before // 12 -// I/O, which is stricter than we're looking for. // 13 -// // 14 -// Not installed as a polyfill, as our public API is `Meteor.defer`. // 15 -// Since we're not trying to be a polyfill, we have some // 16 -// simplifications: // 17 -// // 18 -// If one invocation of a setImmediate callback pauses itself by a // 19 -// call to alert/prompt/showModelDialog, the NobleJS polyfill // 20 -// implementation ensured that no setImmedate callback would run until // 21 -// the first invocation completed. While correct per the spec, what it // 22 -// would mean for us in practice is that any reactive updates relying // 23 -// on Meteor.defer would be hung in the main window until the modal // 24 -// dialog was dismissed. Thus we only ensure that a setImmediate // 25 -// function is called in a later event loop. // 26 -// // 27 -// We don't need to support using a string to be eval'ed for the // 28 -// callback, arguments to the function, or clearImmediate. // 29 - // 30 -"use strict"; // 31 - // 32 -var global = this; // 33 - // 34 - // 35 -// IE 10, Node >= 9.1 // 36 - // 37 -function useSetImmediate() { // 38 - if (! global.setImmediate) // 39 - return null; // 40 - else { // 41 - var setImmediate = function (fn) { // 42 - global.setImmediate(fn); // 43 - }; // 44 - setImmediate.implementation = 'setImmediate'; // 45 - return setImmediate; // 46 - } // 47 -} // 48 - // 49 - // 50 -// Android 2.3.6, Chrome 26, Firefox 20, IE 8-9, iOS 5.1.1 Safari // 51 - // 52 -function usePostMessage() { // 53 - // The test against `importScripts` prevents this implementation // 54 - // from being installed inside a web worker, where // 55 - // `global.postMessage` means something completely different and // 56 - // can't be used for this purpose. // 57 - // 58 - if (!global.postMessage || global.importScripts) { // 59 - return null; // 60 - } // 61 - // 62 - // Avoid synchronous post message implementations. // 63 - // 64 - var postMessageIsAsynchronous = true; // 65 - var oldOnMessage = global.onmessage; // 66 - global.onmessage = function () { // 67 - postMessageIsAsynchronous = false; // 68 - }; // 69 - global.postMessage("", "*"); // 70 - global.onmessage = oldOnMessage; // 71 - // 72 - if (! postMessageIsAsynchronous) // 73 - return null; // 74 - // 75 - var funcIndex = 0; // 76 - var funcs = {}; // 77 - // 78 - // Installs an event handler on `global` for the `message` event: see // 79 - // * https://developer.mozilla.org/en/DOM/window.postMessage // 80 - // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages // 81 - // 82 - // XXX use Random.id() here? // 83 - var MESSAGE_PREFIX = "Meteor._setImmediate." + Math.random() + '.'; // 84 - // 85 - function isStringAndStartsWith(string, putativeStart) { // 86 - return (typeof string === "string" && // 87 - string.substring(0, putativeStart.length) === putativeStart); // 88 - } // 89 - // 90 - function onGlobalMessage(event) { // 91 - // This will catch all incoming messages (even from other // 92 - // windows!), so we need to try reasonably hard to avoid letting // 93 - // anyone else trick us into firing off. We test the origin is // 94 - // still this window, and that a (randomly generated) // 95 - // unpredictable identifying prefix is present. // 96 - if (event.source === global && // 97 - isStringAndStartsWith(event.data, MESSAGE_PREFIX)) { // 98 - var index = event.data.substring(MESSAGE_PREFIX.length); // 99 - try { // 100 - if (funcs[index]) // 101 - funcs[index](); // 102 - } // 103 - finally { // 104 - delete funcs[index]; // 105 - } // 106 - } // 107 - } // 108 - // 109 - if (global.addEventListener) { // 110 - global.addEventListener("message", onGlobalMessage, false); // 111 - } else { // 112 - global.attachEvent("onmessage", onGlobalMessage); // 113 - } // 114 - // 115 - var setImmediate = function (fn) { // 116 - // Make `global` post a message to itself with the handle and // 117 - // identifying prefix, thus asynchronously invoking our // 118 - // onGlobalMessage listener above. // 119 - ++funcIndex; // 120 - funcs[funcIndex] = fn; // 121 - global.postMessage(MESSAGE_PREFIX + funcIndex, "*"); // 122 - }; // 123 - setImmediate.implementation = 'postMessage'; // 124 - return setImmediate; // 125 -} // 126 - // 127 - // 128 -function useTimeout() { // 129 - var setImmediate = function (fn) { // 130 - global.setTimeout(fn, 0); // 131 - }; // 132 - setImmediate.implementation = 'setTimeout'; // 133 - return setImmediate; // 134 -} // 135 - // 136 - // 137 -Meteor._setImmediate = // 138 - useSetImmediate() || // 139 - usePostMessage() || // 140 - useTimeout(); // 141 - // 142 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/timers.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var withoutInvocation = function (f) { // 1 - if (Package.ddp) { // 2 - var _CurrentInvocation = Package.ddp.DDP._CurrentInvocation; // 3 - if (_CurrentInvocation.get() && _CurrentInvocation.get().isSimulation) // 4 - throw new Error("Can't set timers inside simulations"); // 5 - return function () { _CurrentInvocation.withValue(null, f); }; // 6 - } // 7 - else // 8 - return f; // 9 -}; // 10 - // 11 -var bindAndCatch = function (context, f) { // 12 - return Meteor.bindEnvironment(withoutInvocation(f), context); // 13 -}; // 14 - // 15 -_.extend(Meteor, { // 16 - // Meteor.setTimeout and Meteor.setInterval callbacks scheduled // 17 - // inside a server method are not part of the method invocation and // 18 - // should clear out the CurrentInvocation environment variable. // 19 - // 20 - /** // 21 - * @memberOf Meteor // 22 - * @summary Call a function in the future after waiting for a specified delay. // 23 - * @locus Anywhere // 24 - * @param {Function} func The function to run // 25 - * @param {Number} delay Number of milliseconds to wait before calling function // 26 - */ // 27 - setTimeout: function (f, duration) { // 28 - return setTimeout(bindAndCatch("setTimeout callback", f), duration); // 29 - }, // 30 - // 31 - /** // 32 - * @memberOf Meteor // 33 - * @summary Call a function repeatedly, with a time delay between calls. // 34 - * @locus Anywhere // 35 - * @param {Function} func The function to run // 36 - * @param {Number} delay Number of milliseconds to wait between each function call. // 37 - */ // 38 - setInterval: function (f, duration) { // 39 - return setInterval(bindAndCatch("setInterval callback", f), duration); // 40 - }, // 41 - // 42 - /** // 43 - * @memberOf Meteor // 44 - * @summary Cancel a repeating function call scheduled by `Meteor.setInterval`. // 45 - * @locus Anywhere // 46 - * @param {Number} id The handle returned by `Meteor.setInterval` // 47 - */ // 48 - clearInterval: function(x) { // 49 - return clearInterval(x); // 50 - }, // 51 - // 52 - /** // 53 - * @memberOf Meteor // 54 - * @summary Cancel a function call scheduled by `Meteor.setTimeout`. // 55 - * @locus Anywhere // 56 - * @param {Number} id The handle returned by `Meteor.setTimeout` // 57 - */ // 58 - clearTimeout: function(x) { // 59 - return clearTimeout(x); // 60 - }, // 61 - // 62 - // XXX consider making this guarantee ordering of defer'd callbacks, like // 63 - // Tracker.afterFlush or Node's nextTick (in practice). Then tests can do: // 64 - // callSomethingThatDefersSomeWork(); // 65 - // Meteor.defer(expect(somethingThatValidatesThatTheWorkHappened)); // 66 - defer: function (f) { // 67 - Meteor._setImmediate(bindAndCatch("defer callback", f)); // 68 - } // 69 -}); // 70 - // 71 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/errors.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Makes an error subclass which properly contains a stack trace in most // 1 -// environments. constructor can set fields on `this` (and should probably set // 2 -// `message`, which is what gets displayed at the top of a stack trace). // 3 -// // 4 -Meteor.makeErrorType = function (name, constructor) { // 5 - var errorClass = function (/*arguments*/) { // 6 - var self = this; // 7 - // 8 - // Ensure we get a proper stack trace in most Javascript environments // 9 - if (Error.captureStackTrace) { // 10 - // V8 environments (Chrome and Node.js) // 11 - Error.captureStackTrace(self, errorClass); // 12 - } else { // 13 - // Firefox // 14 - var e = new Error; // 15 - e.__proto__ = errorClass.prototype; // 16 - if (e instanceof errorClass) // 17 - self = e; // 18 - } // 19 - // Safari magically works. // 20 - // 21 - constructor.apply(self, arguments); // 22 - // 23 - self.errorType = name; // 24 - // 25 - return self; // 26 - }; // 27 - // 28 - Meteor._inherits(errorClass, Error); // 29 - // 30 - return errorClass; // 31 -}; // 32 - // 33 -// This should probably be in the livedata package, but we don't want // 34 -// to require you to use the livedata package to get it. Eventually we // 35 -// should probably rename it to DDP.Error and put it back in the // 36 -// 'livedata' package (which we should rename to 'ddp' also.) // 37 -// // 38 -// Note: The DDP server assumes that Meteor.Error EJSON-serializes as an object // 39 -// containing 'error' and optionally 'reason' and 'details'. // 40 -// The DDP client manually puts these into Meteor.Error objects. (We don't use // 41 -// EJSON.addType here because the type is determined by location in the // 42 -// protocol, not text on the wire.) // 43 - // 44 -/** // 45 - * @summary This class represents a symbolic error thrown by a method. // 46 - * @locus Anywhere // 47 - * @class // 48 - * @param {String} error A string code uniquely identifying this kind of error. // 49 - * This string should be used by callers of the method to determine the // 50 - * appropriate action to take, instead of attempting to parse the reason // 51 - * or details fields. For example: // 52 - * // 53 - * ``` // 54 - * // on the server, pick a code unique to this error // 55 - * // the reason field should be a useful debug message // 56 - * throw new Meteor.Error("logged-out", // 57 - * "The user must be logged in to post a comment."); // 58 - * // 59 - * // on the client // 60 - * Meteor.call("methodName", function (error) { // 61 - * // identify the error // 62 - * if (error.error === "logged-out") { // 63 - * // show a nice error message // 64 - * Session.set("errorMessage", "Please log in to post a comment."); // 65 - * } // 66 - * }); // 67 - * ``` // 68 - * // 69 - * For legacy reasons, some built-in Meteor functions such as `check` throw // 70 - * errors with a number in this field. // 71 - * // 72 - * @param {String} [reason] Optional. A short human-readable summary of the // 73 - * error, like 'Not Found'. // 74 - * @param {String} [details] Optional. Additional information about the error, // 75 - * like a textual stack trace. // 76 - */ // 77 -Meteor.Error = Meteor.makeErrorType( // 78 - "Meteor.Error", // 79 - function (error, reason, details) { // 80 - var self = this; // 81 - // 82 - // Currently, a numeric code, likely similar to a HTTP code (eg, // 83 - // 404, 500). That is likely to change though. // 84 - self.error = error; // 85 - // 86 - // Optional: A short human-readable summary of the error. Not // 87 - // intended to be shown to end users, just developers. ("Not Found", // 88 - // "Internal Server Error") // 89 - self.reason = reason; // 90 - // 91 - // Optional: Additional information about the error, say for // 92 - // debugging. It might be a (textual) stack trace if the server is // 93 - // willing to provide one. The corresponding thing in HTTP would be // 94 - // the body of a 404 or 500 response. (The difference is that we // 95 - // never expect this to be shown to end users, only developers, so // 96 - // it doesn't need to be pretty.) // 97 - self.details = details; // 98 - // 99 - // This is what gets displayed at the top of a stack trace. Current // 100 - // format is "[404]" (if no reason is set) or "File not found [404]" // 101 - if (self.reason) // 102 - self.message = self.reason + ' [' + self.error + ']'; // 103 - else // 104 - self.message = '[' + self.error + ']'; // 105 - }); // 106 - // 107 -// Meteor.Error is basically data and is sent over DDP, so you should be able to // 108 -// properly EJSON-clone it. This is especially important because if a // 109 -// Meteor.Error is thrown through a Future, the error, reason, and details // 110 -// properties become non-enumerable so a standard Object clone won't preserve // 111 -// them and they will be lost from DDP. // 112 -Meteor.Error.prototype.clone = function () { // 113 - var self = this; // 114 - return new Meteor.Error(self.error, self.reason, self.details); // 115 -}; // 116 - // 117 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/fiber_helpers.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var path = Npm.require('path'); // 1 -var Fiber = Npm.require('fibers'); // 2 -var Future = Npm.require(path.join('fibers', 'future')); // 3 - // 4 -Meteor._noYieldsAllowed = function (f) { // 5 - var savedYield = Fiber.yield; // 6 - Fiber.yield = function () { // 7 - throw new Error("Can't call yield in a noYieldsAllowed block!"); // 8 - }; // 9 - try { // 10 - return f(); // 11 - } finally { // 12 - Fiber.yield = savedYield; // 13 - } // 14 -}; // 15 - // 16 -Meteor._DoubleEndedQueue = Npm.require('double-ended-queue'); // 17 - // 18 -// Meteor._SynchronousQueue is a queue which runs task functions serially. // 19 -// Tasks are assumed to be synchronous: ie, it's assumed that they are // 20 -// done when they return. // 21 -// // 22 -// It has two methods: // 23 -// - queueTask queues a task to be run, and returns immediately. // 24 -// - runTask queues a task to be run, and then yields. It returns // 25 -// when the task finishes running. // 26 -// // 27 -// It's safe to call queueTask from within a task, but not runTask (unless // 28 -// you're calling runTask from a nested Fiber). // 29 -// // 30 -// Somewhat inspired by async.queue, but specific to blocking tasks. // 31 -// XXX break this out into an NPM module? // 32 -// XXX could maybe use the npm 'schlock' module instead, which would // 33 -// also support multiple concurrent "read" tasks // 34 -// // 35 -Meteor._SynchronousQueue = function () { // 36 - var self = this; // 37 - // List of tasks to run (not including a currently-running task if any). Each // 38 - // is an object with field 'task' (the task function to run) and 'future' (the // 39 - // Future associated with the blocking runTask call that queued it, or null if // 40 - // called from queueTask). // 41 - self._taskHandles = new Meteor._DoubleEndedQueue(); // 42 - // This is true if self._run() is either currently executing or scheduled to // 43 - // do so soon. // 44 - self._runningOrRunScheduled = false; // 45 - // During the execution of a task, this is set to the fiber used to execute // 46 - // that task. We use this to throw an error rather than deadlocking if the // 47 - // user calls runTask from within a task on the same fiber. // 48 - self._currentTaskFiber = undefined; // 49 - // This is true if we're currently draining. While we're draining, a further // 50 - // drain is a noop, to prevent infinite loops. "drain" is a heuristic type // 51 - // operation, that has a meaning like unto "what a naive person would expect // 52 - // when modifying a table from an observe" // 53 - self._draining = false; // 54 -}; // 55 - // 56 -_.extend(Meteor._SynchronousQueue.prototype, { // 57 - runTask: function (task) { // 58 - var self = this; // 59 - // 60 - if (!self.safeToRunTask()) { // 61 - if (Fiber.current) // 62 - throw new Error("Can't runTask from another task in the same fiber"); // 63 - else // 64 - throw new Error("Can only call runTask in a Fiber"); // 65 - } // 66 - // 67 - var fut = new Future; // 68 - var handle = { // 69 - task: Meteor.bindEnvironment(task, function (e) { // 70 - Meteor._debug("Exception from task:", e && e.stack || e); // 71 - throw e; // 72 - }), // 73 - future: fut, // 74 - name: task.name // 75 - }; // 76 - self._taskHandles.push(handle); // 77 - self._scheduleRun(); // 78 - // Yield. We'll get back here after the task is run (and will throw if the // 79 - // task throws). // 80 - fut.wait(); // 81 - }, // 82 - queueTask: function (task) { // 83 - var self = this; // 84 - self._taskHandles.push({ // 85 - task: task, // 86 - name: task.name // 87 - }); // 88 - self._scheduleRun(); // 89 - // No need to block. // 90 - }, // 91 - // 92 - flush: function () { // 93 - var self = this; // 94 - self.runTask(function () {}); // 95 - }, // 96 - // 97 - safeToRunTask: function () { // 98 - var self = this; // 99 - return Fiber.current && self._currentTaskFiber !== Fiber.current; // 100 - }, // 101 - // 102 - drain: function () { // 103 - var self = this; // 104 - if (self._draining) // 105 - return; // 106 - if (!self.safeToRunTask()) // 107 - return; // 108 - self._draining = true; // 109 - while (! self._taskHandles.isEmpty()) { // 110 - self.flush(); // 111 - } // 112 - self._draining = false; // 113 - }, // 114 - // 115 - _scheduleRun: function () { // 116 - var self = this; // 117 - // Already running or scheduled? Do nothing. // 118 - if (self._runningOrRunScheduled) // 119 - return; // 120 - // 121 - self._runningOrRunScheduled = true; // 122 - setImmediate(function () { // 123 - Fiber(function () { // 124 - self._run(); // 125 - }).run(); // 126 - }); // 127 - }, // 128 - _run: function () { // 129 - var self = this; // 130 - // 131 - if (!self._runningOrRunScheduled) // 132 - throw new Error("expected to be _runningOrRunScheduled"); // 133 - // 134 - if (self._taskHandles.isEmpty()) { // 135 - // Done running tasks! Don't immediately schedule another run, but // 136 - // allow future tasks to do so. // 137 - self._runningOrRunScheduled = false; // 138 - return; // 139 - } // 140 - var taskHandle = self._taskHandles.shift(); // 141 - // 142 - // Run the task. // 143 - self._currentTaskFiber = Fiber.current; // 144 - var exception = undefined; // 145 - try { // 146 - taskHandle.task(); // 147 - } catch (err) { // 148 - if (taskHandle.future) { // 149 - // We'll throw this exception through runTask. // 150 - exception = err; // 151 - } else { // 152 - Meteor._debug("Exception in queued task: " + err.stack); // 153 - } // 154 - } // 155 - self._currentTaskFiber = undefined; // 156 - // 157 - // Soon, run the next task, if there is any. // 158 - self._runningOrRunScheduled = false; // 159 - self._scheduleRun(); // 160 - // 161 - // If this was queued with runTask, let the runTask call return (throwing if // 162 - // the task threw). // 163 - if (taskHandle.future) { // 164 - if (exception) // 165 - taskHandle.future['throw'](exception); // 166 - else // 167 - taskHandle.future['return'](); // 168 - } // 169 - } // 170 -}); // 171 - // 172 -// Sleep. Mostly used for debugging (eg, inserting latency into server // 173 -// methods). // 174 -// // 175 -Meteor._sleepForMs = function (ms) { // 176 - var fiber = Fiber.current; // 177 - setTimeout(function() { // 178 - fiber.run(); // 179 - }, ms); // 180 - Fiber.yield(); // 181 -}; // 182 - // 183 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/startup_server.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -Meteor.startup = function (callback) { // 1 - if (__meteor_bootstrap__.startupHooks) { // 2 - __meteor_bootstrap__.startupHooks.push(callback); // 3 - } else { // 4 - // We already started up. Just call it now. // 5 - callback(); // 6 - } // 7 -}; // 8 - // 9 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/debug.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var suppress = 0; // 1 - // 2 -// replacement for console.log. This is a temporary API. We should // 3 -// provide a real logging API soon (possibly just a polyfill for // 4 -// console?) // 5 -// // 6 -// NOTE: this is used on the server to print the warning about // 7 -// having autopublish enabled when you probably meant to turn it // 8 -// off. it's not really the proper use of something called // 9 -// _debug. the intent is for this message to go to the terminal and // 10 -// be very visible. if you change _debug to go someplace else, etc, // 11 -// please fix the autopublish code to do something reasonable. // 12 -// // 13 -Meteor._debug = function (/* arguments */) { // 14 - if (suppress) { // 15 - suppress--; // 16 - return; // 17 - } // 18 - if (typeof console !== 'undefined' && // 19 - typeof console.log !== 'undefined') { // 20 - if (arguments.length == 0) { // IE Companion breaks otherwise // 21 - // IE10 PP4 requires at least one argument // 22 - console.log(''); // 23 - } else { // 24 - // IE doesn't have console.log.apply, it's not a real Object. // 25 - // http://stackoverflow.com/questions/5538972/console-log-apply-not-working-in-ie9 // 26 - // http://patik.com/blog/complete-cross-browser-console-log/ // 27 - if (typeof console.log.apply === "function") { // 28 - // Most browsers // 29 - // 30 - // Chrome and Safari only hyperlink URLs to source files in first argument of // 31 - // console.log, so try to call it with one argument if possible. // 32 - // Approach taken here: If all arguments are strings, join them on space. // 33 - // See https://github.com/meteor/meteor/pull/732#issuecomment-13975991 // 34 - var allArgumentsOfTypeString = true; // 35 - for (var i = 0; i < arguments.length; i++) // 36 - if (typeof arguments[i] !== "string") // 37 - allArgumentsOfTypeString = false; // 38 - // 39 - if (allArgumentsOfTypeString) // 40 - console.log.apply(console, [Array.prototype.join.call(arguments, " ")]); // 41 - else // 42 - console.log.apply(console, arguments); // 43 - // 44 - } else if (typeof Function.prototype.bind === "function") { // 45 - // IE9 // 46 - var log = Function.prototype.bind.call(console.log, console); // 47 - log.apply(console, arguments); // 48 - } else { // 49 - // IE8 // 50 - Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); // 51 - } // 52 - } // 53 - } // 54 -}; // 55 - // 56 -// Suppress the next 'count' Meteor._debug messsages. Use this to // 57 -// stop tests from spamming the console. // 58 -// // 59 -Meteor._suppress_log = function (count) { // 60 - suppress += count; // 61 -}; // 62 - // 63 -Meteor._supressed_log_expected = function () { // 64 - return suppress !== 0; // 65 -}; // 66 - // 67 - // 68 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/dynamics_nodejs.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Fiber-aware implementation of dynamic scoping, for use on the server // 1 - // 2 -var Fiber = Npm.require('fibers'); // 3 - // 4 -var nextSlot = 0; // 5 - // 6 -Meteor._nodeCodeMustBeInFiber = function () { // 7 - if (!Fiber.current) { // 8 - throw new Error("Meteor code must always run within a Fiber. " + // 9 - "Try wrapping callbacks that you pass to non-Meteor " + // 10 - "libraries with Meteor.bindEnvironment."); // 11 - } // 12 -}; // 13 - // 14 -Meteor.EnvironmentVariable = function () { // 15 - this.slot = nextSlot++; // 16 -}; // 17 - // 18 -_.extend(Meteor.EnvironmentVariable.prototype, { // 19 - get: function () { // 20 - Meteor._nodeCodeMustBeInFiber(); // 21 - // 22 - return Fiber.current._meteor_dynamics && // 23 - Fiber.current._meteor_dynamics[this.slot]; // 24 - }, // 25 - // 26 - // Most Meteor code ought to run inside a fiber, and the // 27 - // _nodeCodeMustBeInFiber assertion helps you remember to include appropriate // 28 - // bindEnvironment calls (which will get you the *right value* for your // 29 - // environment variables, on the server). // 30 - // // 31 - // In some very special cases, it's more important to run Meteor code on the // 32 - // server in non-Fiber contexts rather than to strongly enforce the safeguard // 33 - // against forgetting to use bindEnvironment. For example, using `check` in // 34 - // some top-level constructs like connect handlers without needing unnecessary // 35 - // Fibers on every request is more important that possibly failing to find the // 36 - // correct argumentChecker. So this function is just like get(), but it // 37 - // returns null rather than throwing when called from outside a Fiber. (On the // 38 - // client, it is identical to get().) // 39 - getOrNullIfOutsideFiber: function () { // 40 - if (!Fiber.current) // 41 - return null; // 42 - return this.get(); // 43 - }, // 44 - // 45 - withValue: function (value, func) { // 46 - Meteor._nodeCodeMustBeInFiber(); // 47 - // 48 - if (!Fiber.current._meteor_dynamics) // 49 - Fiber.current._meteor_dynamics = []; // 50 - var currentValues = Fiber.current._meteor_dynamics; // 51 - // 52 - var saved = currentValues[this.slot]; // 53 - try { // 54 - currentValues[this.slot] = value; // 55 - var ret = func(); // 56 - } finally { // 57 - currentValues[this.slot] = saved; // 58 - } // 59 - // 60 - return ret; // 61 - } // 62 -}); // 63 - // 64 -// Meteor application code is always supposed to be run inside a // 65 -// fiber. bindEnvironment ensures that the function it wraps is run from // 66 -// inside a fiber and ensures it sees the values of Meteor environment // 67 -// variables that are set at the time bindEnvironment is called. // 68 -// // 69 -// If an environment-bound function is called from outside a fiber (eg, from // 70 -// an asynchronous callback from a non-Meteor library such as MongoDB), it'll // 71 -// kick off a new fiber to execute the function, and returns undefined as soon // 72 -// as that fiber returns or yields (and func's return value is ignored). // 73 -// // 74 -// If it's called inside a fiber, it works normally (the // 75 -// return value of the function will be passed through, and no new // 76 -// fiber will be created.) // 77 -// // 78 -// `onException` should be a function or a string. When it is a // 79 -// function, it is called as a callback when the bound function raises // 80 -// an exception. If it is a string, it should be a description of the // 81 -// callback, and when an exception is raised a debug message will be // 82 -// printed with the description. // 83 -Meteor.bindEnvironment = function (func, onException, _this) { // 84 - Meteor._nodeCodeMustBeInFiber(); // 85 - // 86 - var boundValues = _.clone(Fiber.current._meteor_dynamics || []); // 87 - // 88 - if (!onException || typeof(onException) === 'string') { // 89 - var description = onException || "callback of async function"; // 90 - onException = function (error) { // 91 - Meteor._debug( // 92 - "Exception in " + description + ":", // 93 - error && error.stack || error // 94 - ); // 95 - }; // 96 - } // 97 - // 98 - return function (/* arguments */) { // 99 - var args = _.toArray(arguments); // 100 - // 101 - var runWithEnvironment = function () { // 102 - var savedValues = Fiber.current._meteor_dynamics; // 103 - try { // 104 - // Need to clone boundValues in case two fibers invoke this // 105 - // function at the same time // 106 - Fiber.current._meteor_dynamics = _.clone(boundValues); // 107 - var ret = func.apply(_this, args); // 108 - } catch (e) { // 109 - // note: callback-hook currently relies on the fact that if onException // 110 - // throws and you were originally calling the wrapped callback from // 111 - // within a Fiber, the wrapped call throws. // 112 - onException(e); // 113 - } finally { // 114 - Fiber.current._meteor_dynamics = savedValues; // 115 - } // 116 - return ret; // 117 - }; // 118 - // 119 - if (Fiber.current) // 120 - return runWithEnvironment(); // 121 - Fiber(runWithEnvironment).run(); // 122 - }; // 123 -}; // 124 - // 125 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/url_server.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -if (process.env.ROOT_URL && // 1 - typeof __meteor_runtime_config__ === "object") { // 2 - __meteor_runtime_config__.ROOT_URL = process.env.ROOT_URL; // 3 - if (__meteor_runtime_config__.ROOT_URL) { // 4 - var parsedUrl = Npm.require('url').parse(__meteor_runtime_config__.ROOT_URL); // 5 - // Sometimes users try to pass, eg, ROOT_URL=mydomain.com. // 6 - if (!parsedUrl.host) { // 7 - throw Error("$ROOT_URL, if specified, must be an URL"); // 8 - } // 9 - var pathPrefix = parsedUrl.pathname; // 10 - if (pathPrefix.slice(-1) === '/') { // 11 - // remove trailing slash (or turn "/" into "") // 12 - pathPrefix = pathPrefix.slice(0, -1); // 13 - } // 14 - __meteor_runtime_config__.ROOT_URL_PATH_PREFIX = pathPrefix; // 15 - } else { // 16 - __meteor_runtime_config__.ROOT_URL_PATH_PREFIX = ""; // 17 - } // 18 -} // 19 - // 20 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/url_common.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/** // 1 - * @summary Generate an absolute URL pointing to the application. The server reads from the `ROOT_URL` environment variable to determine where it is running. This is taken care of automatically for apps deployed with `meteor deploy`, but must be provided when using `meteor build`. - * @locus Anywhere // 3 - * @param {String} [path] A path to append to the root URL. Do not include a leading "`/`". // 4 - * @param {Object} [options] // 5 - * @param {Boolean} options.secure Create an HTTPS URL. // 6 - * @param {Boolean} options.replaceLocalhost Replace localhost with 127.0.0.1. Useful for services that don't recognize localhost as a domain name. - * @param {String} options.rootUrl Override the default ROOT_URL from the server environment. For example: "`http://foo.example.com`" - */ // 9 -Meteor.absoluteUrl = function (path, options) { // 10 - // path is optional // 11 - if (!options && typeof path === 'object') { // 12 - options = path; // 13 - path = undefined; // 14 - } // 15 - // merge options with defaults // 16 - options = _.extend({}, Meteor.absoluteUrl.defaultOptions, options || {}); // 17 - // 18 - var url = options.rootUrl; // 19 - if (!url) // 20 - throw new Error("Must pass options.rootUrl or set ROOT_URL in the server environment"); // 21 - // 22 - if (!/^http[s]?:\/\//i.test(url)) // url starts with 'http://' or 'https://' // 23 - url = 'http://' + url; // we will later fix to https if options.secure is set // 24 - // 25 - if (!/\/$/.test(url)) // url ends with '/' // 26 - url += '/'; // 27 - // 28 - if (path) // 29 - url += path; // 30 - // 31 - // turn http to https if secure option is set, and we're not talking // 32 - // to localhost. // 33 - if (options.secure && // 34 - /^http:/.test(url) && // url starts with 'http:' // 35 - !/http:\/\/localhost[:\/]/.test(url) && // doesn't match localhost // 36 - !/http:\/\/127\.0\.0\.1[:\/]/.test(url)) // or 127.0.0.1 // 37 - url = url.replace(/^http:/, 'https:'); // 38 - // 39 - if (options.replaceLocalhost) // 40 - url = url.replace(/^http:\/\/localhost([:\/].*)/, 'http://127.0.0.1$1'); // 41 - // 42 - return url; // 43 -}; // 44 - // 45 -// allow later packages to override default options // 46 -Meteor.absoluteUrl.defaultOptions = { }; // 47 -if (typeof __meteor_runtime_config__ === "object" && // 48 - __meteor_runtime_config__.ROOT_URL) // 49 - Meteor.absoluteUrl.defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL; // 50 - // 51 - // 52 -Meteor._relativeToSiteRootUrl = function (link) { // 53 - if (typeof __meteor_runtime_config__ === "object" && // 54 - link.substr(0, 1) === "/") // 55 - link = (__meteor_runtime_config__.ROOT_URL_PATH_PREFIX || "") + link; // 56 - return link; // 57 -}; // 58 - // 59 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/meteor/flush-buffers-on-exit-in-windows.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -if (process.platform === "win32") { // 1 - /* // 2 - * Based on https://github.com/cowboy/node-exit // 3 - * // 4 - * Copyright (c) 2013 "Cowboy" Ben Alman // 5 - * Licensed under the MIT license. // 6 - */ // 7 - var origProcessExit = process.exit.bind(process); // 8 - process.exit = function (exitCode) { // 9 - var streams = [process.stdout, process.stderr]; // 10 - var drainCount = 0; // 11 - // Actually exit if all streams are drained. // 12 - function tryToExit() { // 13 - if (drainCount === streams.length) { // 14 - origProcessExit(exitCode); // 15 - } // 16 - } // 17 - streams.forEach(function(stream) { // 18 - // Count drained streams now, but monitor non-drained streams. // 19 - if (stream.bufferSize === 0) { // 20 - drainCount++; // 21 - } else { // 22 - stream.write('', 'utf-8', function() { // 23 - drainCount++; // 24 - tryToExit(); // 25 - }); // 26 - } // 27 - // Prevent further writing. // 28 - stream.write = function() {}; // 29 - }); // 30 - // If all streams were already drained, exit now. // 31 - tryToExit(); // 32 - // In Windows, when run as a Node.js child process, a script utilizing // 33 - // this library might just exit with a 0 exit code, regardless. This code, // 34 - // despite the fact that it looks a bit crazy, appears to fix that. // 35 - process.on('exit', function() { // 36 - origProcessExit(exitCode); // 37 - }); // 38 - }; // 39 -} // 40 -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.meteor = { - Meteor: Meteor -}; - -})(); - -//# sourceMappingURL=meteor.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/meteor.js.map b/web-app/.meteor/local/build/programs/server/packages/meteor.js.map deleted file mode 100644 index 89f6d71..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/meteor.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["meteor/server_environment.js","meteor/helpers.js","meteor/setimmediate.js","meteor/timers.js","meteor/errors.js","meteor/fiber_helpers.js","meteor/startup_server.js","meteor/debug.js","meteor/dynamics_nodejs.js","meteor/url_server.js","meteor/url_common.js","meteor/flush-buffers-on-exit-in-windows.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,U;AACA,kB;AACA,iB;AACA,kB;AACA,E;;AAEA,qB;;AAEA,kC;AACA,O;AACA,8D;AACA,e;AACA,0F;AACA,G;AACA,C;;AAEA,2C;AACA,gD;AACA,oD;AACA,qE;AACA,C;;;;;;;;;;;;;;;;;;;ACpBA,oB;AACA,4C;;AAEA,oD;AACA,8C;AACA,K;AACA,oO;AACA,oB;AACA,mB;AACA,K;AACA,2D;AACA,C;;AAEA,iE;AACA,uB;;AAEA,kB;AACA,mE;AACA,2B;AACA,I;AACA,yC;AACA,gD;AACA,iC;AACA,yB;AACA,8B;AACA,K;AACA,e;AACA,I;;AAEA,qE;AACA,6D;AACA,I;AACA,4C;AACA,gD;AACA,6B;AACA,wB;AACA,sB;AACA,qB;AACA,K;;AAEA,e;AACA,I;;AAEA,mE;AACA,kD;AACA,I;AACA,4C;AACA,sB;AACA,oB;AACA,oD;AACA,6B;AACA,0B;AACA,qB;AACA,c;AACA,O;AACA,qB;AACA,kC;AACA,c;AACA,sB;AACA,K;;AAEA,iD;AACA,+B;;AAEA,e;AACA,qB;AACA,U;AACA,wC;AACA,4C;;AAEA,2B;AACA,K;AACA,I;;AAEA,6E;AACA,gF;AACA,mC;AACA,4C;AACA,iD;AACA,+E;AACA,wE;;AAEA,K;AACA,qB;AACA,8b;AACA,oB;AACA,mF;AACA,yG;AACA,K;AACA,qC;AACA,uC;AACA,iC;AACA,yC;AACA,mB;;AAEA,qD;AACA,6B;AACA,8B;AACA,mC;AACA,oC;AACA,2B;AACA,W;AACA,gB;AACA,S;AACA,O;;AAEA,uB;AACA,8B;AACA,4B;AACA,gB;AACA,iC;AACA,oC;AACA,S;AACA,mD;AACA,O;;AAEA,oD;AACA,2C;AACA,uC;AACA,M;AACA,I;;AAEA,uE;AACA,wB;AACA,wC;AACA,0C;AACA,8E;AACA,uC;AACA,oC;AACA,6B;AACA,uE;AACA,mB;AACA,6B;AACA,iC;AACA,K;;AAEA,8E;AACA,8B;AACA,+B;AACA,M;AACA,wC;AACA,mC;AACA,uC;AACA,iB;AACA,G;AACA,G;;AAEA,iC;;AAEA,G;AACA,uB;AACA,G;AACA,2C;AACA,+B;AACA,4E;AACA,gC;AACA,G;AACA,mD;AACA,E;;AAEA,sB;AACA,Y;AACA,yB;AACA,gD;AACA,iC;AACA,M;AACA,G;AACA,C;;;;;;;;;;;;;;;;;;;ACvKA,qD;AACA,E;AACA,2C;AACA,E;AACA,gC;AACA,E;AACA,2B;AACA,E;AACA,6C;AACA,qD;AACA,E;AACA,mE;AACA,iD;AACA,E;AACA,oE;AACA,wD;AACA,mB;AACA,E;AACA,kE;AACA,6D;AACA,sE;AACA,uE;AACA,qE;AACA,mE;AACA,iE;AACA,4C;AACA,E;AACA,gE;AACA,0D;;AAEA,a;;AAEA,kB;;;AAGA,qB;;AAEA,4B;AACA,4B;AACA,gB;AACA,Q;AACA,sC;AACA,8B;AACA,M;AACA,iD;AACA,wB;AACA,G;AACA,C;;;AAGA,iE;;AAEA,2B;AACA,kE;AACA,oD;AACA,kE;AACA,oC;;AAEA,oD;AACA,gB;AACA,G;;AAEA,oD;;AAEA,uC;AACA,sC;AACA,kC;AACA,wC;AACA,I;AACA,8B;AACA,kC;;AAEA,kC;AACA,gB;;AAEA,oB;AACA,iB;;AAEA,uE;AACA,8D;AACA,mG;;AAEA,8B;AACA,qE;;AAEA,yD;AACA,yC;AACA,yE;AACA,G;;AAEA,mC;AACA,6D;AACA,oE;AACA,kE;AACA,yD;AACA,mD;AACA,kC;AACA,4D;AACA,8D;AACA,W;AACA,yB;AACA,yB;AACA,O;AACA,e;AACA,4B;AACA,O;AACA,K;AACA,G;;AAEA,gC;AACA,+D;AACA,U;AACA,qD;AACA,G;;AAEA,oC;AACA,iE;AACA,2D;AACA,sC;AACA,gB;AACA,0B;AACA,wD;AACA,I;AACA,8C;AACA,sB;AACA,C;;;AAGA,uB;AACA,oC;AACA,6B;AACA,I;AACA,6C;AACA,sB;AACA,C;;;AAGA,sB;AACA,sB;AACA,qB;AACA,e;;;;;;;;;;;;;;;;;;;AC5IA,sC;AACA,oB;AACA,gE;AACA,0E;AACA,6D;AACA,kE;AACA,G;AACA,M;AACA,a;AACA,E;;AAEA,0C;AACA,+D;AACA,E;;AAEA,kB;AACA,iE;AACA,qE;AACA,iE;;AAEA,K;AACA,qB;AACA,gF;AACA,oB;AACA,+C;AACA,iF;AACA,K;AACA,sC;AACA,wE;AACA,I;;AAEA,K;AACA,qB;AACA,0E;AACA,oB;AACA,+C;AACA,qF;AACA,K;AACA,uC;AACA,0E;AACA,I;;AAEA,K;AACA,qB;AACA,iF;AACA,oB;AACA,mE;AACA,K;AACA,8B;AACA,4B;AACA,I;;AAEA,K;AACA,qB;AACA,sE;AACA,oB;AACA,kE;AACA,K;AACA,6B;AACA,2B;AACA,I;;AAEA,2E;AACA,4E;AACA,0C;AACA,wE;AACA,uB;AACA,4D;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACrEA,wE;AACA,8E;AACA,wE;AACA,E;AACA,qD;AACA,6C;AACA,oB;;AAEA,yE;AACA,kC;AACA,6C;AACA,gD;AACA,Y;AACA,gB;AACA,wB;AACA,yC;AACA,kC;AACA,iB;AACA,K;AACA,8B;;AAEA,uC;;AAEA,0B;;AAEA,gB;AACA,I;;AAEA,sC;;AAEA,oB;AACA,E;;AAEA,qE;AACA,sE;AACA,gE;AACA,6D;AACA,E;AACA,+E;AACA,4D;AACA,8E;AACA,uE;AACA,mC;;AAEA,G;AACA,sE;AACA,kB;AACA,S;AACA,+E;AACA,uE;AACA,wE;AACA,kC;AACA,E;AACA,M;AACA,qD;AACA,uD;AACA,wC;AACA,sD;AACA,E;AACA,mB;AACA,+C;AACA,0B;AACA,wC;AACA,mC;AACA,uE;AACA,M;AACA,M;AACA,M;AACA,G;AACA,2E;AACA,sC;AACA,G;AACA,4E;AACA,2B;AACA,+E;AACA,8B;AACA,G;AACA,oC;AACA,iB;AACA,qC;AACA,oB;;AAEA,oE;AACA,kD;AACA,uB;;AAEA,iE;AACA,wE;AACA,+B;AACA,yB;;AAEA,gE;AACA,sE;AACA,uE;AACA,oE;AACA,sE;AACA,qC;AACA,2B;;AAEA,uE;AACA,wE;AACA,oB;AACA,2D;AACA,Q;AACA,4C;AACA,K;;AAEA,gF;AACA,qE;AACA,0E;AACA,6E;AACA,uC;AACA,4C;AACA,kB;AACA,iE;AACA,E;;;;;;;;;;;;;;;;;;;ACnHA,+B;AACA,kC;AACA,wD;;AAEA,wC;AACA,+B;AACA,6B;AACA,oE;AACA,I;AACA,O;AACA,e;AACA,a;AACA,6B;AACA,G;AACA,E;;AAEA,6D;;AAEA,0E;AACA,sE;AACA,yB;AACA,E;AACA,sB;AACA,kE;AACA,mE;AACA,sC;AACA,E;AACA,0E;AACA,+C;AACA,E;AACA,oE;AACA,yC;AACA,oE;AACA,oD;AACA,E;AACA,wC;AACA,kB;AACA,+E;AACA,gF;AACA,gF;AACA,4B;AACA,qD;AACA,8E;AACA,gB;AACA,sC;AACA,6E;AACA,4E;AACA,6D;AACA,qC;AACA,+E;AACA,6E;AACA,8E;AACA,4C;AACA,yB;AACA,E;;AAEA,8C;AACA,4B;AACA,oB;;AAEA,gC;AACA,wB;AACA,6E;AACA,U;AACA,4D;AACA,K;;AAEA,yB;AACA,kB;AACA,uD;AACA,iE;AACA,gB;AACA,S;AACA,kB;AACA,qB;AACA,M;AACA,mC;AACA,wB;AACA,8E;AACA,oB;AACA,e;AACA,I;AACA,8B;AACA,oB;AACA,4B;AACA,iB;AACA,qB;AACA,O;AACA,wB;AACA,wB;AACA,I;;AAEA,sB;AACA,oB;AACA,iC;AACA,I;;AAEA,8B;AACA,oB;AACA,qE;AACA,I;;AAEA,sB;AACA,oB;AACA,uB;AACA,a;AACA,8B;AACA,a;AACA,0B;AACA,2C;AACA,mB;AACA,K;AACA,2B;AACA,I;;AAEA,6B;AACA,oB;AACA,gD;AACA,oC;AACA,a;;AAEA,uC;AACA,8B;AACA,yB;AACA,oB;AACA,e;AACA,O;AACA,I;AACA,qB;AACA,oB;;AAEA,qC;AACA,+D;;AAEA,sC;AACA,wE;AACA,qC;AACA,0C;AACA,a;AACA,K;AACA,+C;;AAEA,oB;AACA,2C;AACA,8B;AACA,S;AACA,wB;AACA,mB;AACA,8B;AACA,sD;AACA,wB;AACA,c;AACA,gE;AACA,O;AACA,K;AACA,uC;;AAEA,gD;AACA,wC;AACA,wB;;AAEA,gF;AACA,uB;AACA,4B;AACA,oB;AACA,8C;AACA,U;AACA,sC;AACA,K;AACA,G;AACA,G;;AAEA,sE;AACA,Y;AACA,E;AACA,oC;AACA,4B;AACA,yB;AACA,gB;AACA,S;AACA,gB;AACA,E;;;;;;;;;;;;;;;;;;;ACrLA,sC;AACA,0C;AACA,qD;AACA,U;AACA,+C;AACA,e;AACA,G;AACA,E;;;;;;;;;;;;;;;;;;;ACPA,iB;;AAEA,kE;AACA,gE;AACA,Y;AACA,E;AACA,8D;AACA,gE;AACA,0D;AACA,mE;AACA,mE;AACA,8D;AACA,E;AACA,4C;AACA,iB;AACA,e;AACA,W;AACA,G;AACA,uC;AACA,2C;AACA,iE;AACA,gD;AACA,sB;AACA,Y;AACA,mE;AACA,wF;AACA,kE;AACA,oD;AACA,wB;;AAEA,qF;AACA,wE;AACA,iF;AACA,8E;AACA,4C;AACA,kD;AACA,+C;AACA,6C;;AAEA,qC;AACA,kF;AACA,Y;AACA,gD;;AAEA,iE;AACA,c;AACA,qE;AACA,sC;AACA,c;AACA,c;AACA,kG;AACA,O;AACA,K;AACA,G;AACA,E;;AAEA,iE;AACA,wC;AACA,E;AACA,yC;AACA,oB;AACA,E;;AAEA,8C;AACA,wB;AACA,E;;;;;;;;;;;;;;;;;;;;ACjEA,uE;;AAEA,kC;;AAEA,iB;;AAEA,6C;AACA,uB;AACA,oE;AACA,2E;AACA,8D;AACA,G;AACA,E;;AAEA,0C;AACA,yB;AACA,E;;AAEA,gD;AACA,oB;AACA,oC;;AAEA,4C;AACA,gD;AACA,I;;AAEA,0D;AACA,+E;AACA,yE;AACA,2C;AACA,I;AACA,8E;AACA,+E;AACA,6E;AACA,gF;AACA,gF;AACA,yE;AACA,gF;AACA,uC;AACA,wC;AACA,uB;AACA,kB;AACA,sB;AACA,I;;AAEA,qC;AACA,oC;;AAEA,wC;AACA,0C;AACA,uD;;AAEA,yC;AACA,S;AACA,uC;AACA,uB;AACA,e;AACA,uC;AACA,K;;AAEA,e;AACA,G;AACA,G;;AAEA,gE;AACA,wE;AACA,sE;AACA,gE;AACA,E;AACA,4E;AACA,6E;AACA,8E;AACA,wE;AACA,E;AACA,wD;AACA,kE;AACA,0B;AACA,E;AACA,gE;AACA,sE;AACA,sE;AACA,oE;AACA,gC;AACA,8D;AACA,kC;;AAEA,kE;;AAEA,yD;AACA,kE;AACA,oC;AACA,oB;AACA,4C;AACA,qC;AACA,Q;AACA,M;AACA,G;;AAEA,qC;AACA,oC;;AAEA,0C;AACA,uD;AACA,W;AACA,mE;AACA,oC;AACA,8D;AACA,0C;AACA,mB;AACA,+E;AACA,2E;AACA,mD;AACA,uB;AACA,iB;AACA,qD;AACA,O;AACA,iB;AACA,M;;AAEA,sB;AACA,kC;AACA,oC;AACA,I;AACA,E;;;;;;;;;;;;;;;;;;;AC3HA,2B;AACA,oD;AACA,4D;AACA,2C;AACA,iF;AACA,8D;AACA,0B;AACA,6D;AACA,K;AACA,wC;AACA,uC;AACA,oD;AACA,2C;AACA,K;AACA,gE;AACA,U;AACA,wD;AACA,G;AACA,C;;;;;;;;;;;;;;;;;;;AClBA,G;AACA,yR;AACA,kB;AACA,2F;AACA,4B;AACA,uD;AACA,mJ;AACA,qI;AACA,G;AACA,+C;AACA,qB;AACA,6C;AACA,mB;AACA,qB;AACA,G;AACA,gC;AACA,2E;;AAEA,4B;AACA,W;AACA,2F;;AAEA,8E;AACA,iF;;AAEA,4C;AACA,e;;AAEA,W;AACA,gB;;AAEA,sE;AACA,kB;AACA,uB;AACA,sD;AACA,wE;AACA,8D;AACA,0C;;AAEA,+B;AACA,4E;;AAEA,a;AACA,E;;AAEA,mD;AACA,wC;AACA,oD;AACA,uC;AACA,iF;;;AAGA,iD;AACA,sD;AACA,gC;AACA,yE;AACA,c;AACA,E;;;;;;;;;;;;;;;;;;;ACzDA,mC;AACA,I;AACA,iD;AACA,I;AACA,0C;AACA,oC;AACA,K;AACA,mD;AACA,sC;AACA,mD;AACA,uB;AACA,gD;AACA,0B;AACA,0C;AACA,kC;AACA,O;AACA,K;AACA,sC;AACA,oE;AACA,oC;AACA,qB;AACA,c;AACA,8C;AACA,uB;AACA,sB;AACA,W;AACA,O;AACA,iC;AACA,mC;AACA,O;AACA,qD;AACA,gB;AACA,0E;AACA,8E;AACA,uE;AACA,mC;AACA,gC;AACA,O;AACA,I;AACA,C","file":"/packages/meteor.js","sourcesContent":["Meteor = {\n isClient: false,\n isServer: true,\n isCordova: false\n};\n\nMeteor.settings = {};\n\nif (process.env.METEOR_SETTINGS) {\n try {\n Meteor.settings = JSON.parse(process.env.METEOR_SETTINGS);\n } catch (e) {\n throw new Error(\"METEOR_SETTINGS are not valid JSON: \" + process.env.METEOR_SETTINGS);\n }\n}\n\n// Push a subset of settings to the client.\nif (Meteor.settings && Meteor.settings.public &&\n typeof __meteor_runtime_config__ === \"object\") {\n __meteor_runtime_config__.PUBLIC_SETTINGS = Meteor.settings.public;\n}\n","if (Meteor.isServer)\n var Future = Npm.require('fibers/future');\n\nif (typeof __meteor_runtime_config__ === 'object' &&\n __meteor_runtime_config__.meteorRelease) {\n /**\n * @summary `Meteor.release` is a string containing the name of the [release](#meteorupdate) with which the project was built (for example, `\"1.2.3\"`). It is `undefined` if the project was built using a git checkout of Meteor.\n * @locus Anywhere\n * @type {String}\n */\n Meteor.release = __meteor_runtime_config__.meteorRelease;\n}\n\n// XXX find a better home for these? Ideally they would be _.get,\n// _.ensure, _.delete..\n\n_.extend(Meteor, {\n // _get(a,b,c,d) returns a[b][c][d], or else undefined if a[b] or\n // a[b][c] doesn't exist.\n //\n _get: function (obj /*, arguments */) {\n for (var i = 1; i < arguments.length; i++) {\n if (!(arguments[i] in obj))\n return undefined;\n obj = obj[arguments[i]];\n }\n return obj;\n },\n\n // _ensure(a,b,c,d) ensures that a[b][c][d] exists. If it does not,\n // it is created and set to {}. Either way, it is returned.\n //\n _ensure: function (obj /*, arguments */) {\n for (var i = 1; i < arguments.length; i++) {\n var key = arguments[i];\n if (!(key in obj))\n obj[key] = {};\n obj = obj[key];\n }\n\n return obj;\n },\n\n // _delete(a, b, c, d) deletes a[b][c][d], then a[b][c] unless it\n // isn't empty, then a[b] unless it isn't empty.\n //\n _delete: function (obj /*, arguments */) {\n var stack = [obj];\n var leaf = true;\n for (var i = 1; i < arguments.length - 1; i++) {\n var key = arguments[i];\n if (!(key in obj)) {\n leaf = false;\n break;\n }\n obj = obj[key];\n if (typeof obj !== \"object\")\n break;\n stack.push(obj);\n }\n\n for (var i = stack.length - 1; i >= 0; i--) {\n var key = arguments[i+1];\n\n if (leaf)\n leaf = false;\n else\n for (var other in stack[i][key])\n return; // not empty -- we're done\n\n delete stack[i][key];\n }\n },\n\n // wrapAsync can wrap any function that takes some number of arguments that\n // can't be undefined, followed by some optional arguments, where the callback\n // is the last optional argument.\n // e.g. fs.readFile(pathname, [callback]),\n // fs.open(pathname, flags, [mode], [callback])\n // For maximum effectiveness and least confusion, wrapAsync should be used on\n // functions where the callback is the only argument of type Function.\n\n /**\n * @memberOf Meteor\n * @summary Wrap a function that takes a callback function as its final parameter. On the server, the wrapped function can be used either synchronously (without passing a callback) or asynchronously (when a callback is passed). On the client, a callback is always required; errors will be logged if there is no callback. If a callback is provided, the environment captured when the original function was called will be restored in the callback.\n * @locus Anywhere\n * @param {Function} func A function that takes a callback as its final parameter\n * @param {Object} [context] Optional `this` object against which the original function will be invoked\n */\n wrapAsync: function (fn, context) {\n return function (/* arguments */) {\n var self = context || this;\n var newArgs = _.toArray(arguments);\n var callback;\n\n for (var i = newArgs.length - 1; i >= 0; --i) {\n var arg = newArgs[i];\n var type = typeof arg;\n if (type !== \"undefined\") {\n if (type === \"function\") {\n callback = arg;\n }\n break;\n }\n }\n\n if (! callback) {\n if (Meteor.isClient) {\n callback = logErr;\n } else {\n var fut = new Future();\n callback = fut.resolver();\n }\n ++i; // Insert the callback just after arg.\n }\n\n newArgs[i] = Meteor.bindEnvironment(callback);\n var result = fn.apply(self, newArgs);\n return fut ? fut.wait() : result;\n };\n },\n\n // Sets child's prototype to a new object whose prototype is parent's\n // prototype. Used as:\n // Meteor._inherits(ClassB, ClassA).\n // _.extend(ClassB.prototype, { ... })\n // Inspired by CoffeeScript's `extend` and Google Closure's `goog.inherits`.\n _inherits: function (Child, Parent) {\n // copy Parent static properties\n for (var key in Parent) {\n // make sure we only copy hasOwnProperty properties vs. prototype\n // properties\n if (_.has(Parent, key))\n Child[key] = Parent[key];\n }\n\n // a middle member of prototype chain: takes the prototype from the Parent\n var Middle = function () {\n this.constructor = Child;\n };\n Middle.prototype = Parent.prototype;\n Child.prototype = new Middle();\n Child.__super__ = Parent.prototype;\n return Child;\n }\n});\n\nvar warnedAboutWrapAsync = false;\n\n/**\n * @deprecated in 0.9.3\n */\nMeteor._wrapAsync = function(fn, context) {\n if (! warnedAboutWrapAsync) {\n Meteor._debug(\"Meteor._wrapAsync has been renamed to Meteor.wrapAsync\");\n warnedAboutWrapAsync = true;\n }\n return Meteor.wrapAsync.apply(Meteor, arguments);\n};\n\nfunction logErr(err) {\n if (err) {\n return Meteor._debug(\n \"Exception in callback of async function\",\n err.stack ? err.stack : err\n );\n }\n}\n","// Chooses one of three setImmediate implementations:\n//\n// * Native setImmediate (IE 10, Node 0.9+)\n//\n// * postMessage (many browsers)\n//\n// * setTimeout (fallback)\n//\n// The postMessage implementation is based on\n// https://github.com/NobleJS/setImmediate/tree/1.0.1\n//\n// Don't use `nextTick` for Node since it runs its callbacks before\n// I/O, which is stricter than we're looking for.\n//\n// Not installed as a polyfill, as our public API is `Meteor.defer`.\n// Since we're not trying to be a polyfill, we have some\n// simplifications:\n//\n// If one invocation of a setImmediate callback pauses itself by a\n// call to alert/prompt/showModelDialog, the NobleJS polyfill\n// implementation ensured that no setImmedate callback would run until\n// the first invocation completed. While correct per the spec, what it\n// would mean for us in practice is that any reactive updates relying\n// on Meteor.defer would be hung in the main window until the modal\n// dialog was dismissed. Thus we only ensure that a setImmediate\n// function is called in a later event loop.\n//\n// We don't need to support using a string to be eval'ed for the\n// callback, arguments to the function, or clearImmediate.\n\n\"use strict\";\n\nvar global = this;\n\n\n// IE 10, Node >= 9.1\n\nfunction useSetImmediate() {\n if (! global.setImmediate)\n return null;\n else {\n var setImmediate = function (fn) {\n global.setImmediate(fn);\n };\n setImmediate.implementation = 'setImmediate';\n return setImmediate;\n }\n}\n\n\n// Android 2.3.6, Chrome 26, Firefox 20, IE 8-9, iOS 5.1.1 Safari\n\nfunction usePostMessage() {\n // The test against `importScripts` prevents this implementation\n // from being installed inside a web worker, where\n // `global.postMessage` means something completely different and\n // can't be used for this purpose.\n\n if (!global.postMessage || global.importScripts) {\n return null;\n }\n\n // Avoid synchronous post message implementations.\n\n var postMessageIsAsynchronous = true;\n var oldOnMessage = global.onmessage;\n global.onmessage = function () {\n postMessageIsAsynchronous = false;\n };\n global.postMessage(\"\", \"*\");\n global.onmessage = oldOnMessage;\n\n if (! postMessageIsAsynchronous)\n return null;\n\n var funcIndex = 0;\n var funcs = {};\n\n // Installs an event handler on `global` for the `message` event: see\n // * https://developer.mozilla.org/en/DOM/window.postMessage\n // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages\n\n // XXX use Random.id() here?\n var MESSAGE_PREFIX = \"Meteor._setImmediate.\" + Math.random() + '.';\n\n function isStringAndStartsWith(string, putativeStart) {\n return (typeof string === \"string\" &&\n string.substring(0, putativeStart.length) === putativeStart);\n }\n\n function onGlobalMessage(event) {\n // This will catch all incoming messages (even from other\n // windows!), so we need to try reasonably hard to avoid letting\n // anyone else trick us into firing off. We test the origin is\n // still this window, and that a (randomly generated)\n // unpredictable identifying prefix is present.\n if (event.source === global &&\n isStringAndStartsWith(event.data, MESSAGE_PREFIX)) {\n var index = event.data.substring(MESSAGE_PREFIX.length);\n try {\n if (funcs[index])\n funcs[index]();\n }\n finally {\n delete funcs[index];\n }\n }\n }\n\n if (global.addEventListener) {\n global.addEventListener(\"message\", onGlobalMessage, false);\n } else {\n global.attachEvent(\"onmessage\", onGlobalMessage);\n }\n\n var setImmediate = function (fn) {\n // Make `global` post a message to itself with the handle and\n // identifying prefix, thus asynchronously invoking our\n // onGlobalMessage listener above.\n ++funcIndex;\n funcs[funcIndex] = fn;\n global.postMessage(MESSAGE_PREFIX + funcIndex, \"*\");\n };\n setImmediate.implementation = 'postMessage';\n return setImmediate;\n}\n\n\nfunction useTimeout() {\n var setImmediate = function (fn) {\n global.setTimeout(fn, 0);\n };\n setImmediate.implementation = 'setTimeout';\n return setImmediate;\n}\n\n\nMeteor._setImmediate =\n useSetImmediate() ||\n usePostMessage() ||\n useTimeout();\n","var withoutInvocation = function (f) {\n if (Package.ddp) {\n var _CurrentInvocation = Package.ddp.DDP._CurrentInvocation;\n if (_CurrentInvocation.get() && _CurrentInvocation.get().isSimulation)\n throw new Error(\"Can't set timers inside simulations\");\n return function () { _CurrentInvocation.withValue(null, f); };\n }\n else\n return f;\n};\n\nvar bindAndCatch = function (context, f) {\n return Meteor.bindEnvironment(withoutInvocation(f), context);\n};\n\n_.extend(Meteor, {\n // Meteor.setTimeout and Meteor.setInterval callbacks scheduled\n // inside a server method are not part of the method invocation and\n // should clear out the CurrentInvocation environment variable.\n\n /**\n * @memberOf Meteor\n * @summary Call a function in the future after waiting for a specified delay.\n * @locus Anywhere\n * @param {Function} func The function to run\n * @param {Number} delay Number of milliseconds to wait before calling function\n */\n setTimeout: function (f, duration) {\n return setTimeout(bindAndCatch(\"setTimeout callback\", f), duration);\n },\n\n /**\n * @memberOf Meteor\n * @summary Call a function repeatedly, with a time delay between calls.\n * @locus Anywhere\n * @param {Function} func The function to run\n * @param {Number} delay Number of milliseconds to wait between each function call.\n */\n setInterval: function (f, duration) {\n return setInterval(bindAndCatch(\"setInterval callback\", f), duration);\n },\n\n /**\n * @memberOf Meteor\n * @summary Cancel a repeating function call scheduled by `Meteor.setInterval`.\n * @locus Anywhere\n * @param {Number} id The handle returned by `Meteor.setInterval`\n */\n clearInterval: function(x) {\n return clearInterval(x);\n },\n\n /**\n * @memberOf Meteor\n * @summary Cancel a function call scheduled by `Meteor.setTimeout`.\n * @locus Anywhere\n * @param {Number} id The handle returned by `Meteor.setTimeout`\n */\n clearTimeout: function(x) {\n return clearTimeout(x);\n },\n\n // XXX consider making this guarantee ordering of defer'd callbacks, like\n // Tracker.afterFlush or Node's nextTick (in practice). Then tests can do:\n // callSomethingThatDefersSomeWork();\n // Meteor.defer(expect(somethingThatValidatesThatTheWorkHappened));\n defer: function (f) {\n Meteor._setImmediate(bindAndCatch(\"defer callback\", f));\n }\n});\n","// Makes an error subclass which properly contains a stack trace in most\n// environments. constructor can set fields on `this` (and should probably set\n// `message`, which is what gets displayed at the top of a stack trace).\n//\nMeteor.makeErrorType = function (name, constructor) {\n var errorClass = function (/*arguments*/) {\n var self = this;\n\n // Ensure we get a proper stack trace in most Javascript environments\n if (Error.captureStackTrace) {\n // V8 environments (Chrome and Node.js)\n Error.captureStackTrace(self, errorClass);\n } else {\n // Firefox\n var e = new Error;\n e.__proto__ = errorClass.prototype;\n if (e instanceof errorClass)\n self = e;\n }\n // Safari magically works.\n\n constructor.apply(self, arguments);\n\n self.errorType = name;\n\n return self;\n };\n\n Meteor._inherits(errorClass, Error);\n\n return errorClass;\n};\n\n// This should probably be in the livedata package, but we don't want\n// to require you to use the livedata package to get it. Eventually we\n// should probably rename it to DDP.Error and put it back in the\n// 'livedata' package (which we should rename to 'ddp' also.)\n//\n// Note: The DDP server assumes that Meteor.Error EJSON-serializes as an object\n// containing 'error' and optionally 'reason' and 'details'.\n// The DDP client manually puts these into Meteor.Error objects. (We don't use\n// EJSON.addType here because the type is determined by location in the\n// protocol, not text on the wire.)\n\n/**\n * @summary This class represents a symbolic error thrown by a method.\n * @locus Anywhere\n * @class\n * @param {String} error A string code uniquely identifying this kind of error.\n * This string should be used by callers of the method to determine the\n * appropriate action to take, instead of attempting to parse the reason\n * or details fields. For example:\n *\n * ```\n * // on the server, pick a code unique to this error\n * // the reason field should be a useful debug message\n * throw new Meteor.Error(\"logged-out\", \n * \"The user must be logged in to post a comment.\");\n *\n * // on the client\n * Meteor.call(\"methodName\", function (error) {\n * // identify the error\n * if (error.error === \"logged-out\") {\n * // show a nice error message\n * Session.set(\"errorMessage\", \"Please log in to post a comment.\");\n * }\n * });\n * ```\n * \n * For legacy reasons, some built-in Meteor functions such as `check` throw\n * errors with a number in this field.\n * \n * @param {String} [reason] Optional. A short human-readable summary of the\n * error, like 'Not Found'.\n * @param {String} [details] Optional. Additional information about the error,\n * like a textual stack trace.\n */\nMeteor.Error = Meteor.makeErrorType(\n \"Meteor.Error\",\n function (error, reason, details) {\n var self = this;\n\n // Currently, a numeric code, likely similar to a HTTP code (eg,\n // 404, 500). That is likely to change though.\n self.error = error;\n\n // Optional: A short human-readable summary of the error. Not\n // intended to be shown to end users, just developers. (\"Not Found\",\n // \"Internal Server Error\")\n self.reason = reason;\n\n // Optional: Additional information about the error, say for\n // debugging. It might be a (textual) stack trace if the server is\n // willing to provide one. The corresponding thing in HTTP would be\n // the body of a 404 or 500 response. (The difference is that we\n // never expect this to be shown to end users, only developers, so\n // it doesn't need to be pretty.)\n self.details = details;\n\n // This is what gets displayed at the top of a stack trace. Current\n // format is \"[404]\" (if no reason is set) or \"File not found [404]\"\n if (self.reason)\n self.message = self.reason + ' [' + self.error + ']';\n else\n self.message = '[' + self.error + ']';\n });\n\n// Meteor.Error is basically data and is sent over DDP, so you should be able to\n// properly EJSON-clone it. This is especially important because if a\n// Meteor.Error is thrown through a Future, the error, reason, and details\n// properties become non-enumerable so a standard Object clone won't preserve\n// them and they will be lost from DDP.\nMeteor.Error.prototype.clone = function () {\n var self = this;\n return new Meteor.Error(self.error, self.reason, self.details);\n};\n","var path = Npm.require('path');\nvar Fiber = Npm.require('fibers');\nvar Future = Npm.require(path.join('fibers', 'future'));\n\nMeteor._noYieldsAllowed = function (f) {\n var savedYield = Fiber.yield;\n Fiber.yield = function () {\n throw new Error(\"Can't call yield in a noYieldsAllowed block!\");\n };\n try {\n return f();\n } finally {\n Fiber.yield = savedYield;\n }\n};\n\nMeteor._DoubleEndedQueue = Npm.require('double-ended-queue');\n\n// Meteor._SynchronousQueue is a queue which runs task functions serially.\n// Tasks are assumed to be synchronous: ie, it's assumed that they are\n// done when they return.\n//\n// It has two methods:\n// - queueTask queues a task to be run, and returns immediately.\n// - runTask queues a task to be run, and then yields. It returns\n// when the task finishes running.\n//\n// It's safe to call queueTask from within a task, but not runTask (unless\n// you're calling runTask from a nested Fiber).\n//\n// Somewhat inspired by async.queue, but specific to blocking tasks.\n// XXX break this out into an NPM module?\n// XXX could maybe use the npm 'schlock' module instead, which would\n// also support multiple concurrent \"read\" tasks\n//\nMeteor._SynchronousQueue = function () {\n var self = this;\n // List of tasks to run (not including a currently-running task if any). Each\n // is an object with field 'task' (the task function to run) and 'future' (the\n // Future associated with the blocking runTask call that queued it, or null if\n // called from queueTask).\n self._taskHandles = new Meteor._DoubleEndedQueue();\n // This is true if self._run() is either currently executing or scheduled to\n // do so soon.\n self._runningOrRunScheduled = false;\n // During the execution of a task, this is set to the fiber used to execute\n // that task. We use this to throw an error rather than deadlocking if the\n // user calls runTask from within a task on the same fiber.\n self._currentTaskFiber = undefined;\n // This is true if we're currently draining. While we're draining, a further\n // drain is a noop, to prevent infinite loops. \"drain\" is a heuristic type\n // operation, that has a meaning like unto \"what a naive person would expect\n // when modifying a table from an observe\"\n self._draining = false;\n};\n\n_.extend(Meteor._SynchronousQueue.prototype, {\n runTask: function (task) {\n var self = this;\n\n if (!self.safeToRunTask()) {\n if (Fiber.current)\n throw new Error(\"Can't runTask from another task in the same fiber\");\n else\n throw new Error(\"Can only call runTask in a Fiber\");\n }\n\n var fut = new Future;\n var handle = {\n task: Meteor.bindEnvironment(task, function (e) {\n Meteor._debug(\"Exception from task:\", e && e.stack || e);\n throw e;\n }),\n future: fut,\n name: task.name\n };\n self._taskHandles.push(handle);\n self._scheduleRun();\n // Yield. We'll get back here after the task is run (and will throw if the\n // task throws).\n fut.wait();\n },\n queueTask: function (task) {\n var self = this;\n self._taskHandles.push({\n task: task,\n name: task.name\n });\n self._scheduleRun();\n // No need to block.\n },\n\n flush: function () {\n var self = this;\n self.runTask(function () {});\n },\n\n safeToRunTask: function () {\n var self = this;\n return Fiber.current && self._currentTaskFiber !== Fiber.current;\n },\n\n drain: function () {\n var self = this;\n if (self._draining)\n return;\n if (!self.safeToRunTask())\n return;\n self._draining = true;\n while (! self._taskHandles.isEmpty()) {\n self.flush();\n }\n self._draining = false;\n },\n\n _scheduleRun: function () {\n var self = this;\n // Already running or scheduled? Do nothing.\n if (self._runningOrRunScheduled)\n return;\n\n self._runningOrRunScheduled = true;\n setImmediate(function () {\n Fiber(function () {\n self._run();\n }).run();\n });\n },\n _run: function () {\n var self = this;\n\n if (!self._runningOrRunScheduled)\n throw new Error(\"expected to be _runningOrRunScheduled\");\n\n if (self._taskHandles.isEmpty()) {\n // Done running tasks! Don't immediately schedule another run, but\n // allow future tasks to do so.\n self._runningOrRunScheduled = false;\n return;\n }\n var taskHandle = self._taskHandles.shift();\n\n // Run the task.\n self._currentTaskFiber = Fiber.current;\n var exception = undefined;\n try {\n taskHandle.task();\n } catch (err) {\n if (taskHandle.future) {\n // We'll throw this exception through runTask.\n exception = err;\n } else {\n Meteor._debug(\"Exception in queued task: \" + err.stack);\n }\n }\n self._currentTaskFiber = undefined;\n\n // Soon, run the next task, if there is any.\n self._runningOrRunScheduled = false;\n self._scheduleRun();\n\n // If this was queued with runTask, let the runTask call return (throwing if\n // the task threw).\n if (taskHandle.future) {\n if (exception)\n taskHandle.future['throw'](exception);\n else\n taskHandle.future['return']();\n }\n }\n});\n\n// Sleep. Mostly used for debugging (eg, inserting latency into server\n// methods).\n//\nMeteor._sleepForMs = function (ms) {\n var fiber = Fiber.current;\n setTimeout(function() {\n fiber.run();\n }, ms);\n Fiber.yield();\n};\n","Meteor.startup = function (callback) {\n if (__meteor_bootstrap__.startupHooks) {\n __meteor_bootstrap__.startupHooks.push(callback);\n } else {\n // We already started up. Just call it now.\n callback();\n }\n};\n","var suppress = 0;\n\n// replacement for console.log. This is a temporary API. We should\n// provide a real logging API soon (possibly just a polyfill for\n// console?)\n//\n// NOTE: this is used on the server to print the warning about\n// having autopublish enabled when you probably meant to turn it\n// off. it's not really the proper use of something called\n// _debug. the intent is for this message to go to the terminal and\n// be very visible. if you change _debug to go someplace else, etc,\n// please fix the autopublish code to do something reasonable.\n//\nMeteor._debug = function (/* arguments */) {\n if (suppress) {\n suppress--;\n return;\n }\n if (typeof console !== 'undefined' &&\n typeof console.log !== 'undefined') {\n if (arguments.length == 0) { // IE Companion breaks otherwise\n // IE10 PP4 requires at least one argument\n console.log('');\n } else {\n // IE doesn't have console.log.apply, it's not a real Object.\n // http://stackoverflow.com/questions/5538972/console-log-apply-not-working-in-ie9\n // http://patik.com/blog/complete-cross-browser-console-log/\n if (typeof console.log.apply === \"function\") {\n // Most browsers\n\n // Chrome and Safari only hyperlink URLs to source files in first argument of\n // console.log, so try to call it with one argument if possible.\n // Approach taken here: If all arguments are strings, join them on space.\n // See https://github.com/meteor/meteor/pull/732#issuecomment-13975991\n var allArgumentsOfTypeString = true;\n for (var i = 0; i < arguments.length; i++)\n if (typeof arguments[i] !== \"string\")\n allArgumentsOfTypeString = false;\n\n if (allArgumentsOfTypeString)\n console.log.apply(console, [Array.prototype.join.call(arguments, \" \")]);\n else\n console.log.apply(console, arguments);\n\n } else if (typeof Function.prototype.bind === \"function\") {\n // IE9\n var log = Function.prototype.bind.call(console.log, console);\n log.apply(console, arguments);\n } else {\n // IE8\n Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));\n }\n }\n }\n};\n\n// Suppress the next 'count' Meteor._debug messsages. Use this to\n// stop tests from spamming the console.\n//\nMeteor._suppress_log = function (count) {\n suppress += count;\n};\n\nMeteor._supressed_log_expected = function () {\n return suppress !== 0;\n};\n\n","// Fiber-aware implementation of dynamic scoping, for use on the server\n\nvar Fiber = Npm.require('fibers');\n\nvar nextSlot = 0;\n\nMeteor._nodeCodeMustBeInFiber = function () {\n if (!Fiber.current) {\n throw new Error(\"Meteor code must always run within a Fiber. \" +\n \"Try wrapping callbacks that you pass to non-Meteor \" +\n \"libraries with Meteor.bindEnvironment.\");\n }\n};\n\nMeteor.EnvironmentVariable = function () {\n this.slot = nextSlot++;\n};\n\n_.extend(Meteor.EnvironmentVariable.prototype, {\n get: function () {\n Meteor._nodeCodeMustBeInFiber();\n\n return Fiber.current._meteor_dynamics &&\n Fiber.current._meteor_dynamics[this.slot];\n },\n\n // Most Meteor code ought to run inside a fiber, and the\n // _nodeCodeMustBeInFiber assertion helps you remember to include appropriate\n // bindEnvironment calls (which will get you the *right value* for your\n // environment variables, on the server).\n //\n // In some very special cases, it's more important to run Meteor code on the\n // server in non-Fiber contexts rather than to strongly enforce the safeguard\n // against forgetting to use bindEnvironment. For example, using `check` in\n // some top-level constructs like connect handlers without needing unnecessary\n // Fibers on every request is more important that possibly failing to find the\n // correct argumentChecker. So this function is just like get(), but it\n // returns null rather than throwing when called from outside a Fiber. (On the\n // client, it is identical to get().)\n getOrNullIfOutsideFiber: function () {\n if (!Fiber.current)\n return null;\n return this.get();\n },\n\n withValue: function (value, func) {\n Meteor._nodeCodeMustBeInFiber();\n\n if (!Fiber.current._meteor_dynamics)\n Fiber.current._meteor_dynamics = [];\n var currentValues = Fiber.current._meteor_dynamics;\n\n var saved = currentValues[this.slot];\n try {\n currentValues[this.slot] = value;\n var ret = func();\n } finally {\n currentValues[this.slot] = saved;\n }\n\n return ret;\n }\n});\n\n// Meteor application code is always supposed to be run inside a\n// fiber. bindEnvironment ensures that the function it wraps is run from\n// inside a fiber and ensures it sees the values of Meteor environment\n// variables that are set at the time bindEnvironment is called.\n//\n// If an environment-bound function is called from outside a fiber (eg, from\n// an asynchronous callback from a non-Meteor library such as MongoDB), it'll\n// kick off a new fiber to execute the function, and returns undefined as soon\n// as that fiber returns or yields (and func's return value is ignored).\n//\n// If it's called inside a fiber, it works normally (the\n// return value of the function will be passed through, and no new\n// fiber will be created.)\n//\n// `onException` should be a function or a string. When it is a\n// function, it is called as a callback when the bound function raises\n// an exception. If it is a string, it should be a description of the\n// callback, and when an exception is raised a debug message will be\n// printed with the description.\nMeteor.bindEnvironment = function (func, onException, _this) {\n Meteor._nodeCodeMustBeInFiber();\n\n var boundValues = _.clone(Fiber.current._meteor_dynamics || []);\n\n if (!onException || typeof(onException) === 'string') {\n var description = onException || \"callback of async function\";\n onException = function (error) {\n Meteor._debug(\n \"Exception in \" + description + \":\",\n error && error.stack || error\n );\n };\n }\n\n return function (/* arguments */) {\n var args = _.toArray(arguments);\n\n var runWithEnvironment = function () {\n var savedValues = Fiber.current._meteor_dynamics;\n try {\n // Need to clone boundValues in case two fibers invoke this\n // function at the same time\n Fiber.current._meteor_dynamics = _.clone(boundValues);\n var ret = func.apply(_this, args);\n } catch (e) {\n // note: callback-hook currently relies on the fact that if onException\n // throws and you were originally calling the wrapped callback from\n // within a Fiber, the wrapped call throws.\n onException(e);\n } finally {\n Fiber.current._meteor_dynamics = savedValues;\n }\n return ret;\n };\n\n if (Fiber.current)\n return runWithEnvironment();\n Fiber(runWithEnvironment).run();\n };\n};\n","if (process.env.ROOT_URL &&\n typeof __meteor_runtime_config__ === \"object\") {\n __meteor_runtime_config__.ROOT_URL = process.env.ROOT_URL;\n if (__meteor_runtime_config__.ROOT_URL) {\n var parsedUrl = Npm.require('url').parse(__meteor_runtime_config__.ROOT_URL);\n // Sometimes users try to pass, eg, ROOT_URL=mydomain.com.\n if (!parsedUrl.host) {\n throw Error(\"$ROOT_URL, if specified, must be an URL\");\n }\n var pathPrefix = parsedUrl.pathname;\n if (pathPrefix.slice(-1) === '/') {\n // remove trailing slash (or turn \"/\" into \"\")\n pathPrefix = pathPrefix.slice(0, -1);\n }\n __meteor_runtime_config__.ROOT_URL_PATH_PREFIX = pathPrefix;\n } else {\n __meteor_runtime_config__.ROOT_URL_PATH_PREFIX = \"\";\n }\n}\n","/**\n * @summary Generate an absolute URL pointing to the application. The server reads from the `ROOT_URL` environment variable to determine where it is running. This is taken care of automatically for apps deployed with `meteor deploy`, but must be provided when using `meteor build`.\n * @locus Anywhere\n * @param {String} [path] A path to append to the root URL. Do not include a leading \"`/`\".\n * @param {Object} [options]\n * @param {Boolean} options.secure Create an HTTPS URL.\n * @param {Boolean} options.replaceLocalhost Replace localhost with 127.0.0.1. Useful for services that don't recognize localhost as a domain name.\n * @param {String} options.rootUrl Override the default ROOT_URL from the server environment. For example: \"`http://foo.example.com`\"\n */\nMeteor.absoluteUrl = function (path, options) {\n // path is optional\n if (!options && typeof path === 'object') {\n options = path;\n path = undefined;\n }\n // merge options with defaults\n options = _.extend({}, Meteor.absoluteUrl.defaultOptions, options || {});\n\n var url = options.rootUrl;\n if (!url)\n throw new Error(\"Must pass options.rootUrl or set ROOT_URL in the server environment\");\n\n if (!/^http[s]?:\\/\\//i.test(url)) // url starts with 'http://' or 'https://'\n url = 'http://' + url; // we will later fix to https if options.secure is set\n\n if (!/\\/$/.test(url)) // url ends with '/'\n url += '/';\n\n if (path)\n url += path;\n\n // turn http to https if secure option is set, and we're not talking\n // to localhost.\n if (options.secure &&\n /^http:/.test(url) && // url starts with 'http:'\n !/http:\\/\\/localhost[:\\/]/.test(url) && // doesn't match localhost\n !/http:\\/\\/127\\.0\\.0\\.1[:\\/]/.test(url)) // or 127.0.0.1\n url = url.replace(/^http:/, 'https:');\n\n if (options.replaceLocalhost)\n url = url.replace(/^http:\\/\\/localhost([:\\/].*)/, 'http://127.0.0.1$1');\n\n return url;\n};\n\n// allow later packages to override default options\nMeteor.absoluteUrl.defaultOptions = { };\nif (typeof __meteor_runtime_config__ === \"object\" &&\n __meteor_runtime_config__.ROOT_URL)\n Meteor.absoluteUrl.defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL;\n\n\nMeteor._relativeToSiteRootUrl = function (link) {\n if (typeof __meteor_runtime_config__ === \"object\" &&\n link.substr(0, 1) === \"/\")\n link = (__meteor_runtime_config__.ROOT_URL_PATH_PREFIX || \"\") + link;\n return link;\n};\n","if (process.platform === \"win32\") {\n /*\n * Based on https://github.com/cowboy/node-exit\n *\n * Copyright (c) 2013 \"Cowboy\" Ben Alman\n * Licensed under the MIT license.\n */\n var origProcessExit = process.exit.bind(process);\n process.exit = function (exitCode) {\n var streams = [process.stdout, process.stderr];\n var drainCount = 0;\n // Actually exit if all streams are drained.\n function tryToExit() {\n if (drainCount === streams.length) {\n origProcessExit(exitCode);\n }\n }\n streams.forEach(function(stream) {\n // Count drained streams now, but monitor non-drained streams.\n if (stream.bufferSize === 0) {\n drainCount++;\n } else {\n stream.write('', 'utf-8', function() {\n drainCount++;\n tryToExit();\n });\n }\n // Prevent further writing.\n stream.write = function() {};\n });\n // If all streams were already drained, exit now.\n tryToExit();\n // In Windows, when run as a Node.js child process, a script utilizing\n // this library might just exit with a 0 exit code, regardless. This code,\n // despite the fact that it looks a bit crazy, appears to fix that.\n process.on('exit', function() {\n origProcessExit(exitCode);\n });\n };\n}"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/minimongo.js b/web-app/.meteor/local/build/programs/server/packages/minimongo.js deleted file mode 100644 index c397368..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/minimongo.js +++ /dev/null @@ -1,4420 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var EJSON = Package.ejson.EJSON; -var IdMap = Package['id-map'].IdMap; -var OrderedDict = Package['ordered-dict'].OrderedDict; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; -var Random = Package.random.Random; -var GeoJSON = Package['geojson-utils'].GeoJSON; - -/* Package-scope variables */ -var LocalCollection, Minimongo, MinimongoTest, MinimongoError, isArray, isPlainObject, isIndexable, isOperatorObject, isNumericKey, regexpElementMatcher, equalityElementMatcher, ELEMENT_OPERATORS, makeLookupFunction, expandArraysInBranches, projectionDetails, pathsToTree, combineImportantPathsIntoProjection; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/minimongo.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// XXX type checking on selectors (graceful error if malformed) // 1 - // 2 -// LocalCollection: a set of documents that supports queries and modifiers. // 3 - // 4 -// Cursor: a specification for a particular subset of documents, w/ // 5 -// a defined order, limit, and offset. creating a Cursor with LocalCollection.find(), // 6 - // 7 -// ObserveHandle: the return value of a live query. // 8 - // 9 -LocalCollection = function (name) { // 10 - var self = this; // 11 - self.name = name; // 12 - // _id -> document (also containing id) // 13 - self._docs = new LocalCollection._IdMap; // 14 - // 15 - self._observeQueue = new Meteor._SynchronousQueue(); // 16 - // 17 - self.next_qid = 1; // live query id generator // 18 - // 19 - // qid -> live query object. keys: // 20 - // ordered: bool. ordered queries have addedBefore/movedBefore callbacks. // 21 - // results: array (ordered) or object (unordered) of current results // 22 - // (aliased with self._docs!) // 23 - // resultsSnapshot: snapshot of results. null if not paused. // 24 - // cursor: Cursor object for the query. // 25 - // selector, sorter, (callbacks): functions // 26 - self.queries = {}; // 27 - // 28 - // null if not saving originals; an IdMap from id to original document value if // 29 - // saving originals. See comments before saveOriginals(). // 30 - self._savedOriginals = null; // 31 - // 32 - // True when observers are paused and we should not send callbacks. // 33 - self.paused = false; // 34 -}; // 35 - // 36 -Minimongo = {}; // 37 - // 38 -// Object exported only for unit testing. // 39 -// Use it to export private functions to test in Tinytest. // 40 -MinimongoTest = {}; // 41 - // 42 -LocalCollection._applyChanges = function (doc, changeFields) { // 43 - _.each(changeFields, function (value, key) { // 44 - if (value === undefined) // 45 - delete doc[key]; // 46 - else // 47 - doc[key] = value; // 48 - }); // 49 -}; // 50 - // 51 -MinimongoError = function (message) { // 52 - var e = new Error(message); // 53 - e.name = "MinimongoError"; // 54 - return e; // 55 -}; // 56 - // 57 - // 58 -// options may include sort, skip, limit, reactive // 59 -// sort may be any of these forms: // 60 -// {a: 1, b: -1} // 61 -// [["a", "asc"], ["b", "desc"]] // 62 -// ["a", ["b", "desc"]] // 63 -// (in the first form you're beholden to key enumeration order in // 64 -// your javascript VM) // 65 -// // 66 -// reactive: if given, and false, don't register with Tracker (default // 67 -// is true) // 68 -// // 69 -// XXX possibly should support retrieving a subset of fields? and // 70 -// have it be a hint (ignored on the client, when not copying the // 71 -// doc?) // 72 -// // 73 -// XXX sort does not yet support subkeys ('a.b') .. fix that! // 74 -// XXX add one more sort form: "key" // 75 -// XXX tests // 76 -LocalCollection.prototype.find = function (selector, options) { // 77 - // default syntax for everything is to omit the selector argument. // 78 - // but if selector is explicitly passed in as false or undefined, we // 79 - // want a selector that matches nothing. // 80 - if (arguments.length === 0) // 81 - selector = {}; // 82 - // 83 - return new LocalCollection.Cursor(this, selector, options); // 84 -}; // 85 - // 86 -// don't call this ctor directly. use LocalCollection.find(). // 87 - // 88 -LocalCollection.Cursor = function (collection, selector, options) { // 89 - var self = this; // 90 - if (!options) options = {}; // 91 - // 92 - self.collection = collection; // 93 - self.sorter = null; // 94 - // 95 - if (LocalCollection._selectorIsId(selector)) { // 96 - // stash for fast path // 97 - self._selectorId = selector; // 98 - self.matcher = new Minimongo.Matcher(selector); // 99 - } else { // 100 - self._selectorId = undefined; // 101 - self.matcher = new Minimongo.Matcher(selector); // 102 - if (self.matcher.hasGeoQuery() || options.sort) { // 103 - self.sorter = new Minimongo.Sorter(options.sort || [], // 104 - { matcher: self.matcher }); // 105 - } // 106 - } // 107 - self.skip = options.skip; // 108 - self.limit = options.limit; // 109 - self.fields = options.fields; // 110 - // 111 - self._projectionFn = LocalCollection._compileProjection(self.fields || {}); // 112 - // 113 - self._transform = LocalCollection.wrapTransform(options.transform); // 114 - // 115 - // by default, queries register w/ Tracker when it is available. // 116 - if (typeof Tracker !== "undefined") // 117 - self.reactive = (options.reactive === undefined) ? true : options.reactive; // 118 -}; // 119 - // 120 -// Since we don't actually have a "nextObject" interface, there's really no // 121 -// reason to have a "rewind" interface. All it did was make multiple calls // 122 -// to fetch/map/forEach return nothing the second time. // 123 -// XXX COMPAT WITH 0.8.1 // 124 -LocalCollection.Cursor.prototype.rewind = function () { // 125 -}; // 126 - // 127 -LocalCollection.prototype.findOne = function (selector, options) { // 128 - if (arguments.length === 0) // 129 - selector = {}; // 130 - // 131 - // NOTE: by setting limit 1 here, we end up using very inefficient // 132 - // code that recomputes the whole query on each update. The upside is // 133 - // that when you reactively depend on a findOne you only get // 134 - // invalidated when the found object changes, not any object in the // 135 - // collection. Most findOne will be by id, which has a fast path, so // 136 - // this might not be a big deal. In most cases, invalidation causes // 137 - // the called to re-query anyway, so this should be a net performance // 138 - // improvement. // 139 - options = options || {}; // 140 - options.limit = 1; // 141 - // 142 - return this.find(selector, options).fetch()[0]; // 143 -}; // 144 - // 145 -/** // 146 - * @callback IterationCallback // 147 - * @param {Object} doc // 148 - * @param {Number} index // 149 - */ // 150 -/** // 151 - * @summary Call `callback` once for each matching document, sequentially and synchronously. // 152 - * @locus Anywhere // 153 - * @method forEach // 154 - * @instance // 155 - * @memberOf Mongo.Cursor // 156 - * @param {IterationCallback} callback Function to call. It will be called with three arguments: the document, a 0-based index, and cursor itself. - * @param {Any} [thisArg] An object which will be the value of `this` inside `callback`. // 158 - */ // 159 -LocalCollection.Cursor.prototype.forEach = function (callback, thisArg) { // 160 - var self = this; // 161 - // 162 - var objects = self._getRawObjects({ordered: true}); // 163 - // 164 - if (self.reactive) { // 165 - self._depend({ // 166 - addedBefore: true, // 167 - removed: true, // 168 - changed: true, // 169 - movedBefore: true}); // 170 - } // 171 - // 172 - _.each(objects, function (elt, i) { // 173 - // This doubles as a clone operation. // 174 - elt = self._projectionFn(elt); // 175 - // 176 - if (self._transform) // 177 - elt = self._transform(elt); // 178 - callback.call(thisArg, elt, i, self); // 179 - }); // 180 -}; // 181 - // 182 -LocalCollection.Cursor.prototype.getTransform = function () { // 183 - return this._transform; // 184 -}; // 185 - // 186 -/** // 187 - * @summary Map callback over all matching documents. Returns an Array. // 188 - * @locus Anywhere // 189 - * @method map // 190 - * @instance // 191 - * @memberOf Mongo.Cursor // 192 - * @param {IterationCallback} callback Function to call. It will be called with three arguments: the document, a 0-based index, and cursor itself. - * @param {Any} [thisArg] An object which will be the value of `this` inside `callback`. // 194 - */ // 195 -LocalCollection.Cursor.prototype.map = function (callback, thisArg) { // 196 - var self = this; // 197 - var res = []; // 198 - self.forEach(function (doc, index) { // 199 - res.push(callback.call(thisArg, doc, index, self)); // 200 - }); // 201 - return res; // 202 -}; // 203 - // 204 -/** // 205 - * @summary Return all matching documents as an Array. // 206 - * @memberOf Mongo.Cursor // 207 - * @method fetch // 208 - * @instance // 209 - * @locus Anywhere // 210 - * @returns {Object[]} // 211 - */ // 212 -LocalCollection.Cursor.prototype.fetch = function () { // 213 - var self = this; // 214 - var res = []; // 215 - self.forEach(function (doc) { // 216 - res.push(doc); // 217 - }); // 218 - return res; // 219 -}; // 220 - // 221 -/** // 222 - * @summary Returns the number of documents that match a query. // 223 - * @memberOf Mongo.Cursor // 224 - * @method count // 225 - * @instance // 226 - * @locus Anywhere // 227 - * @returns {Number} // 228 - */ // 229 -LocalCollection.Cursor.prototype.count = function () { // 230 - var self = this; // 231 - // 232 - if (self.reactive) // 233 - self._depend({added: true, removed: true}, // 234 - true /* allow the observe to be unordered */); // 235 - // 236 - return self._getRawObjects({ordered: true}).length; // 237 -}; // 238 - // 239 -LocalCollection.Cursor.prototype._publishCursor = function (sub) { // 240 - var self = this; // 241 - if (! self.collection.name) // 242 - throw new Error("Can't publish a cursor from a collection without a name."); // 243 - var collection = self.collection.name; // 244 - // 245 - // XXX minimongo should not depend on mongo-livedata! // 246 - return Mongo.Collection._publishCursor(self, sub, collection); // 247 -}; // 248 - // 249 -LocalCollection.Cursor.prototype._getCollectionName = function () { // 250 - var self = this; // 251 - return self.collection.name; // 252 -}; // 253 - // 254 -LocalCollection._observeChangesCallbacksAreOrdered = function (callbacks) { // 255 - if (callbacks.added && callbacks.addedBefore) // 256 - throw new Error("Please specify only one of added() and addedBefore()"); // 257 - return !!(callbacks.addedBefore || callbacks.movedBefore); // 258 -}; // 259 - // 260 -LocalCollection._observeCallbacksAreOrdered = function (callbacks) { // 261 - if (callbacks.addedAt && callbacks.added) // 262 - throw new Error("Please specify only one of added() and addedAt()"); // 263 - if (callbacks.changedAt && callbacks.changed) // 264 - throw new Error("Please specify only one of changed() and changedAt()"); // 265 - if (callbacks.removed && callbacks.removedAt) // 266 - throw new Error("Please specify only one of removed() and removedAt()"); // 267 - // 268 - return !!(callbacks.addedAt || callbacks.movedTo || callbacks.changedAt // 269 - || callbacks.removedAt); // 270 -}; // 271 - // 272 -// the handle that comes back from observe. // 273 -LocalCollection.ObserveHandle = function () {}; // 274 - // 275 -// options to contain: // 276 -// * callbacks for observe(): // 277 -// - addedAt (document, atIndex) // 278 -// - added (document) // 279 -// - changedAt (newDocument, oldDocument, atIndex) // 280 -// - changed (newDocument, oldDocument) // 281 -// - removedAt (document, atIndex) // 282 -// - removed (document) // 283 -// - movedTo (document, oldIndex, newIndex) // 284 -// // 285 -// attributes available on returned query handle: // 286 -// * stop(): end updates // 287 -// * collection: the collection this query is querying // 288 -// // 289 -// iff x is a returned query handle, (x instanceof // 290 -// LocalCollection.ObserveHandle) is true // 291 -// // 292 -// initial results delivered through added callback // 293 -// XXX maybe callbacks should take a list of objects, to expose transactions? // 294 -// XXX maybe support field limiting (to limit what you're notified on) // 295 - // 296 -_.extend(LocalCollection.Cursor.prototype, { // 297 - /** // 298 - * @summary Watch a query. Receive callbacks as the result set changes. // 299 - * @locus Anywhere // 300 - * @memberOf Mongo.Cursor // 301 - * @instance // 302 - * @param {Object} callbacks Functions to call to deliver the result set as it changes // 303 - */ // 304 - observe: function (options) { // 305 - var self = this; // 306 - return LocalCollection._observeFromObserveChanges(self, options); // 307 - }, // 308 - // 309 - /** // 310 - * @summary Watch a query. Receive callbacks as the result set changes. Only the differences between the old and new documents are passed to the callbacks. - * @locus Anywhere // 312 - * @memberOf Mongo.Cursor // 313 - * @instance // 314 - * @param {Object} callbacks Functions to call to deliver the result set as it changes // 315 - */ // 316 - observeChanges: function (options) { // 317 - var self = this; // 318 - // 319 - var ordered = LocalCollection._observeChangesCallbacksAreOrdered(options); // 320 - // 321 - // there are several places that assume you aren't combining skip/limit with // 322 - // unordered observe. eg, update's EJSON.clone, and the "there are several" // 323 - // comment in _modifyAndNotify // 324 - // XXX allow skip/limit with unordered observe // 325 - if (!options._allow_unordered && !ordered && (self.skip || self.limit)) // 326 - throw new Error("must use ordered observe (ie, 'addedBefore' instead of 'added') with skip or limit"); // 327 - // 328 - if (self.fields && (self.fields._id === 0 || self.fields._id === false)) // 329 - throw Error("You may not observe a cursor with {fields: {_id: 0}}"); // 330 - // 331 - var query = { // 332 - matcher: self.matcher, // not fast pathed // 333 - sorter: ordered && self.sorter, // 334 - distances: ( // 335 - self.matcher.hasGeoQuery() && ordered && new LocalCollection._IdMap), // 336 - resultsSnapshot: null, // 337 - ordered: ordered, // 338 - cursor: self, // 339 - projectionFn: self._projectionFn // 340 - }; // 341 - var qid; // 342 - // 343 - // Non-reactive queries call added[Before] and then never call anything // 344 - // else. // 345 - if (self.reactive) { // 346 - qid = self.collection.next_qid++; // 347 - self.collection.queries[qid] = query; // 348 - } // 349 - query.results = self._getRawObjects({ // 350 - ordered: ordered, distances: query.distances}); // 351 - if (self.collection.paused) // 352 - query.resultsSnapshot = (ordered ? [] : new LocalCollection._IdMap); // 353 - // 354 - // wrap callbacks we were passed. callbacks only fire when not paused and // 355 - // are never undefined // 356 - // Filters out blacklisted fields according to cursor's projection. // 357 - // XXX wrong place for this? // 358 - // 359 - // furthermore, callbacks enqueue until the operation we're working on is // 360 - // done. // 361 - var wrapCallback = function (f) { // 362 - if (!f) // 363 - return function () {}; // 364 - return function (/*args*/) { // 365 - var context = this; // 366 - var args = arguments; // 367 - // 368 - if (self.collection.paused) // 369 - return; // 370 - // 371 - self.collection._observeQueue.queueTask(function () { // 372 - f.apply(context, args); // 373 - }); // 374 - }; // 375 - }; // 376 - query.added = wrapCallback(options.added); // 377 - query.changed = wrapCallback(options.changed); // 378 - query.removed = wrapCallback(options.removed); // 379 - if (ordered) { // 380 - query.addedBefore = wrapCallback(options.addedBefore); // 381 - query.movedBefore = wrapCallback(options.movedBefore); // 382 - } // 383 - // 384 - if (!options._suppress_initial && !self.collection.paused) { // 385 - // XXX unify ordered and unordered interface // 386 - var each = ordered // 387 - ? _.bind(_.each, null, query.results) // 388 - : _.bind(query.results.forEach, query.results); // 389 - each(function (doc) { // 390 - var fields = EJSON.clone(doc); // 391 - // 392 - delete fields._id; // 393 - if (ordered) // 394 - query.addedBefore(doc._id, self._projectionFn(fields), null); // 395 - query.added(doc._id, self._projectionFn(fields)); // 396 - }); // 397 - } // 398 - // 399 - var handle = new LocalCollection.ObserveHandle; // 400 - _.extend(handle, { // 401 - collection: self.collection, // 402 - stop: function () { // 403 - if (self.reactive) // 404 - delete self.collection.queries[qid]; // 405 - } // 406 - }); // 407 - // 408 - if (self.reactive && Tracker.active) { // 409 - // XXX in many cases, the same observe will be recreated when // 410 - // the current autorun is rerun. we could save work by // 411 - // letting it linger across rerun and potentially get // 412 - // repurposed if the same observe is performed, using logic // 413 - // similar to that of Meteor.subscribe. // 414 - Tracker.onInvalidate(function () { // 415 - handle.stop(); // 416 - }); // 417 - } // 418 - // run the observe callbacks resulting from the initial contents // 419 - // before we leave the observe. // 420 - self.collection._observeQueue.drain(); // 421 - // 422 - return handle; // 423 - } // 424 -}); // 425 - // 426 -// Returns a collection of matching objects, but doesn't deep copy them. // 427 -// // 428 -// If ordered is set, returns a sorted array, respecting sorter, skip, and limit // 429 -// properties of the query. if sorter is falsey, no sort -- you get the natural // 430 -// order. // 431 -// // 432 -// If ordered is not set, returns an object mapping from ID to doc (sorter, skip // 433 -// and limit should not be set). // 434 -// // 435 -// If ordered is set and this cursor is a $near geoquery, then this function // 436 -// will use an _IdMap to track each distance from the $near argument point in // 437 -// order to use it as a sort key. If an _IdMap is passed in the 'distances' // 438 -// argument, this function will clear it and use it for this purpose (otherwise // 439 -// it will just create its own _IdMap). The observeChanges implementation uses // 440 -// this to remember the distances after this function returns. // 441 -LocalCollection.Cursor.prototype._getRawObjects = function (options) { // 442 - var self = this; // 443 - options = options || {}; // 444 - // 445 - // XXX use OrderedDict instead of array, and make IdMap and OrderedDict // 446 - // compatible // 447 - var results = options.ordered ? [] : new LocalCollection._IdMap; // 448 - // 449 - // fast path for single ID value // 450 - if (self._selectorId !== undefined) { // 451 - // If you have non-zero skip and ask for a single id, you get // 452 - // nothing. This is so it matches the behavior of the '{_id: foo}' // 453 - // path. // 454 - if (self.skip) // 455 - return results; // 456 - // 457 - var selectedDoc = self.collection._docs.get(self._selectorId); // 458 - if (selectedDoc) { // 459 - if (options.ordered) // 460 - results.push(selectedDoc); // 461 - else // 462 - results.set(self._selectorId, selectedDoc); // 463 - } // 464 - return results; // 465 - } // 466 - // 467 - // slow path for arbitrary selector, sort, skip, limit // 468 - // 469 - // in the observeChanges case, distances is actually part of the "query" (ie, // 470 - // live results set) object. in other cases, distances is only used inside // 471 - // this function. // 472 - var distances; // 473 - if (self.matcher.hasGeoQuery() && options.ordered) { // 474 - if (options.distances) { // 475 - distances = options.distances; // 476 - distances.clear(); // 477 - } else { // 478 - distances = new LocalCollection._IdMap(); // 479 - } // 480 - } // 481 - // 482 - self.collection._docs.forEach(function (doc, id) { // 483 - var matchResult = self.matcher.documentMatches(doc); // 484 - if (matchResult.result) { // 485 - if (options.ordered) { // 486 - results.push(doc); // 487 - if (distances && matchResult.distance !== undefined) // 488 - distances.set(id, matchResult.distance); // 489 - } else { // 490 - results.set(id, doc); // 491 - } // 492 - } // 493 - // Fast path for limited unsorted queries. // 494 - // XXX 'length' check here seems wrong for ordered // 495 - if (self.limit && !self.skip && !self.sorter && // 496 - results.length === self.limit) // 497 - return false; // break // 498 - return true; // continue // 499 - }); // 500 - // 501 - if (!options.ordered) // 502 - return results; // 503 - // 504 - if (self.sorter) { // 505 - var comparator = self.sorter.getComparator({distances: distances}); // 506 - results.sort(comparator); // 507 - } // 508 - // 509 - var idx_start = self.skip || 0; // 510 - var idx_end = self.limit ? (self.limit + idx_start) : results.length; // 511 - return results.slice(idx_start, idx_end); // 512 -}; // 513 - // 514 -// XXX Maybe we need a version of observe that just calls a callback if // 515 -// anything changed. // 516 -LocalCollection.Cursor.prototype._depend = function (changers, _allow_unordered) { // 517 - var self = this; // 518 - // 519 - if (Tracker.active) { // 520 - var v = new Tracker.Dependency; // 521 - v.depend(); // 522 - var notifyChange = _.bind(v.changed, v); // 523 - // 524 - var options = { // 525 - _suppress_initial: true, // 526 - _allow_unordered: _allow_unordered // 527 - }; // 528 - _.each(['added', 'changed', 'removed', 'addedBefore', 'movedBefore'], // 529 - function (fnName) { // 530 - if (changers[fnName]) // 531 - options[fnName] = notifyChange; // 532 - }); // 533 - // 534 - // observeChanges will stop() when this computation is invalidated // 535 - self.observeChanges(options); // 536 - } // 537 -}; // 538 - // 539 -// XXX enforce rule that field names can't start with '$' or contain '.' // 540 -// (real mongodb does in fact enforce this) // 541 -// XXX possibly enforce that 'undefined' does not appear (we assume // 542 -// this in our handling of null and $exists) // 543 -LocalCollection.prototype.insert = function (doc, callback) { // 544 - var self = this; // 545 - doc = EJSON.clone(doc); // 546 - // 547 - if (!_.has(doc, '_id')) { // 548 - // if you really want to use ObjectIDs, set this global. // 549 - // Mongo.Collection specifies its own ids and does not use this code. // 550 - doc._id = LocalCollection._useOID ? new LocalCollection._ObjectID() // 551 - : Random.id(); // 552 - } // 553 - var id = doc._id; // 554 - // 555 - if (self._docs.has(id)) // 556 - throw MinimongoError("Duplicate _id '" + id + "'"); // 557 - // 558 - self._saveOriginal(id, undefined); // 559 - self._docs.set(id, doc); // 560 - // 561 - var queriesToRecompute = []; // 562 - // trigger live queries that match // 563 - for (var qid in self.queries) { // 564 - var query = self.queries[qid]; // 565 - var matchResult = query.matcher.documentMatches(doc); // 566 - if (matchResult.result) { // 567 - if (query.distances && matchResult.distance !== undefined) // 568 - query.distances.set(id, matchResult.distance); // 569 - if (query.cursor.skip || query.cursor.limit) // 570 - queriesToRecompute.push(qid); // 571 - else // 572 - LocalCollection._insertInResults(query, doc); // 573 - } // 574 - } // 575 - // 576 - _.each(queriesToRecompute, function (qid) { // 577 - if (self.queries[qid]) // 578 - self._recomputeResults(self.queries[qid]); // 579 - }); // 580 - self._observeQueue.drain(); // 581 - // 582 - // Defer because the caller likely doesn't expect the callback to be run // 583 - // immediately. // 584 - if (callback) // 585 - Meteor.defer(function () { // 586 - callback(null, id); // 587 - }); // 588 - return id; // 589 -}; // 590 - // 591 -// Iterates over a subset of documents that could match selector; calls // 592 -// f(doc, id) on each of them. Specifically, if selector specifies // 593 -// specific _id's, it only looks at those. doc is *not* cloned: it is the // 594 -// same object that is in _docs. // 595 -LocalCollection.prototype._eachPossiblyMatchingDoc = function (selector, f) { // 596 - var self = this; // 597 - var specificIds = LocalCollection._idsMatchedBySelector(selector); // 598 - if (specificIds) { // 599 - for (var i = 0; i < specificIds.length; ++i) { // 600 - var id = specificIds[i]; // 601 - var doc = self._docs.get(id); // 602 - if (doc) { // 603 - var breakIfFalse = f(doc, id); // 604 - if (breakIfFalse === false) // 605 - break; // 606 - } // 607 - } // 608 - } else { // 609 - self._docs.forEach(f); // 610 - } // 611 -}; // 612 - // 613 -LocalCollection.prototype.remove = function (selector, callback) { // 614 - var self = this; // 615 - // 616 - // Easy special case: if we're not calling observeChanges callbacks and we're // 617 - // not saving originals and we got asked to remove everything, then just empty // 618 - // everything directly. // 619 - if (self.paused && !self._savedOriginals && EJSON.equals(selector, {})) { // 620 - var result = self._docs.size(); // 621 - self._docs.clear(); // 622 - _.each(self.queries, function (query) { // 623 - if (query.ordered) { // 624 - query.results = []; // 625 - } else { // 626 - query.results.clear(); // 627 - } // 628 - }); // 629 - if (callback) { // 630 - Meteor.defer(function () { // 631 - callback(null, result); // 632 - }); // 633 - } // 634 - return result; // 635 - } // 636 - // 637 - var matcher = new Minimongo.Matcher(selector); // 638 - var remove = []; // 639 - self._eachPossiblyMatchingDoc(selector, function (doc, id) { // 640 - if (matcher.documentMatches(doc).result) // 641 - remove.push(id); // 642 - }); // 643 - // 644 - var queriesToRecompute = []; // 645 - var queryRemove = []; // 646 - for (var i = 0; i < remove.length; i++) { // 647 - var removeId = remove[i]; // 648 - var removeDoc = self._docs.get(removeId); // 649 - _.each(self.queries, function (query, qid) { // 650 - if (query.matcher.documentMatches(removeDoc).result) { // 651 - if (query.cursor.skip || query.cursor.limit) // 652 - queriesToRecompute.push(qid); // 653 - else // 654 - queryRemove.push({qid: qid, doc: removeDoc}); // 655 - } // 656 - }); // 657 - self._saveOriginal(removeId, removeDoc); // 658 - self._docs.remove(removeId); // 659 - } // 660 - // 661 - // run live query callbacks _after_ we've removed the documents. // 662 - _.each(queryRemove, function (remove) { // 663 - var query = self.queries[remove.qid]; // 664 - if (query) { // 665 - query.distances && query.distances.remove(remove.doc._id); // 666 - LocalCollection._removeFromResults(query, remove.doc); // 667 - } // 668 - }); // 669 - _.each(queriesToRecompute, function (qid) { // 670 - var query = self.queries[qid]; // 671 - if (query) // 672 - self._recomputeResults(query); // 673 - }); // 674 - self._observeQueue.drain(); // 675 - result = remove.length; // 676 - if (callback) // 677 - Meteor.defer(function () { // 678 - callback(null, result); // 679 - }); // 680 - return result; // 681 -}; // 682 - // 683 -// XXX atomicity: if multi is true, and one modification fails, do // 684 -// we rollback the whole operation, or what? // 685 -LocalCollection.prototype.update = function (selector, mod, options, callback) { // 686 - var self = this; // 687 - if (! callback && options instanceof Function) { // 688 - callback = options; // 689 - options = null; // 690 - } // 691 - if (!options) options = {}; // 692 - // 693 - var matcher = new Minimongo.Matcher(selector); // 694 - // 695 - // Save the original results of any query that we might need to // 696 - // _recomputeResults on, because _modifyAndNotify will mutate the objects in // 697 - // it. (We don't need to save the original results of paused queries because // 698 - // they already have a resultsSnapshot and we won't be diffing in // 699 - // _recomputeResults.) // 700 - var qidToOriginalResults = {}; // 701 - _.each(self.queries, function (query, qid) { // 702 - // XXX for now, skip/limit implies ordered observe, so query.results is // 703 - // always an array // 704 - if ((query.cursor.skip || query.cursor.limit) && ! self.paused) // 705 - qidToOriginalResults[qid] = EJSON.clone(query.results); // 706 - }); // 707 - var recomputeQids = {}; // 708 - // 709 - var updateCount = 0; // 710 - // 711 - self._eachPossiblyMatchingDoc(selector, function (doc, id) { // 712 - var queryResult = matcher.documentMatches(doc); // 713 - if (queryResult.result) { // 714 - // XXX Should we save the original even if mod ends up being a no-op? // 715 - self._saveOriginal(id, doc); // 716 - self._modifyAndNotify(doc, mod, recomputeQids, queryResult.arrayIndices); // 717 - ++updateCount; // 718 - if (!options.multi) // 719 - return false; // break // 720 - } // 721 - return true; // 722 - }); // 723 - // 724 - _.each(recomputeQids, function (dummy, qid) { // 725 - var query = self.queries[qid]; // 726 - if (query) // 727 - self._recomputeResults(query, qidToOriginalResults[qid]); // 728 - }); // 729 - self._observeQueue.drain(); // 730 - // 731 - // If we are doing an upsert, and we didn't modify any documents yet, then // 732 - // it's time to do an insert. Figure out what document we are inserting, and // 733 - // generate an id for it. // 734 - var insertedId; // 735 - if (updateCount === 0 && options.upsert) { // 736 - var newDoc = LocalCollection._removeDollarOperators(selector); // 737 - LocalCollection._modify(newDoc, mod, {isInsert: true}); // 738 - if (! newDoc._id && options.insertedId) // 739 - newDoc._id = options.insertedId; // 740 - insertedId = self.insert(newDoc); // 741 - updateCount = 1; // 742 - } // 743 - // 744 - // Return the number of affected documents, or in the upsert case, an object // 745 - // containing the number of affected docs and the id of the doc that was // 746 - // inserted, if any. // 747 - var result; // 748 - if (options._returnObject) { // 749 - result = { // 750 - numberAffected: updateCount // 751 - }; // 752 - if (insertedId !== undefined) // 753 - result.insertedId = insertedId; // 754 - } else { // 755 - result = updateCount; // 756 - } // 757 - // 758 - if (callback) // 759 - Meteor.defer(function () { // 760 - callback(null, result); // 761 - }); // 762 - return result; // 763 -}; // 764 - // 765 -// A convenience wrapper on update. LocalCollection.upsert(sel, mod) is // 766 -// equivalent to LocalCollection.update(sel, mod, { upsert: true, _returnObject: // 767 -// true }). // 768 -LocalCollection.prototype.upsert = function (selector, mod, options, callback) { // 769 - var self = this; // 770 - if (! callback && typeof options === "function") { // 771 - callback = options; // 772 - options = {}; // 773 - } // 774 - return self.update(selector, mod, _.extend({}, options, { // 775 - upsert: true, // 776 - _returnObject: true // 777 - }), callback); // 778 -}; // 779 - // 780 -LocalCollection.prototype._modifyAndNotify = function ( // 781 - doc, mod, recomputeQids, arrayIndices) { // 782 - var self = this; // 783 - // 784 - var matched_before = {}; // 785 - for (var qid in self.queries) { // 786 - var query = self.queries[qid]; // 787 - if (query.ordered) { // 788 - matched_before[qid] = query.matcher.documentMatches(doc).result; // 789 - } else { // 790 - // Because we don't support skip or limit (yet) in unordered queries, we // 791 - // can just do a direct lookup. // 792 - matched_before[qid] = query.results.has(doc._id); // 793 - } // 794 - } // 795 - // 796 - var old_doc = EJSON.clone(doc); // 797 - // 798 - LocalCollection._modify(doc, mod, {arrayIndices: arrayIndices}); // 799 - // 800 - for (qid in self.queries) { // 801 - query = self.queries[qid]; // 802 - var before = matched_before[qid]; // 803 - var afterMatch = query.matcher.documentMatches(doc); // 804 - var after = afterMatch.result; // 805 - if (after && query.distances && afterMatch.distance !== undefined) // 806 - query.distances.set(doc._id, afterMatch.distance); // 807 - // 808 - if (query.cursor.skip || query.cursor.limit) { // 809 - // We need to recompute any query where the doc may have been in the // 810 - // cursor's window either before or after the update. (Note that if skip // 811 - // or limit is set, "before" and "after" being true do not necessarily // 812 - // mean that the document is in the cursor's output after skip/limit is // 813 - // applied... but if they are false, then the document definitely is NOT // 814 - // in the output. So it's safe to skip recompute if neither before or // 815 - // after are true.) // 816 - if (before || after) // 817 - recomputeQids[qid] = true; // 818 - } else if (before && !after) { // 819 - LocalCollection._removeFromResults(query, doc); // 820 - } else if (!before && after) { // 821 - LocalCollection._insertInResults(query, doc); // 822 - } else if (before && after) { // 823 - LocalCollection._updateInResults(query, doc, old_doc); // 824 - } // 825 - } // 826 -}; // 827 - // 828 -// XXX the sorted-query logic below is laughably inefficient. we'll // 829 -// need to come up with a better datastructure for this. // 830 -// // 831 -// XXX the logic for observing with a skip or a limit is even more // 832 -// laughably inefficient. we recompute the whole results every time! // 833 - // 834 -LocalCollection._insertInResults = function (query, doc) { // 835 - var fields = EJSON.clone(doc); // 836 - delete fields._id; // 837 - if (query.ordered) { // 838 - if (!query.sorter) { // 839 - query.addedBefore(doc._id, query.projectionFn(fields), null); // 840 - query.results.push(doc); // 841 - } else { // 842 - var i = LocalCollection._insertInSortedList( // 843 - query.sorter.getComparator({distances: query.distances}), // 844 - query.results, doc); // 845 - var next = query.results[i+1]; // 846 - if (next) // 847 - next = next._id; // 848 - else // 849 - next = null; // 850 - query.addedBefore(doc._id, query.projectionFn(fields), next); // 851 - } // 852 - query.added(doc._id, query.projectionFn(fields)); // 853 - } else { // 854 - query.added(doc._id, query.projectionFn(fields)); // 855 - query.results.set(doc._id, doc); // 856 - } // 857 -}; // 858 - // 859 -LocalCollection._removeFromResults = function (query, doc) { // 860 - if (query.ordered) { // 861 - var i = LocalCollection._findInOrderedResults(query, doc); // 862 - query.removed(doc._id); // 863 - query.results.splice(i, 1); // 864 - } else { // 865 - var id = doc._id; // in case callback mutates doc // 866 - query.removed(doc._id); // 867 - query.results.remove(id); // 868 - } // 869 -}; // 870 - // 871 -LocalCollection._updateInResults = function (query, doc, old_doc) { // 872 - if (!EJSON.equals(doc._id, old_doc._id)) // 873 - throw new Error("Can't change a doc's _id while updating"); // 874 - var projectionFn = query.projectionFn; // 875 - var changedFields = LocalCollection._makeChangedFields( // 876 - projectionFn(doc), projectionFn(old_doc)); // 877 - // 878 - if (!query.ordered) { // 879 - if (!_.isEmpty(changedFields)) { // 880 - query.changed(doc._id, changedFields); // 881 - query.results.set(doc._id, doc); // 882 - } // 883 - return; // 884 - } // 885 - // 886 - var orig_idx = LocalCollection._findInOrderedResults(query, doc); // 887 - // 888 - if (!_.isEmpty(changedFields)) // 889 - query.changed(doc._id, changedFields); // 890 - if (!query.sorter) // 891 - return; // 892 - // 893 - // just take it out and put it back in again, and see if the index // 894 - // changes // 895 - query.results.splice(orig_idx, 1); // 896 - var new_idx = LocalCollection._insertInSortedList( // 897 - query.sorter.getComparator({distances: query.distances}), // 898 - query.results, doc); // 899 - if (orig_idx !== new_idx) { // 900 - var next = query.results[new_idx+1]; // 901 - if (next) // 902 - next = next._id; // 903 - else // 904 - next = null; // 905 - query.movedBefore && query.movedBefore(doc._id, next); // 906 - } // 907 -}; // 908 - // 909 -// Recomputes the results of a query and runs observe callbacks for the // 910 -// difference between the previous results and the current results (unless // 911 -// paused). Used for skip/limit queries. // 912 -// // 913 -// When this is used by insert or remove, it can just use query.results for the // 914 -// old results (and there's no need to pass in oldResults), because these // 915 -// operations don't mutate the documents in the collection. Update needs to pass // 916 -// in an oldResults which was deep-copied before the modifier was applied. // 917 -// // 918 -// oldResults is guaranteed to be ignored if the query is not paused. // 919 -LocalCollection.prototype._recomputeResults = function (query, oldResults) { // 920 - var self = this; // 921 - if (! self.paused && ! oldResults) // 922 - oldResults = query.results; // 923 - if (query.distances) // 924 - query.distances.clear(); // 925 - query.results = query.cursor._getRawObjects({ // 926 - ordered: query.ordered, distances: query.distances}); // 927 - // 928 - if (! self.paused) { // 929 - LocalCollection._diffQueryChanges( // 930 - query.ordered, oldResults, query.results, query, // 931 - { projectionFn: query.projectionFn }); // 932 - } // 933 -}; // 934 - // 935 - // 936 -LocalCollection._findInOrderedResults = function (query, doc) { // 937 - if (!query.ordered) // 938 - throw new Error("Can't call _findInOrderedResults on unordered query"); // 939 - for (var i = 0; i < query.results.length; i++) // 940 - if (query.results[i] === doc) // 941 - return i; // 942 - throw Error("object missing from query"); // 943 -}; // 944 - // 945 -// This binary search puts a value between any equal values, and the first // 946 -// lesser value. // 947 -LocalCollection._binarySearch = function (cmp, array, value) { // 948 - var first = 0, rangeLength = array.length; // 949 - // 950 - while (rangeLength > 0) { // 951 - var halfRange = Math.floor(rangeLength/2); // 952 - if (cmp(value, array[first + halfRange]) >= 0) { // 953 - first += halfRange + 1; // 954 - rangeLength -= halfRange + 1; // 955 - } else { // 956 - rangeLength = halfRange; // 957 - } // 958 - } // 959 - return first; // 960 -}; // 961 - // 962 -LocalCollection._insertInSortedList = function (cmp, array, value) { // 963 - if (array.length === 0) { // 964 - array.push(value); // 965 - return 0; // 966 - } // 967 - // 968 - var idx = LocalCollection._binarySearch(cmp, array, value); // 969 - array.splice(idx, 0, value); // 970 - return idx; // 971 -}; // 972 - // 973 -// To track what documents are affected by a piece of code, call saveOriginals() // 974 -// before it and retrieveOriginals() after it. retrieveOriginals returns an // 975 -// object whose keys are the ids of the documents that were affected since the // 976 -// call to saveOriginals(), and the values are equal to the document's contents // 977 -// at the time of saveOriginals. (In the case of an inserted document, undefined // 978 -// is the value.) You must alternate between calls to saveOriginals() and // 979 -// retrieveOriginals(). // 980 -LocalCollection.prototype.saveOriginals = function () { // 981 - var self = this; // 982 - if (self._savedOriginals) // 983 - throw new Error("Called saveOriginals twice without retrieveOriginals"); // 984 - self._savedOriginals = new LocalCollection._IdMap; // 985 -}; // 986 -LocalCollection.prototype.retrieveOriginals = function () { // 987 - var self = this; // 988 - if (!self._savedOriginals) // 989 - throw new Error("Called retrieveOriginals without saveOriginals"); // 990 - // 991 - var originals = self._savedOriginals; // 992 - self._savedOriginals = null; // 993 - return originals; // 994 -}; // 995 - // 996 -LocalCollection.prototype._saveOriginal = function (id, doc) { // 997 - var self = this; // 998 - // Are we even trying to save originals? // 999 - if (!self._savedOriginals) // 1000 - return; // 1001 - // Have we previously mutated the original (and so 'doc' is not actually // 1002 - // original)? (Note the 'has' check rather than truth: we store undefined // 1003 - // here for inserted docs!) // 1004 - if (self._savedOriginals.has(id)) // 1005 - return; // 1006 - self._savedOriginals.set(id, EJSON.clone(doc)); // 1007 -}; // 1008 - // 1009 -// Pause the observers. No callbacks from observers will fire until // 1010 -// 'resumeObservers' is called. // 1011 -LocalCollection.prototype.pauseObservers = function () { // 1012 - // No-op if already paused. // 1013 - if (this.paused) // 1014 - return; // 1015 - // 1016 - // Set the 'paused' flag such that new observer messages don't fire. // 1017 - this.paused = true; // 1018 - // 1019 - // Take a snapshot of the query results for each query. // 1020 - for (var qid in this.queries) { // 1021 - var query = this.queries[qid]; // 1022 - // 1023 - query.resultsSnapshot = EJSON.clone(query.results); // 1024 - } // 1025 -}; // 1026 - // 1027 -// Resume the observers. Observers immediately receive change // 1028 -// notifications to bring them to the current state of the // 1029 -// database. Note that this is not just replaying all the changes that // 1030 -// happened during the pause, it is a smarter 'coalesced' diff. // 1031 -LocalCollection.prototype.resumeObservers = function () { // 1032 - var self = this; // 1033 - // No-op if not paused. // 1034 - if (!this.paused) // 1035 - return; // 1036 - // 1037 - // Unset the 'paused' flag. Make sure to do this first, otherwise // 1038 - // observer methods won't actually fire when we trigger them. // 1039 - this.paused = false; // 1040 - // 1041 - for (var qid in this.queries) { // 1042 - var query = self.queries[qid]; // 1043 - // Diff the current results against the snapshot and send to observers. // 1044 - // pass the query object for its observer callbacks. // 1045 - LocalCollection._diffQueryChanges( // 1046 - query.ordered, query.resultsSnapshot, query.results, query, // 1047 - { projectionFn: query.projectionFn }); // 1048 - query.resultsSnapshot = null; // 1049 - } // 1050 - self._observeQueue.drain(); // 1051 -}; // 1052 - // 1053 - // 1054 -// NB: used by livedata // 1055 -LocalCollection._idStringify = function (id) { // 1056 - if (id instanceof LocalCollection._ObjectID) { // 1057 - return id.valueOf(); // 1058 - } else if (typeof id === 'string') { // 1059 - if (id === "") { // 1060 - return id; // 1061 - } else if (id.substr(0, 1) === "-" || // escape previously dashed strings // 1062 - id.substr(0, 1) === "~" || // escape escaped numbers, true, false // 1063 - LocalCollection._looksLikeObjectID(id) || // escape object-id-form strings // 1064 - id.substr(0, 1) === '{') { // escape object-form strings, for maybe implementing later // 1065 - return "-" + id; // 1066 - } else { // 1067 - return id; // other strings go through unchanged. // 1068 - } // 1069 - } else if (id === undefined) { // 1070 - return '-'; // 1071 - } else if (typeof id === 'object' && id !== null) { // 1072 - throw new Error("Meteor does not currently support objects other than ObjectID as ids"); // 1073 - } else { // Numbers, true, false, null // 1074 - return "~" + JSON.stringify(id); // 1075 - } // 1076 -}; // 1077 - // 1078 - // 1079 -// NB: used by livedata // 1080 -LocalCollection._idParse = function (id) { // 1081 - if (id === "") { // 1082 - return id; // 1083 - } else if (id === '-') { // 1084 - return undefined; // 1085 - } else if (id.substr(0, 1) === '-') { // 1086 - return id.substr(1); // 1087 - } else if (id.substr(0, 1) === '~') { // 1088 - return JSON.parse(id.substr(1)); // 1089 - } else if (LocalCollection._looksLikeObjectID(id)) { // 1090 - return new LocalCollection._ObjectID(id); // 1091 - } else { // 1092 - return id; // 1093 - } // 1094 -}; // 1095 - // 1096 -LocalCollection._makeChangedFields = function (newDoc, oldDoc) { // 1097 - var fields = {}; // 1098 - LocalCollection._diffObjects(oldDoc, newDoc, { // 1099 - leftOnly: function (key, value) { // 1100 - fields[key] = undefined; // 1101 - }, // 1102 - rightOnly: function (key, value) { // 1103 - fields[key] = value; // 1104 - }, // 1105 - both: function (key, leftValue, rightValue) { // 1106 - if (!EJSON.equals(leftValue, rightValue)) // 1107 - fields[key] = rightValue; // 1108 - } // 1109 - }); // 1110 - return fields; // 1111 -}; // 1112 - // 1113 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/wrap_transform.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Wrap a transform function to return objects that have the _id field // 1 -// of the untransformed document. This ensures that subsystems such as // 2 -// the observe-sequence package that call `observe` can keep track of // 3 -// the documents identities. // 4 -// // 5 -// - Require that it returns objects // 6 -// - If the return value has an _id field, verify that it matches the // 7 -// original _id field // 8 -// - If the return value doesn't have an _id field, add it back. // 9 -LocalCollection.wrapTransform = function (transform) { // 10 - if (! transform) // 11 - return null; // 12 - // 13 - // No need to doubly-wrap transforms. // 14 - if (transform.__wrappedTransform__) // 15 - return transform; // 16 - // 17 - var wrapped = function (doc) { // 18 - if (!_.has(doc, '_id')) { // 19 - // XXX do we ever have a transform on the oplog's collection? because that // 20 - // collection has no _id. // 21 - throw new Error("can only transform documents with _id"); // 22 - } // 23 - // 24 - var id = doc._id; // 25 - // XXX consider making tracker a weak dependency and checking Package.tracker here // 26 - var transformed = Tracker.nonreactive(function () { // 27 - return transform(doc); // 28 - }); // 29 - // 30 - if (!isPlainObject(transformed)) { // 31 - throw new Error("transform must return object"); // 32 - } // 33 - // 34 - if (_.has(transformed, '_id')) { // 35 - if (!EJSON.equals(transformed._id, id)) { // 36 - throw new Error("transformed document can't have different _id"); // 37 - } // 38 - } else { // 39 - transformed._id = id; // 40 - } // 41 - return transformed; // 42 - }; // 43 - wrapped.__wrappedTransform__ = true; // 44 - return wrapped; // 45 -}; // 46 - // 47 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/helpers.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Like _.isArray, but doesn't regard polyfilled Uint8Arrays on old browsers as // 1 -// arrays. // 2 -// XXX maybe this should be EJSON.isArray // 3 -isArray = function (x) { // 4 - return _.isArray(x) && !EJSON.isBinary(x); // 5 -}; // 6 - // 7 -// XXX maybe this should be EJSON.isObject, though EJSON doesn't know about // 8 -// RegExp // 9 -// XXX note that _type(undefined) === 3!!!! // 10 -isPlainObject = LocalCollection._isPlainObject = function (x) { // 11 - return x && LocalCollection._f._type(x) === 3; // 12 -}; // 13 - // 14 -isIndexable = function (x) { // 15 - return isArray(x) || isPlainObject(x); // 16 -}; // 17 - // 18 -// Returns true if this is an object with at least one key and all keys begin // 19 -// with $. Unless inconsistentOK is set, throws if some keys begin with $ and // 20 -// others don't. // 21 -isOperatorObject = function (valueSelector, inconsistentOK) { // 22 - if (!isPlainObject(valueSelector)) // 23 - return false; // 24 - // 25 - var theseAreOperators = undefined; // 26 - _.each(valueSelector, function (value, selKey) { // 27 - var thisIsOperator = selKey.substr(0, 1) === '$'; // 28 - if (theseAreOperators === undefined) { // 29 - theseAreOperators = thisIsOperator; // 30 - } else if (theseAreOperators !== thisIsOperator) { // 31 - if (!inconsistentOK) // 32 - throw new Error("Inconsistent operator: " + // 33 - JSON.stringify(valueSelector)); // 34 - theseAreOperators = false; // 35 - } // 36 - }); // 37 - return !!theseAreOperators; // {} has no operators // 38 -}; // 39 - // 40 - // 41 -// string can be converted to integer // 42 -isNumericKey = function (s) { // 43 - return /^[0-9]+$/.test(s); // 44 -}; // 45 - // 46 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/selector.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// The minimongo selector compiler! // 1 - // 2 -// Terminology: // 3 -// - a "selector" is the EJSON object representing a selector // 4 -// - a "matcher" is its compiled form (whether a full Minimongo.Matcher // 5 -// object or one of the component lambdas that matches parts of it) // 6 -// - a "result object" is an object with a "result" field and maybe // 7 -// distance and arrayIndices. // 8 -// - a "branched value" is an object with a "value" field and maybe // 9 -// "dontIterate" and "arrayIndices". // 10 -// - a "document" is a top-level object that can be stored in a collection. // 11 -// - a "lookup function" is a function that takes in a document and returns // 12 -// an array of "branched values". // 13 -// - a "branched matcher" maps from an array of branched values to a result // 14 -// object. // 15 -// - an "element matcher" maps from a single value to a bool. // 16 - // 17 -// Main entry point. // 18 -// var matcher = new Minimongo.Matcher({a: {$gt: 5}}); // 19 -// if (matcher.documentMatches({a: 7})) ... // 20 -Minimongo.Matcher = function (selector) { // 21 - var self = this; // 22 - // A set (object mapping string -> *) of all of the document paths looked // 23 - // at by the selector. Also includes the empty string if it may look at any // 24 - // path (eg, $where). // 25 - self._paths = {}; // 26 - // Set to true if compilation finds a $near. // 27 - self._hasGeoQuery = false; // 28 - // Set to true if compilation finds a $where. // 29 - self._hasWhere = false; // 30 - // Set to false if compilation finds anything other than a simple equality or // 31 - // one or more of '$gt', '$gte', '$lt', '$lte', '$ne', '$in', '$nin' used with // 32 - // scalars as operands. // 33 - self._isSimple = true; // 34 - // Set to a dummy document which always matches this Matcher. Or set to null // 35 - // if such document is too hard to find. // 36 - self._matchingDocument = undefined; // 37 - // A clone of the original selector. It may just be a function if the user // 38 - // passed in a function; otherwise is definitely an object (eg, IDs are // 39 - // translated into {_id: ID} first. Used by canBecomeTrueByModifier and // 40 - // Sorter._useWithMatcher. // 41 - self._selector = null; // 42 - self._docMatcher = self._compileSelector(selector); // 43 -}; // 44 - // 45 -_.extend(Minimongo.Matcher.prototype, { // 46 - documentMatches: function (doc) { // 47 - if (!doc || typeof doc !== "object") { // 48 - throw Error("documentMatches needs a document"); // 49 - } // 50 - return this._docMatcher(doc); // 51 - }, // 52 - hasGeoQuery: function () { // 53 - return this._hasGeoQuery; // 54 - }, // 55 - hasWhere: function () { // 56 - return this._hasWhere; // 57 - }, // 58 - isSimple: function () { // 59 - return this._isSimple; // 60 - }, // 61 - // 62 - // Given a selector, return a function that takes one argument, a // 63 - // document. It returns a result object. // 64 - _compileSelector: function (selector) { // 65 - var self = this; // 66 - // you can pass a literal function instead of a selector // 67 - if (selector instanceof Function) { // 68 - self._isSimple = false; // 69 - self._selector = selector; // 70 - self._recordPathUsed(''); // 71 - return function (doc) { // 72 - return {result: !!selector.call(doc)}; // 73 - }; // 74 - } // 75 - // 76 - // shorthand -- scalars match _id // 77 - if (LocalCollection._selectorIsId(selector)) { // 78 - self._selector = {_id: selector}; // 79 - self._recordPathUsed('_id'); // 80 - return function (doc) { // 81 - return {result: EJSON.equals(doc._id, selector)}; // 82 - }; // 83 - } // 84 - // 85 - // protect against dangerous selectors. falsey and {_id: falsey} are both // 86 - // likely programmer error, and not what you want, particularly for // 87 - // destructive operations. // 88 - if (!selector || (('_id' in selector) && !selector._id)) { // 89 - self._isSimple = false; // 90 - return nothingMatcher; // 91 - } // 92 - // 93 - // Top level can't be an array or true or binary. // 94 - if (typeof(selector) === 'boolean' || isArray(selector) || // 95 - EJSON.isBinary(selector)) // 96 - throw new Error("Invalid selector: " + selector); // 97 - // 98 - self._selector = EJSON.clone(selector); // 99 - return compileDocumentSelector(selector, self, {isRoot: true}); // 100 - }, // 101 - _recordPathUsed: function (path) { // 102 - this._paths[path] = true; // 103 - }, // 104 - // Returns a list of key paths the given selector is looking for. It includes // 105 - // the empty string if there is a $where. // 106 - _getPaths: function () { // 107 - return _.keys(this._paths); // 108 - } // 109 -}); // 110 - // 111 - // 112 -// Takes in a selector that could match a full document (eg, the original // 113 -// selector). Returns a function mapping document->result object. // 114 -// // 115 -// matcher is the Matcher object we are compiling. // 116 -// // 117 -// If this is the root document selector (ie, not wrapped in $and or the like), // 118 -// then isRoot is true. (This is used by $near.) // 119 -var compileDocumentSelector = function (docSelector, matcher, options) { // 120 - options = options || {}; // 121 - var docMatchers = []; // 122 - _.each(docSelector, function (subSelector, key) { // 123 - if (key.substr(0, 1) === '$') { // 124 - // Outer operators are either logical operators (they recurse back into // 125 - // this function), or $where. // 126 - if (!_.has(LOGICAL_OPERATORS, key)) // 127 - throw new Error("Unrecognized logical operator: " + key); // 128 - matcher._isSimple = false; // 129 - docMatchers.push(LOGICAL_OPERATORS[key](subSelector, matcher, // 130 - options.inElemMatch)); // 131 - } else { // 132 - // Record this path, but only if we aren't in an elemMatcher, since in an // 133 - // elemMatch this is a path inside an object in an array, not in the doc // 134 - // root. // 135 - if (!options.inElemMatch) // 136 - matcher._recordPathUsed(key); // 137 - var lookUpByIndex = makeLookupFunction(key); // 138 - var valueMatcher = // 139 - compileValueSelector(subSelector, matcher, options.isRoot); // 140 - docMatchers.push(function (doc) { // 141 - var branchValues = lookUpByIndex(doc); // 142 - return valueMatcher(branchValues); // 143 - }); // 144 - } // 145 - }); // 146 - // 147 - return andDocumentMatchers(docMatchers); // 148 -}; // 149 - // 150 -// Takes in a selector that could match a key-indexed value in a document; eg, // 151 -// {$gt: 5, $lt: 9}, or a regular expression, or any non-expression object (to // 152 -// indicate equality). Returns a branched matcher: a function mapping // 153 -// [branched value]->result object. // 154 -var compileValueSelector = function (valueSelector, matcher, isRoot) { // 155 - if (valueSelector instanceof RegExp) { // 156 - matcher._isSimple = false; // 157 - return convertElementMatcherToBranchedMatcher( // 158 - regexpElementMatcher(valueSelector)); // 159 - } else if (isOperatorObject(valueSelector)) { // 160 - return operatorBranchedMatcher(valueSelector, matcher, isRoot); // 161 - } else { // 162 - return convertElementMatcherToBranchedMatcher( // 163 - equalityElementMatcher(valueSelector)); // 164 - } // 165 -}; // 166 - // 167 -// Given an element matcher (which evaluates a single value), returns a branched // 168 -// value (which evaluates the element matcher on all the branches and returns a // 169 -// more structured return value possibly including arrayIndices). // 170 -var convertElementMatcherToBranchedMatcher = function ( // 171 - elementMatcher, options) { // 172 - options = options || {}; // 173 - return function (branches) { // 174 - var expanded = branches; // 175 - if (!options.dontExpandLeafArrays) { // 176 - expanded = expandArraysInBranches( // 177 - branches, options.dontIncludeLeafArrays); // 178 - } // 179 - var ret = {}; // 180 - ret.result = _.any(expanded, function (element) { // 181 - var matched = elementMatcher(element.value); // 182 - // 183 - // Special case for $elemMatch: it means "true, and use this as an array // 184 - // index if I didn't already have one". // 185 - if (typeof matched === 'number') { // 186 - // XXX This code dates from when we only stored a single array index // 187 - // (for the outermost array). Should we be also including deeper array // 188 - // indices from the $elemMatch match? // 189 - if (!element.arrayIndices) // 190 - element.arrayIndices = [matched]; // 191 - matched = true; // 192 - } // 193 - // 194 - // If some element matched, and it's tagged with array indices, include // 195 - // those indices in our result object. // 196 - if (matched && element.arrayIndices) // 197 - ret.arrayIndices = element.arrayIndices; // 198 - // 199 - return matched; // 200 - }); // 201 - return ret; // 202 - }; // 203 -}; // 204 - // 205 -// Takes a RegExp object and returns an element matcher. // 206 -regexpElementMatcher = function (regexp) { // 207 - return function (value) { // 208 - if (value instanceof RegExp) { // 209 - // Comparing two regexps means seeing if the regexps are identical // 210 - // (really!). Underscore knows how. // 211 - return _.isEqual(value, regexp); // 212 - } // 213 - // Regexps only work against strings. // 214 - if (typeof value !== 'string') // 215 - return false; // 216 - // 217 - // Reset regexp's state to avoid inconsistent matching for objects with the // 218 - // same value on consecutive calls of regexp.test. This happens only if the // 219 - // regexp has the 'g' flag. Also note that ES6 introduces a new flag 'y' for // 220 - // which we should *not* change the lastIndex but MongoDB doesn't support // 221 - // either of these flags. // 222 - regexp.lastIndex = 0; // 223 - // 224 - return regexp.test(value); // 225 - }; // 226 -}; // 227 - // 228 -// Takes something that is not an operator object and returns an element matcher // 229 -// for equality with that thing. // 230 -equalityElementMatcher = function (elementSelector) { // 231 - if (isOperatorObject(elementSelector)) // 232 - throw Error("Can't create equalityValueSelector for operator object"); // 233 - // 234 - // Special-case: null and undefined are equal (if you got undefined in there // 235 - // somewhere, or if you got it due to some branch being non-existent in the // 236 - // weird special case), even though they aren't with EJSON.equals. // 237 - if (elementSelector == null) { // undefined or null // 238 - return function (value) { // 239 - return value == null; // undefined or null // 240 - }; // 241 - } // 242 - // 243 - return function (value) { // 244 - return LocalCollection._f._equal(elementSelector, value); // 245 - }; // 246 -}; // 247 - // 248 -// Takes an operator object (an object with $ keys) and returns a branched // 249 -// matcher for it. // 250 -var operatorBranchedMatcher = function (valueSelector, matcher, isRoot) { // 251 - // Each valueSelector works separately on the various branches. So one // 252 - // operator can match one branch and another can match another branch. This // 253 - // is OK. // 254 - // 255 - var operatorMatchers = []; // 256 - _.each(valueSelector, function (operand, operator) { // 257 - // XXX we should actually implement $eq, which is new in 2.6 // 258 - var simpleRange = _.contains(['$lt', '$lte', '$gt', '$gte'], operator) && // 259 - _.isNumber(operand); // 260 - var simpleInequality = operator === '$ne' && !_.isObject(operand); // 261 - var simpleInclusion = _.contains(['$in', '$nin'], operator) && // 262 - _.isArray(operand) && !_.any(operand, _.isObject); // 263 - // 264 - if (! (operator === '$eq' || simpleRange || // 265 - simpleInclusion || simpleInequality)) { // 266 - matcher._isSimple = false; // 267 - } // 268 - // 269 - if (_.has(VALUE_OPERATORS, operator)) { // 270 - operatorMatchers.push( // 271 - VALUE_OPERATORS[operator](operand, valueSelector, matcher, isRoot)); // 272 - } else if (_.has(ELEMENT_OPERATORS, operator)) { // 273 - var options = ELEMENT_OPERATORS[operator]; // 274 - operatorMatchers.push( // 275 - convertElementMatcherToBranchedMatcher( // 276 - options.compileElementSelector( // 277 - operand, valueSelector, matcher), // 278 - options)); // 279 - } else { // 280 - throw new Error("Unrecognized operator: " + operator); // 281 - } // 282 - }); // 283 - // 284 - return andBranchedMatchers(operatorMatchers); // 285 -}; // 286 - // 287 -var compileArrayOfDocumentSelectors = function ( // 288 - selectors, matcher, inElemMatch) { // 289 - if (!isArray(selectors) || _.isEmpty(selectors)) // 290 - throw Error("$and/$or/$nor must be nonempty array"); // 291 - return _.map(selectors, function (subSelector) { // 292 - if (!isPlainObject(subSelector)) // 293 - throw Error("$or/$and/$nor entries need to be full objects"); // 294 - return compileDocumentSelector( // 295 - subSelector, matcher, {inElemMatch: inElemMatch}); // 296 - }); // 297 -}; // 298 - // 299 -// Operators that appear at the top level of a document selector. // 300 -var LOGICAL_OPERATORS = { // 301 - $and: function (subSelector, matcher, inElemMatch) { // 302 - var matchers = compileArrayOfDocumentSelectors( // 303 - subSelector, matcher, inElemMatch); // 304 - return andDocumentMatchers(matchers); // 305 - }, // 306 - // 307 - $or: function (subSelector, matcher, inElemMatch) { // 308 - var matchers = compileArrayOfDocumentSelectors( // 309 - subSelector, matcher, inElemMatch); // 310 - // 311 - // Special case: if there is only one matcher, use it directly, *preserving* // 312 - // any arrayIndices it returns. // 313 - if (matchers.length === 1) // 314 - return matchers[0]; // 315 - // 316 - return function (doc) { // 317 - var result = _.any(matchers, function (f) { // 318 - return f(doc).result; // 319 - }); // 320 - // $or does NOT set arrayIndices when it has multiple // 321 - // sub-expressions. (Tested against MongoDB.) // 322 - return {result: result}; // 323 - }; // 324 - }, // 325 - // 326 - $nor: function (subSelector, matcher, inElemMatch) { // 327 - var matchers = compileArrayOfDocumentSelectors( // 328 - subSelector, matcher, inElemMatch); // 329 - return function (doc) { // 330 - var result = _.all(matchers, function (f) { // 331 - return !f(doc).result; // 332 - }); // 333 - // Never set arrayIndices, because we only match if nothing in particular // 334 - // "matched" (and because this is consistent with MongoDB). // 335 - return {result: result}; // 336 - }; // 337 - }, // 338 - // 339 - $where: function (selectorValue, matcher) { // 340 - // Record that *any* path may be used. // 341 - matcher._recordPathUsed(''); // 342 - matcher._hasWhere = true; // 343 - if (!(selectorValue instanceof Function)) { // 344 - // XXX MongoDB seems to have more complex logic to decide where or or not // 345 - // to add "return"; not sure exactly what it is. // 346 - selectorValue = Function("obj", "return " + selectorValue); // 347 - } // 348 - return function (doc) { // 349 - // We make the document available as both `this` and `obj`. // 350 - // XXX not sure what we should do if this throws // 351 - return {result: selectorValue.call(doc, doc)}; // 352 - }; // 353 - }, // 354 - // 355 - // This is just used as a comment in the query (in MongoDB, it also ends up in // 356 - // query logs); it has no effect on the actual selection. // 357 - $comment: function () { // 358 - return function () { // 359 - return {result: true}; // 360 - }; // 361 - } // 362 -}; // 363 - // 364 -// Returns a branched matcher that matches iff the given matcher does not. // 365 -// Note that this implicitly "deMorganizes" the wrapped function. ie, it // 366 -// means that ALL branch values need to fail to match innerBranchedMatcher. // 367 -var invertBranchedMatcher = function (branchedMatcher) { // 368 - return function (branchValues) { // 369 - var invertMe = branchedMatcher(branchValues); // 370 - // We explicitly choose to strip arrayIndices here: it doesn't make sense to // 371 - // say "update the array element that does not match something", at least // 372 - // in mongo-land. // 373 - return {result: !invertMe.result}; // 374 - }; // 375 -}; // 376 - // 377 -// Operators that (unlike LOGICAL_OPERATORS) pertain to individual paths in a // 378 -// document, but (unlike ELEMENT_OPERATORS) do not have a simple definition as // 379 -// "match each branched value independently and combine with // 380 -// convertElementMatcherToBranchedMatcher". // 381 -var VALUE_OPERATORS = { // 382 - $not: function (operand, valueSelector, matcher) { // 383 - return invertBranchedMatcher(compileValueSelector(operand, matcher)); // 384 - }, // 385 - $ne: function (operand) { // 386 - return invertBranchedMatcher(convertElementMatcherToBranchedMatcher( // 387 - equalityElementMatcher(operand))); // 388 - }, // 389 - $nin: function (operand) { // 390 - return invertBranchedMatcher(convertElementMatcherToBranchedMatcher( // 391 - ELEMENT_OPERATORS.$in.compileElementSelector(operand))); // 392 - }, // 393 - $exists: function (operand) { // 394 - var exists = convertElementMatcherToBranchedMatcher(function (value) { // 395 - return value !== undefined; // 396 - }); // 397 - return operand ? exists : invertBranchedMatcher(exists); // 398 - }, // 399 - // $options just provides options for $regex; its logic is inside $regex // 400 - $options: function (operand, valueSelector) { // 401 - if (!_.has(valueSelector, '$regex')) // 402 - throw Error("$options needs a $regex"); // 403 - return everythingMatcher; // 404 - }, // 405 - // $maxDistance is basically an argument to $near // 406 - $maxDistance: function (operand, valueSelector) { // 407 - if (!valueSelector.$near) // 408 - throw Error("$maxDistance needs a $near"); // 409 - return everythingMatcher; // 410 - }, // 411 - $all: function (operand, valueSelector, matcher) { // 412 - if (!isArray(operand)) // 413 - throw Error("$all requires array"); // 414 - // Not sure why, but this seems to be what MongoDB does. // 415 - if (_.isEmpty(operand)) // 416 - return nothingMatcher; // 417 - // 418 - var branchedMatchers = []; // 419 - _.each(operand, function (criterion) { // 420 - // XXX handle $all/$elemMatch combination // 421 - if (isOperatorObject(criterion)) // 422 - throw Error("no $ expressions in $all"); // 423 - // This is always a regexp or equality selector. // 424 - branchedMatchers.push(compileValueSelector(criterion, matcher)); // 425 - }); // 426 - // andBranchedMatchers does NOT require all selectors to return true on the // 427 - // SAME branch. // 428 - return andBranchedMatchers(branchedMatchers); // 429 - }, // 430 - $near: function (operand, valueSelector, matcher, isRoot) { // 431 - if (!isRoot) // 432 - throw Error("$near can't be inside another $ operator"); // 433 - matcher._hasGeoQuery = true; // 434 - // 435 - // There are two kinds of geodata in MongoDB: coordinate pairs and // 436 - // GeoJSON. They use different distance metrics, too. GeoJSON queries are // 437 - // marked with a $geometry property. // 438 - // 439 - var maxDistance, point, distance; // 440 - if (isPlainObject(operand) && _.has(operand, '$geometry')) { // 441 - // GeoJSON "2dsphere" mode. // 442 - maxDistance = operand.$maxDistance; // 443 - point = operand.$geometry; // 444 - distance = function (value) { // 445 - // XXX: for now, we don't calculate the actual distance between, say, // 446 - // polygon and circle. If people care about this use-case it will get // 447 - // a priority. // 448 - if (!value || !value.type) // 449 - return null; // 450 - if (value.type === "Point") { // 451 - return GeoJSON.pointDistance(point, value); // 452 - } else { // 453 - return GeoJSON.geometryWithinRadius(value, point, maxDistance) // 454 - ? 0 : maxDistance + 1; // 455 - } // 456 - }; // 457 - } else { // 458 - maxDistance = valueSelector.$maxDistance; // 459 - if (!isArray(operand) && !isPlainObject(operand)) // 460 - throw Error("$near argument must be coordinate pair or GeoJSON"); // 461 - point = pointToArray(operand); // 462 - distance = function (value) { // 463 - if (!isArray(value) && !isPlainObject(value)) // 464 - return null; // 465 - return distanceCoordinatePairs(point, value); // 466 - }; // 467 - } // 468 - // 469 - return function (branchedValues) { // 470 - // There might be multiple points in the document that match the given // 471 - // field. Only one of them needs to be within $maxDistance, but we need to // 472 - // evaluate all of them and use the nearest one for the implicit sort // 473 - // specifier. (That's why we can't just use ELEMENT_OPERATORS here.) // 474 - // // 475 - // Note: This differs from MongoDB's implementation, where a document will // 476 - // actually show up *multiple times* in the result set, with one entry for // 477 - // each within-$maxDistance branching point. // 478 - branchedValues = expandArraysInBranches(branchedValues); // 479 - var result = {result: false}; // 480 - _.each(branchedValues, function (branch) { // 481 - var curDistance = distance(branch.value); // 482 - // Skip branches that aren't real points or are too far away. // 483 - if (curDistance === null || curDistance > maxDistance) // 484 - return; // 485 - // Skip anything that's a tie. // 486 - if (result.distance !== undefined && result.distance <= curDistance) // 487 - return; // 488 - result.result = true; // 489 - result.distance = curDistance; // 490 - if (!branch.arrayIndices) // 491 - delete result.arrayIndices; // 492 - else // 493 - result.arrayIndices = branch.arrayIndices; // 494 - }); // 495 - return result; // 496 - }; // 497 - } // 498 -}; // 499 - // 500 -// Helpers for $near. // 501 -var distanceCoordinatePairs = function (a, b) { // 502 - a = pointToArray(a); // 503 - b = pointToArray(b); // 504 - var x = a[0] - b[0]; // 505 - var y = a[1] - b[1]; // 506 - if (_.isNaN(x) || _.isNaN(y)) // 507 - return null; // 508 - return Math.sqrt(x * x + y * y); // 509 -}; // 510 -// Makes sure we get 2 elements array and assume the first one to be x and // 511 -// the second one to y no matter what user passes. // 512 -// In case user passes { lon: x, lat: y } returns [x, y] // 513 -var pointToArray = function (point) { // 514 - return _.map(point, _.identity); // 515 -}; // 516 - // 517 -// Helper for $lt/$gt/$lte/$gte. // 518 -var makeInequality = function (cmpValueComparator) { // 519 - return { // 520 - compileElementSelector: function (operand) { // 521 - // Arrays never compare false with non-arrays for any inequality. // 522 - // XXX This was behavior we observed in pre-release MongoDB 2.5, but // 523 - // it seems to have been reverted. // 524 - // See https://jira.mongodb.org/browse/SERVER-11444 // 525 - if (isArray(operand)) { // 526 - return function () { // 527 - return false; // 528 - }; // 529 - } // 530 - // 531 - // Special case: consider undefined and null the same (so true with // 532 - // $gte/$lte). // 533 - if (operand === undefined) // 534 - operand = null; // 535 - // 536 - var operandType = LocalCollection._f._type(operand); // 537 - // 538 - return function (value) { // 539 - if (value === undefined) // 540 - value = null; // 541 - // Comparisons are never true among things of different type (except // 542 - // null vs undefined). // 543 - if (LocalCollection._f._type(value) !== operandType) // 544 - return false; // 545 - return cmpValueComparator(LocalCollection._f._cmp(value, operand)); // 546 - }; // 547 - } // 548 - }; // 549 -}; // 550 - // 551 -// Each element selector contains: // 552 -// - compileElementSelector, a function with args: // 553 -// - operand - the "right hand side" of the operator // 554 -// - valueSelector - the "context" for the operator (so that $regex can find // 555 -// $options) // 556 -// - matcher - the Matcher this is going into (so that $elemMatch can compile // 557 -// more things) // 558 -// returning a function mapping a single value to bool. // 559 -// - dontExpandLeafArrays, a bool which prevents expandArraysInBranches from // 560 -// being called // 561 -// - dontIncludeLeafArrays, a bool which causes an argument to be passed to // 562 -// expandArraysInBranches if it is called // 563 -ELEMENT_OPERATORS = { // 564 - $lt: makeInequality(function (cmpValue) { // 565 - return cmpValue < 0; // 566 - }), // 567 - $gt: makeInequality(function (cmpValue) { // 568 - return cmpValue > 0; // 569 - }), // 570 - $lte: makeInequality(function (cmpValue) { // 571 - return cmpValue <= 0; // 572 - }), // 573 - $gte: makeInequality(function (cmpValue) { // 574 - return cmpValue >= 0; // 575 - }), // 576 - $mod: { // 577 - compileElementSelector: function (operand) { // 578 - if (!(isArray(operand) && operand.length === 2 // 579 - && typeof(operand[0]) === 'number' // 580 - && typeof(operand[1]) === 'number')) { // 581 - throw Error("argument to $mod must be an array of two numbers"); // 582 - } // 583 - // XXX could require to be ints or round or something // 584 - var divisor = operand[0]; // 585 - var remainder = operand[1]; // 586 - return function (value) { // 587 - return typeof value === 'number' && value % divisor === remainder; // 588 - }; // 589 - } // 590 - }, // 591 - $in: { // 592 - compileElementSelector: function (operand) { // 593 - if (!isArray(operand)) // 594 - throw Error("$in needs an array"); // 595 - // 596 - var elementMatchers = []; // 597 - _.each(operand, function (option) { // 598 - if (option instanceof RegExp) // 599 - elementMatchers.push(regexpElementMatcher(option)); // 600 - else if (isOperatorObject(option)) // 601 - throw Error("cannot nest $ under $in"); // 602 - else // 603 - elementMatchers.push(equalityElementMatcher(option)); // 604 - }); // 605 - // 606 - return function (value) { // 607 - // Allow {a: {$in: [null]}} to match when 'a' does not exist. // 608 - if (value === undefined) // 609 - value = null; // 610 - return _.any(elementMatchers, function (e) { // 611 - return e(value); // 612 - }); // 613 - }; // 614 - } // 615 - }, // 616 - $size: { // 617 - // {a: [[5, 5]]} must match {a: {$size: 1}} but not {a: {$size: 2}}, so we // 618 - // don't want to consider the element [5,5] in the leaf array [[5,5]] as a // 619 - // possible value. // 620 - dontExpandLeafArrays: true, // 621 - compileElementSelector: function (operand) { // 622 - if (typeof operand === 'string') { // 623 - // Don't ask me why, but by experimentation, this seems to be what Mongo // 624 - // does. // 625 - operand = 0; // 626 - } else if (typeof operand !== 'number') { // 627 - throw Error("$size needs a number"); // 628 - } // 629 - return function (value) { // 630 - return isArray(value) && value.length === operand; // 631 - }; // 632 - } // 633 - }, // 634 - $type: { // 635 - // {a: [5]} must not match {a: {$type: 4}} (4 means array), but it should // 636 - // match {a: {$type: 1}} (1 means number), and {a: [[5]]} must match {$a: // 637 - // {$type: 4}}. Thus, when we see a leaf array, we *should* expand it but // 638 - // should *not* include it itself. // 639 - dontIncludeLeafArrays: true, // 640 - compileElementSelector: function (operand) { // 641 - if (typeof operand !== 'number') // 642 - throw Error("$type needs a number"); // 643 - return function (value) { // 644 - return value !== undefined // 645 - && LocalCollection._f._type(value) === operand; // 646 - }; // 647 - } // 648 - }, // 649 - $regex: { // 650 - compileElementSelector: function (operand, valueSelector) { // 651 - if (!(typeof operand === 'string' || operand instanceof RegExp)) // 652 - throw Error("$regex has to be a string or RegExp"); // 653 - // 654 - var regexp; // 655 - if (valueSelector.$options !== undefined) { // 656 - // Options passed in $options (even the empty string) always overrides // 657 - // options in the RegExp object itself. (See also // 658 - // Mongo.Collection._rewriteSelector.) // 659 - // 660 - // Be clear that we only support the JS-supported options, not extended // 661 - // ones (eg, Mongo supports x and s). Ideally we would implement x and s // 662 - // by transforming the regexp, but not today... // 663 - if (/[^gim]/.test(valueSelector.$options)) // 664 - throw new Error("Only the i, m, and g regexp options are supported"); // 665 - // 666 - var regexSource = operand instanceof RegExp ? operand.source : operand; // 667 - regexp = new RegExp(regexSource, valueSelector.$options); // 668 - } else if (operand instanceof RegExp) { // 669 - regexp = operand; // 670 - } else { // 671 - regexp = new RegExp(operand); // 672 - } // 673 - return regexpElementMatcher(regexp); // 674 - } // 675 - }, // 676 - $elemMatch: { // 677 - dontExpandLeafArrays: true, // 678 - compileElementSelector: function (operand, valueSelector, matcher) { // 679 - if (!isPlainObject(operand)) // 680 - throw Error("$elemMatch need an object"); // 681 - // 682 - var subMatcher, isDocMatcher; // 683 - if (isOperatorObject(operand, true)) { // 684 - subMatcher = compileValueSelector(operand, matcher); // 685 - isDocMatcher = false; // 686 - } else { // 687 - // This is NOT the same as compileValueSelector(operand), and not just // 688 - // because of the slightly different calling convention. // 689 - // {$elemMatch: {x: 3}} means "an element has a field x:3", not // 690 - // "consists only of a field x:3". Also, regexps and sub-$ are allowed. // 691 - subMatcher = compileDocumentSelector(operand, matcher, // 692 - {inElemMatch: true}); // 693 - isDocMatcher = true; // 694 - } // 695 - // 696 - return function (value) { // 697 - if (!isArray(value)) // 698 - return false; // 699 - for (var i = 0; i < value.length; ++i) { // 700 - var arrayElement = value[i]; // 701 - var arg; // 702 - if (isDocMatcher) { // 703 - // We can only match {$elemMatch: {b: 3}} against objects. // 704 - // (We can also match against arrays, if there's numeric indices, // 705 - // eg {$elemMatch: {'0.b': 3}} or {$elemMatch: {0: 3}}.) // 706 - if (!isPlainObject(arrayElement) && !isArray(arrayElement)) // 707 - return false; // 708 - arg = arrayElement; // 709 - } else { // 710 - // dontIterate ensures that {a: {$elemMatch: {$gt: 5}}} matches // 711 - // {a: [8]} but not {a: [[8]]} // 712 - arg = [{value: arrayElement, dontIterate: true}]; // 713 - } // 714 - // XXX support $near in $elemMatch by propagating $distance? // 715 - if (subMatcher(arg).result) // 716 - return i; // specially understood to mean "use as arrayIndices" // 717 - } // 718 - return false; // 719 - }; // 720 - } // 721 - } // 722 -}; // 723 - // 724 -// makeLookupFunction(key) returns a lookup function. // 725 -// // 726 -// A lookup function takes in a document and returns an array of matching // 727 -// branches. If no arrays are found while looking up the key, this array will // 728 -// have exactly one branches (possibly 'undefined', if some segment of the key // 729 -// was not found). // 730 -// // 731 -// If arrays are found in the middle, this can have more than one element, since // 732 -// we "branch". When we "branch", if there are more key segments to look up, // 733 -// then we only pursue branches that are plain objects (not arrays or scalars). // 734 -// This means we can actually end up with no branches! // 735 -// // 736 -// We do *NOT* branch on arrays that are found at the end (ie, at the last // 737 -// dotted member of the key). We just return that array; if you want to // 738 -// effectively "branch" over the array's values, post-process the lookup // 739 -// function with expandArraysInBranches. // 740 -// // 741 -// Each branch is an object with keys: // 742 -// - value: the value at the branch // 743 -// - dontIterate: an optional bool; if true, it means that 'value' is an array // 744 -// that expandArraysInBranches should NOT expand. This specifically happens // 745 -// when there is a numeric index in the key, and ensures the // 746 -// perhaps-surprising MongoDB behavior where {'a.0': 5} does NOT // 747 -// match {a: [[5]]}. // 748 -// - arrayIndices: if any array indexing was done during lookup (either due to // 749 -// explicit numeric indices or implicit branching), this will be an array of // 750 -// the array indices used, from outermost to innermost; it is falsey or // 751 -// absent if no array index is used. If an explicit numeric index is used, // 752 -// the index will be followed in arrayIndices by the string 'x'. // 753 -// // 754 -// Note: arrayIndices is used for two purposes. First, it is used to // 755 -// implement the '$' modifier feature, which only ever looks at its first // 756 -// element. // 757 -// // 758 -// Second, it is used for sort key generation, which needs to be able to tell // 759 -// the difference between different paths. Moreover, it needs to // 760 -// differentiate between explicit and implicit branching, which is why // 761 -// there's the somewhat hacky 'x' entry: this means that explicit and // 762 -// implicit array lookups will have different full arrayIndices paths. (That // 763 -// code only requires that different paths have different arrayIndices; it // 764 -// doesn't actually "parse" arrayIndices. As an alternative, arrayIndices // 765 -// could contain objects with flags like "implicit", but I think that only // 766 -// makes the code surrounding them more complex.) // 767 -// // 768 -// (By the way, this field ends up getting passed around a lot without // 769 -// cloning, so never mutate any arrayIndices field/var in this package!) // 770 -// // 771 -// // 772 -// At the top level, you may only pass in a plain object or array. // 773 -// // 774 -// See the test 'minimongo - lookup' for some examples of what lookup functions // 775 -// return. // 776 -makeLookupFunction = function (key, options) { // 777 - options = options || {}; // 778 - var parts = key.split('.'); // 779 - var firstPart = parts.length ? parts[0] : ''; // 780 - var firstPartIsNumeric = isNumericKey(firstPart); // 781 - var nextPartIsNumeric = parts.length >= 2 && isNumericKey(parts[1]); // 782 - var lookupRest; // 783 - if (parts.length > 1) { // 784 - lookupRest = makeLookupFunction(parts.slice(1).join('.')); // 785 - } // 786 - // 787 - var omitUnnecessaryFields = function (retVal) { // 788 - if (!retVal.dontIterate) // 789 - delete retVal.dontIterate; // 790 - if (retVal.arrayIndices && !retVal.arrayIndices.length) // 791 - delete retVal.arrayIndices; // 792 - return retVal; // 793 - }; // 794 - // 795 - // Doc will always be a plain object or an array. // 796 - // apply an explicit numeric index, an array. // 797 - return function (doc, arrayIndices) { // 798 - if (!arrayIndices) // 799 - arrayIndices = []; // 800 - // 801 - if (isArray(doc)) { // 802 - // If we're being asked to do an invalid lookup into an array (non-integer // 803 - // or out-of-bounds), return no results (which is different from returning // 804 - // a single undefined result, in that `null` equality checks won't match). // 805 - if (!(firstPartIsNumeric && firstPart < doc.length)) // 806 - return []; // 807 - // 808 - // Remember that we used this array index. Include an 'x' to indicate that // 809 - // the previous index came from being considered as an explicit array // 810 - // index (not branching). // 811 - arrayIndices = arrayIndices.concat(+firstPart, 'x'); // 812 - } // 813 - // 814 - // Do our first lookup. // 815 - var firstLevel = doc[firstPart]; // 816 - // 817 - // If there is no deeper to dig, return what we found. // 818 - // // 819 - // If what we found is an array, most value selectors will choose to treat // 820 - // the elements of the array as matchable values in their own right, but // 821 - // that's done outside of the lookup function. (Exceptions to this are $size // 822 - // and stuff relating to $elemMatch. eg, {a: {$size: 2}} does not match {a: // 823 - // [[1, 2]]}.) // 824 - // // 825 - // That said, if we just did an *explicit* array lookup (on doc) to find // 826 - // firstLevel, and firstLevel is an array too, we do NOT want value // 827 - // selectors to iterate over it. eg, {'a.0': 5} does not match {a: [[5]]}. // 828 - // So in that case, we mark the return value as "don't iterate". // 829 - if (!lookupRest) { // 830 - return [omitUnnecessaryFields({ // 831 - value: firstLevel, // 832 - dontIterate: isArray(doc) && isArray(firstLevel), // 833 - arrayIndices: arrayIndices})]; // 834 - } // 835 - // 836 - // We need to dig deeper. But if we can't, because what we've found is not // 837 - // an array or plain object, we're done. If we just did a numeric index into // 838 - // an array, we return nothing here (this is a change in Mongo 2.5 from // 839 - // Mongo 2.4, where {'a.0.b': null} stopped matching {a: [5]}). Otherwise, // 840 - // return a single `undefined` (which can, for example, match via equality // 841 - // with `null`). // 842 - if (!isIndexable(firstLevel)) { // 843 - if (isArray(doc)) // 844 - return []; // 845 - return [omitUnnecessaryFields({value: undefined, // 846 - arrayIndices: arrayIndices})]; // 847 - } // 848 - // 849 - var result = []; // 850 - var appendToResult = function (more) { // 851 - Array.prototype.push.apply(result, more); // 852 - }; // 853 - // 854 - // Dig deeper: look up the rest of the parts on whatever we've found. // 855 - // (lookupRest is smart enough to not try to do invalid lookups into // 856 - // firstLevel if it's an array.) // 857 - appendToResult(lookupRest(firstLevel, arrayIndices)); // 858 - // 859 - // If we found an array, then in *addition* to potentially treating the next // 860 - // part as a literal integer lookup, we should also "branch": try to look up // 861 - // the rest of the parts on each array element in parallel. // 862 - // // 863 - // In this case, we *only* dig deeper into array elements that are plain // 864 - // objects. (Recall that we only got this far if we have further to dig.) // 865 - // This makes sense: we certainly don't dig deeper into non-indexable // 866 - // objects. And it would be weird to dig into an array: it's simpler to have // 867 - // a rule that explicit integer indexes only apply to an outer array, not to // 868 - // an array you find after a branching search. // 869 - // // 870 - // In the special case of a numeric part in a *sort selector* (not a query // 871 - // selector), we skip the branching: we ONLY allow the numeric part to mean // 872 - // "look up this index" in that case, not "also look up this index in all // 873 - // the elements of the array". // 874 - if (isArray(firstLevel) && !(nextPartIsNumeric && options.forSort)) { // 875 - _.each(firstLevel, function (branch, arrayIndex) { // 876 - if (isPlainObject(branch)) { // 877 - appendToResult(lookupRest( // 878 - branch, // 879 - arrayIndices.concat(arrayIndex))); // 880 - } // 881 - }); // 882 - } // 883 - // 884 - return result; // 885 - }; // 886 -}; // 887 -MinimongoTest.makeLookupFunction = makeLookupFunction; // 888 - // 889 -expandArraysInBranches = function (branches, skipTheArrays) { // 890 - var branchesOut = []; // 891 - _.each(branches, function (branch) { // 892 - var thisIsArray = isArray(branch.value); // 893 - // We include the branch itself, *UNLESS* we it's an array that we're going // 894 - // to iterate and we're told to skip arrays. (That's right, we include some // 895 - // arrays even skipTheArrays is true: these are arrays that were found via // 896 - // explicit numerical indices.) // 897 - if (!(skipTheArrays && thisIsArray && !branch.dontIterate)) { // 898 - branchesOut.push({ // 899 - value: branch.value, // 900 - arrayIndices: branch.arrayIndices // 901 - }); // 902 - } // 903 - if (thisIsArray && !branch.dontIterate) { // 904 - _.each(branch.value, function (leaf, i) { // 905 - branchesOut.push({ // 906 - value: leaf, // 907 - arrayIndices: (branch.arrayIndices || []).concat(i) // 908 - }); // 909 - }); // 910 - } // 911 - }); // 912 - return branchesOut; // 913 -}; // 914 - // 915 -var nothingMatcher = function (docOrBranchedValues) { // 916 - return {result: false}; // 917 -}; // 918 - // 919 -var everythingMatcher = function (docOrBranchedValues) { // 920 - return {result: true}; // 921 -}; // 922 - // 923 - // 924 -// NB: We are cheating and using this function to implement "AND" for both // 925 -// "document matchers" and "branched matchers". They both return result objects // 926 -// but the argument is different: for the former it's a whole doc, whereas for // 927 -// the latter it's an array of "branched values". // 928 -var andSomeMatchers = function (subMatchers) { // 929 - if (subMatchers.length === 0) // 930 - return everythingMatcher; // 931 - if (subMatchers.length === 1) // 932 - return subMatchers[0]; // 933 - // 934 - return function (docOrBranches) { // 935 - var ret = {}; // 936 - ret.result = _.all(subMatchers, function (f) { // 937 - var subResult = f(docOrBranches); // 938 - // Copy a 'distance' number out of the first sub-matcher that has // 939 - // one. Yes, this means that if there are multiple $near fields in a // 940 - // query, something arbitrary happens; this appears to be consistent with // 941 - // Mongo. // 942 - if (subResult.result && subResult.distance !== undefined // 943 - && ret.distance === undefined) { // 944 - ret.distance = subResult.distance; // 945 - } // 946 - // Similarly, propagate arrayIndices from sub-matchers... but to match // 947 - // MongoDB behavior, this time the *last* sub-matcher with arrayIndices // 948 - // wins. // 949 - if (subResult.result && subResult.arrayIndices) { // 950 - ret.arrayIndices = subResult.arrayIndices; // 951 - } // 952 - return subResult.result; // 953 - }); // 954 - // 955 - // If we didn't actually match, forget any extra metadata we came up with. // 956 - if (!ret.result) { // 957 - delete ret.distance; // 958 - delete ret.arrayIndices; // 959 - } // 960 - return ret; // 961 - }; // 962 -}; // 963 - // 964 -var andDocumentMatchers = andSomeMatchers; // 965 -var andBranchedMatchers = andSomeMatchers; // 966 - // 967 - // 968 -// helpers used by compiled selector code // 969 -LocalCollection._f = { // 970 - // XXX for _all and _in, consider building 'inquery' at compile time.. // 971 - // 972 - _type: function (v) { // 973 - if (typeof v === "number") // 974 - return 1; // 975 - if (typeof v === "string") // 976 - return 2; // 977 - if (typeof v === "boolean") // 978 - return 8; // 979 - if (isArray(v)) // 980 - return 4; // 981 - if (v === null) // 982 - return 10; // 983 - if (v instanceof RegExp) // 984 - // note that typeof(/x/) === "object" // 985 - return 11; // 986 - if (typeof v === "function") // 987 - return 13; // 988 - if (v instanceof Date) // 989 - return 9; // 990 - if (EJSON.isBinary(v)) // 991 - return 5; // 992 - if (v instanceof LocalCollection._ObjectID) // 993 - return 7; // 994 - return 3; // object // 995 - // 996 - // XXX support some/all of these: // 997 - // 14, symbol // 998 - // 15, javascript code with scope // 999 - // 16, 18: 32-bit/64-bit integer // 1000 - // 17, timestamp // 1001 - // 255, minkey // 1002 - // 127, maxkey // 1003 - }, // 1004 - // 1005 - // deep equality test: use for literal document and array matches // 1006 - _equal: function (a, b) { // 1007 - return EJSON.equals(a, b, {keyOrderSensitive: true}); // 1008 - }, // 1009 - // 1010 - // maps a type code to a value that can be used to sort values of // 1011 - // different types // 1012 - _typeorder: function (t) { // 1013 - // http://www.mongodb.org/display/DOCS/What+is+the+Compare+Order+for+BSON+Types // 1014 - // XXX what is the correct sort position for Javascript code? // 1015 - // ('100' in the matrix below) // 1016 - // XXX minkey/maxkey // 1017 - return [-1, // (not a type) // 1018 - 1, // number // 1019 - 2, // string // 1020 - 3, // object // 1021 - 4, // array // 1022 - 5, // binary // 1023 - -1, // deprecated // 1024 - 6, // ObjectID // 1025 - 7, // bool // 1026 - 8, // Date // 1027 - 0, // null // 1028 - 9, // RegExp // 1029 - -1, // deprecated // 1030 - 100, // JS code // 1031 - 2, // deprecated (symbol) // 1032 - 100, // JS code // 1033 - 1, // 32-bit int // 1034 - 8, // Mongo timestamp // 1035 - 1 // 64-bit int // 1036 - ][t]; // 1037 - }, // 1038 - // 1039 - // compare two values of unknown type according to BSON ordering // 1040 - // semantics. (as an extension, consider 'undefined' to be less than // 1041 - // any other value.) return negative if a is less, positive if b is // 1042 - // less, or 0 if equal // 1043 - _cmp: function (a, b) { // 1044 - if (a === undefined) // 1045 - return b === undefined ? 0 : -1; // 1046 - if (b === undefined) // 1047 - return 1; // 1048 - var ta = LocalCollection._f._type(a); // 1049 - var tb = LocalCollection._f._type(b); // 1050 - var oa = LocalCollection._f._typeorder(ta); // 1051 - var ob = LocalCollection._f._typeorder(tb); // 1052 - if (oa !== ob) // 1053 - return oa < ob ? -1 : 1; // 1054 - if (ta !== tb) // 1055 - // XXX need to implement this if we implement Symbol or integers, or // 1056 - // Timestamp // 1057 - throw Error("Missing type coercion logic in _cmp"); // 1058 - if (ta === 7) { // ObjectID // 1059 - // Convert to string. // 1060 - ta = tb = 2; // 1061 - a = a.toHexString(); // 1062 - b = b.toHexString(); // 1063 - } // 1064 - if (ta === 9) { // Date // 1065 - // Convert to millis. // 1066 - ta = tb = 1; // 1067 - a = a.getTime(); // 1068 - b = b.getTime(); // 1069 - } // 1070 - // 1071 - if (ta === 1) // double // 1072 - return a - b; // 1073 - if (tb === 2) // string // 1074 - return a < b ? -1 : (a === b ? 0 : 1); // 1075 - if (ta === 3) { // Object // 1076 - // this could be much more efficient in the expected case ... // 1077 - var to_array = function (obj) { // 1078 - var ret = []; // 1079 - for (var key in obj) { // 1080 - ret.push(key); // 1081 - ret.push(obj[key]); // 1082 - } // 1083 - return ret; // 1084 - }; // 1085 - return LocalCollection._f._cmp(to_array(a), to_array(b)); // 1086 - } // 1087 - if (ta === 4) { // Array // 1088 - for (var i = 0; ; i++) { // 1089 - if (i === a.length) // 1090 - return (i === b.length) ? 0 : -1; // 1091 - if (i === b.length) // 1092 - return 1; // 1093 - var s = LocalCollection._f._cmp(a[i], b[i]); // 1094 - if (s !== 0) // 1095 - return s; // 1096 - } // 1097 - } // 1098 - if (ta === 5) { // binary // 1099 - // Surprisingly, a small binary blob is always less than a large one in // 1100 - // Mongo. // 1101 - if (a.length !== b.length) // 1102 - return a.length - b.length; // 1103 - for (i = 0; i < a.length; i++) { // 1104 - if (a[i] < b[i]) // 1105 - return -1; // 1106 - if (a[i] > b[i]) // 1107 - return 1; // 1108 - } // 1109 - return 0; // 1110 - } // 1111 - if (ta === 8) { // boolean // 1112 - if (a) return b ? 0 : 1; // 1113 - return b ? -1 : 0; // 1114 - } // 1115 - if (ta === 10) // null // 1116 - return 0; // 1117 - if (ta === 11) // regexp // 1118 - throw Error("Sorting not supported on regular expression"); // XXX // 1119 - // 13: javascript code // 1120 - // 14: symbol // 1121 - // 15: javascript code with scope // 1122 - // 16: 32-bit integer // 1123 - // 17: timestamp // 1124 - // 18: 64-bit integer // 1125 - // 255: minkey // 1126 - // 127: maxkey // 1127 - if (ta === 13) // javascript code // 1128 - throw Error("Sorting not supported on Javascript code"); // XXX // 1129 - throw Error("Unknown type to sort"); // 1130 - } // 1131 -}; // 1132 - // 1133 -// Oddball function used by upsert. // 1134 -LocalCollection._removeDollarOperators = function (selector) { // 1135 - var selectorDoc = {}; // 1136 - for (var k in selector) // 1137 - if (k.substr(0, 1) !== '$') // 1138 - selectorDoc[k] = selector[k]; // 1139 - return selectorDoc; // 1140 -}; // 1141 - // 1142 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/sort.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Give a sort spec, which can be in any of these forms: // 1 -// {"key1": 1, "key2": -1} // 2 -// [["key1", "asc"], ["key2", "desc"]] // 3 -// ["key1", ["key2", "desc"]] // 4 -// // 5 -// (.. with the first form being dependent on the key enumeration // 6 -// behavior of your javascript VM, which usually does what you mean in // 7 -// this case if the key names don't look like integers ..) // 8 -// // 9 -// return a function that takes two objects, and returns -1 if the // 10 -// first object comes first in order, 1 if the second object comes // 11 -// first, or 0 if neither object comes before the other. // 12 - // 13 -Minimongo.Sorter = function (spec, options) { // 14 - var self = this; // 15 - options = options || {}; // 16 - // 17 - self._sortSpecParts = []; // 18 - // 19 - var addSpecPart = function (path, ascending) { // 20 - if (!path) // 21 - throw Error("sort keys must be non-empty"); // 22 - if (path.charAt(0) === '$') // 23 - throw Error("unsupported sort key: " + path); // 24 - self._sortSpecParts.push({ // 25 - path: path, // 26 - lookup: makeLookupFunction(path, {forSort: true}), // 27 - ascending: ascending // 28 - }); // 29 - }; // 30 - // 31 - if (spec instanceof Array) { // 32 - for (var i = 0; i < spec.length; i++) { // 33 - if (typeof spec[i] === "string") { // 34 - addSpecPart(spec[i], true); // 35 - } else { // 36 - addSpecPart(spec[i][0], spec[i][1] !== "desc"); // 37 - } // 38 - } // 39 - } else if (typeof spec === "object") { // 40 - _.each(spec, function (value, key) { // 41 - addSpecPart(key, value >= 0); // 42 - }); // 43 - } else { // 44 - throw Error("Bad sort specification: " + JSON.stringify(spec)); // 45 - } // 46 - // 47 - // To implement affectedByModifier, we piggy-back on top of Matcher's // 48 - // affectedByModifier code; we create a selector that is affected by the same // 49 - // modifiers as this sort order. This is only implemented on the server. // 50 - if (self.affectedByModifier) { // 51 - var selector = {}; // 52 - _.each(self._sortSpecParts, function (spec) { // 53 - selector[spec.path] = 1; // 54 - }); // 55 - self._selectorForAffectedByModifier = new Minimongo.Matcher(selector); // 56 - } // 57 - // 58 - self._keyComparator = composeComparators( // 59 - _.map(self._sortSpecParts, function (spec, i) { // 60 - return self._keyFieldComparator(i); // 61 - })); // 62 - // 63 - // If you specify a matcher for this Sorter, _keyFilter may be set to a // 64 - // function which selects whether or not a given "sort key" (tuple of values // 65 - // for the different sort spec fields) is compatible with the selector. // 66 - self._keyFilter = null; // 67 - options.matcher && self._useWithMatcher(options.matcher); // 68 -}; // 69 - // 70 -// In addition to these methods, sorter_project.js defines combineIntoProjection // 71 -// on the server only. // 72 -_.extend(Minimongo.Sorter.prototype, { // 73 - getComparator: function (options) { // 74 - var self = this; // 75 - // 76 - // If we have no distances, just use the comparator from the source // 77 - // specification (which defaults to "everything is equal". // 78 - if (!options || !options.distances) { // 79 - return self._getBaseComparator(); // 80 - } // 81 - // 82 - var distances = options.distances; // 83 - // 84 - // Return a comparator which first tries the sort specification, and if that // 85 - // says "it's equal", breaks ties using $near distances. // 86 - return composeComparators([self._getBaseComparator(), function (a, b) { // 87 - if (!distances.has(a._id)) // 88 - throw Error("Missing distance for " + a._id); // 89 - if (!distances.has(b._id)) // 90 - throw Error("Missing distance for " + b._id); // 91 - return distances.get(a._id) - distances.get(b._id); // 92 - }]); // 93 - }, // 94 - // 95 - _getPaths: function () { // 96 - var self = this; // 97 - return _.pluck(self._sortSpecParts, 'path'); // 98 - }, // 99 - // 100 - // Finds the minimum key from the doc, according to the sort specs. (We say // 101 - // "minimum" here but this is with respect to the sort spec, so "descending" // 102 - // sort fields mean we're finding the max for that field.) // 103 - // // 104 - // Note that this is NOT "find the minimum value of the first field, the // 105 - // minimum value of the second field, etc"... it's "choose the // 106 - // lexicographically minimum value of the key vector, allowing only keys which // 107 - // you can find along the same paths". ie, for a doc {a: [{x: 0, y: 5}, {x: // 108 - // 1, y: 3}]} with sort spec {'a.x': 1, 'a.y': 1}, the only keys are [0,5] and // 109 - // [1,3], and the minimum key is [0,5]; notably, [0,3] is NOT a key. // 110 - _getMinKeyFromDoc: function (doc) { // 111 - var self = this; // 112 - var minKey = null; // 113 - // 114 - self._generateKeysFromDoc(doc, function (key) { // 115 - if (!self._keyCompatibleWithSelector(key)) // 116 - return; // 117 - // 118 - if (minKey === null) { // 119 - minKey = key; // 120 - return; // 121 - } // 122 - if (self._compareKeys(key, minKey) < 0) { // 123 - minKey = key; // 124 - } // 125 - }); // 126 - // 127 - // This could happen if our key filter somehow filters out all the keys even // 128 - // though somehow the selector matches. // 129 - if (minKey === null) // 130 - throw Error("sort selector found no keys in doc?"); // 131 - return minKey; // 132 - }, // 133 - // 134 - _keyCompatibleWithSelector: function (key) { // 135 - var self = this; // 136 - return !self._keyFilter || self._keyFilter(key); // 137 - }, // 138 - // 139 - // Iterates over each possible "key" from doc (ie, over each branch), calling // 140 - // 'cb' with the key. // 141 - _generateKeysFromDoc: function (doc, cb) { // 142 - var self = this; // 143 - // 144 - if (self._sortSpecParts.length === 0) // 145 - throw new Error("can't generate keys without a spec"); // 146 - // 147 - // maps index -> ({'' -> value} or {path -> value}) // 148 - var valuesByIndexAndPath = []; // 149 - // 150 - var pathFromIndices = function (indices) { // 151 - return indices.join(',') + ','; // 152 - }; // 153 - // 154 - var knownPaths = null; // 155 - // 156 - _.each(self._sortSpecParts, function (spec, whichField) { // 157 - // Expand any leaf arrays that we find, and ignore those arrays // 158 - // themselves. (We never sort based on an array itself.) // 159 - var branches = expandArraysInBranches(spec.lookup(doc), true); // 160 - // 161 - // If there are no values for a key (eg, key goes to an empty array), // 162 - // pretend we found one null value. // 163 - if (!branches.length) // 164 - branches = [{value: null}]; // 165 - // 166 - var usedPaths = false; // 167 - valuesByIndexAndPath[whichField] = {}; // 168 - _.each(branches, function (branch) { // 169 - if (!branch.arrayIndices) { // 170 - // If there are no array indices for a branch, then it must be the // 171 - // only branch, because the only thing that produces multiple branches // 172 - // is the use of arrays. // 173 - if (branches.length > 1) // 174 - throw Error("multiple branches but no array used?"); // 175 - valuesByIndexAndPath[whichField][''] = branch.value; // 176 - return; // 177 - } // 178 - // 179 - usedPaths = true; // 180 - var path = pathFromIndices(branch.arrayIndices); // 181 - if (_.has(valuesByIndexAndPath[whichField], path)) // 182 - throw Error("duplicate path: " + path); // 183 - valuesByIndexAndPath[whichField][path] = branch.value; // 184 - // 185 - // If two sort fields both go into arrays, they have to go into the // 186 - // exact same arrays and we have to find the same paths. This is // 187 - // roughly the same condition that makes MongoDB throw this strange // 188 - // error message. eg, the main thing is that if sort spec is {a: 1, // 189 - // b:1} then a and b cannot both be arrays. // 190 - // // 191 - // (In MongoDB it seems to be OK to have {a: 1, 'a.x.y': 1} where 'a' // 192 - // and 'a.x.y' are both arrays, but we don't allow this for now. // 193 - // #NestedArraySort // 194 - // XXX achieve full compatibility here // 195 - if (knownPaths && !_.has(knownPaths, path)) { // 196 - throw Error("cannot index parallel arrays"); // 197 - } // 198 - }); // 199 - // 200 - if (knownPaths) { // 201 - // Similarly to above, paths must match everywhere, unless this is a // 202 - // non-array field. // 203 - if (!_.has(valuesByIndexAndPath[whichField], '') && // 204 - _.size(knownPaths) !== _.size(valuesByIndexAndPath[whichField])) { // 205 - throw Error("cannot index parallel arrays!"); // 206 - } // 207 - } else if (usedPaths) { // 208 - knownPaths = {}; // 209 - _.each(valuesByIndexAndPath[whichField], function (x, path) { // 210 - knownPaths[path] = true; // 211 - }); // 212 - } // 213 - }); // 214 - // 215 - if (!knownPaths) { // 216 - // Easy case: no use of arrays. // 217 - var soleKey = _.map(valuesByIndexAndPath, function (values) { // 218 - if (!_.has(values, '')) // 219 - throw Error("no value in sole key case?"); // 220 - return values['']; // 221 - }); // 222 - cb(soleKey); // 223 - return; // 224 - } // 225 - // 226 - _.each(knownPaths, function (x, path) { // 227 - var key = _.map(valuesByIndexAndPath, function (values) { // 228 - if (_.has(values, '')) // 229 - return values['']; // 230 - if (!_.has(values, path)) // 231 - throw Error("missing path?"); // 232 - return values[path]; // 233 - }); // 234 - cb(key); // 235 - }); // 236 - }, // 237 - // 238 - // Takes in two keys: arrays whose lengths match the number of spec // 239 - // parts. Returns negative, 0, or positive based on using the sort spec to // 240 - // compare fields. // 241 - _compareKeys: function (key1, key2) { // 242 - var self = this; // 243 - if (key1.length !== self._sortSpecParts.length || // 244 - key2.length !== self._sortSpecParts.length) { // 245 - throw Error("Key has wrong length"); // 246 - } // 247 - // 248 - return self._keyComparator(key1, key2); // 249 - }, // 250 - // 251 - // Given an index 'i', returns a comparator that compares two key arrays based // 252 - // on field 'i'. // 253 - _keyFieldComparator: function (i) { // 254 - var self = this; // 255 - var invert = !self._sortSpecParts[i].ascending; // 256 - return function (key1, key2) { // 257 - var compare = LocalCollection._f._cmp(key1[i], key2[i]); // 258 - if (invert) // 259 - compare = -compare; // 260 - return compare; // 261 - }; // 262 - }, // 263 - // 264 - // Returns a comparator that represents the sort specification (but not // 265 - // including a possible geoquery distance tie-breaker). // 266 - _getBaseComparator: function () { // 267 - var self = this; // 268 - // 269 - // If we're only sorting on geoquery distance and no specs, just say // 270 - // everything is equal. // 271 - if (!self._sortSpecParts.length) { // 272 - return function (doc1, doc2) { // 273 - return 0; // 274 - }; // 275 - } // 276 - // 277 - return function (doc1, doc2) { // 278 - var key1 = self._getMinKeyFromDoc(doc1); // 279 - var key2 = self._getMinKeyFromDoc(doc2); // 280 - return self._compareKeys(key1, key2); // 281 - }; // 282 - }, // 283 - // 284 - // In MongoDB, if you have documents // 285 - // {_id: 'x', a: [1, 10]} and // 286 - // {_id: 'y', a: [5, 15]}, // 287 - // then C.find({}, {sort: {a: 1}}) puts x before y (1 comes before 5). // 288 - // But C.find({a: {$gt: 3}}, {sort: {a: 1}}) puts y before x (1 does not // 289 - // match the selector, and 5 comes before 10). // 290 - // // 291 - // The way this works is pretty subtle! For example, if the documents // 292 - // are instead {_id: 'x', a: [{x: 1}, {x: 10}]}) and // 293 - // {_id: 'y', a: [{x: 5}, {x: 15}]}), // 294 - // then C.find({'a.x': {$gt: 3}}, {sort: {'a.x': 1}}) and // 295 - // C.find({a: {$elemMatch: {x: {$gt: 3}}}}, {sort: {'a.x': 1}}) // 296 - // both follow this rule (y before x). (ie, you do have to apply this // 297 - // through $elemMatch.) // 298 - // // 299 - // So if you pass a matcher to this sorter's constructor, we will attempt to // 300 - // skip sort keys that don't match the selector. The logic here is pretty // 301 - // subtle and undocumented; we've gotten as close as we can figure out based // 302 - // on our understanding of Mongo's behavior. // 303 - _useWithMatcher: function (matcher) { // 304 - var self = this; // 305 - // 306 - if (self._keyFilter) // 307 - throw Error("called _useWithMatcher twice?"); // 308 - // 309 - // If we are only sorting by distance, then we're not going to bother to // 310 - // build a key filter. // 311 - // XXX figure out how geoqueries interact with this stuff // 312 - if (_.isEmpty(self._sortSpecParts)) // 313 - return; // 314 - // 315 - var selector = matcher._selector; // 316 - // 317 - // If the user just passed a literal function to find(), then we can't get a // 318 - // key filter from it. // 319 - if (selector instanceof Function) // 320 - return; // 321 - // 322 - var constraintsByPath = {}; // 323 - _.each(self._sortSpecParts, function (spec, i) { // 324 - constraintsByPath[spec.path] = []; // 325 - }); // 326 - // 327 - _.each(selector, function (subSelector, key) { // 328 - // XXX support $and and $or // 329 - // 330 - var constraints = constraintsByPath[key]; // 331 - if (!constraints) // 332 - return; // 333 - // 334 - // XXX it looks like the real MongoDB implementation isn't "does the // 335 - // regexp match" but "does the value fall into a range named by the // 336 - // literal prefix of the regexp", ie "foo" in /^foo(bar|baz)+/ But // 337 - // "does the regexp match" is a good approximation. // 338 - if (subSelector instanceof RegExp) { // 339 - // As far as we can tell, using either of the options that both we and // 340 - // MongoDB support ('i' and 'm') disables use of the key filter. This // 341 - // makes sense: MongoDB mostly appears to be calculating ranges of an // 342 - // index to use, which means it only cares about regexps that match // 343 - // one range (with a literal prefix), and both 'i' and 'm' prevent the // 344 - // literal prefix of the regexp from actually meaning one range. // 345 - if (subSelector.ignoreCase || subSelector.multiline) // 346 - return; // 347 - constraints.push(regexpElementMatcher(subSelector)); // 348 - return; // 349 - } // 350 - // 351 - if (isOperatorObject(subSelector)) { // 352 - _.each(subSelector, function (operand, operator) { // 353 - if (_.contains(['$lt', '$lte', '$gt', '$gte'], operator)) { // 354 - // XXX this depends on us knowing that these operators don't use any // 355 - // of the arguments to compileElementSelector other than operand. // 356 - constraints.push( // 357 - ELEMENT_OPERATORS[operator].compileElementSelector(operand)); // 358 - } // 359 - // 360 - // See comments in the RegExp block above. // 361 - if (operator === '$regex' && !subSelector.$options) { // 362 - constraints.push( // 363 - ELEMENT_OPERATORS.$regex.compileElementSelector( // 364 - operand, subSelector)); // 365 - } // 366 - // 367 - // XXX support {$exists: true}, $mod, $type, $in, $elemMatch // 368 - }); // 369 - return; // 370 - } // 371 - // 372 - // OK, it's an equality thing. // 373 - constraints.push(equalityElementMatcher(subSelector)); // 374 - }); // 375 - // 376 - // It appears that the first sort field is treated differently from the // 377 - // others; we shouldn't create a key filter unless the first sort field is // 378 - // restricted, though after that point we can restrict the other sort fields // 379 - // or not as we wish. // 380 - if (_.isEmpty(constraintsByPath[self._sortSpecParts[0].path])) // 381 - return; // 382 - // 383 - self._keyFilter = function (key) { // 384 - return _.all(self._sortSpecParts, function (specPart, index) { // 385 - return _.all(constraintsByPath[specPart.path], function (f) { // 386 - return f(key[index]); // 387 - }); // 388 - }); // 389 - }; // 390 - } // 391 -}); // 392 - // 393 -// Given an array of comparators // 394 -// (functions (a,b)->(negative or positive or zero)), returns a single // 395 -// comparator which uses each comparator in order and returns the first // 396 -// non-zero value. // 397 -var composeComparators = function (comparatorArray) { // 398 - return function (a, b) { // 399 - for (var i = 0; i < comparatorArray.length; ++i) { // 400 - var compare = comparatorArray[i](a, b); // 401 - if (compare !== 0) // 402 - return compare; // 403 - } // 404 - return 0; // 405 - }; // 406 -}; // 407 - // 408 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/projection.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Knows how to compile a fields projection to a predicate function. // 1 -// @returns - Function: a closure that filters out an object according to the // 2 -// fields projection rules: // 3 -// @param obj - Object: MongoDB-styled document // 4 -// @returns - Object: a document with the fields filtered out // 5 -// according to projection rules. Doesn't retain subfields // 6 -// of passed argument. // 7 -LocalCollection._compileProjection = function (fields) { // 8 - LocalCollection._checkSupportedProjection(fields); // 9 - // 10 - var _idProjection = _.isUndefined(fields._id) ? true : fields._id; // 11 - var details = projectionDetails(fields); // 12 - // 13 - // returns transformed doc according to ruleTree // 14 - var transform = function (doc, ruleTree) { // 15 - // Special case for "sets" // 16 - if (_.isArray(doc)) // 17 - return _.map(doc, function (subdoc) { return transform(subdoc, ruleTree); }); // 18 - // 19 - var res = details.including ? {} : EJSON.clone(doc); // 20 - _.each(ruleTree, function (rule, key) { // 21 - if (!_.has(doc, key)) // 22 - return; // 23 - if (_.isObject(rule)) { // 24 - // For sub-objects/subsets we branch // 25 - if (_.isObject(doc[key])) // 26 - res[key] = transform(doc[key], rule); // 27 - // Otherwise we don't even touch this subfield // 28 - } else if (details.including) // 29 - res[key] = EJSON.clone(doc[key]); // 30 - else // 31 - delete res[key]; // 32 - }); // 33 - // 34 - return res; // 35 - }; // 36 - // 37 - return function (obj) { // 38 - var res = transform(obj, details.tree); // 39 - // 40 - if (_idProjection && _.has(obj, '_id')) // 41 - res._id = obj._id; // 42 - if (!_idProjection && _.has(res, '_id')) // 43 - delete res._id; // 44 - return res; // 45 - }; // 46 -}; // 47 - // 48 -// Traverses the keys of passed projection and constructs a tree where all // 49 -// leaves are either all True or all False // 50 -// @returns Object: // 51 -// - tree - Object - tree representation of keys involved in projection // 52 -// (exception for '_id' as it is a special case handled separately) // 53 -// - including - Boolean - "take only certain fields" type of projection // 54 -projectionDetails = function (fields) { // 55 - // Find the non-_id keys (_id is handled specially because it is included unless // 56 - // explicitly excluded). Sort the keys, so that our code to detect overlaps // 57 - // like 'foo' and 'foo.bar' can assume that 'foo' comes first. // 58 - var fieldsKeys = _.keys(fields).sort(); // 59 - // 60 - // If there are other rules other than '_id', treat '_id' differently in a // 61 - // separate case. If '_id' is the only rule, use it to understand if it is // 62 - // including/excluding projection. // 63 - if (fieldsKeys.length > 0 && !(fieldsKeys.length === 1 && fieldsKeys[0] === '_id')) // 64 - fieldsKeys = _.reject(fieldsKeys, function (key) { return key === '_id'; }); // 65 - // 66 - var including = null; // Unknown // 67 - // 68 - _.each(fieldsKeys, function (keyPath) { // 69 - var rule = !!fields[keyPath]; // 70 - if (including === null) // 71 - including = rule; // 72 - if (including !== rule) // 73 - // This error message is copies from MongoDB shell // 74 - throw MinimongoError("You cannot currently mix including and excluding fields."); // 75 - }); // 76 - // 77 - // 78 - var projectionRulesTree = pathsToTree( // 79 - fieldsKeys, // 80 - function (path) { return including; }, // 81 - function (node, path, fullPath) { // 82 - // Check passed projection fields' keys: If you have two rules such as // 83 - // 'foo.bar' and 'foo.bar.baz', then the result becomes ambiguous. If // 84 - // that happens, there is a probability you are doing something wrong, // 85 - // framework should notify you about such mistake earlier on cursor // 86 - // compilation step than later during runtime. Note, that real mongo // 87 - // doesn't do anything about it and the later rule appears in projection // 88 - // project, more priority it takes. // 89 - // // 90 - // Example, assume following in mongo shell: // 91 - // > db.coll.insert({ a: { b: 23, c: 44 } }) // 92 - // > db.coll.find({}, { 'a': 1, 'a.b': 1 }) // 93 - // { "_id" : ObjectId("520bfe456024608e8ef24af3"), "a" : { "b" : 23 } } // 94 - // > db.coll.find({}, { 'a.b': 1, 'a': 1 }) // 95 - // { "_id" : ObjectId("520bfe456024608e8ef24af3"), "a" : { "b" : 23, "c" : 44 } } // 96 - // // 97 - // Note, how second time the return set of keys is different. // 98 - // 99 - var currentPath = fullPath; // 100 - var anotherPath = path; // 101 - throw MinimongoError("both " + currentPath + " and " + anotherPath + // 102 - " found in fields option, using both of them may trigger " + // 103 - "unexpected behavior. Did you mean to use only one of them?"); // 104 - }); // 105 - // 106 - return { // 107 - tree: projectionRulesTree, // 108 - including: including // 109 - }; // 110 -}; // 111 - // 112 -// paths - Array: list of mongo style paths // 113 -// newLeafFn - Function: of form function(path) should return a scalar value to // 114 -// put into list created for that path // 115 -// conflictFn - Function: of form function(node, path, fullPath) is called // 116 -// when building a tree path for 'fullPath' node on // 117 -// 'path' was already a leaf with a value. Must return a // 118 -// conflict resolution. // 119 -// initial tree - Optional Object: starting tree. // 120 -// @returns - Object: tree represented as a set of nested objects // 121 -pathsToTree = function (paths, newLeafFn, conflictFn, tree) { // 122 - tree = tree || {}; // 123 - _.each(paths, function (keyPath) { // 124 - var treePos = tree; // 125 - var pathArr = keyPath.split('.'); // 126 - // 127 - // use _.all just for iteration with break // 128 - var success = _.all(pathArr.slice(0, -1), function (key, idx) { // 129 - if (!_.has(treePos, key)) // 130 - treePos[key] = {}; // 131 - else if (!_.isObject(treePos[key])) { // 132 - treePos[key] = conflictFn(treePos[key], // 133 - pathArr.slice(0, idx + 1).join('.'), // 134 - keyPath); // 135 - // break out of loop if we are failing for this path // 136 - if (!_.isObject(treePos[key])) // 137 - return false; // 138 - } // 139 - // 140 - treePos = treePos[key]; // 141 - return true; // 142 - }); // 143 - // 144 - if (success) { // 145 - var lastKey = _.last(pathArr); // 146 - if (!_.has(treePos, lastKey)) // 147 - treePos[lastKey] = newLeafFn(keyPath); // 148 - else // 149 - treePos[lastKey] = conflictFn(treePos[lastKey], keyPath, keyPath); // 150 - } // 151 - }); // 152 - // 153 - return tree; // 154 -}; // 155 - // 156 -LocalCollection._checkSupportedProjection = function (fields) { // 157 - if (!_.isObject(fields) || _.isArray(fields)) // 158 - throw MinimongoError("fields option must be an object"); // 159 - // 160 - _.each(fields, function (val, keyPath) { // 161 - if (_.contains(keyPath.split('.'), '$')) // 162 - throw MinimongoError("Minimongo doesn't support $ operator in projections yet."); // 163 - if (_.indexOf([1, 0, true, false], val) === -1) // 164 - throw MinimongoError("Projection values should be one of 1, 0, true, or false"); // 165 - }); // 166 -}; // 167 - // 168 - // 169 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/modify.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// XXX need a strategy for passing the binding of $ into this // 1 -// function, from the compiled selector // 2 -// // 3 -// maybe just {key.up.to.just.before.dollarsign: array_index} // 4 -// // 5 -// XXX atomicity: if one modification fails, do we roll back the whole // 6 -// change? // 7 -// // 8 -// options: // 9 -// - isInsert is set when _modify is being called to compute the document to // 10 -// insert as part of an upsert operation. We use this primarily to figure // 11 -// out when to set the fields in $setOnInsert, if present. // 12 -LocalCollection._modify = function (doc, mod, options) { // 13 - options = options || {}; // 14 - if (!isPlainObject(mod)) // 15 - throw MinimongoError("Modifier must be an object"); // 16 - var isModifier = isOperatorObject(mod); // 17 - // 18 - var newDoc; // 19 - // 20 - if (!isModifier) { // 21 - if (mod._id && !EJSON.equals(doc._id, mod._id)) // 22 - throw MinimongoError("Cannot change the _id of a document"); // 23 - // 24 - // replace the whole document // 25 - for (var k in mod) { // 26 - if (/\./.test(k)) // 27 - throw MinimongoError( // 28 - "When replacing document, field name may not contain '.'"); // 29 - } // 30 - newDoc = mod; // 31 - } else { // 32 - // apply modifiers to the doc. // 33 - newDoc = EJSON.clone(doc); // 34 - // 35 - _.each(mod, function (operand, op) { // 36 - var modFunc = MODIFIERS[op]; // 37 - // Treat $setOnInsert as $set if this is an insert. // 38 - if (options.isInsert && op === '$setOnInsert') // 39 - modFunc = MODIFIERS['$set']; // 40 - if (!modFunc) // 41 - throw MinimongoError("Invalid modifier specified " + op); // 42 - _.each(operand, function (arg, keypath) { // 43 - if (keypath === '') { // 44 - throw MinimongoError("An empty update path is not valid."); // 45 - } // 46 - // 47 - if (keypath === '_id') { // 48 - throw MinimongoError("Mod on _id not allowed"); // 49 - } // 50 - // 51 - var keyparts = keypath.split('.'); // 52 - // 53 - if (! _.all(keyparts, _.identity)) { // 54 - throw MinimongoError( // 55 - "The update path '" + keypath + // 56 - "' contains an empty field name, which is not allowed."); // 57 - } // 58 - // 59 - var noCreate = _.has(NO_CREATE_MODIFIERS, op); // 60 - var forbidArray = (op === "$rename"); // 61 - var target = findModTarget(newDoc, keyparts, { // 62 - noCreate: NO_CREATE_MODIFIERS[op], // 63 - forbidArray: (op === "$rename"), // 64 - arrayIndices: options.arrayIndices // 65 - }); // 66 - var field = keyparts.pop(); // 67 - modFunc(target, field, arg, keypath, newDoc); // 68 - }); // 69 - }); // 70 - } // 71 - // 72 - // move new document into place. // 73 - _.each(_.keys(doc), function (k) { // 74 - // Note: this used to be for (var k in doc) however, this does not // 75 - // work right in Opera. Deleting from a doc while iterating over it // 76 - // would sometimes cause opera to skip some keys. // 77 - if (k !== '_id') // 78 - delete doc[k]; // 79 - }); // 80 - _.each(newDoc, function (v, k) { // 81 - doc[k] = v; // 82 - }); // 83 -}; // 84 - // 85 -// for a.b.c.2.d.e, keyparts should be ['a', 'b', 'c', '2', 'd', 'e'], // 86 -// and then you would operate on the 'e' property of the returned // 87 -// object. // 88 -// // 89 -// if options.noCreate is falsey, creates intermediate levels of // 90 -// structure as necessary, like mkdir -p (and raises an exception if // 91 -// that would mean giving a non-numeric property to an array.) if // 92 -// options.noCreate is true, return undefined instead. // 93 -// // 94 -// may modify the last element of keyparts to signal to the caller that it needs // 95 -// to use a different value to index into the returned object (for example, // 96 -// ['a', '01'] -> ['a', 1]). // 97 -// // 98 -// if forbidArray is true, return null if the keypath goes through an array. // 99 -// // 100 -// if options.arrayIndices is set, use its first element for the (first) '$' in // 101 -// the path. // 102 -var findModTarget = function (doc, keyparts, options) { // 103 - options = options || {}; // 104 - var usedArrayIndex = false; // 105 - for (var i = 0; i < keyparts.length; i++) { // 106 - var last = (i === keyparts.length - 1); // 107 - var keypart = keyparts[i]; // 108 - var indexable = isIndexable(doc); // 109 - if (!indexable) { // 110 - if (options.noCreate) // 111 - return undefined; // 112 - var e = MinimongoError( // 113 - "cannot use the part '" + keypart + "' to traverse " + doc); // 114 - e.setPropertyError = true; // 115 - throw e; // 116 - } // 117 - if (doc instanceof Array) { // 118 - if (options.forbidArray) // 119 - return null; // 120 - if (keypart === '$') { // 121 - if (usedArrayIndex) // 122 - throw MinimongoError("Too many positional (i.e. '$') elements"); // 123 - if (!options.arrayIndices || !options.arrayIndices.length) { // 124 - throw MinimongoError("The positional operator did not find the " + // 125 - "match needed from the query"); // 126 - } // 127 - keypart = options.arrayIndices[0]; // 128 - usedArrayIndex = true; // 129 - } else if (isNumericKey(keypart)) { // 130 - keypart = parseInt(keypart); // 131 - } else { // 132 - if (options.noCreate) // 133 - return undefined; // 134 - throw MinimongoError( // 135 - "can't append to array using string field name [" // 136 - + keypart + "]"); // 137 - } // 138 - if (last) // 139 - // handle 'a.01' // 140 - keyparts[i] = keypart; // 141 - if (options.noCreate && keypart >= doc.length) // 142 - return undefined; // 143 - while (doc.length < keypart) // 144 - doc.push(null); // 145 - if (!last) { // 146 - if (doc.length === keypart) // 147 - doc.push({}); // 148 - else if (typeof doc[keypart] !== "object") // 149 - throw MinimongoError("can't modify field '" + keyparts[i + 1] + // 150 - "' of list value " + JSON.stringify(doc[keypart])); // 151 - } // 152 - } else { // 153 - if (keypart.length && keypart.substr(0, 1) === '$') // 154 - throw MinimongoError("can't set field named " + keypart); // 155 - if (!(keypart in doc)) { // 156 - if (options.noCreate) // 157 - return undefined; // 158 - if (!last) // 159 - doc[keypart] = {}; // 160 - } // 161 - } // 162 - // 163 - if (last) // 164 - return doc; // 165 - doc = doc[keypart]; // 166 - } // 167 - // 168 - // notreached // 169 -}; // 170 - // 171 -var NO_CREATE_MODIFIERS = { // 172 - $unset: true, // 173 - $pop: true, // 174 - $rename: true, // 175 - $pull: true, // 176 - $pullAll: true // 177 -}; // 178 - // 179 -var MODIFIERS = { // 180 - $inc: function (target, field, arg) { // 181 - if (typeof arg !== "number") // 182 - throw MinimongoError("Modifier $inc allowed for numbers only"); // 183 - if (field in target) { // 184 - if (typeof target[field] !== "number") // 185 - throw MinimongoError("Cannot apply $inc modifier to non-number"); // 186 - target[field] += arg; // 187 - } else { // 188 - target[field] = arg; // 189 - } // 190 - }, // 191 - $set: function (target, field, arg) { // 192 - if (!_.isObject(target)) { // not an array or an object // 193 - var e = MinimongoError("Cannot set property on non-object field"); // 194 - e.setPropertyError = true; // 195 - throw e; // 196 - } // 197 - if (target === null) { // 198 - var e = MinimongoError("Cannot set property on null"); // 199 - e.setPropertyError = true; // 200 - throw e; // 201 - } // 202 - target[field] = EJSON.clone(arg); // 203 - }, // 204 - $setOnInsert: function (target, field, arg) { // 205 - // converted to `$set` in `_modify` // 206 - }, // 207 - $unset: function (target, field, arg) { // 208 - if (target !== undefined) { // 209 - if (target instanceof Array) { // 210 - if (field in target) // 211 - target[field] = null; // 212 - } else // 213 - delete target[field]; // 214 - } // 215 - }, // 216 - $push: function (target, field, arg) { // 217 - if (target[field] === undefined) // 218 - target[field] = []; // 219 - if (!(target[field] instanceof Array)) // 220 - throw MinimongoError("Cannot apply $push modifier to non-array"); // 221 - // 222 - if (!(arg && arg.$each)) { // 223 - // Simple mode: not $each // 224 - target[field].push(EJSON.clone(arg)); // 225 - return; // 226 - } // 227 - // 228 - // Fancy mode: $each (and maybe $slice and $sort) // 229 - var toPush = arg.$each; // 230 - if (!(toPush instanceof Array)) // 231 - throw MinimongoError("$each must be an array"); // 232 - // 233 - // Parse $slice. // 234 - var slice = undefined; // 235 - if ('$slice' in arg) { // 236 - if (typeof arg.$slice !== "number") // 237 - throw MinimongoError("$slice must be a numeric value"); // 238 - // XXX should check to make sure integer // 239 - if (arg.$slice > 0) // 240 - throw MinimongoError("$slice in $push must be zero or negative"); // 241 - slice = arg.$slice; // 242 - } // 243 - // 244 - // Parse $sort. // 245 - var sortFunction = undefined; // 246 - if (arg.$sort) { // 247 - if (slice === undefined) // 248 - throw MinimongoError("$sort requires $slice to be present"); // 249 - // XXX this allows us to use a $sort whose value is an array, but that's // 250 - // actually an extension of the Node driver, so it won't work // 251 - // server-side. Could be confusing! // 252 - // XXX is it correct that we don't do geo-stuff here? // 253 - sortFunction = new Minimongo.Sorter(arg.$sort).getComparator(); // 254 - for (var i = 0; i < toPush.length; i++) { // 255 - if (LocalCollection._f._type(toPush[i]) !== 3) { // 256 - throw MinimongoError("$push like modifiers using $sort " + // 257 - "require all elements to be objects"); // 258 - } // 259 - } // 260 - } // 261 - // 262 - // Actually push. // 263 - for (var j = 0; j < toPush.length; j++) // 264 - target[field].push(EJSON.clone(toPush[j])); // 265 - // 266 - // Actually sort. // 267 - if (sortFunction) // 268 - target[field].sort(sortFunction); // 269 - // 270 - // Actually slice. // 271 - if (slice !== undefined) { // 272 - if (slice === 0) // 273 - target[field] = []; // differs from Array.slice! // 274 - else // 275 - target[field] = target[field].slice(slice); // 276 - } // 277 - }, // 278 - $pushAll: function (target, field, arg) { // 279 - if (!(typeof arg === "object" && arg instanceof Array)) // 280 - throw MinimongoError("Modifier $pushAll/pullAll allowed for arrays only"); // 281 - var x = target[field]; // 282 - if (x === undefined) // 283 - target[field] = arg; // 284 - else if (!(x instanceof Array)) // 285 - throw MinimongoError("Cannot apply $pushAll modifier to non-array"); // 286 - else { // 287 - for (var i = 0; i < arg.length; i++) // 288 - x.push(arg[i]); // 289 - } // 290 - }, // 291 - $addToSet: function (target, field, arg) { // 292 - var isEach = false; // 293 - if (typeof arg === "object") { // 294 - //check if first key is '$each' // 295 - for (var k in arg) { // 296 - if (k === "$each") // 297 - isEach = true; // 298 - break; // 299 - } // 300 - } // 301 - var values = isEach ? arg["$each"] : [arg]; // 302 - var x = target[field]; // 303 - if (x === undefined) // 304 - target[field] = values; // 305 - else if (!(x instanceof Array)) // 306 - throw MinimongoError("Cannot apply $addToSet modifier to non-array"); // 307 - else { // 308 - _.each(values, function (value) { // 309 - for (var i = 0; i < x.length; i++) // 310 - if (LocalCollection._f._equal(value, x[i])) // 311 - return; // 312 - x.push(EJSON.clone(value)); // 313 - }); // 314 - } // 315 - }, // 316 - $pop: function (target, field, arg) { // 317 - if (target === undefined) // 318 - return; // 319 - var x = target[field]; // 320 - if (x === undefined) // 321 - return; // 322 - else if (!(x instanceof Array)) // 323 - throw MinimongoError("Cannot apply $pop modifier to non-array"); // 324 - else { // 325 - if (typeof arg === 'number' && arg < 0) // 326 - x.splice(0, 1); // 327 - else // 328 - x.pop(); // 329 - } // 330 - }, // 331 - $pull: function (target, field, arg) { // 332 - if (target === undefined) // 333 - return; // 334 - var x = target[field]; // 335 - if (x === undefined) // 336 - return; // 337 - else if (!(x instanceof Array)) // 338 - throw MinimongoError("Cannot apply $pull/pullAll modifier to non-array"); // 339 - else { // 340 - var out = []; // 341 - if (typeof arg === "object" && !(arg instanceof Array)) { // 342 - // XXX would be much nicer to compile this once, rather than // 343 - // for each document we modify.. but usually we're not // 344 - // modifying that many documents, so we'll let it slide for // 345 - // now // 346 - // 347 - // XXX Minimongo.Matcher isn't up for the job, because we need // 348 - // to permit stuff like {$pull: {a: {$gt: 4}}}.. something // 349 - // like {$gt: 4} is not normally a complete selector. // 350 - // same issue as $elemMatch possibly? // 351 - var matcher = new Minimongo.Matcher(arg); // 352 - for (var i = 0; i < x.length; i++) // 353 - if (!matcher.documentMatches(x[i]).result) // 354 - out.push(x[i]); // 355 - } else { // 356 - for (var i = 0; i < x.length; i++) // 357 - if (!LocalCollection._f._equal(x[i], arg)) // 358 - out.push(x[i]); // 359 - } // 360 - target[field] = out; // 361 - } // 362 - }, // 363 - $pullAll: function (target, field, arg) { // 364 - if (!(typeof arg === "object" && arg instanceof Array)) // 365 - throw MinimongoError("Modifier $pushAll/pullAll allowed for arrays only"); // 366 - if (target === undefined) // 367 - return; // 368 - var x = target[field]; // 369 - if (x === undefined) // 370 - return; // 371 - else if (!(x instanceof Array)) // 372 - throw MinimongoError("Cannot apply $pull/pullAll modifier to non-array"); // 373 - else { // 374 - var out = []; // 375 - for (var i = 0; i < x.length; i++) { // 376 - var exclude = false; // 377 - for (var j = 0; j < arg.length; j++) { // 378 - if (LocalCollection._f._equal(x[i], arg[j])) { // 379 - exclude = true; // 380 - break; // 381 - } // 382 - } // 383 - if (!exclude) // 384 - out.push(x[i]); // 385 - } // 386 - target[field] = out; // 387 - } // 388 - }, // 389 - $rename: function (target, field, arg, keypath, doc) { // 390 - if (keypath === arg) // 391 - // no idea why mongo has this restriction.. // 392 - throw MinimongoError("$rename source must differ from target"); // 393 - if (target === null) // 394 - throw MinimongoError("$rename source field invalid"); // 395 - if (typeof arg !== "string") // 396 - throw MinimongoError("$rename target must be a string"); // 397 - if (target === undefined) // 398 - return; // 399 - var v = target[field]; // 400 - delete target[field]; // 401 - // 402 - var keyparts = arg.split('.'); // 403 - var target2 = findModTarget(doc, keyparts, {forbidArray: true}); // 404 - if (target2 === null) // 405 - throw MinimongoError("$rename target field invalid"); // 406 - var field2 = keyparts.pop(); // 407 - target2[field2] = v; // 408 - }, // 409 - $bit: function (target, field, arg) { // 410 - // XXX mongo only supports $bit on integers, and we only support // 411 - // native javascript numbers (doubles) so far, so we can't support $bit // 412 - throw MinimongoError("$bit is not supported"); // 413 - } // 414 -}; // 415 - // 416 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/diff.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// ordered: bool. // 1 -// old_results and new_results: collections of documents. // 2 -// if ordered, they are arrays. // 3 -// if unordered, they are IdMaps // 4 -LocalCollection._diffQueryChanges = function (ordered, oldResults, newResults, // 5 - observer, options) { // 6 - if (ordered) // 7 - LocalCollection._diffQueryOrderedChanges( // 8 - oldResults, newResults, observer, options); // 9 - else // 10 - LocalCollection._diffQueryUnorderedChanges( // 11 - oldResults, newResults, observer, options); // 12 -}; // 13 - // 14 -LocalCollection._diffQueryUnorderedChanges = function (oldResults, newResults, // 15 - observer, options) { // 16 - options = options || {}; // 17 - var projectionFn = options.projectionFn || EJSON.clone; // 18 - // 19 - if (observer.movedBefore) { // 20 - throw new Error("_diffQueryUnordered called with a movedBefore observer!"); // 21 - } // 22 - // 23 - newResults.forEach(function (newDoc, id) { // 24 - var oldDoc = oldResults.get(id); // 25 - if (oldDoc) { // 26 - if (observer.changed && !EJSON.equals(oldDoc, newDoc)) { // 27 - var projectedNew = projectionFn(newDoc); // 28 - var projectedOld = projectionFn(oldDoc); // 29 - var changedFields = // 30 - LocalCollection._makeChangedFields(projectedNew, projectedOld); // 31 - if (! _.isEmpty(changedFields)) { // 32 - observer.changed(id, changedFields); // 33 - } // 34 - } // 35 - } else if (observer.added) { // 36 - var fields = projectionFn(newDoc); // 37 - delete fields._id; // 38 - observer.added(newDoc._id, fields); // 39 - } // 40 - }); // 41 - // 42 - if (observer.removed) { // 43 - oldResults.forEach(function (oldDoc, id) { // 44 - if (!newResults.has(id)) // 45 - observer.removed(id); // 46 - }); // 47 - } // 48 -}; // 49 - // 50 - // 51 -LocalCollection._diffQueryOrderedChanges = function (old_results, new_results, // 52 - observer, options) { // 53 - options = options || {}; // 54 - var projectionFn = options.projectionFn || EJSON.clone; // 55 - // 56 - var new_presence_of_id = {}; // 57 - _.each(new_results, function (doc) { // 58 - if (new_presence_of_id[doc._id]) // 59 - Meteor._debug("Duplicate _id in new_results"); // 60 - new_presence_of_id[doc._id] = true; // 61 - }); // 62 - // 63 - var old_index_of_id = {}; // 64 - _.each(old_results, function (doc, i) { // 65 - if (doc._id in old_index_of_id) // 66 - Meteor._debug("Duplicate _id in old_results"); // 67 - old_index_of_id[doc._id] = i; // 68 - }); // 69 - // 70 - // ALGORITHM: // 71 - // // 72 - // To determine which docs should be considered "moved" (and which // 73 - // merely change position because of other docs moving) we run // 74 - // a "longest common subsequence" (LCS) algorithm. The LCS of the // 75 - // old doc IDs and the new doc IDs gives the docs that should NOT be // 76 - // considered moved. // 77 - // 78 - // To actually call the appropriate callbacks to get from the old state to the // 79 - // new state: // 80 - // 81 - // First, we call removed() on all the items that only appear in the old // 82 - // state. // 83 - // 84 - // Then, once we have the items that should not move, we walk through the new // 85 - // results array group-by-group, where a "group" is a set of items that have // 86 - // moved, anchored on the end by an item that should not move. One by one, we // 87 - // move each of those elements into place "before" the anchoring end-of-group // 88 - // item, and fire changed events on them if necessary. Then we fire a changed // 89 - // event on the anchor, and move on to the next group. There is always at // 90 - // least one group; the last group is anchored by a virtual "null" id at the // 91 - // end. // 92 - // 93 - // Asymptotically: O(N k) where k is number of ops, or potentially // 94 - // O(N log N) if inner loop of LCS were made to be binary search. // 95 - // 96 - // 97 - //////// LCS (longest common sequence, with respect to _id) // 98 - // (see Wikipedia article on Longest Increasing Subsequence, // 99 - // where the LIS is taken of the sequence of old indices of the // 100 - // docs in new_results) // 101 - // // 102 - // unmoved: the output of the algorithm; members of the LCS, // 103 - // in the form of indices into new_results // 104 - var unmoved = []; // 105 - // max_seq_len: length of LCS found so far // 106 - var max_seq_len = 0; // 107 - // seq_ends[i]: the index into new_results of the last doc in a // 108 - // common subsequence of length of i+1 <= max_seq_len // 109 - var N = new_results.length; // 110 - var seq_ends = new Array(N); // 111 - // ptrs: the common subsequence ending with new_results[n] extends // 112 - // a common subsequence ending with new_results[ptr[n]], unless // 113 - // ptr[n] is -1. // 114 - var ptrs = new Array(N); // 115 - // virtual sequence of old indices of new results // 116 - var old_idx_seq = function(i_new) { // 117 - return old_index_of_id[new_results[i_new]._id]; // 118 - }; // 119 - // for each item in new_results, use it to extend a common subsequence // 120 - // of length j <= max_seq_len // 121 - for(var i=0; i 0) { // 130 - if (old_idx_seq(seq_ends[j-1]) < old_idx_seq(i)) // 131 - break; // 132 - j--; // 133 - } // 134 - // 135 - ptrs[i] = (j === 0 ? -1 : seq_ends[j-1]); // 136 - seq_ends[j] = i; // 137 - if (j+1 > max_seq_len) // 138 - max_seq_len = j+1; // 139 - } // 140 - } // 141 - // 142 - // pull out the LCS/LIS into unmoved // 143 - var idx = (max_seq_len === 0 ? -1 : seq_ends[max_seq_len-1]); // 144 - while (idx >= 0) { // 145 - unmoved.push(idx); // 146 - idx = ptrs[idx]; // 147 - } // 148 - // the unmoved item list is built backwards, so fix that // 149 - unmoved.reverse(); // 150 - // 151 - // the last group is always anchored by the end of the result list, which is // 152 - // an id of "null" // 153 - unmoved.push(new_results.length); // 154 - // 155 - _.each(old_results, function (doc) { // 156 - if (!new_presence_of_id[doc._id]) // 157 - observer.removed && observer.removed(doc._id); // 158 - }); // 159 - // for each group of things in the new_results that is anchored by an unmoved // 160 - // element, iterate through the things before it. // 161 - var startOfGroup = 0; // 162 - _.each(unmoved, function (endOfGroup) { // 163 - var groupId = new_results[endOfGroup] ? new_results[endOfGroup]._id : null; // 164 - var oldDoc, newDoc, fields, projectedNew, projectedOld; // 165 - for (var i = startOfGroup; i < endOfGroup; i++) { // 166 - newDoc = new_results[i]; // 167 - if (!_.has(old_index_of_id, newDoc._id)) { // 168 - fields = projectionFn(newDoc); // 169 - delete fields._id; // 170 - observer.addedBefore && observer.addedBefore(newDoc._id, fields, groupId); // 171 - observer.added && observer.added(newDoc._id, fields); // 172 - } else { // 173 - // moved // 174 - oldDoc = old_results[old_index_of_id[newDoc._id]]; // 175 - projectedNew = projectionFn(newDoc); // 176 - projectedOld = projectionFn(oldDoc); // 177 - fields = LocalCollection._makeChangedFields(projectedNew, projectedOld); // 178 - if (!_.isEmpty(fields)) { // 179 - observer.changed && observer.changed(newDoc._id, fields); // 180 - } // 181 - observer.movedBefore && observer.movedBefore(newDoc._id, groupId); // 182 - } // 183 - } // 184 - if (groupId) { // 185 - newDoc = new_results[endOfGroup]; // 186 - oldDoc = old_results[old_index_of_id[newDoc._id]]; // 187 - projectedNew = projectionFn(newDoc); // 188 - projectedOld = projectionFn(oldDoc); // 189 - fields = LocalCollection._makeChangedFields(projectedNew, projectedOld); // 190 - if (!_.isEmpty(fields)) { // 191 - observer.changed && observer.changed(newDoc._id, fields); // 192 - } // 193 - } // 194 - startOfGroup = endOfGroup+1; // 195 - }); // 196 - // 197 - // 198 -}; // 199 - // 200 - // 201 -// General helper for diff-ing two objects. // 202 -// callbacks is an object like so: // 203 -// { leftOnly: function (key, leftValue) {...}, // 204 -// rightOnly: function (key, rightValue) {...}, // 205 -// both: function (key, leftValue, rightValue) {...}, // 206 -// } // 207 -LocalCollection._diffObjects = function (left, right, callbacks) { // 208 - _.each(left, function (leftValue, key) { // 209 - if (_.has(right, key)) // 210 - callbacks.both && callbacks.both(key, leftValue, right[key]); // 211 - else // 212 - callbacks.leftOnly && callbacks.leftOnly(key, leftValue); // 213 - }); // 214 - if (callbacks.rightOnly) { // 215 - _.each(right, function(rightValue, key) { // 216 - if (!_.has(left, key)) // 217 - callbacks.rightOnly(key, rightValue); // 218 - }); // 219 - } // 220 -}; // 221 - // 222 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/id_map.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -LocalCollection._IdMap = function () { // 1 - var self = this; // 2 - IdMap.call(self, LocalCollection._idStringify, LocalCollection._idParse); // 3 -}; // 4 - // 5 -Meteor._inherits(LocalCollection._IdMap, IdMap); // 6 - // 7 - // 8 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/observe.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// XXX maybe move these into another ObserveHelpers package or something // 1 - // 2 -// _CachingChangeObserver is an object which receives observeChanges callbacks // 3 -// and keeps a cache of the current cursor state up to date in self.docs. Users // 4 -// of this class should read the docs field but not modify it. You should pass // 5 -// the "applyChange" field as the callbacks to the underlying observeChanges // 6 -// call. Optionally, you can specify your own observeChanges callbacks which are // 7 -// invoked immediately before the docs field is updated; this object is made // 8 -// available as `this` to those callbacks. // 9 -LocalCollection._CachingChangeObserver = function (options) { // 10 - var self = this; // 11 - options = options || {}; // 12 - // 13 - var orderedFromCallbacks = options.callbacks && // 14 - LocalCollection._observeChangesCallbacksAreOrdered(options.callbacks); // 15 - if (_.has(options, 'ordered')) { // 16 - self.ordered = options.ordered; // 17 - if (options.callbacks && options.ordered !== orderedFromCallbacks) // 18 - throw Error("ordered option doesn't match callbacks"); // 19 - } else if (options.callbacks) { // 20 - self.ordered = orderedFromCallbacks; // 21 - } else { // 22 - throw Error("must provide ordered or callbacks"); // 23 - } // 24 - var callbacks = options.callbacks || {}; // 25 - // 26 - if (self.ordered) { // 27 - self.docs = new OrderedDict(LocalCollection._idStringify); // 28 - self.applyChange = { // 29 - addedBefore: function (id, fields, before) { // 30 - var doc = EJSON.clone(fields); // 31 - doc._id = id; // 32 - callbacks.addedBefore && callbacks.addedBefore.call( // 33 - self, id, fields, before); // 34 - // This line triggers if we provide added with movedBefore. // 35 - callbacks.added && callbacks.added.call(self, id, fields); // 36 - // XXX could `before` be a falsy ID? Technically // 37 - // idStringify seems to allow for them -- though // 38 - // OrderedDict won't call stringify on a falsy arg. // 39 - self.docs.putBefore(id, doc, before || null); // 40 - }, // 41 - movedBefore: function (id, before) { // 42 - var doc = self.docs.get(id); // 43 - callbacks.movedBefore && callbacks.movedBefore.call(self, id, before); // 44 - self.docs.moveBefore(id, before || null); // 45 - } // 46 - }; // 47 - } else { // 48 - self.docs = new LocalCollection._IdMap; // 49 - self.applyChange = { // 50 - added: function (id, fields) { // 51 - var doc = EJSON.clone(fields); // 52 - callbacks.added && callbacks.added.call(self, id, fields); // 53 - doc._id = id; // 54 - self.docs.set(id, doc); // 55 - } // 56 - }; // 57 - } // 58 - // 59 - // The methods in _IdMap and OrderedDict used by these callbacks are // 60 - // identical. // 61 - self.applyChange.changed = function (id, fields) { // 62 - var doc = self.docs.get(id); // 63 - if (!doc) // 64 - throw new Error("Unknown id for changed: " + id); // 65 - callbacks.changed && callbacks.changed.call( // 66 - self, id, EJSON.clone(fields)); // 67 - LocalCollection._applyChanges(doc, fields); // 68 - }; // 69 - self.applyChange.removed = function (id) { // 70 - callbacks.removed && callbacks.removed.call(self, id); // 71 - self.docs.remove(id); // 72 - }; // 73 -}; // 74 - // 75 -LocalCollection._observeFromObserveChanges = function (cursor, observeCallbacks) { // 76 - var transform = cursor.getTransform() || function (doc) {return doc;}; // 77 - var suppressed = !!observeCallbacks._suppress_initial; // 78 - // 79 - var observeChangesCallbacks; // 80 - if (LocalCollection._observeCallbacksAreOrdered(observeCallbacks)) { // 81 - // The "_no_indices" option sets all index arguments to -1 and skips the // 82 - // linear scans required to generate them. This lets observers that don't // 83 - // need absolute indices benefit from the other features of this API -- // 84 - // relative order, transforms, and applyChanges -- without the speed hit. // 85 - var indices = !observeCallbacks._no_indices; // 86 - observeChangesCallbacks = { // 87 - addedBefore: function (id, fields, before) { // 88 - var self = this; // 89 - if (suppressed || !(observeCallbacks.addedAt || observeCallbacks.added)) // 90 - return; // 91 - var doc = transform(_.extend(fields, {_id: id})); // 92 - if (observeCallbacks.addedAt) { // 93 - var index = indices // 94 - ? (before ? self.docs.indexOf(before) : self.docs.size()) : -1; // 95 - observeCallbacks.addedAt(doc, index, before); // 96 - } else { // 97 - observeCallbacks.added(doc); // 98 - } // 99 - }, // 100 - changed: function (id, fields) { // 101 - var self = this; // 102 - if (!(observeCallbacks.changedAt || observeCallbacks.changed)) // 103 - return; // 104 - var doc = EJSON.clone(self.docs.get(id)); // 105 - if (!doc) // 106 - throw new Error("Unknown id for changed: " + id); // 107 - var oldDoc = transform(EJSON.clone(doc)); // 108 - LocalCollection._applyChanges(doc, fields); // 109 - doc = transform(doc); // 110 - if (observeCallbacks.changedAt) { // 111 - var index = indices ? self.docs.indexOf(id) : -1; // 112 - observeCallbacks.changedAt(doc, oldDoc, index); // 113 - } else { // 114 - observeCallbacks.changed(doc, oldDoc); // 115 - } // 116 - }, // 117 - movedBefore: function (id, before) { // 118 - var self = this; // 119 - if (!observeCallbacks.movedTo) // 120 - return; // 121 - var from = indices ? self.docs.indexOf(id) : -1; // 122 - // 123 - var to = indices // 124 - ? (before ? self.docs.indexOf(before) : self.docs.size()) : -1; // 125 - // When not moving backwards, adjust for the fact that removing the // 126 - // document slides everything back one slot. // 127 - if (to > from) // 128 - --to; // 129 - observeCallbacks.movedTo(transform(EJSON.clone(self.docs.get(id))), // 130 - from, to, before || null); // 131 - }, // 132 - removed: function (id) { // 133 - var self = this; // 134 - if (!(observeCallbacks.removedAt || observeCallbacks.removed)) // 135 - return; // 136 - // technically maybe there should be an EJSON.clone here, but it's about // 137 - // to be removed from self.docs! // 138 - var doc = transform(self.docs.get(id)); // 139 - if (observeCallbacks.removedAt) { // 140 - var index = indices ? self.docs.indexOf(id) : -1; // 141 - observeCallbacks.removedAt(doc, index); // 142 - } else { // 143 - observeCallbacks.removed(doc); // 144 - } // 145 - } // 146 - }; // 147 - } else { // 148 - observeChangesCallbacks = { // 149 - added: function (id, fields) { // 150 - if (!suppressed && observeCallbacks.added) { // 151 - var doc = _.extend(fields, {_id: id}); // 152 - observeCallbacks.added(transform(doc)); // 153 - } // 154 - }, // 155 - changed: function (id, fields) { // 156 - var self = this; // 157 - if (observeCallbacks.changed) { // 158 - var oldDoc = self.docs.get(id); // 159 - var doc = EJSON.clone(oldDoc); // 160 - LocalCollection._applyChanges(doc, fields); // 161 - observeCallbacks.changed(transform(doc), // 162 - transform(EJSON.clone(oldDoc))); // 163 - } // 164 - }, // 165 - removed: function (id) { // 166 - var self = this; // 167 - if (observeCallbacks.removed) { // 168 - observeCallbacks.removed(transform(self.docs.get(id))); // 169 - } // 170 - } // 171 - }; // 172 - } // 173 - // 174 - var changeObserver = new LocalCollection._CachingChangeObserver( // 175 - {callbacks: observeChangesCallbacks}); // 176 - var handle = cursor.observeChanges(changeObserver.applyChange); // 177 - suppressed = false; // 178 - // 179 - return handle; // 180 -}; // 181 - // 182 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/objectid.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -LocalCollection._looksLikeObjectID = function (str) { // 1 - return str.length === 24 && str.match(/^[0-9a-f]*$/); // 2 -}; // 3 - // 4 -LocalCollection._ObjectID = function (hexString) { // 5 - //random-based impl of Mongo ObjectID // 6 - var self = this; // 7 - if (hexString) { // 8 - hexString = hexString.toLowerCase(); // 9 - if (!LocalCollection._looksLikeObjectID(hexString)) { // 10 - throw new Error("Invalid hexadecimal string for creating an ObjectID"); // 11 - } // 12 - // meant to work with _.isEqual(), which relies on structural equality // 13 - self._str = hexString; // 14 - } else { // 15 - self._str = Random.hexString(24); // 16 - } // 17 -}; // 18 - // 19 -LocalCollection._ObjectID.prototype.toString = function () { // 20 - var self = this; // 21 - return "ObjectID(\"" + self._str + "\")"; // 22 -}; // 23 - // 24 -LocalCollection._ObjectID.prototype.equals = function (other) { // 25 - var self = this; // 26 - return other instanceof LocalCollection._ObjectID && // 27 - self.valueOf() === other.valueOf(); // 28 -}; // 29 - // 30 -LocalCollection._ObjectID.prototype.clone = function () { // 31 - var self = this; // 32 - return new LocalCollection._ObjectID(self._str); // 33 -}; // 34 - // 35 -LocalCollection._ObjectID.prototype.typeName = function() { // 36 - return "oid"; // 37 -}; // 38 - // 39 -LocalCollection._ObjectID.prototype.getTimestamp = function() { // 40 - var self = this; // 41 - return parseInt(self._str.substr(0, 8), 16); // 42 -}; // 43 - // 44 -LocalCollection._ObjectID.prototype.valueOf = // 45 - LocalCollection._ObjectID.prototype.toJSONValue = // 46 - LocalCollection._ObjectID.prototype.toHexString = // 47 - function () { return this._str; }; // 48 - // 49 -// Is this selector just shorthand for lookup by _id? // 50 -LocalCollection._selectorIsId = function (selector) { // 51 - return (typeof selector === "string") || // 52 - (typeof selector === "number") || // 53 - selector instanceof LocalCollection._ObjectID; // 54 -}; // 55 - // 56 -// Is the selector just lookup by _id (shorthand or not)? // 57 -LocalCollection._selectorIsIdPerhapsAsObject = function (selector) { // 58 - return LocalCollection._selectorIsId(selector) || // 59 - (selector && typeof selector === "object" && // 60 - selector._id && LocalCollection._selectorIsId(selector._id) && // 61 - _.size(selector) === 1); // 62 -}; // 63 - // 64 -// If this is a selector which explicitly constrains the match by ID to a finite // 65 -// number of documents, returns a list of their IDs. Otherwise returns // 66 -// null. Note that the selector may have other restrictions so it may not even // 67 -// match those document! We care about $in and $and since those are generated // 68 -// access-controlled update and remove. // 69 -LocalCollection._idsMatchedBySelector = function (selector) { // 70 - // Is the selector just an ID? // 71 - if (LocalCollection._selectorIsId(selector)) // 72 - return [selector]; // 73 - if (!selector) // 74 - return null; // 75 - // 76 - // Do we have an _id clause? // 77 - if (_.has(selector, '_id')) { // 78 - // Is the _id clause just an ID? // 79 - if (LocalCollection._selectorIsId(selector._id)) // 80 - return [selector._id]; // 81 - // Is the _id clause {_id: {$in: ["x", "y", "z"]}}? // 82 - if (selector._id && selector._id.$in // 83 - && _.isArray(selector._id.$in) // 84 - && !_.isEmpty(selector._id.$in) // 85 - && _.all(selector._id.$in, LocalCollection._selectorIsId)) { // 86 - return selector._id.$in; // 87 - } // 88 - return null; // 89 - } // 90 - // 91 - // If this is a top-level $and, and any of the clauses constrain their // 92 - // documents, then the whole selector is constrained by any one clause's // 93 - // constraint. (Well, by their intersection, but that seems unlikely.) // 94 - if (selector.$and && _.isArray(selector.$and)) { // 95 - for (var i = 0; i < selector.$and.length; ++i) { // 96 - var subIds = LocalCollection._idsMatchedBySelector(selector.$and[i]); // 97 - if (subIds) // 98 - return subIds; // 99 - } // 100 - } // 101 - // 102 - return null; // 103 -}; // 104 - // 105 -EJSON.addType("oid", function (str) { // 106 - return new LocalCollection._ObjectID(str); // 107 -}); // 108 - // 109 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/selector_projection.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Knows how to combine a mongo selector and a fields projection to a new fields // 1 -// projection taking into account active fields from the passed selector. // 2 -// @returns Object - projection object (same as fields option of mongo cursor) // 3 -Minimongo.Matcher.prototype.combineIntoProjection = function (projection) { // 4 - var self = this; // 5 - var selectorPaths = Minimongo._pathsElidingNumericKeys(self._getPaths()); // 6 - // 7 - // Special case for $where operator in the selector - projection should depend // 8 - // on all fields of the document. getSelectorPaths returns a list of paths // 9 - // selector depends on. If one of the paths is '' (empty string) representing // 10 - // the root or the whole document, complete projection should be returned. // 11 - if (_.contains(selectorPaths, '')) // 12 - return {}; // 13 - // 14 - return combineImportantPathsIntoProjection(selectorPaths, projection); // 15 -}; // 16 - // 17 -Minimongo._pathsElidingNumericKeys = function (paths) { // 18 - var self = this; // 19 - return _.map(paths, function (path) { // 20 - return _.reject(path.split('.'), isNumericKey).join('.'); // 21 - }); // 22 -}; // 23 - // 24 -combineImportantPathsIntoProjection = function (paths, projection) { // 25 - var prjDetails = projectionDetails(projection); // 26 - var tree = prjDetails.tree; // 27 - var mergedProjection = {}; // 28 - // 29 - // merge the paths to include // 30 - tree = pathsToTree(paths, // 31 - function (path) { return true; }, // 32 - function (node, path, fullPath) { return true; }, // 33 - tree); // 34 - mergedProjection = treeToPaths(tree); // 35 - if (prjDetails.including) { // 36 - // both selector and projection are pointing on fields to include // 37 - // so we can just return the merged tree // 38 - return mergedProjection; // 39 - } else { // 40 - // selector is pointing at fields to include // 41 - // projection is pointing at fields to exclude // 42 - // make sure we don't exclude important paths // 43 - var mergedExclProjection = {}; // 44 - _.each(mergedProjection, function (incl, path) { // 45 - if (!incl) // 46 - mergedExclProjection[path] = false; // 47 - }); // 48 - // 49 - return mergedExclProjection; // 50 - } // 51 -}; // 52 - // 53 -// Returns a set of key paths similar to // 54 -// { 'foo.bar': 1, 'a.b.c': 1 } // 55 -var treeToPaths = function (tree, prefix) { // 56 - prefix = prefix || ''; // 57 - var result = {}; // 58 - // 59 - _.each(tree, function (val, key) { // 60 - if (_.isObject(val)) // 61 - _.extend(result, treeToPaths(val, prefix + key + '.')); // 62 - else // 63 - result[prefix + key] = val; // 64 - }); // 65 - // 66 - return result; // 67 -}; // 68 - // 69 - // 70 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/selector_modifier.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// Returns true if the modifier applied to some document may change the result // 1 -// of matching the document by selector // 2 -// The modifier is always in a form of Object: // 3 -// - $set // 4 -// - 'a.b.22.z': value // 5 -// - 'foo.bar': 42 // 6 -// - $unset // 7 -// - 'abc.d': 1 // 8 -Minimongo.Matcher.prototype.affectedByModifier = function (modifier) { // 9 - var self = this; // 10 - // safe check for $set/$unset being objects // 11 - modifier = _.extend({ $set: {}, $unset: {} }, modifier); // 12 - var modifiedPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset)); // 13 - var meaningfulPaths = self._getPaths(); // 14 - // 15 - return _.any(modifiedPaths, function (path) { // 16 - var mod = path.split('.'); // 17 - return _.any(meaningfulPaths, function (meaningfulPath) { // 18 - var sel = meaningfulPath.split('.'); // 19 - var i = 0, j = 0; // 20 - // 21 - while (i < sel.length && j < mod.length) { // 22 - if (isNumericKey(sel[i]) && isNumericKey(mod[j])) { // 23 - // foo.4.bar selector affected by foo.4 modifier // 24 - // foo.3.bar selector unaffected by foo.4 modifier // 25 - if (sel[i] === mod[j]) // 26 - i++, j++; // 27 - else // 28 - return false; // 29 - } else if (isNumericKey(sel[i])) { // 30 - // foo.4.bar selector unaffected by foo.bar modifier // 31 - return false; // 32 - } else if (isNumericKey(mod[j])) { // 33 - j++; // 34 - } else if (sel[i] === mod[j]) // 35 - i++, j++; // 36 - else // 37 - return false; // 38 - } // 39 - // 40 - // One is a prefix of another, taking numeric fields into account // 41 - return true; // 42 - }); // 43 - }); // 44 -}; // 45 - // 46 -// Minimongo.Sorter gets a similar method, which delegates to a Matcher it made // 47 -// for this exact purpose. // 48 -Minimongo.Sorter.prototype.affectedByModifier = function (modifier) { // 49 - var self = this; // 50 - return self._selectorForAffectedByModifier.affectedByModifier(modifier); // 51 -}; // 52 - // 53 -// @param modifier - Object: MongoDB-styled modifier with `$set`s and `$unsets` // 54 -// only. (assumed to come from oplog) // 55 -// @returns - Boolean: if after applying the modifier, selector can start // 56 -// accepting the modified value. // 57 -// NOTE: assumes that document affected by modifier didn't match this Matcher // 58 -// before, so if modifier can't convince selector in a positive change it would // 59 -// stay 'false'. // 60 -// Currently doesn't support $-operators and numeric indices precisely. // 61 -Minimongo.Matcher.prototype.canBecomeTrueByModifier = function (modifier) { // 62 - var self = this; // 63 - if (!this.affectedByModifier(modifier)) // 64 - return false; // 65 - // 66 - modifier = _.extend({$set:{}, $unset:{}}, modifier); // 67 - var modifierPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset)); // 68 - // 69 - if (!self.isSimple()) // 70 - return true; // 71 - // 72 - if (_.any(self._getPaths(), pathHasNumericKeys) || // 73 - _.any(modifierPaths, pathHasNumericKeys)) // 74 - return true; // 75 - // 76 - // check if there is a $set or $unset that indicates something is an // 77 - // object rather than a scalar in the actual object where we saw $-operator // 78 - // NOTE: it is correct since we allow only scalars in $-operators // 79 - // Example: for selector {'a.b': {$gt: 5}} the modifier {'a.b.c':7} would // 80 - // definitely set the result to false as 'a.b' appears to be an object. // 81 - var expectedScalarIsObject = _.any(self._selector, function (sel, path) { // 82 - if (! isOperatorObject(sel)) // 83 - return false; // 84 - return _.any(modifierPaths, function (modifierPath) { // 85 - return startsWith(modifierPath, path + '.'); // 86 - }); // 87 - }); // 88 - // 89 - if (expectedScalarIsObject) // 90 - return false; // 91 - // 92 - // See if we can apply the modifier on the ideally matching object. If it // 93 - // still matches the selector, then the modifier could have turned the real // 94 - // object in the database into something matching. // 95 - var matchingDocument = EJSON.clone(self.matchingDocument()); // 96 - // 97 - // The selector is too complex, anything can happen. // 98 - if (matchingDocument === null) // 99 - return true; // 100 - // 101 - try { // 102 - LocalCollection._modify(matchingDocument, modifier); // 103 - } catch (e) { // 104 - // Couldn't set a property on a field which is a scalar or null in the // 105 - // selector. // 106 - // Example: // 107 - // real document: { 'a.b': 3 } // 108 - // selector: { 'a': 12 } // 109 - // converted selector (ideal document): { 'a': 12 } // 110 - // modifier: { $set: { 'a.b': 4 } } // 111 - // We don't know what real document was like but from the error raised by // 112 - // $set on a scalar field we can reason that the structure of real document // 113 - // is completely different. // 114 - if (e.name === "MinimongoError" && e.setPropertyError) // 115 - return false; // 116 - throw e; // 117 - } // 118 - // 119 - return self.documentMatches(matchingDocument).result; // 120 -}; // 121 - // 122 -// Returns an object that would match the selector if possible or null if the // 123 -// selector is too complex for us to analyze // 124 -// { 'a.b': { ans: 42 }, 'foo.bar': null, 'foo.baz': "something" } // 125 -// => { a: { b: { ans: 42 } }, foo: { bar: null, baz: "something" } } // 126 -Minimongo.Matcher.prototype.matchingDocument = function () { // 127 - var self = this; // 128 - // 129 - // check if it was computed before // 130 - if (self._matchingDocument !== undefined) // 131 - return self._matchingDocument; // 132 - // 133 - // If the analysis of this selector is too hard for our implementation // 134 - // fallback to "YES" // 135 - var fallback = false; // 136 - self._matchingDocument = pathsToTree(self._getPaths(), // 137 - function (path) { // 138 - var valueSelector = self._selector[path]; // 139 - if (isOperatorObject(valueSelector)) { // 140 - // if there is a strict equality, there is a good // 141 - // chance we can use one of those as "matching" // 142 - // dummy value // 143 - if (valueSelector.$in) { // 144 - var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); // 145 - // 146 - // Return anything from $in that matches the whole selector for this // 147 - // path. If nothing matches, returns `undefined` as nothing can make // 148 - // this selector into `true`. // 149 - return _.find(valueSelector.$in, function (x) { // 150 - return matcher.documentMatches({ placeholder: x }).result; // 151 - }); // 152 - } else if (onlyContainsKeys(valueSelector, ['$gt', '$gte', '$lt', '$lte'])) { // 153 - var lowerBound = -Infinity, upperBound = Infinity; // 154 - _.each(['$lte', '$lt'], function (op) { // 155 - if (_.has(valueSelector, op) && valueSelector[op] < upperBound) // 156 - upperBound = valueSelector[op]; // 157 - }); // 158 - _.each(['$gte', '$gt'], function (op) { // 159 - if (_.has(valueSelector, op) && valueSelector[op] > lowerBound) // 160 - lowerBound = valueSelector[op]; // 161 - }); // 162 - // 163 - var middle = (lowerBound + upperBound) / 2; // 164 - var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); // 165 - if (!matcher.documentMatches({ placeholder: middle }).result && // 166 - (middle === lowerBound || middle === upperBound)) // 167 - fallback = true; // 168 - // 169 - return middle; // 170 - } else if (onlyContainsKeys(valueSelector, ['$nin',' $ne'])) { // 171 - // Since self._isSimple makes sure $nin and $ne are not combined with // 172 - // objects or arrays, we can confidently return an empty object as it // 173 - // never matches any scalar. // 174 - return {}; // 175 - } else { // 176 - fallback = true; // 177 - } // 178 - } // 179 - return self._selector[path]; // 180 - }, // 181 - _.identity /*conflict resolution is no resolution*/); // 182 - // 183 - if (fallback) // 184 - self._matchingDocument = null; // 185 - // 186 - return self._matchingDocument; // 187 -}; // 188 - // 189 -var getPaths = function (sel) { // 190 - return _.keys(new Minimongo.Matcher(sel)._paths); // 191 - return _.chain(sel).map(function (v, k) { // 192 - // we don't know how to handle $where because it can be anything // 193 - if (k === "$where") // 194 - return ''; // matches everything // 195 - // we branch from $or/$and/$nor operator // 196 - if (_.contains(['$or', '$and', '$nor'], k)) // 197 - return _.map(v, getPaths); // 198 - // the value is a literal or some comparison operator // 199 - return k; // 200 - }).flatten().uniq().value(); // 201 -}; // 202 - // 203 -// A helper to ensure object has only certain keys // 204 -var onlyContainsKeys = function (obj, keys) { // 205 - return _.all(obj, function (v, k) { // 206 - return _.contains(keys, k); // 207 - }); // 208 -}; // 209 - // 210 -var pathHasNumericKeys = function (path) { // 211 - return _.any(path.split('.'), isNumericKey); // 212 -} // 213 - // 214 -// XXX from Underscore.String (http://epeli.github.com/underscore.string/) // 215 -var startsWith = function(str, starts) { // 216 - return str.length >= starts.length && // 217 - str.substring(0, starts.length) === starts; // 218 -}; // 219 - // 220 - // 221 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/minimongo/sorter_projection.js // -// // -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -Minimongo.Sorter.prototype.combineIntoProjection = function (projection) { // 1 - var self = this; // 2 - var specPaths = Minimongo._pathsElidingNumericKeys(self._getPaths()); // 3 - return combineImportantPathsIntoProjection(specPaths, projection); // 4 -}; // 5 - // 6 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.minimongo = { - LocalCollection: LocalCollection, - Minimongo: Minimongo, - MinimongoTest: MinimongoTest -}; - -})(); - -//# sourceMappingURL=minimongo.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/minimongo.js.map b/web-app/.meteor/local/build/programs/server/packages/minimongo.js.map deleted file mode 100644 index f8922c4..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/minimongo.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["minimongo/minimongo.js","minimongo/wrap_transform.js","minimongo/helpers.js","minimongo/selector.js","minimongo/sort.js","minimongo/projection.js","minimongo/modify.js","minimongo/diff.js","minimongo/id_map.js","minimongo/observe.js","minimongo/objectid.js","minimongo/selector_projection.js","minimongo/selector_modifier.js","minimongo/sorter_projection.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,+D;;AAEA,2E;;AAEA,mE;AACA,sF;;AAEA,mD;;AAEA,mC;AACA,kB;AACA,mB;AACA,yC;AACA,0C;;AAEA,sD;;AAEA,+C;;AAEA,oC;AACA,4E;AACA,uE;AACA,kC;AACA,+D;AACA,0C;AACA,8C;AACA,oB;;AAEA,iF;AACA,2D;AACA,8B;;AAEA,qE;AACA,sB;AACA,E;;AAEA,e;;AAEA,yC;AACA,0D;AACA,mB;;AAEA,8D;AACA,8C;AACA,4B;AACA,sB;AACA,Q;AACA,uB;AACA,K;AACA,E;;AAEA,qC;AACA,6B;AACA,4B;AACA,W;AACA,E;;;AAGA,kD;AACA,kC;AACA,oB;AACA,oC;AACA,2B;AACA,mE;AACA,wB;AACA,E;AACA,sE;AACA,W;AACA,E;AACA,iE;AACA,iE;AACA,Q;AACA,E;AACA,6D;AACA,oC;AACA,Y;AACA,+D;AACA,oE;AACA,sE;AACA,0C;AACA,6B;AACA,kB;;AAEA,6D;AACA,E;;AAEA,8D;;AAEA,mE;AACA,kB;AACA,6B;;AAEA,+B;AACA,qB;;AAEA,gD;AACA,0B;AACA,gC;AACA,mD;AACA,U;AACA,iC;AACA,mD;AACA,qD;AACA,4D;AACA,oE;AACA,K;AACA,G;AACA,2B;AACA,6B;AACA,+B;;AAEA,6E;;AAEA,qE;;AAEA,kE;AACA,qC;AACA,+E;AACA,E;;AAEA,2E;AACA,2E;AACA,uD;AACA,wB;AACA,uD;AACA,E;;AAEA,kE;AACA,6B;AACA,kB;;AAEA,oE;AACA,uE;AACA,8D;AACA,qE;AACA,sE;AACA,qE;AACA,uE;AACA,iB;AACA,0B;AACA,oB;;AAEA,iD;AACA,E;;AAEA,G;AACA,8B;AACA,sB;AACA,wB;AACA,G;AACA,G;AACA,4F;AACA,kB;AACA,mB;AACA,Y;AACA,yB;AACA,2J;AACA,wF;AACA,G;AACA,yE;AACA,kB;;AAEA,qD;;AAEA,sB;AACA,kB;AACA,wB;AACA,oB;AACA,oB;AACA,0B;AACA,G;;AAEA,qC;AACA,yC;AACA,kC;;AAEA,wB;AACA,iC;AACA,yC;AACA,K;AACA,E;;AAEA,6D;AACA,yB;AACA,E;;AAEA,G;AACA,wE;AACA,kB;AACA,c;AACA,Y;AACA,yB;AACA,2J;AACA,wF;AACA,G;AACA,qE;AACA,kB;AACA,e;AACA,sC;AACA,uD;AACA,K;AACA,a;AACA,E;;AAEA,G;AACA,sD;AACA,yB;AACA,iB;AACA,Y;AACA,kB;AACA,sB;AACA,G;AACA,sD;AACA,kB;AACA,e;AACA,+B;AACA,kB;AACA,K;AACA,a;AACA,E;;AAEA,G;AACA,+D;AACA,yB;AACA,iB;AACA,Y;AACA,kB;AACA,oB;AACA,G;AACA,sD;AACA,kB;;AAEA,oB;AACA,8C;AACA,+D;;AAEA,qD;AACA,E;;AAEA,kE;AACA,kB;AACA,6B;AACA,gF;AACA,wC;;AAEA,uD;AACA,gE;AACA,E;;AAEA,mE;AACA,kB;AACA,8B;AACA,E;;AAEA,2E;AACA,+C;AACA,4E;AACA,4D;AACA,E;;AAEA,oE;AACA,2C;AACA,wE;AACA,+C;AACA,4E;AACA,+C;AACA,4E;;AAEA,yE;AACA,oC;AACA,E;;AAEA,2C;AACA,+C;;AAEA,sB;AACA,8B;AACA,mC;AACA,wB;AACA,qD;AACA,0C;AACA,qC;AACA,0B;AACA,8C;AACA,E;AACA,iD;AACA,yB;AACA,uD;AACA,E;AACA,kD;AACA,yC;AACA,E;AACA,mD;AACA,6E;AACA,sE;;AAEA,4C;AACA,K;AACA,0E;AACA,oB;AACA,2B;AACA,c;AACA,wF;AACA,K;AACA,+B;AACA,oB;AACA,qE;AACA,I;;AAEA,K;AACA,+J;AACA,oB;AACA,2B;AACA,c;AACA,wF;AACA,K;AACA,sC;AACA,oB;;AAEA,8E;;AAEA,gF;AACA,gF;AACA,kC;AACA,kD;AACA,2E;AACA,4G;;AAEA,4E;AACA,0E;;AAEA,iB;AACA,+C;AACA,qC;AACA,kB;AACA,6E;AACA,4B;AACA,uB;AACA,mB;AACA,sC;AACA,M;AACA,Y;;AAEA,2E;AACA,Y;AACA,wB;AACA,uC;AACA,2C;AACA,K;AACA,yC;AACA,qD;AACA,+B;AACA,0E;;AAEA,6E;AACA,0B;AACA,uE;AACA,gC;;AAEA,6E;AACA,Y;AACA,qC;AACA,a;AACA,8B;AACA,kC;AACA,2B;AACA,6B;;AAEA,mC;AACA,iB;;AAEA,6D;AACA,iC;AACA,W;AACA,Q;AACA,M;AACA,8C;AACA,kD;AACA,kD;AACA,kB;AACA,4D;AACA,4D;AACA,K;;AAEA,gE;AACA,kD;AACA,wB;AACA,iD;AACA,2D;AACA,2B;AACA,sC;;AAEA,0B;AACA,oB;AACA,uE;AACA,yD;AACA,S;AACA,K;;AAEA,mD;AACA,sB;AACA,kC;AACA,yB;AACA,0B;AACA,8C;AACA,O;AACA,O;;AAEA,0C;AACA,mE;AACA,6D;AACA,2D;AACA,iE;AACA,6C;AACA,wC;AACA,sB;AACA,S;AACA,K;AACA,oE;AACA,mC;AACA,0C;;AAEA,kB;AACA,G;AACA,G;;AAEA,wE;AACA,E;AACA,gF;AACA,gF;AACA,S;AACA,E;AACA,gF;AACA,gC;AACA,E;AACA,4E;AACA,6E;AACA,2E;AACA,+E;AACA,8E;AACA,8D;AACA,sE;AACA,kB;AACA,0B;;AAEA,yE;AACA,e;AACA,kE;;AAEA,kC;AACA,uC;AACA,iE;AACA,sE;AACA,Y;AACA,kB;AACA,qB;;AAEA,kE;AACA,sB;AACA,0B;AACA,kC;AACA,U;AACA,mD;AACA,K;AACA,mB;AACA,G;;AAEA,wD;;AAEA,+E;AACA,6E;AACA,mB;AACA,gB;AACA,sD;AACA,4B;AACA,oC;AACA,wB;AACA,Y;AACA,+C;AACA,K;AACA,G;;AAEA,oD;AACA,wD;AACA,6B;AACA,4B;AACA,0B;AACA,4D;AACA,kD;AACA,c;AACA,6B;AACA,O;AACA,K;AACA,8C;AACA,sD;AACA,mD;AACA,sC;AACA,6B;AACA,6B;AACA,K;;AAEA,uB;AACA,mB;;AAEA,oB;AACA,uE;AACA,6B;AACA,G;;AAEA,iC;AACA,uE;AACA,2C;AACA,E;;AAEA,uE;AACA,oB;AACA,kF;AACA,kB;;AAEA,uB;AACA,mC;AACA,e;AACA,4C;;AAEA,mB;AACA,8B;AACA,wC;AACA,M;AACA,yE;AACA,8B;AACA,kC;AACA,8C;AACA,c;;AAEA,sE;AACA,iC;AACA,G;AACA,E;;AAEA,wE;AACA,2C;AACA,mE;AACA,4C;AACA,6D;AACA,kB;AACA,yB;;AAEA,2B;AACA,4D;AACA,yE;AACA,uE;AACA,oD;AACA,G;AACA,mB;;AAEA,yB;AACA,uD;;AAEA,oC;AACA,0B;;AAEA,8B;AACA,oC;AACA,iC;AACA,kC;AACA,yD;AACA,6B;AACA,gE;AACA,sD;AACA,kD;AACA,qC;AACA,U;AACA,qD;AACA,K;AACA,G;;AAEA,6C;AACA,0B;AACA,gD;AACA,K;AACA,6B;;AAEA,0E;AACA,iB;AACA,e;AACA,8B;AACA,yB;AACA,O;AACA,Y;AACA,E;;AAEA,uE;AACA,mE;AACA,0E;AACA,gC;AACA,6E;AACA,kB;AACA,oE;AACA,oB;AACA,kD;AACA,8B;AACA,mC;AACA,gB;AACA,sC;AACA,mC;AACA,gB;AACA,O;AACA,K;AACA,U;AACA,0B;AACA,G;AACA,E;;AAEA,kE;AACA,kB;;AAEA,+E;AACA,gF;AACA,yB;AACA,2E;AACA,mC;AACA,uB;AACA,2C;AACA,0B;AACA,2B;AACA,c;AACA,8B;AACA,O;AACA,O;AACA,mB;AACA,gC;AACA,+B;AACA,S;AACA,K;AACA,kB;AACA,G;;AAEA,gD;AACA,kB;AACA,8D;AACA,4C;AACA,sB;AACA,K;;AAEA,8B;AACA,uB;AACA,2C;AACA,6B;AACA,6C;AACA,gD;AACA,4D;AACA,oD;AACA,uC;AACA,Y;AACA,uD;AACA,O;AACA,O;AACA,4C;AACA,gC;AACA,G;;AAEA,kE;AACA,yC;AACA,yC;AACA,gB;AACA,gE;AACA,4D;AACA,K;AACA,K;AACA,6C;AACA,kC;AACA,c;AACA,oC;AACA,K;AACA,6B;AACA,yB;AACA,e;AACA,8B;AACA,6B;AACA,O;AACA,gB;AACA,E;;AAEA,kE;AACA,4C;AACA,gF;AACA,kB;AACA,kD;AACA,uB;AACA,mB;AACA,G;AACA,6B;;AAEA,gD;;AAEA,iE;AACA,8E;AACA,8E;AACA,mE;AACA,wB;AACA,gC;AACA,8C;AACA,2E;AACA,sB;AACA,mE;AACA,6D;AACA,K;AACA,yB;;AAEA,sB;;AAEA,8D;AACA,mD;AACA,6B;AACA,2E;AACA,kC;AACA,+E;AACA,oB;AACA,yB;AACA,+B;AACA,K;AACA,gB;AACA,K;;AAEA,+C;AACA,kC;AACA,c;AACA,+D;AACA,K;AACA,6B;;AAEA,4E;AACA,8E;AACA,2B;AACA,iB;AACA,4C;AACA,kE;AACA,2D;AACA,2C;AACA,sC;AACA,qC;AACA,oB;AACA,G;;AAEA,8E;AACA,0E;AACA,sB;AACA,a;AACA,8B;AACA,c;AACA,iC;AACA,M;AACA,iC;AACA,qC;AACA,U;AACA,yB;AACA,G;;AAEA,e;AACA,8B;AACA,6B;AACA,O;AACA,gB;AACA,E;;AAEA,uE;AACA,gF;AACA,W;AACA,gF;AACA,kB;AACA,oD;AACA,uB;AACA,iB;AACA,G;AACA,2D;AACA,iB;AACA,uB;AACA,gB;AACA,E;;AAEA,uD;AACA,4C;AACA,kB;;AAEA,0B;AACA,iC;AACA,kC;AACA,wB;AACA,sE;AACA,Y;AACA,8E;AACA,qC;AACA,uD;AACA,K;AACA,G;;AAEA,iC;;AAEA,kE;;AAEA,6B;AACA,8B;AACA,qC;AACA,wD;AACA,kC;AACA,sE;AACA,wD;;AAEA,kD;AACA,0E;AACA,8E;AACA,4E;AACA,6E;AACA,8E;AACA,2E;AACA,yB;AACA,0B;AACA,kC;AACA,kC;AACA,qD;AACA,kC;AACA,mD;AACA,iC;AACA,4D;AACA,K;AACA,G;AACA,E;;AAEA,mE;AACA,wD;AACA,E;AACA,kE;AACA,oE;;AAEA,0D;AACA,gC;AACA,oB;AACA,sB;AACA,wB;AACA,mE;AACA,8B;AACA,Y;AACA,kD;AACA,iE;AACA,4B;AACA,oC;AACA,e;AACA,wB;AACA,U;AACA,oB;AACA,mE;AACA,K;AACA,qD;AACA,U;AACA,qD;AACA,oC;AACA,G;AACA,E;;AAEA,4D;AACA,sB;AACA,8D;AACA,2B;AACA,+B;AACA,U;AACA,sD;AACA,2B;AACA,6B;AACA,G;AACA,E;;AAEA,mE;AACA,0C;AACA,+D;AACA,wC;AACA,yD;AACA,8C;;AAEA,uB;AACA,oC;AACA,4C;AACA,sC;AACA,K;AACA,W;AACA,G;;AAEA,mE;;AAEA,gC;AACA,0C;AACA,oB;AACA,W;;AAEA,oE;AACA,Y;AACA,oC;AACA,oD;AACA,6D;AACA,wB;AACA,6B;AACA,wC;AACA,a;AACA,sB;AACA,Q;AACA,kB;AACA,0D;AACA,G;AACA,E;;AAEA,uE;AACA,0E;AACA,wC;AACA,E;AACA,+E;AACA,yE;AACA,gF;AACA,0E;AACA,E;AACA,qE;AACA,4E;AACA,kB;AACA,oC;AACA,+B;AACA,sB;AACA,4B;AACA,+C;AACA,yD;;AAEA,sB;AACA,sC;AACA,sD;AACA,4C;AACA,G;AACA,E;;;AAGA,+D;AACA,qB;AACA,2E;AACA,gD;AACA,iC;AACA,e;AACA,2C;AACA,E;;AAEA,0E;AACA,gB;AACA,8D;AACA,4C;;AAEA,2B;AACA,8C;AACA,oD;AACA,6B;AACA,mC;AACA,Y;AACA,8B;AACA,K;AACA,G;AACA,e;AACA,E;;AAEA,oE;AACA,2B;AACA,sB;AACA,a;AACA,G;;AAEA,6D;AACA,8B;AACA,a;AACA,E;;AAEA,gF;AACA,2E;AACA,8E;AACA,+E;AACA,gF;AACA,yE;AACA,uB;AACA,uD;AACA,kB;AACA,2B;AACA,4E;AACA,oD;AACA,E;AACA,2D;AACA,kB;AACA,4B;AACA,sE;;AAEA,uC;AACA,8B;AACA,mB;AACA,E;;AAEA,8D;AACA,kB;AACA,0C;AACA,4B;AACA,W;AACA,0E;AACA,4E;AACA,6B;AACA,mC;AACA,W;AACA,iD;AACA,E;;AAEA,mE;AACA,+B;AACA,wD;AACA,6B;AACA,kB;AACA,W;;AAEA,sE;AACA,qB;;AAEA,yD;AACA,iC;AACA,kC;;AAEA,uD;AACA,G;AACA,E;;AAEA,6D;AACA,0D;AACA,sE;AACA,+D;AACA,yD;AACA,kB;AACA,yB;AACA,mB;AACA,W;;AAEA,mE;AACA,+D;AACA,sB;;AAEA,iC;AACA,kC;AACA,2E;AACA,wD;AACA,sC;AACA,iE;AACA,4C;AACA,iC;AACA,G;AACA,6B;AACA,E;;;AAGA,uB;AACA,8C;AACA,gD;AACA,wB;AACA,sC;AACA,oB;AACA,gB;AACA,6E;AACA,gF;AACA,yF;AACA,qG;AACA,sB;AACA,Y;AACA,uD;AACA,K;AACA,gC;AACA,e;AACA,qD;AACA,4F;AACA,wC;AACA,oC;AACA,G;AACA,E;;;AAGA,uB;AACA,0C;AACA,kB;AACA,c;AACA,0B;AACA,qB;AACA,uC;AACA,wB;AACA,uC;AACA,oC;AACA,sD;AACA,6C;AACA,U;AACA,c;AACA,G;AACA,E;;AAEA,gE;AACA,kB;AACA,gD;AACA,qC;AACA,8B;AACA,M;AACA,sC;AACA,0B;AACA,M;AACA,iD;AACA,+C;AACA,iC;AACA,K;AACA,K;AACA,gB;AACA,E;;;;;;;;;;;;;;;;;;;ACvlCA,sE;AACA,sE;AACA,qE;AACA,4B;AACA,E;AACA,oC;AACA,qE;AACA,uB;AACA,gE;AACA,sD;AACA,kB;AACA,gB;;AAEA,uC;AACA,qC;AACA,qB;;AAEA,gC;AACA,6B;AACA,gF;AACA,+B;AACA,+D;AACA,K;;AAEA,qB;AACA,sF;AACA,uD;AACA,4B;AACA,O;;AAEA,sC;AACA,sD;AACA,K;;AAEA,oC;AACA,+C;AACA,yE;AACA,O;AACA,Y;AACA,2B;AACA,K;AACA,uB;AACA,I;AACA,sC;AACA,iB;AACA,E;;;;;;;;;;;;;;;;;;;AC7CA,+E;AACA,U;AACA,yC;AACA,wB;AACA,4C;AACA,E;;AAEA,2E;AACA,S;AACA,2C;AACA,+D;AACA,gD;AACA,E;;AAEA,4B;AACA,wC;AACA,E;;AAEA,6E;AACA,8E;AACA,gB;AACA,6D;AACA,oC;AACA,iB;;AAEA,oC;AACA,kD;AACA,qD;AACA,0C;AACA,yC;AACA,sD;AACA,0B;AACA,mD;AACA,uD;AACA,gC;AACA,K;AACA,K;AACA,qD;AACA,E;;;AAGA,qC;AACA,6B;AACA,4B;AACA,E;;;;;;;;;;;;;;;;;;;AC5CA,mC;;AAEA,e;AACA,8D;AACA,wE;AACA,sE;AACA,oE;AACA,gC;AACA,oE;AACA,uC;AACA,4E;AACA,4E;AACA,oC;AACA,4E;AACA,a;AACA,8D;;AAEA,oB;AACA,wD;AACA,6C;AACA,yC;AACA,kB;AACA,2E;AACA,6E;AACA,uB;AACA,mB;AACA,8C;AACA,4B;AACA,+C;AACA,yB;AACA,+E;AACA,gF;AACA,yB;AACA,wB;AACA,8E;AACA,0C;AACA,qC;AACA,4E;AACA,yE;AACA,yE;AACA,4B;AACA,wB;AACA,qD;AACA,E;;AAEA,uC;AACA,mC;AACA,0C;AACA,sD;AACA,K;AACA,iC;AACA,I;AACA,4B;AACA,6B;AACA,I;AACA,yB;AACA,0B;AACA,I;AACA,yB;AACA,0B;AACA,I;;AAEA,mE;AACA,0C;AACA,yC;AACA,oB;AACA,4D;AACA,uC;AACA,6B;AACA,gC;AACA,+B;AACA,6B;AACA,8C;AACA,Q;AACA,K;;AAEA,qC;AACA,kD;AACA,uC;AACA,kC;AACA,6B;AACA,yD;AACA,Q;AACA,K;;AAEA,8E;AACA,uE;AACA,8B;AACA,8D;AACA,6B;AACA,4B;AACA,K;;AAEA,qD;AACA,8D;AACA,iC;AACA,uD;;AAEA,2C;AACA,mE;AACA,I;AACA,oC;AACA,6B;AACA,I;AACA,+E;AACA,2C;AACA,0B;AACA,+B;AACA,G;AACA,G;;;AAGA,yE;AACA,iE;AACA,E;AACA,kD;AACA,E;AACA,+E;AACA,gD;AACA,wE;AACA,0B;AACA,uB;AACA,mD;AACA,mC;AACA,6E;AACA,mC;AACA,yC;AACA,iE;AACA,gC;AACA,mE;AACA,oE;AACA,Y;AACA,+E;AACA,8E;AACA,c;AACA,+B;AACA,qC;AACA,kD;AACA,wB;AACA,mE;AACA,uC;AACA,8C;AACA,0C;AACA,S;AACA,K;AACA,K;;AAEA,0C;AACA,E;;AAEA,8E;AACA,8E;AACA,sE;AACA,mC;AACA,sE;AACA,wC;AACA,8B;AACA,kD;AACA,2C;AACA,+C;AACA,mE;AACA,U;AACA,kD;AACA,6C;AACA,G;AACA,E;;AAEA,gF;AACA,+E;AACA,iE;AACA,uD;AACA,8B;AACA,0B;AACA,8B;AACA,4B;AACA,wC;AACA,wC;AACA,iD;AACA,K;AACA,iB;AACA,qD;AACA,kD;;AAEA,8E;AACA,6C;AACA,wC;AACA,4E;AACA,8E;AACA,6C;AACA,kC;AACA,2C;AACA,uB;AACA,O;;AAEA,6E;AACA,4C;AACA,0C;AACA,gD;;AAEA,qB;AACA,O;AACA,e;AACA,I;AACA,E;;AAEA,wD;AACA,0C;AACA,2B;AACA,kC;AACA,wE;AACA,yC;AACA,sC;AACA,K;AACA,yC;AACA,kC;AACA,mB;;AAEA,+E;AACA,+E;AACA,gF;AACA,6E;AACA,6B;AACA,yB;;AAEA,8B;AACA,I;AACA,E;;AAEA,gF;AACA,gC;AACA,qD;AACA,wC;AACA,0E;;AAEA,8E;AACA,6E;AACA,oE;AACA,sD;AACA,6B;AACA,iD;AACA,M;AACA,G;;AAEA,2B;AACA,6D;AACA,I;AACA,E;;AAEA,0E;AACA,kB;AACA,yE;AACA,yE;AACA,8E;AACA,W;;AAEA,4B;AACA,sD;AACA,gE;AACA,6E;AACA,0B;AACA,sE;AACA,kE;AACA,wD;;AAEA,+C;AACA,kD;AACA,gC;AACA,K;;AAEA,2C;AACA,4B;AACA,4E;AACA,oD;AACA,gD;AACA,4B;AACA,+C;AACA,yC;AACA,6C;AACA,oB;AACA,Y;AACA,4D;AACA,K;AACA,K;;AAEA,+C;AACA,E;;AAEA,gD;AACA,sC;AACA,kD;AACA,wD;AACA,kD;AACA,oC;AACA,mE;AACA,mC;AACA,wD;AACA,K;AACA,E;;AAEA,iE;AACA,yB;AACA,sD;AACA,mD;AACA,yC;AACA,yC;AACA,I;;AAEA,qD;AACA,mD;AACA,yC;;AAEA,gF;AACA,mC;AACA,8B;AACA,yB;;AAEA,2B;AACA,iD;AACA,6B;AACA,S;AACA,2D;AACA,mD;AACA,8B;AACA,M;AACA,I;;AAEA,sD;AACA,mD;AACA,yC;AACA,2B;AACA,iD;AACA,8B;AACA,S;AACA,+E;AACA,iE;AACA,8B;AACA,M;AACA,I;;AAEA,6C;AACA,0C;AACA,gC;AACA,6B;AACA,+C;AACA,+E;AACA,sD;AACA,iE;AACA,K;AACA,2B;AACA,iE;AACA,sD;AACA,oD;AACA,M;AACA,I;;AAEA,gF;AACA,2D;AACA,yB;AACA,wB;AACA,4B;AACA,M;AACA,G;AACA,E;;AAEA,0E;AACA,yE;AACA,2E;AACA,wD;AACA,kC;AACA,iD;AACA,gF;AACA,6E;AACA,qB;AACA,sC;AACA,I;AACA,E;;AAEA,6E;AACA,8E;AACA,4D;AACA,2C;AACA,uB;AACA,oD;AACA,yE;AACA,I;AACA,2B;AACA,wE;AACA,wC;AACA,I;AACA,4B;AACA,wE;AACA,8D;AACA,I;AACA,+B;AACA,0E;AACA,iC;AACA,O;AACA,4D;AACA,I;AACA,0E;AACA,+C;AACA,wC;AACA,6C;AACA,6B;AACA,I;AACA,mD;AACA,mD;AACA,6B;AACA,gD;AACA,6B;AACA,I;AACA,oD;AACA,0B;AACA,yC;AACA,4D;AACA,2B;AACA,4B;;AAEA,8B;AACA,0C;AACA,+C;AACA,sC;AACA,gD;AACA,sD;AACA,sE;AACA,O;AACA,+E;AACA,mB;AACA,iD;AACA,I;AACA,6D;AACA,gB;AACA,8D;AACA,gC;;AAEA,sE;AACA,6E;AACA,wC;;AAEA,qC;AACA,gE;AACA,iC;AACA,yC;AACA,gC;AACA,mC;AACA,6E;AACA,6E;AACA,sB;AACA,kC;AACA,sB;AACA,qC;AACA,qD;AACA,gB;AACA,wE;AACA,kC;AACA,S;AACA,Q;AACA,Y;AACA,+C;AACA,uD;AACA,yE;AACA,oC;AACA,mC;AACA,qD;AACA,sB;AACA,qD;AACA,Q;AACA,K;;AAEA,sC;AACA,4E;AACA,gF;AACA,2E;AACA,0E;AACA,Q;AACA,gF;AACA,gF;AACA,kD;AACA,8D;AACA,mC;AACA,gD;AACA,iD;AACA,qE;AACA,8D;AACA,iB;AACA,sC;AACA,4E;AACA,iB;AACA,6B;AACA,sC;AACA,iC;AACA,qC;AACA,Y;AACA,oD;AACA,S;AACA,oB;AACA,M;AACA,G;AACA,E;;AAEA,qB;AACA,+C;AACA,sB;AACA,sB;AACA,sB;AACA,sB;AACA,+B;AACA,gB;AACA,kC;AACA,E;AACA,0E;AACA,kD;AACA,wD;AACA,qC;AACA,kC;AACA,E;;AAEA,gC;AACA,oD;AACA,U;AACA,gD;AACA,uE;AACA,0E;AACA,4C;AACA,6D;AACA,6B;AACA,4B;AACA,uB;AACA,U;AACA,O;;AAEA,yE;AACA,oB;AACA,gC;AACA,uB;;AAEA,0D;;AAEA,+B;AACA,gC;AACA,uB;AACA,4E;AACA,8B;AACA,4D;AACA,uB;AACA,2E;AACA,Q;AACA,K;AACA,I;AACA,E;;AAEA,kC;AACA,mD;AACA,uD;AACA,+E;AACA,iB;AACA,gF;AACA,oB;AACA,0D;AACA,6E;AACA,kB;AACA,4E;AACA,4C;AACA,qB;AACA,2C;AACA,wB;AACA,K;AACA,2C;AACA,wB;AACA,K;AACA,4C;AACA,yB;AACA,K;AACA,4C;AACA,yB;AACA,K;AACA,S;AACA,gD;AACA,oD;AACA,8C;AACA,kD;AACA,wE;AACA,O;AACA,2D;AACA,+B;AACA,iC;AACA,+B;AACA,0E;AACA,Q;AACA,K;AACA,I;AACA,Q;AACA,gD;AACA,4B;AACA,0C;;AAEA,+B;AACA,yC;AACA,qC;AACA,6D;AACA,0C;AACA,iD;AACA,Y;AACA,+D;AACA,S;;AAEA,+B;AACA,qE;AACA,gC;AACA,uB;AACA,oD;AACA,0B;AACA,W;AACA,Q;AACA,K;AACA,I;AACA,U;AACA,8E;AACA,8E;AACA,sB;AACA,+B;AACA,gD;AACA,wC;AACA,gF;AACA,gB;AACA,oB;AACA,+C;AACA,4C;AACA,O;AACA,+B;AACA,0D;AACA,Q;AACA,K;AACA,I;AACA,U;AACA,6E;AACA,6E;AACA,6E;AACA,sC;AACA,gC;AACA,gD;AACA,sC;AACA,4C;AACA,+B;AACA,kC;AACA,yD;AACA,Q;AACA,K;AACA,I;AACA,W;AACA,+D;AACA,sE;AACA,2D;;AAEA,iB;AACA,iD;AACA,8E;AACA,yD;AACA,8C;;AAEA,+E;AACA,gF;AACA,uD;AACA,kD;AACA,+E;;AAEA,+E;AACA,iE;AACA,6C;AACA,yB;AACA,c;AACA,qC;AACA,O;AACA,0C;AACA,K;AACA,I;AACA,e;AACA,+B;AACA,wE;AACA,kC;AACA,iD;;AAEA,mC;AACA,4C;AACA,4D;AACA,6B;AACA,c;AACA,8E;AACA,gE;AACA,uE;AACA,+E;AACA,8D;AACA,kE;AACA,4B;AACA,O;;AAEA,+B;AACA,4B;AACA,uB;AACA,gD;AACA,sC;AACA,kB;AACA,6B;AACA,sE;AACA,6E;AACA,oE;AACA,uE;AACA,2B;AACA,+B;AACA,kB;AACA,2E;AACA,0C;AACA,6D;AACA,W;AACA,sE;AACA,qC;AACA,6E;AACA,S;AACA,qB;AACA,Q;AACA,K;AACA,G;AACA,E;;AAEA,qD;AACA,E;AACA,yE;AACA,8E;AACA,8E;AACA,kB;AACA,E;AACA,gF;AACA,4E;AACA,+E;AACA,sD;AACA,E;AACA,0E;AACA,uE;AACA,wE;AACA,wC;AACA,E;AACA,sC;AACA,oC;AACA,+E;AACA,8E;AACA,+D;AACA,mE;AACA,uB;AACA,+E;AACA,+E;AACA,0E;AACA,6E;AACA,mE;AACA,E;AACA,uE;AACA,4E;AACA,c;AACA,E;AACA,gF;AACA,mE;AACA,yE;AACA,wE;AACA,+E;AACA,6E;AACA,4E;AACA,6E;AACA,oD;AACA,E;AACA,yE;AACA,2E;AACA,E;AACA,E;AACA,kE;AACA,E;AACA,+E;AACA,U;AACA,8C;AACA,0B;AACA,6B;AACA,+C;AACA,mD;AACA,sE;AACA,iB;AACA,yB;AACA,8D;AACA,G;;AAEA,iD;AACA,4B;AACA,gC;AACA,2D;AACA,iC;AACA,kB;AACA,I;;AAEA,mD;AACA,+C;AACA,uC;AACA,sB;AACA,wB;;AAEA,uB;AACA,gF;AACA,gF;AACA,gF;AACA,0D;AACA,kB;;AAEA,gF;AACA,2E;AACA,+B;AACA,0D;AACA,K;;AAEA,2B;AACA,oC;;AAEA,0D;AACA,M;AACA,8E;AACA,4E;AACA,gF;AACA,gF;AACA,kB;AACA,M;AACA,4E;AACA,uE;AACA,+E;AACA,oE;AACA,sB;AACA,qC;AACA,0B;AACA,yD;AACA,sC;AACA,K;;AAEA,+E;AACA,gF;AACA,2E;AACA,8E;AACA,8E;AACA,oB;AACA,mC;AACA,uB;AACA,kB;AACA,sD;AACA,oE;AACA,K;;AAEA,oB;AACA,0C;AACA,+C;AACA,M;;AAEA,yE;AACA,wE;AACA,oC;AACA,yD;;AAEA,gF;AACA,gF;AACA,+D;AACA,M;AACA,4E;AACA,6E;AACA,yE;AACA,gF;AACA,gF;AACA,kD;AACA,M;AACA,8E;AACA,+E;AACA,6E;AACA,kC;AACA,yE;AACA,wD;AACA,oC;AACA,oC;AACA,mB;AACA,8C;AACA,S;AACA,S;AACA,K;;AAEA,kB;AACA,I;AACA,E;AACA,sD;;AAEA,6D;AACA,uB;AACA,sC;AACA,4C;AACA,+E;AACA,gF;AACA,8E;AACA,mC;AACA,iE;AACA,wB;AACA,4B;AACA,yC;AACA,S;AACA,K;AACA,6C;AACA,+C;AACA,0B;AACA,sB;AACA,6D;AACA,W;AACA,S;AACA,K;AACA,K;AACA,qB;AACA,E;;AAEA,qD;AACA,yB;AACA,E;;AAEA,wD;AACA,wB;AACA,E;;;AAGA,0E;AACA,+E;AACA,8E;AACA,iD;AACA,8C;AACA,+B;AACA,6B;AACA,+B;AACA,0B;;AAEA,mC;AACA,iB;AACA,kD;AACA,uC;AACA,uE;AACA,0E;AACA,+E;AACA,e;AACA,8D;AACA,0C;AACA,0C;AACA,O;AACA,4E;AACA,6E;AACA,c;AACA,uD;AACA,kD;AACA,O;AACA,8B;AACA,O;;AAEA,8E;AACA,sB;AACA,0B;AACA,8B;AACA,K;AACA,e;AACA,I;AACA,E;;AAEA,0C;AACA,0C;;;AAGA,yC;AACA,sB;AACA,wE;;AAEA,uB;AACA,8B;AACA,e;AACA,8B;AACA,e;AACA,+B;AACA,e;AACA,mB;AACA,e;AACA,mB;AACA,gB;AACA,4B;AACA,2C;AACA,gB;AACA,gC;AACA,gB;AACA,0B;AACA,e;AACA,0B;AACA,e;AACA,+C;AACA,e;AACA,uB;;AAEA,qC;AACA,iB;AACA,qC;AACA,oC;AACA,oB;AACA,kB;AACA,kB;AACA,I;;AAEA,mE;AACA,2B;AACA,yD;AACA,I;;AAEA,mE;AACA,oB;AACA,4B;AACA,mF;AACA,iE;AACA,kC;AACA,wB;AACA,gC;AACA,0B;AACA,0B;AACA,0B;AACA,yB;AACA,0B;AACA,8B;AACA,4B;AACA,wB;AACA,wB;AACA,wB;AACA,0B;AACA,8B;AACA,2B;AACA,uC;AACA,2B;AACA,8B;AACA,mC;AACA,8B;AACA,gB;AACA,I;;AAEA,kE;AACA,sE;AACA,qE;AACA,wB;AACA,yB;AACA,wB;AACA,sC;AACA,wB;AACA,e;AACA,yC;AACA,yC;AACA,+C;AACA,+C;AACA,kB;AACA,8B;AACA,kB;AACA,0E;AACA,kB;AACA,yD;AACA,+B;AACA,2B;AACA,kB;AACA,0B;AACA,0B;AACA,K;AACA,2B;AACA,2B;AACA,kB;AACA,sB;AACA,sB;AACA,K;;AAEA,2B;AACA,mB;AACA,2B;AACA,4C;AACA,6B;AACA,mE;AACA,qC;AACA,qB;AACA,8B;AACA,wB;AACA,6B;AACA,S;AACA,mB;AACA,Q;AACA,+D;AACA,K;AACA,4B;AACA,8B;AACA,2B;AACA,2C;AACA,2B;AACA,mB;AACA,oD;AACA,oB;AACA,mB;AACA,O;AACA,K;AACA,6B;AACA,6E;AACA,e;AACA,gC;AACA,mC;AACA,sC;AACA,wB;AACA,oB;AACA,wB;AACA,mB;AACA,O;AACA,e;AACA,K;AACA,8B;AACA,8B;AACA,wB;AACA,K;AACA,0B;AACA,e;AACA,4B;AACA,wE;AACA,0B;AACA,iB;AACA,qC;AACA,yB;AACA,oB;AACA,yB;AACA,kB;AACA,kB;AACA,qC;AACA,qE;AACA,wC;AACA,G;AACA,E;;AAEA,mC;AACA,8D;AACA,uB;AACA,yB;AACA,+B;AACA,mC;AACA,qB;AACA,E;;;;;;;;;;;;;;;;;;;ACpnCA,wD;AACA,4B;AACA,wC;AACA,+B;AACA,E;AACA,iE;AACA,sE;AACA,0D;AACA,E;AACA,kE;AACA,kE;AACA,wD;;AAEA,6C;AACA,kB;AACA,0B;;AAEA,2B;;AAEA,gD;AACA,c;AACA,iD;AACA,+B;AACA,mD;AACA,8B;AACA,iB;AACA,wD;AACA,0B;AACA,O;AACA,I;;AAEA,8B;AACA,2C;AACA,wC;AACA,mC;AACA,c;AACA,uD;AACA,O;AACA,K;AACA,wC;AACA,wC;AACA,mC;AACA,O;AACA,U;AACA,mE;AACA,G;;AAEA,uE;AACA,+E;AACA,0E;AACA,gC;AACA,sB;AACA,iD;AACA,8B;AACA,O;AACA,0E;AACA,G;;AAEA,2C;AACA,mD;AACA,yC;AACA,Q;;AAEA,yE;AACA,8E;AACA,yE;AACA,yB;AACA,2D;AACA,E;;AAEA,gF;AACA,sB;AACA,sC;AACA,qC;AACA,oB;;AAEA,uE;AACA,8D;AACA,yC;AACA,uC;AACA,K;;AAEA,sC;;AAEA,gF;AACA,4D;AACA,2E;AACA,gC;AACA,qD;AACA,gC;AACA,qD;AACA,yD;AACA,Q;AACA,I;;AAEA,0B;AACA,oB;AACA,gD;AACA,I;;AAEA,8E;AACA,8E;AACA,4D;AACA,I;AACA,0E;AACA,gE;AACA,gF;AACA,8E;AACA,gF;AACA,sE;AACA,qC;AACA,oB;AACA,sB;;AAEA,mD;AACA,gD;AACA,e;;AAEA,4B;AACA,qB;AACA,e;AACA,O;AACA,+C;AACA,qB;AACA,O;AACA,O;;AAEA,gF;AACA,2C;AACA,wB;AACA,yD;AACA,kB;AACA,I;;AAEA,8C;AACA,oB;AACA,oD;AACA,I;;AAEA,+E;AACA,uB;AACA,4C;AACA,oB;;AAEA,yC;AACA,4D;;AAEA,uD;AACA,kC;;AAEA,8C;AACA,qC;AACA,M;;AAEA,0B;;AAEA,6D;AACA,qE;AACA,+D;AACA,oE;;AAEA,2E;AACA,yC;AACA,2B;AACA,mC;;AAEA,4B;AACA,4C;AACA,0C;AACA,mC;AACA,4E;AACA,gF;AACA,kC;AACA,kC;AACA,gE;AACA,8D;AACA,iB;AACA,S;;AAEA,yB;AACA,wD;AACA,0D;AACA,iD;AACA,8D;;AAEA,2E;AACA,yE;AACA,2E;AACA,4E;AACA,mD;AACA,U;AACA,6E;AACA,wE;AACA,2B;AACA,8C;AACA,qD;AACA,sD;AACA,S;AACA,S;;AAEA,uB;AACA,4E;AACA,2B;AACA,2D;AACA,8E;AACA,uD;AACA,S;AACA,6B;AACA,wB;AACA,qE;AACA,kC;AACA,W;AACA,O;AACA,O;;AAEA,sB;AACA,qC;AACA,mE;AACA,+B;AACA,oD;AACA,0B;AACA,S;AACA,kB;AACA,a;AACA,K;;AAEA,2C;AACA,+D;AACA,8B;AACA,4B;AACA,iC;AACA,uC;AACA,4B;AACA,S;AACA,c;AACA,O;AACA,I;;AAEA,qE;AACA,4E;AACA,oB;AACA,uC;AACA,oB;AACA,qD;AACA,qD;AACA,0C;AACA,K;;AAEA,2C;AACA,I;;AAEA,gF;AACA,kB;AACA,qC;AACA,oB;AACA,mD;AACA,kC;AACA,8D;AACA,iB;AACA,2B;AACA,qB;AACA,M;AACA,I;;AAEA,yE;AACA,yD;AACA,mC;AACA,oB;;AAEA,wE;AACA,2B;AACA,sC;AACA,oC;AACA,iB;AACA,Q;AACA,K;;AAEA,kC;AACA,8C;AACA,8C;AACA,2C;AACA,M;AACA,I;;AAEA,sC;AACA,kC;AACA,+B;AACA,wE;AACA,2E;AACA,gD;AACA,I;AACA,wE;AACA,sD;AACA,mD;AACA,2D;AACA,sE;AACA,wE;AACA,yB;AACA,I;AACA,8E;AACA,2E;AACA,8E;AACA,8C;AACA,uC;AACA,oB;;AAEA,wB;AACA,mD;;AAEA,4E;AACA,0B;AACA,6D;AACA,uC;AACA,a;;AAEA,qC;;AAEA,gF;AACA,0B;AACA,qC;AACA,a;;AAEA,+B;AACA,oD;AACA,wC;AACA,O;;AAEA,kD;AACA,iC;;AAEA,+C;AACA,uB;AACA,e;;AAEA,0E;AACA,yE;AACA,yE;AACA,yD;AACA,0C;AACA,8E;AACA,6E;AACA,6E;AACA,2E;AACA,8E;AACA,wE;AACA,4D;AACA,iB;AACA,4D;AACA,e;AACA,O;;AAEA,0C;AACA,0D;AACA,qE;AACA,gF;AACA,6E;AACA,6B;AACA,2E;AACA,W;;AAEA,oD;AACA,+D;AACA,6B;AACA,8D;AACA,uC;AACA,W;;AAEA,sE;AACA,W;AACA,e;AACA,O;;AAEA,oC;AACA,4D;AACA,O;;AAEA,2E;AACA,8E;AACA,gF;AACA,yB;AACA,kE;AACA,a;;AAEA,sC;AACA,oE;AACA,qE;AACA,+B;AACA,W;AACA,S;AACA,M;AACA,G;AACA,G;;AAEA,gC;AACA,sE;AACA,uE;AACA,kB;AACA,qD;AACA,0B;AACA,sD;AACA,6C;AACA,wB;AACA,uB;AACA,K;AACA,a;AACA,I;AACA,E;;;;;;;;;;;;;;;;;;;ACtZA,oE;AACA,6E;AACA,sC;AACA,0D;AACA,wE;AACA,gF;AACA,4C;AACA,wD;AACA,oD;;AAEA,oE;AACA,0C;;AAEA,kD;AACA,4C;AACA,8B;AACA,uB;AACA,mF;;AAEA,wD;AACA,2C;AACA,2B;AACA,e;AACA,6B;AACA,4C;AACA,iC;AACA,+C;AACA,sD;AACA,mC;AACA,yC;AACA,U;AACA,wB;AACA,O;;AAEA,e;AACA,I;;AAEA,yB;AACA,2C;;AAEA,2C;AACA,wB;AACA,4C;AACA,qB;AACA,e;AACA,I;AACA,E;;AAEA,0E;AACA,0C;AACA,mB;AACA,wE;AACA,oE;AACA,yE;AACA,uC;AACA,kF;AACA,6E;AACA,gE;AACA,yC;;AAEA,4E;AACA,4E;AACA,oC;AACA,qF;AACA,gF;;AAEA,kC;;AAEA,yC;AACA,iC;AACA,2B;AACA,uB;AACA,2B;AACA,wD;AACA,uF;AACA,K;;;AAGA,wC;AACA,e;AACA,0C;AACA,qC;AACA,4E;AACA,2E;AACA,4E;AACA,yE;AACA,2E;AACA,8E;AACA,yC;AACA,Q;AACA,kD;AACA,kD;AACA,iD;AACA,6E;AACA,iD;AACA,uF;AACA,Q;AACA,mE;;AAEA,iC;AACA,6B;AACA,0E;AACA,uF;AACA,yF;AACA,O;;AAEA,U;AACA,8B;AACA,wB;AACA,I;AACA,E;;AAEA,2C;AACA,+E;AACA,4D;AACA,0E;AACA,0E;AACA,+E;AACA,8C;AACA,iD;AACA,iE;AACA,6D;AACA,oB;AACA,oC;AACA,uB;AACA,qC;;AAEA,8C;AACA,mE;AACA,+B;AACA,0B;AACA,2C;AACA,+C;AACA,sE;AACA,2C;AACA,4D;AACA,sC;AACA,uB;AACA,O;;AAEA,6B;AACA,kB;AACA,O;;AAEA,kB;AACA,oC;AACA,mC;AACA,8C;AACA,U;AACA,0E;AACA,K;AACA,K;;AAEA,c;AACA,E;;AAEA,+D;AACA,+C;AACA,4D;;AAEA,0C;AACA,4C;AACA,uF;AACA,mD;AACA,sF;AACA,K;AACA,E;;;;;;;;;;;;;;;;;;;;ACtKA,6D;AACA,uC;AACA,E;AACA,6D;AACA,E;AACA,sE;AACA,U;AACA,E;AACA,W;AACA,8E;AACA,6E;AACA,8D;AACA,wD;AACA,0B;AACA,0B;AACA,uD;AACA,yC;;AAEA,a;;AAEA,oB;AACA,mD;AACA,kE;;AAEA,iC;AACA,wB;AACA,uB;AACA,6B;AACA,qE;AACA,K;AACA,iB;AACA,U;AACA,kC;AACA,8B;;AAEA,wC;AACA,kC;AACA,yD;AACA,oD;AACA,oC;AACA,mB;AACA,iE;AACA,+C;AACA,6B;AACA,qE;AACA,S;;AAEA,gC;AACA,yD;AACA,S;;AAEA,0C;;AAEA,4C;AACA,+B;AACA,2C;AACA,uE;AACA,S;;AAEA,sD;AACA,6C;AACA,sD;AACA,4C;AACA,0C;AACA,4C;AACA,W;AACA,mC;AACA,qD;AACA,S;AACA,O;AACA,G;;AAEA,kC;AACA,oC;AACA,sE;AACA,uE;AACA,qD;AACA,oB;AACA,oB;AACA,K;AACA,kC;AACA,e;AACA,K;AACA,E;;AAEA,sE;AACA,iE;AACA,U;AACA,E;AACA,gE;AACA,oE;AACA,iE;AACA,sD;AACA,E;AACA,gF;AACA,2E;AACA,4B;AACA,E;AACA,4E;AACA,E;AACA,+E;AACA,Y;AACA,uD;AACA,0B;AACA,6B;AACA,6C;AACA,2C;AACA,8B;AACA,qC;AACA,qB;AACA,2B;AACA,yB;AACA,6B;AACA,oE;AACA,gC;AACA,c;AACA,K;AACA,+B;AACA,8B;AACA,oB;AACA,4B;AACA,2B;AACA,0E;AACA,oE;AACA,4E;AACA,8D;AACA,S;AACA,0C;AACA,8B;AACA,yC;AACA,oC;AACA,c;AACA,6B;AACA,2B;AACA,6B;AACA,2D;AACA,qC;AACA,O;AACA,e;AACA,wB;AACA,8B;AACA,oD;AACA,yB;AACA,kC;AACA,uB;AACA,kB;AACA,mC;AACA,uB;AACA,kD;AACA,yE;AACA,yE;AACA,O;AACA,Y;AACA,yD;AACA,iE;AACA,8B;AACA,6B;AACA,2B;AACA,kB;AACA,4B;AACA,O;AACA,K;;AAEA,a;AACA,iB;AACA,uB;AACA,G;;AAEA,e;AACA,E;;AAEA,2B;AACA,e;AACA,a;AACA,gB;AACA,c;AACA,gB;AACA,E;;AAEA,iB;AACA,uC;AACA,gC;AACA,qE;AACA,0B;AACA,4C;AACA,yE;AACA,2B;AACA,Y;AACA,0B;AACA,K;AACA,I;AACA,uC;AACA,2D;AACA,wE;AACA,gC;AACA,c;AACA,K;AACA,0B;AACA,4D;AACA,gC;AACA,c;AACA,K;AACA,qC;AACA,I;AACA,+C;AACA,uC;AACA,I;AACA,yC;AACA,+B;AACA,oC;AACA,4B;AACA,+B;AACA,Y;AACA,6B;AACA,K;AACA,I;AACA,wC;AACA,oC;AACA,yB;AACA,0C;AACA,uE;;AAEA,8B;AACA,+B;AACA,2C;AACA,a;AACA,K;;AAEA,qD;AACA,2B;AACA,mC;AACA,qD;;AAEA,oB;AACA,0B;AACA,0B;AACA,yC;AACA,+D;AACA,8C;AACA,yB;AACA,yE;AACA,yB;AACA,K;;AAEA,mB;AACA,iC;AACA,oB;AACA,8B;AACA,oE;AACA,8E;AACA,mE;AACA,yC;AACA,2D;AACA,qE;AACA,+C;AACA,wD;AACA,oE;AACA,4D;AACA,S;AACA,O;AACA,K;;AAEA,qB;AACA,2C;AACA,iD;;AAEA,qB;AACA,qB;AACA,uC;;AAEA,sB;AACA,8B;AACA,sB;AACA,yD;AACA,U;AACA,mD;AACA,K;AACA,I;AACA,2C;AACA,2D;AACA,gF;AACA,0B;AACA,wB;AACA,0B;AACA,mC;AACA,0E;AACA,U;AACA,0C;AACA,uB;AACA,K;AACA,I;AACA,4C;AACA,uB;AACA,kC;AACA,qC;AACA,0B;AACA,0B;AACA,wB;AACA,c;AACA,O;AACA,K;AACA,+C;AACA,0B;AACA,wB;AACA,6B;AACA,mC;AACA,2E;AACA,U;AACA,uC;AACA,0C;AACA,qD;AACA,mB;AACA,mC;AACA,S;AACA,K;AACA,I;AACA,uC;AACA,6B;AACA,a;AACA,0B;AACA,wB;AACA,a;AACA,mC;AACA,sE;AACA,U;AACA,6C;AACA,uB;AACA,U;AACA,gB;AACA,K;AACA,I;AACA,wC;AACA,6B;AACA,a;AACA,0B;AACA,wB;AACA,a;AACA,mC;AACA,+E;AACA,U;AACA,mB;AACA,+D;AACA,oE;AACA,8D;AACA,mE;AACA,c;;AAEA,sE;AACA,kE;AACA,6D;AACA,6C;AACA,iD;AACA,0C;AACA,oD;AACA,2B;AACA,c;AACA,0C;AACA,oD;AACA,2B;AACA,O;AACA,0B;AACA,K;AACA,I;AACA,2C;AACA,2D;AACA,gF;AACA,6B;AACA,a;AACA,0B;AACA,wB;AACA,a;AACA,mC;AACA,+E;AACA,U;AACA,mB;AACA,0C;AACA,4B;AACA,8C;AACA,wD;AACA,2B;AACA,kB;AACA,W;AACA,S;AACA,qB;AACA,yB;AACA,O;AACA,0B;AACA,K;AACA,I;AACA,wD;AACA,wB;AACA,iD;AACA,qE;AACA,wB;AACA,2D;AACA,gC;AACA,8D;AACA,6B;AACA,a;AACA,0B;AACA,yB;;AAEA,kC;AACA,oE;AACA,yB;AACA,2D;AACA,gC;AACA,wB;AACA,I;AACA,uC;AACA,oE;AACA,2E;AACA,kD;AACA,G;AACA,E;;;;;;;;;;;;;;;;;;;AC9ZA,iB;AACA,yD;AACA,kC;AACA,mC;AACA,8E;AACA,kE;AACA,c;AACA,6C;AACA,iD;AACA,M;AACA,+C;AACA,iD;AACA,E;;AAEA,8E;AACA,2E;AACA,0B;AACA,yD;;AAEA,6B;AACA,+E;AACA,G;;AAEA,4C;AACA,oC;AACA,iB;AACA,8D;AACA,gD;AACA,gD;AACA,2B;AACA,6E;AACA,yC;AACA,8C;AACA,S;AACA,O;AACA,gC;AACA,wC;AACA,wB;AACA,yC;AACA,K;AACA,K;;AAEA,yB;AACA,8C;AACA,8B;AACA,6B;AACA,O;AACA,G;AACA,E;;;AAGA,8E;AACA,yE;AACA,0B;AACA,yD;;AAEA,8B;AACA,sC;AACA,oC;AACA,oD;AACA,uC;AACA,K;;AAEA,2B;AACA,yC;AACA,mC;AACA,oD;AACA,iC;AACA,K;;AAEA,e;AACA,I;AACA,oE;AACA,gE;AACA,oE;AACA,sE;AACA,sB;;AAEA,gF;AACA,e;;AAEA,0E;AACA,W;;AAEA,+E;AACA,8E;AACA,gF;AACA,+E;AACA,gF;AACA,4E;AACA,8E;AACA,S;;AAEA,oE;AACA,mE;;;AAGA,6D;AACA,8D;AACA,iE;AACA,yB;AACA,I;AACA,8D;AACA,4C;AACA,mB;AACA,4C;AACA,sB;AACA,iE;AACA,uD;AACA,6B;AACA,8B;AACA,qE;AACA,iE;AACA,kB;AACA,0B;AACA,mD;AACA,qC;AACA,mD;AACA,I;AACA,wE;AACA,+B;AACA,0B;AACA,4D;AACA,0B;AACA,gE;AACA,sE;AACA,qE;AACA,uE;AACA,oD;AACA,qB;AACA,wD;AACA,gB;AACA,Y;AACA,O;;AAEA,+C;AACA,sB;AACA,4B;AACA,0B;AACA,K;AACA,G;;AAEA,sC;AACA,+D;AACA,oB;AACA,sB;AACA,oB;AACA,G;AACA,0D;AACA,oB;;AAEA,8E;AACA,oB;AACA,mC;;AAEA,sC;AACA,qC;AACA,oD;AACA,K;AACA,+E;AACA,mD;AACA,uB;AACA,yC;AACA,+E;AACA,2D;AACA,qD;AACA,8B;AACA,gD;AACA,sC;AACA,0B;AACA,kF;AACA,6D;AACA,c;AACA,gB;AACA,0D;AACA,4C;AACA,4C;AACA,gF;AACA,iC;AACA,mE;AACA,S;AACA,0E;AACA,O;AACA,K;AACA,kB;AACA,uC;AACA,wD;AACA,0C;AACA,0C;AACA,8E;AACA,+B;AACA,iE;AACA,O;AACA,K;AACA,gC;AACA,K;;;AAGA,E;;;AAGA,2C;AACA,kC;AACA,+C;AACA,iD;AACA,uD;AACA,I;AACA,kE;AACA,0C;AACA,0B;AACA,mE;AACA,Q;AACA,+D;AACA,K;AACA,4B;AACA,6C;AACA,4B;AACA,6C;AACA,O;AACA,G;AACA,E;;;;;;;;;;;;;;;;;;;AC5NA,sC;AACA,kB;AACA,2E;AACA,E;;AAEA,gD;;;;;;;;;;;;;;;;;;;;ACLA,wE;;AAEA,8E;AACA,+E;AACA,8E;AACA,4E;AACA,gF;AACA,4E;AACA,0C;AACA,6D;AACA,kB;AACA,0B;;AAEA,iD;AACA,8E;AACA,kC;AACA,mC;AACA,sE;AACA,4D;AACA,iC;AACA,wC;AACA,U;AACA,qD;AACA,G;AACA,0C;;AAEA,qB;AACA,8D;AACA,wB;AACA,kD;AACA,sC;AACA,qB;AACA,4D;AACA,oC;AACA,mE;AACA,kE;AACA,yD;AACA,wD;AACA,2D;AACA,qD;AACA,Q;AACA,0C;AACA,oC;AACA,8E;AACA,iD;AACA,O;AACA,M;AACA,U;AACA,2C;AACA,wB;AACA,oC;AACA,sC;AACA,kE;AACA,qB;AACA,gC;AACA,O;AACA,M;AACA,G;;AAEA,sE;AACA,e;AACA,oD;AACA,gC;AACA,a;AACA,uD;AACA,gD;AACA,qC;AACA,+C;AACA,I;AACA,4C;AACA,0D;AACA,yB;AACA,I;AACA,E;;AAEA,kF;AACA,wE;AACA,wD;;AAEA,8B;AACA,sE;AACA,4E;AACA,8E;AACA,2E;AACA,6E;AACA,gD;AACA,+B;AACA,kD;AACA,wB;AACA,gF;AACA,iB;AACA,yD;AACA,uC;AACA,6B;AACA,+E;AACA,uD;AACA,gB;AACA,sC;AACA,S;AACA,Q;AACA,sC;AACA,wB;AACA,sE;AACA,iB;AACA,iD;AACA,iB;AACA,2D;AACA,iD;AACA,mD;AACA,6B;AACA,yC;AACA,2D;AACA,yD;AACA,gB;AACA,gD;AACA,S;AACA,Q;AACA,0C;AACA,wB;AACA,sC;AACA,iB;AACA,wD;;AAEA,wB;AACA,6E;AACA,2E;AACA,oD;AACA,sB;AACA,e;AACA,2E;AACA,2D;AACA,Q;AACA,8B;AACA,wB;AACA,sE;AACA,iB;AACA,gF;AACA,wC;AACA,+C;AACA,yC;AACA,2D;AACA,iD;AACA,gB;AACA,wC;AACA,S;AACA,O;AACA,M;AACA,U;AACA,+B;AACA,oC;AACA,oD;AACA,iD;AACA,iD;AACA,S;AACA,Q;AACA,sC;AACA,wB;AACA,uC;AACA,yC;AACA,wC;AACA,qD;AACA,kD;AACA,mE;AACA,S;AACA,Q;AACA,8B;AACA,wB;AACA,uC;AACA,iE;AACA,S;AACA,O;AACA,M;AACA,G;;AAEA,kE;AACA,0C;AACA,iE;AACA,qB;;AAEA,gB;AACA,E;;;;;;;;;;;;;;;;;;;ACpLA,qD;AACA,uD;AACA,E;;AAEA,kD;AACA,uC;AACA,kB;AACA,kB;AACA,wC;AACA,yD;AACA,6E;AACA,K;AACA,0E;AACA,0B;AACA,U;AACA,qC;AACA,G;AACA,E;;AAEA,4D;AACA,kB;AACA,2C;AACA,E;;AAEA,+D;AACA,kB;AACA,sD;AACA,uC;AACA,E;;AAEA,yD;AACA,kB;AACA,kD;AACA,E;;AAEA,2D;AACA,e;AACA,E;;AAEA,+D;AACA,kB;AACA,8C;AACA,E;;AAEA,6C;AACA,qD;AACA,qD;AACA,sC;;AAEA,qD;AACA,qD;AACA,0C;AACA,qC;AACA,kD;AACA,E;;AAEA,yD;AACA,oE;AACA,mD;AACA,gD;AACA,mE;AACA,6B;AACA,E;;AAEA,gF;AACA,uE;AACA,8E;AACA,8E;AACA,uC;AACA,6D;AACA,gC;AACA,8C;AACA,sB;AACA,gB;AACA,gB;;AAEA,8B;AACA,+B;AACA,oC;AACA,oD;AACA,4B;AACA,uD;AACA,wC;AACA,sC;AACA,uC;AACA,oE;AACA,8B;AACA,K;AACA,gB;AACA,G;;AAEA,wE;AACA,0E;AACA,wE;AACA,kD;AACA,oD;AACA,2E;AACA,iB;AACA,sB;AACA,K;AACA,G;;AAEA,c;AACA,E;;AAEA,sC;AACA,4C;AACA,G;;;;;;;;;;;;;;;;;;;AC3GA,gF;AACA,yE;AACA,8E;AACA,2E;AACA,kB;AACA,2E;;AAEA,gF;AACA,4E;AACA,+E;AACA,4E;AACA,oC;AACA,c;;AAEA,wE;AACA,E;;AAEA,uD;AACA,kB;AACA,uC;AACA,6D;AACA,K;AACA,E;;AAEA,oE;AACA,iD;AACA,6B;AACA,4B;;AAEA,+B;AACA,2B;AACA,sD;AACA,sE;AACA,2B;AACA,uC;AACA,6B;AACA,qE;AACA,4C;AACA,4B;AACA,U;AACA,gD;AACA,kD;AACA,iD;AACA,kC;AACA,oD;AACA,gB;AACA,2C;AACA,O;;AAEA,gC;AACA,G;AACA,E;;AAEA,wC;AACA,+B;AACA,2C;AACA,wB;AACA,kB;;AAEA,oC;AACA,wB;AACA,6D;AACA,Q;AACA,iC;AACA,K;;AAEA,gB;AACA,E;;;;;;;;;;;;;;;;;;;;ACnEA,8E;AACA,uC;AACA,8C;AACA,U;AACA,yB;AACA,qB;AACA,Y;AACA,kB;AACA,sE;AACA,kB;AACA,6C;AACA,0D;AACA,4E;AACA,yC;;AAEA,+C;AACA,8B;AACA,6D;AACA,0C;AACA,uB;;AAEA,gD;AACA,2D;AACA,0D;AACA,4D;AACA,gC;AACA,qB;AACA,c;AACA,yB;AACA,0C;AACA,8D;AACA,uB;AACA,0C;AACA,c;AACA,qC;AACA,mB;AACA,Y;AACA,uB;AACA,O;;AAEA,uE;AACA,kB;AACA,O;AACA,K;AACA,E;;AAEA,+E;AACA,0B;AACA,qE;AACA,kB;AACA,0E;AACA,E;;AAEA,+E;AACA,+D;AACA,yE;AACA,oD;AACA,6E;AACA,+E;AACA,gB;AACA,uE;AACA,2E;AACA,kB;AACA,yC;AACA,iB;;AAEA,sD;AACA,4E;;AAEA,uB;AACA,gB;;AAEA,oD;AACA,+C;AACA,gB;;AAEA,sE;AACA,6E;AACA,mE;AACA,2E;AACA,yE;AACA,2E;AACA,gC;AACA,mB;AACA,yD;AACA,kD;AACA,O;AACA,K;;AAEA,6B;AACA,iB;;AAEA,2E;AACA,6E;AACA,oD;AACA,8D;;AAEA,sD;AACA,gC;AACA,gB;;AAEA,O;AACA,wD;AACA,e;AACA,0E;AACA,gB;AACA,e;AACA,kC;AACA,4B;AACA,uD;AACA,uC;AACA,6E;AACA,+E;AACA,+B;AACA,0D;AACA,mB;AACA,Y;AACA,G;;AAEA,uD;AACA,E;;AAEA,6E;AACA,4C;AACA,kE;AACA,qE;AACA,4D;AACA,kB;;AAEA,oC;AACA,2C;AACA,kC;;AAEA,wE;AACA,sB;AACA,uB;AACA,wD;AACA,qB;AACA,+C;AACA,4C;AACA,yD;AACA,uD;AACA,sB;AACA,gC;AACA,8E;;AAEA,8E;AACA,8E;AACA,uC;AACA,yD;AACA,sE;AACA,a;AACA,qF;AACA,4D;AACA,iD;AACA,2E;AACA,6C;AACA,a;AACA,iD;AACA,2E;AACA,6C;AACA,a;;AAEA,qD;AACA,8E;AACA,yE;AACA,+D;AACA,4B;;AAEA,wB;AACA,sE;AACA,+E;AACA,+E;AACA,sC;AACA,oB;AACA,gB;AACA,0B;AACA,S;AACA,O;AACA,kC;AACA,M;AACA,yD;;AAEA,e;AACA,kC;;AAEA,gC;AACA,E;;AAEA,+B;AACA,mD;AACA,2C;AACA,oE;AACA,uB;AACA,sC;AACA,4C;AACA,+C;AACA,gC;AACA,yD;AACA,a;AACA,8B;AACA,E;;AAEA,kD;AACA,6C;AACA,qC;AACA,+B;AACA,K;AACA,E;;AAEA,0C;AACA,8C;AACA,C;;AAEA,0E;AACA,wC;AACA,uC;AACA,+C;AACA,E;;;;;;;;;;;;;;;;;;;;AC1NA,0E;AACA,kB;AACA,uE;AACA,oE;AACA,E","file":"/packages/minimongo.js","sourcesContent":["// XXX type checking on selectors (graceful error if malformed)\n\n// LocalCollection: a set of documents that supports queries and modifiers.\n\n// Cursor: a specification for a particular subset of documents, w/\n// a defined order, limit, and offset. creating a Cursor with LocalCollection.find(),\n\n// ObserveHandle: the return value of a live query.\n\nLocalCollection = function (name) {\n var self = this;\n self.name = name;\n // _id -> document (also containing id)\n self._docs = new LocalCollection._IdMap;\n\n self._observeQueue = new Meteor._SynchronousQueue();\n\n self.next_qid = 1; // live query id generator\n\n // qid -> live query object. keys:\n // ordered: bool. ordered queries have addedBefore/movedBefore callbacks.\n // results: array (ordered) or object (unordered) of current results\n // (aliased with self._docs!)\n // resultsSnapshot: snapshot of results. null if not paused.\n // cursor: Cursor object for the query.\n // selector, sorter, (callbacks): functions\n self.queries = {};\n\n // null if not saving originals; an IdMap from id to original document value if\n // saving originals. See comments before saveOriginals().\n self._savedOriginals = null;\n\n // True when observers are paused and we should not send callbacks.\n self.paused = false;\n};\n\nMinimongo = {};\n\n// Object exported only for unit testing.\n// Use it to export private functions to test in Tinytest.\nMinimongoTest = {};\n\nLocalCollection._applyChanges = function (doc, changeFields) {\n _.each(changeFields, function (value, key) {\n if (value === undefined)\n delete doc[key];\n else\n doc[key] = value;\n });\n};\n\nMinimongoError = function (message) {\n var e = new Error(message);\n e.name = \"MinimongoError\";\n return e;\n};\n\n\n// options may include sort, skip, limit, reactive\n// sort may be any of these forms:\n// {a: 1, b: -1}\n// [[\"a\", \"asc\"], [\"b\", \"desc\"]]\n// [\"a\", [\"b\", \"desc\"]]\n// (in the first form you're beholden to key enumeration order in\n// your javascript VM)\n//\n// reactive: if given, and false, don't register with Tracker (default\n// is true)\n//\n// XXX possibly should support retrieving a subset of fields? and\n// have it be a hint (ignored on the client, when not copying the\n// doc?)\n//\n// XXX sort does not yet support subkeys ('a.b') .. fix that!\n// XXX add one more sort form: \"key\"\n// XXX tests\nLocalCollection.prototype.find = function (selector, options) {\n // default syntax for everything is to omit the selector argument.\n // but if selector is explicitly passed in as false or undefined, we\n // want a selector that matches nothing.\n if (arguments.length === 0)\n selector = {};\n\n return new LocalCollection.Cursor(this, selector, options);\n};\n\n// don't call this ctor directly. use LocalCollection.find().\n\nLocalCollection.Cursor = function (collection, selector, options) {\n var self = this;\n if (!options) options = {};\n\n self.collection = collection;\n self.sorter = null;\n\n if (LocalCollection._selectorIsId(selector)) {\n // stash for fast path\n self._selectorId = selector;\n self.matcher = new Minimongo.Matcher(selector);\n } else {\n self._selectorId = undefined;\n self.matcher = new Minimongo.Matcher(selector);\n if (self.matcher.hasGeoQuery() || options.sort) {\n self.sorter = new Minimongo.Sorter(options.sort || [],\n { matcher: self.matcher });\n }\n }\n self.skip = options.skip;\n self.limit = options.limit;\n self.fields = options.fields;\n\n self._projectionFn = LocalCollection._compileProjection(self.fields || {});\n\n self._transform = LocalCollection.wrapTransform(options.transform);\n\n // by default, queries register w/ Tracker when it is available.\n if (typeof Tracker !== \"undefined\")\n self.reactive = (options.reactive === undefined) ? true : options.reactive;\n};\n\n// Since we don't actually have a \"nextObject\" interface, there's really no\n// reason to have a \"rewind\" interface. All it did was make multiple calls\n// to fetch/map/forEach return nothing the second time.\n// XXX COMPAT WITH 0.8.1\nLocalCollection.Cursor.prototype.rewind = function () {\n};\n\nLocalCollection.prototype.findOne = function (selector, options) {\n if (arguments.length === 0)\n selector = {};\n\n // NOTE: by setting limit 1 here, we end up using very inefficient\n // code that recomputes the whole query on each update. The upside is\n // that when you reactively depend on a findOne you only get\n // invalidated when the found object changes, not any object in the\n // collection. Most findOne will be by id, which has a fast path, so\n // this might not be a big deal. In most cases, invalidation causes\n // the called to re-query anyway, so this should be a net performance\n // improvement.\n options = options || {};\n options.limit = 1;\n\n return this.find(selector, options).fetch()[0];\n};\n\n/**\n * @callback IterationCallback\n * @param {Object} doc\n * @param {Number} index\n */\n/**\n * @summary Call `callback` once for each matching document, sequentially and synchronously.\n * @locus Anywhere\n * @method forEach\n * @instance\n * @memberOf Mongo.Cursor\n * @param {IterationCallback} callback Function to call. It will be called with three arguments: the document, a 0-based index, and cursor itself.\n * @param {Any} [thisArg] An object which will be the value of `this` inside `callback`.\n */\nLocalCollection.Cursor.prototype.forEach = function (callback, thisArg) {\n var self = this;\n\n var objects = self._getRawObjects({ordered: true});\n\n if (self.reactive) {\n self._depend({\n addedBefore: true,\n removed: true,\n changed: true,\n movedBefore: true});\n }\n\n _.each(objects, function (elt, i) {\n // This doubles as a clone operation.\n elt = self._projectionFn(elt);\n\n if (self._transform)\n elt = self._transform(elt);\n callback.call(thisArg, elt, i, self);\n });\n};\n\nLocalCollection.Cursor.prototype.getTransform = function () {\n return this._transform;\n};\n\n/**\n * @summary Map callback over all matching documents. Returns an Array.\n * @locus Anywhere\n * @method map\n * @instance\n * @memberOf Mongo.Cursor\n * @param {IterationCallback} callback Function to call. It will be called with three arguments: the document, a 0-based index, and cursor itself.\n * @param {Any} [thisArg] An object which will be the value of `this` inside `callback`.\n */\nLocalCollection.Cursor.prototype.map = function (callback, thisArg) {\n var self = this;\n var res = [];\n self.forEach(function (doc, index) {\n res.push(callback.call(thisArg, doc, index, self));\n });\n return res;\n};\n\n/**\n * @summary Return all matching documents as an Array.\n * @memberOf Mongo.Cursor\n * @method fetch\n * @instance\n * @locus Anywhere\n * @returns {Object[]}\n */\nLocalCollection.Cursor.prototype.fetch = function () {\n var self = this;\n var res = [];\n self.forEach(function (doc) {\n res.push(doc);\n });\n return res;\n};\n\n/**\n * @summary Returns the number of documents that match a query.\n * @memberOf Mongo.Cursor\n * @method count\n * @instance\n * @locus Anywhere\n * @returns {Number}\n */\nLocalCollection.Cursor.prototype.count = function () {\n var self = this;\n\n if (self.reactive)\n self._depend({added: true, removed: true},\n true /* allow the observe to be unordered */);\n\n return self._getRawObjects({ordered: true}).length;\n};\n\nLocalCollection.Cursor.prototype._publishCursor = function (sub) {\n var self = this;\n if (! self.collection.name)\n throw new Error(\"Can't publish a cursor from a collection without a name.\");\n var collection = self.collection.name;\n\n // XXX minimongo should not depend on mongo-livedata!\n return Mongo.Collection._publishCursor(self, sub, collection);\n};\n\nLocalCollection.Cursor.prototype._getCollectionName = function () {\n var self = this;\n return self.collection.name;\n};\n\nLocalCollection._observeChangesCallbacksAreOrdered = function (callbacks) {\n if (callbacks.added && callbacks.addedBefore)\n throw new Error(\"Please specify only one of added() and addedBefore()\");\n return !!(callbacks.addedBefore || callbacks.movedBefore);\n};\n\nLocalCollection._observeCallbacksAreOrdered = function (callbacks) {\n if (callbacks.addedAt && callbacks.added)\n throw new Error(\"Please specify only one of added() and addedAt()\");\n if (callbacks.changedAt && callbacks.changed)\n throw new Error(\"Please specify only one of changed() and changedAt()\");\n if (callbacks.removed && callbacks.removedAt)\n throw new Error(\"Please specify only one of removed() and removedAt()\");\n\n return !!(callbacks.addedAt || callbacks.movedTo || callbacks.changedAt\n || callbacks.removedAt);\n};\n\n// the handle that comes back from observe.\nLocalCollection.ObserveHandle = function () {};\n\n// options to contain:\n// * callbacks for observe():\n// - addedAt (document, atIndex)\n// - added (document)\n// - changedAt (newDocument, oldDocument, atIndex)\n// - changed (newDocument, oldDocument)\n// - removedAt (document, atIndex)\n// - removed (document)\n// - movedTo (document, oldIndex, newIndex)\n//\n// attributes available on returned query handle:\n// * stop(): end updates\n// * collection: the collection this query is querying\n//\n// iff x is a returned query handle, (x instanceof\n// LocalCollection.ObserveHandle) is true\n//\n// initial results delivered through added callback\n// XXX maybe callbacks should take a list of objects, to expose transactions?\n// XXX maybe support field limiting (to limit what you're notified on)\n\n_.extend(LocalCollection.Cursor.prototype, {\n /**\n * @summary Watch a query. Receive callbacks as the result set changes.\n * @locus Anywhere\n * @memberOf Mongo.Cursor\n * @instance\n * @param {Object} callbacks Functions to call to deliver the result set as it changes\n */\n observe: function (options) {\n var self = this;\n return LocalCollection._observeFromObserveChanges(self, options);\n },\n\n /**\n * @summary Watch a query. Receive callbacks as the result set changes. Only the differences between the old and new documents are passed to the callbacks.\n * @locus Anywhere\n * @memberOf Mongo.Cursor\n * @instance\n * @param {Object} callbacks Functions to call to deliver the result set as it changes\n */\n observeChanges: function (options) {\n var self = this;\n\n var ordered = LocalCollection._observeChangesCallbacksAreOrdered(options);\n\n // there are several places that assume you aren't combining skip/limit with\n // unordered observe. eg, update's EJSON.clone, and the \"there are several\"\n // comment in _modifyAndNotify\n // XXX allow skip/limit with unordered observe\n if (!options._allow_unordered && !ordered && (self.skip || self.limit))\n throw new Error(\"must use ordered observe (ie, 'addedBefore' instead of 'added') with skip or limit\");\n\n if (self.fields && (self.fields._id === 0 || self.fields._id === false))\n throw Error(\"You may not observe a cursor with {fields: {_id: 0}}\");\n\n var query = {\n matcher: self.matcher, // not fast pathed\n sorter: ordered && self.sorter,\n distances: (\n self.matcher.hasGeoQuery() && ordered && new LocalCollection._IdMap),\n resultsSnapshot: null,\n ordered: ordered,\n cursor: self,\n projectionFn: self._projectionFn\n };\n var qid;\n\n // Non-reactive queries call added[Before] and then never call anything\n // else.\n if (self.reactive) {\n qid = self.collection.next_qid++;\n self.collection.queries[qid] = query;\n }\n query.results = self._getRawObjects({\n ordered: ordered, distances: query.distances});\n if (self.collection.paused)\n query.resultsSnapshot = (ordered ? [] : new LocalCollection._IdMap);\n\n // wrap callbacks we were passed. callbacks only fire when not paused and\n // are never undefined\n // Filters out blacklisted fields according to cursor's projection.\n // XXX wrong place for this?\n\n // furthermore, callbacks enqueue until the operation we're working on is\n // done.\n var wrapCallback = function (f) {\n if (!f)\n return function () {};\n return function (/*args*/) {\n var context = this;\n var args = arguments;\n\n if (self.collection.paused)\n return;\n\n self.collection._observeQueue.queueTask(function () {\n f.apply(context, args);\n });\n };\n };\n query.added = wrapCallback(options.added);\n query.changed = wrapCallback(options.changed);\n query.removed = wrapCallback(options.removed);\n if (ordered) {\n query.addedBefore = wrapCallback(options.addedBefore);\n query.movedBefore = wrapCallback(options.movedBefore);\n }\n\n if (!options._suppress_initial && !self.collection.paused) {\n // XXX unify ordered and unordered interface\n var each = ordered\n ? _.bind(_.each, null, query.results)\n : _.bind(query.results.forEach, query.results);\n each(function (doc) {\n var fields = EJSON.clone(doc);\n\n delete fields._id;\n if (ordered)\n query.addedBefore(doc._id, self._projectionFn(fields), null);\n query.added(doc._id, self._projectionFn(fields));\n });\n }\n\n var handle = new LocalCollection.ObserveHandle;\n _.extend(handle, {\n collection: self.collection,\n stop: function () {\n if (self.reactive)\n delete self.collection.queries[qid];\n }\n });\n\n if (self.reactive && Tracker.active) {\n // XXX in many cases, the same observe will be recreated when\n // the current autorun is rerun. we could save work by\n // letting it linger across rerun and potentially get\n // repurposed if the same observe is performed, using logic\n // similar to that of Meteor.subscribe.\n Tracker.onInvalidate(function () {\n handle.stop();\n });\n }\n // run the observe callbacks resulting from the initial contents\n // before we leave the observe.\n self.collection._observeQueue.drain();\n\n return handle;\n }\n});\n\n// Returns a collection of matching objects, but doesn't deep copy them.\n//\n// If ordered is set, returns a sorted array, respecting sorter, skip, and limit\n// properties of the query. if sorter is falsey, no sort -- you get the natural\n// order.\n//\n// If ordered is not set, returns an object mapping from ID to doc (sorter, skip\n// and limit should not be set).\n//\n// If ordered is set and this cursor is a $near geoquery, then this function\n// will use an _IdMap to track each distance from the $near argument point in\n// order to use it as a sort key. If an _IdMap is passed in the 'distances'\n// argument, this function will clear it and use it for this purpose (otherwise\n// it will just create its own _IdMap). The observeChanges implementation uses\n// this to remember the distances after this function returns.\nLocalCollection.Cursor.prototype._getRawObjects = function (options) {\n var self = this;\n options = options || {};\n\n // XXX use OrderedDict instead of array, and make IdMap and OrderedDict\n // compatible\n var results = options.ordered ? [] : new LocalCollection._IdMap;\n\n // fast path for single ID value\n if (self._selectorId !== undefined) {\n // If you have non-zero skip and ask for a single id, you get\n // nothing. This is so it matches the behavior of the '{_id: foo}'\n // path.\n if (self.skip)\n return results;\n\n var selectedDoc = self.collection._docs.get(self._selectorId);\n if (selectedDoc) {\n if (options.ordered)\n results.push(selectedDoc);\n else\n results.set(self._selectorId, selectedDoc);\n }\n return results;\n }\n\n // slow path for arbitrary selector, sort, skip, limit\n\n // in the observeChanges case, distances is actually part of the \"query\" (ie,\n // live results set) object. in other cases, distances is only used inside\n // this function.\n var distances;\n if (self.matcher.hasGeoQuery() && options.ordered) {\n if (options.distances) {\n distances = options.distances;\n distances.clear();\n } else {\n distances = new LocalCollection._IdMap();\n }\n }\n\n self.collection._docs.forEach(function (doc, id) {\n var matchResult = self.matcher.documentMatches(doc);\n if (matchResult.result) {\n if (options.ordered) {\n results.push(doc);\n if (distances && matchResult.distance !== undefined)\n distances.set(id, matchResult.distance);\n } else {\n results.set(id, doc);\n }\n }\n // Fast path for limited unsorted queries.\n // XXX 'length' check here seems wrong for ordered\n if (self.limit && !self.skip && !self.sorter &&\n results.length === self.limit)\n return false; // break\n return true; // continue\n });\n\n if (!options.ordered)\n return results;\n\n if (self.sorter) {\n var comparator = self.sorter.getComparator({distances: distances});\n results.sort(comparator);\n }\n\n var idx_start = self.skip || 0;\n var idx_end = self.limit ? (self.limit + idx_start) : results.length;\n return results.slice(idx_start, idx_end);\n};\n\n// XXX Maybe we need a version of observe that just calls a callback if\n// anything changed.\nLocalCollection.Cursor.prototype._depend = function (changers, _allow_unordered) {\n var self = this;\n\n if (Tracker.active) {\n var v = new Tracker.Dependency;\n v.depend();\n var notifyChange = _.bind(v.changed, v);\n\n var options = {\n _suppress_initial: true,\n _allow_unordered: _allow_unordered\n };\n _.each(['added', 'changed', 'removed', 'addedBefore', 'movedBefore'],\n function (fnName) {\n if (changers[fnName])\n options[fnName] = notifyChange;\n });\n\n // observeChanges will stop() when this computation is invalidated\n self.observeChanges(options);\n }\n};\n\n// XXX enforce rule that field names can't start with '$' or contain '.'\n// (real mongodb does in fact enforce this)\n// XXX possibly enforce that 'undefined' does not appear (we assume\n// this in our handling of null and $exists)\nLocalCollection.prototype.insert = function (doc, callback) {\n var self = this;\n doc = EJSON.clone(doc);\n\n if (!_.has(doc, '_id')) {\n // if you really want to use ObjectIDs, set this global.\n // Mongo.Collection specifies its own ids and does not use this code.\n doc._id = LocalCollection._useOID ? new LocalCollection._ObjectID()\n : Random.id();\n }\n var id = doc._id;\n\n if (self._docs.has(id))\n throw MinimongoError(\"Duplicate _id '\" + id + \"'\");\n\n self._saveOriginal(id, undefined);\n self._docs.set(id, doc);\n\n var queriesToRecompute = [];\n // trigger live queries that match\n for (var qid in self.queries) {\n var query = self.queries[qid];\n var matchResult = query.matcher.documentMatches(doc);\n if (matchResult.result) {\n if (query.distances && matchResult.distance !== undefined)\n query.distances.set(id, matchResult.distance);\n if (query.cursor.skip || query.cursor.limit)\n queriesToRecompute.push(qid);\n else\n LocalCollection._insertInResults(query, doc);\n }\n }\n\n _.each(queriesToRecompute, function (qid) {\n if (self.queries[qid])\n self._recomputeResults(self.queries[qid]);\n });\n self._observeQueue.drain();\n\n // Defer because the caller likely doesn't expect the callback to be run\n // immediately.\n if (callback)\n Meteor.defer(function () {\n callback(null, id);\n });\n return id;\n};\n\n// Iterates over a subset of documents that could match selector; calls\n// f(doc, id) on each of them. Specifically, if selector specifies\n// specific _id's, it only looks at those. doc is *not* cloned: it is the\n// same object that is in _docs.\nLocalCollection.prototype._eachPossiblyMatchingDoc = function (selector, f) {\n var self = this;\n var specificIds = LocalCollection._idsMatchedBySelector(selector);\n if (specificIds) {\n for (var i = 0; i < specificIds.length; ++i) {\n var id = specificIds[i];\n var doc = self._docs.get(id);\n if (doc) {\n var breakIfFalse = f(doc, id);\n if (breakIfFalse === false)\n break;\n }\n }\n } else {\n self._docs.forEach(f);\n }\n};\n\nLocalCollection.prototype.remove = function (selector, callback) {\n var self = this;\n\n // Easy special case: if we're not calling observeChanges callbacks and we're\n // not saving originals and we got asked to remove everything, then just empty\n // everything directly.\n if (self.paused && !self._savedOriginals && EJSON.equals(selector, {})) {\n var result = self._docs.size();\n self._docs.clear();\n _.each(self.queries, function (query) {\n if (query.ordered) {\n query.results = [];\n } else {\n query.results.clear();\n }\n });\n if (callback) {\n Meteor.defer(function () {\n callback(null, result);\n });\n }\n return result;\n }\n\n var matcher = new Minimongo.Matcher(selector);\n var remove = [];\n self._eachPossiblyMatchingDoc(selector, function (doc, id) {\n if (matcher.documentMatches(doc).result)\n remove.push(id);\n });\n\n var queriesToRecompute = [];\n var queryRemove = [];\n for (var i = 0; i < remove.length; i++) {\n var removeId = remove[i];\n var removeDoc = self._docs.get(removeId);\n _.each(self.queries, function (query, qid) {\n if (query.matcher.documentMatches(removeDoc).result) {\n if (query.cursor.skip || query.cursor.limit)\n queriesToRecompute.push(qid);\n else\n queryRemove.push({qid: qid, doc: removeDoc});\n }\n });\n self._saveOriginal(removeId, removeDoc);\n self._docs.remove(removeId);\n }\n\n // run live query callbacks _after_ we've removed the documents.\n _.each(queryRemove, function (remove) {\n var query = self.queries[remove.qid];\n if (query) {\n query.distances && query.distances.remove(remove.doc._id);\n LocalCollection._removeFromResults(query, remove.doc);\n }\n });\n _.each(queriesToRecompute, function (qid) {\n var query = self.queries[qid];\n if (query)\n self._recomputeResults(query);\n });\n self._observeQueue.drain();\n result = remove.length;\n if (callback)\n Meteor.defer(function () {\n callback(null, result);\n });\n return result;\n};\n\n// XXX atomicity: if multi is true, and one modification fails, do\n// we rollback the whole operation, or what?\nLocalCollection.prototype.update = function (selector, mod, options, callback) {\n var self = this;\n if (! callback && options instanceof Function) {\n callback = options;\n options = null;\n }\n if (!options) options = {};\n\n var matcher = new Minimongo.Matcher(selector);\n\n // Save the original results of any query that we might need to\n // _recomputeResults on, because _modifyAndNotify will mutate the objects in\n // it. (We don't need to save the original results of paused queries because\n // they already have a resultsSnapshot and we won't be diffing in\n // _recomputeResults.)\n var qidToOriginalResults = {};\n _.each(self.queries, function (query, qid) {\n // XXX for now, skip/limit implies ordered observe, so query.results is\n // always an array\n if ((query.cursor.skip || query.cursor.limit) && ! self.paused)\n qidToOriginalResults[qid] = EJSON.clone(query.results);\n });\n var recomputeQids = {};\n\n var updateCount = 0;\n\n self._eachPossiblyMatchingDoc(selector, function (doc, id) {\n var queryResult = matcher.documentMatches(doc);\n if (queryResult.result) {\n // XXX Should we save the original even if mod ends up being a no-op?\n self._saveOriginal(id, doc);\n self._modifyAndNotify(doc, mod, recomputeQids, queryResult.arrayIndices);\n ++updateCount;\n if (!options.multi)\n return false; // break\n }\n return true;\n });\n\n _.each(recomputeQids, function (dummy, qid) {\n var query = self.queries[qid];\n if (query)\n self._recomputeResults(query, qidToOriginalResults[qid]);\n });\n self._observeQueue.drain();\n\n // If we are doing an upsert, and we didn't modify any documents yet, then\n // it's time to do an insert. Figure out what document we are inserting, and\n // generate an id for it.\n var insertedId;\n if (updateCount === 0 && options.upsert) {\n var newDoc = LocalCollection._removeDollarOperators(selector);\n LocalCollection._modify(newDoc, mod, {isInsert: true});\n if (! newDoc._id && options.insertedId)\n newDoc._id = options.insertedId;\n insertedId = self.insert(newDoc);\n updateCount = 1;\n }\n\n // Return the number of affected documents, or in the upsert case, an object\n // containing the number of affected docs and the id of the doc that was\n // inserted, if any.\n var result;\n if (options._returnObject) {\n result = {\n numberAffected: updateCount\n };\n if (insertedId !== undefined)\n result.insertedId = insertedId;\n } else {\n result = updateCount;\n }\n\n if (callback)\n Meteor.defer(function () {\n callback(null, result);\n });\n return result;\n};\n\n// A convenience wrapper on update. LocalCollection.upsert(sel, mod) is\n// equivalent to LocalCollection.update(sel, mod, { upsert: true, _returnObject:\n// true }).\nLocalCollection.prototype.upsert = function (selector, mod, options, callback) {\n var self = this;\n if (! callback && typeof options === \"function\") {\n callback = options;\n options = {};\n }\n return self.update(selector, mod, _.extend({}, options, {\n upsert: true,\n _returnObject: true\n }), callback);\n};\n\nLocalCollection.prototype._modifyAndNotify = function (\n doc, mod, recomputeQids, arrayIndices) {\n var self = this;\n\n var matched_before = {};\n for (var qid in self.queries) {\n var query = self.queries[qid];\n if (query.ordered) {\n matched_before[qid] = query.matcher.documentMatches(doc).result;\n } else {\n // Because we don't support skip or limit (yet) in unordered queries, we\n // can just do a direct lookup.\n matched_before[qid] = query.results.has(doc._id);\n }\n }\n\n var old_doc = EJSON.clone(doc);\n\n LocalCollection._modify(doc, mod, {arrayIndices: arrayIndices});\n\n for (qid in self.queries) {\n query = self.queries[qid];\n var before = matched_before[qid];\n var afterMatch = query.matcher.documentMatches(doc);\n var after = afterMatch.result;\n if (after && query.distances && afterMatch.distance !== undefined)\n query.distances.set(doc._id, afterMatch.distance);\n\n if (query.cursor.skip || query.cursor.limit) {\n // We need to recompute any query where the doc may have been in the\n // cursor's window either before or after the update. (Note that if skip\n // or limit is set, \"before\" and \"after\" being true do not necessarily\n // mean that the document is in the cursor's output after skip/limit is\n // applied... but if they are false, then the document definitely is NOT\n // in the output. So it's safe to skip recompute if neither before or\n // after are true.)\n if (before || after)\n recomputeQids[qid] = true;\n } else if (before && !after) {\n LocalCollection._removeFromResults(query, doc);\n } else if (!before && after) {\n LocalCollection._insertInResults(query, doc);\n } else if (before && after) {\n LocalCollection._updateInResults(query, doc, old_doc);\n }\n }\n};\n\n// XXX the sorted-query logic below is laughably inefficient. we'll\n// need to come up with a better datastructure for this.\n//\n// XXX the logic for observing with a skip or a limit is even more\n// laughably inefficient. we recompute the whole results every time!\n\nLocalCollection._insertInResults = function (query, doc) {\n var fields = EJSON.clone(doc);\n delete fields._id;\n if (query.ordered) {\n if (!query.sorter) {\n query.addedBefore(doc._id, query.projectionFn(fields), null);\n query.results.push(doc);\n } else {\n var i = LocalCollection._insertInSortedList(\n query.sorter.getComparator({distances: query.distances}),\n query.results, doc);\n var next = query.results[i+1];\n if (next)\n next = next._id;\n else\n next = null;\n query.addedBefore(doc._id, query.projectionFn(fields), next);\n }\n query.added(doc._id, query.projectionFn(fields));\n } else {\n query.added(doc._id, query.projectionFn(fields));\n query.results.set(doc._id, doc);\n }\n};\n\nLocalCollection._removeFromResults = function (query, doc) {\n if (query.ordered) {\n var i = LocalCollection._findInOrderedResults(query, doc);\n query.removed(doc._id);\n query.results.splice(i, 1);\n } else {\n var id = doc._id; // in case callback mutates doc\n query.removed(doc._id);\n query.results.remove(id);\n }\n};\n\nLocalCollection._updateInResults = function (query, doc, old_doc) {\n if (!EJSON.equals(doc._id, old_doc._id))\n throw new Error(\"Can't change a doc's _id while updating\");\n var projectionFn = query.projectionFn;\n var changedFields = LocalCollection._makeChangedFields(\n projectionFn(doc), projectionFn(old_doc));\n\n if (!query.ordered) {\n if (!_.isEmpty(changedFields)) {\n query.changed(doc._id, changedFields);\n query.results.set(doc._id, doc);\n }\n return;\n }\n\n var orig_idx = LocalCollection._findInOrderedResults(query, doc);\n\n if (!_.isEmpty(changedFields))\n query.changed(doc._id, changedFields);\n if (!query.sorter)\n return;\n\n // just take it out and put it back in again, and see if the index\n // changes\n query.results.splice(orig_idx, 1);\n var new_idx = LocalCollection._insertInSortedList(\n query.sorter.getComparator({distances: query.distances}),\n query.results, doc);\n if (orig_idx !== new_idx) {\n var next = query.results[new_idx+1];\n if (next)\n next = next._id;\n else\n next = null;\n query.movedBefore && query.movedBefore(doc._id, next);\n }\n};\n\n// Recomputes the results of a query and runs observe callbacks for the\n// difference between the previous results and the current results (unless\n// paused). Used for skip/limit queries.\n//\n// When this is used by insert or remove, it can just use query.results for the\n// old results (and there's no need to pass in oldResults), because these\n// operations don't mutate the documents in the collection. Update needs to pass\n// in an oldResults which was deep-copied before the modifier was applied.\n//\n// oldResults is guaranteed to be ignored if the query is not paused.\nLocalCollection.prototype._recomputeResults = function (query, oldResults) {\n var self = this;\n if (! self.paused && ! oldResults)\n oldResults = query.results;\n if (query.distances)\n query.distances.clear();\n query.results = query.cursor._getRawObjects({\n ordered: query.ordered, distances: query.distances});\n\n if (! self.paused) {\n LocalCollection._diffQueryChanges(\n query.ordered, oldResults, query.results, query,\n { projectionFn: query.projectionFn });\n }\n};\n\n\nLocalCollection._findInOrderedResults = function (query, doc) {\n if (!query.ordered)\n throw new Error(\"Can't call _findInOrderedResults on unordered query\");\n for (var i = 0; i < query.results.length; i++)\n if (query.results[i] === doc)\n return i;\n throw Error(\"object missing from query\");\n};\n\n// This binary search puts a value between any equal values, and the first\n// lesser value.\nLocalCollection._binarySearch = function (cmp, array, value) {\n var first = 0, rangeLength = array.length;\n\n while (rangeLength > 0) {\n var halfRange = Math.floor(rangeLength/2);\n if (cmp(value, array[first + halfRange]) >= 0) {\n first += halfRange + 1;\n rangeLength -= halfRange + 1;\n } else {\n rangeLength = halfRange;\n }\n }\n return first;\n};\n\nLocalCollection._insertInSortedList = function (cmp, array, value) {\n if (array.length === 0) {\n array.push(value);\n return 0;\n }\n\n var idx = LocalCollection._binarySearch(cmp, array, value);\n array.splice(idx, 0, value);\n return idx;\n};\n\n// To track what documents are affected by a piece of code, call saveOriginals()\n// before it and retrieveOriginals() after it. retrieveOriginals returns an\n// object whose keys are the ids of the documents that were affected since the\n// call to saveOriginals(), and the values are equal to the document's contents\n// at the time of saveOriginals. (In the case of an inserted document, undefined\n// is the value.) You must alternate between calls to saveOriginals() and\n// retrieveOriginals().\nLocalCollection.prototype.saveOriginals = function () {\n var self = this;\n if (self._savedOriginals)\n throw new Error(\"Called saveOriginals twice without retrieveOriginals\");\n self._savedOriginals = new LocalCollection._IdMap;\n};\nLocalCollection.prototype.retrieveOriginals = function () {\n var self = this;\n if (!self._savedOriginals)\n throw new Error(\"Called retrieveOriginals without saveOriginals\");\n\n var originals = self._savedOriginals;\n self._savedOriginals = null;\n return originals;\n};\n\nLocalCollection.prototype._saveOriginal = function (id, doc) {\n var self = this;\n // Are we even trying to save originals?\n if (!self._savedOriginals)\n return;\n // Have we previously mutated the original (and so 'doc' is not actually\n // original)? (Note the 'has' check rather than truth: we store undefined\n // here for inserted docs!)\n if (self._savedOriginals.has(id))\n return;\n self._savedOriginals.set(id, EJSON.clone(doc));\n};\n\n// Pause the observers. No callbacks from observers will fire until\n// 'resumeObservers' is called.\nLocalCollection.prototype.pauseObservers = function () {\n // No-op if already paused.\n if (this.paused)\n return;\n\n // Set the 'paused' flag such that new observer messages don't fire.\n this.paused = true;\n\n // Take a snapshot of the query results for each query.\n for (var qid in this.queries) {\n var query = this.queries[qid];\n\n query.resultsSnapshot = EJSON.clone(query.results);\n }\n};\n\n// Resume the observers. Observers immediately receive change\n// notifications to bring them to the current state of the\n// database. Note that this is not just replaying all the changes that\n// happened during the pause, it is a smarter 'coalesced' diff.\nLocalCollection.prototype.resumeObservers = function () {\n var self = this;\n // No-op if not paused.\n if (!this.paused)\n return;\n\n // Unset the 'paused' flag. Make sure to do this first, otherwise\n // observer methods won't actually fire when we trigger them.\n this.paused = false;\n\n for (var qid in this.queries) {\n var query = self.queries[qid];\n // Diff the current results against the snapshot and send to observers.\n // pass the query object for its observer callbacks.\n LocalCollection._diffQueryChanges(\n query.ordered, query.resultsSnapshot, query.results, query,\n { projectionFn: query.projectionFn });\n query.resultsSnapshot = null;\n }\n self._observeQueue.drain();\n};\n\n\n// NB: used by livedata\nLocalCollection._idStringify = function (id) {\n if (id instanceof LocalCollection._ObjectID) {\n return id.valueOf();\n } else if (typeof id === 'string') {\n if (id === \"\") {\n return id;\n } else if (id.substr(0, 1) === \"-\" || // escape previously dashed strings\n id.substr(0, 1) === \"~\" || // escape escaped numbers, true, false\n LocalCollection._looksLikeObjectID(id) || // escape object-id-form strings\n id.substr(0, 1) === '{') { // escape object-form strings, for maybe implementing later\n return \"-\" + id;\n } else {\n return id; // other strings go through unchanged.\n }\n } else if (id === undefined) {\n return '-';\n } else if (typeof id === 'object' && id !== null) {\n throw new Error(\"Meteor does not currently support objects other than ObjectID as ids\");\n } else { // Numbers, true, false, null\n return \"~\" + JSON.stringify(id);\n }\n};\n\n\n// NB: used by livedata\nLocalCollection._idParse = function (id) {\n if (id === \"\") {\n return id;\n } else if (id === '-') {\n return undefined;\n } else if (id.substr(0, 1) === '-') {\n return id.substr(1);\n } else if (id.substr(0, 1) === '~') {\n return JSON.parse(id.substr(1));\n } else if (LocalCollection._looksLikeObjectID(id)) {\n return new LocalCollection._ObjectID(id);\n } else {\n return id;\n }\n};\n\nLocalCollection._makeChangedFields = function (newDoc, oldDoc) {\n var fields = {};\n LocalCollection._diffObjects(oldDoc, newDoc, {\n leftOnly: function (key, value) {\n fields[key] = undefined;\n },\n rightOnly: function (key, value) {\n fields[key] = value;\n },\n both: function (key, leftValue, rightValue) {\n if (!EJSON.equals(leftValue, rightValue))\n fields[key] = rightValue;\n }\n });\n return fields;\n};\n","// Wrap a transform function to return objects that have the _id field\n// of the untransformed document. This ensures that subsystems such as\n// the observe-sequence package that call `observe` can keep track of\n// the documents identities.\n//\n// - Require that it returns objects\n// - If the return value has an _id field, verify that it matches the\n// original _id field\n// - If the return value doesn't have an _id field, add it back.\nLocalCollection.wrapTransform = function (transform) {\n if (! transform)\n return null;\n\n // No need to doubly-wrap transforms.\n if (transform.__wrappedTransform__)\n return transform;\n\n var wrapped = function (doc) {\n if (!_.has(doc, '_id')) {\n // XXX do we ever have a transform on the oplog's collection? because that\n // collection has no _id.\n throw new Error(\"can only transform documents with _id\");\n }\n\n var id = doc._id;\n // XXX consider making tracker a weak dependency and checking Package.tracker here\n var transformed = Tracker.nonreactive(function () {\n return transform(doc);\n });\n\n if (!isPlainObject(transformed)) {\n throw new Error(\"transform must return object\");\n }\n\n if (_.has(transformed, '_id')) {\n if (!EJSON.equals(transformed._id, id)) {\n throw new Error(\"transformed document can't have different _id\");\n }\n } else {\n transformed._id = id;\n }\n return transformed;\n };\n wrapped.__wrappedTransform__ = true;\n return wrapped;\n};\n","// Like _.isArray, but doesn't regard polyfilled Uint8Arrays on old browsers as\n// arrays.\n// XXX maybe this should be EJSON.isArray\nisArray = function (x) {\n return _.isArray(x) && !EJSON.isBinary(x);\n};\n\n// XXX maybe this should be EJSON.isObject, though EJSON doesn't know about\n// RegExp\n// XXX note that _type(undefined) === 3!!!!\nisPlainObject = LocalCollection._isPlainObject = function (x) {\n return x && LocalCollection._f._type(x) === 3;\n};\n\nisIndexable = function (x) {\n return isArray(x) || isPlainObject(x);\n};\n\n// Returns true if this is an object with at least one key and all keys begin\n// with $. Unless inconsistentOK is set, throws if some keys begin with $ and\n// others don't.\nisOperatorObject = function (valueSelector, inconsistentOK) {\n if (!isPlainObject(valueSelector))\n return false;\n\n var theseAreOperators = undefined;\n _.each(valueSelector, function (value, selKey) {\n var thisIsOperator = selKey.substr(0, 1) === '$';\n if (theseAreOperators === undefined) {\n theseAreOperators = thisIsOperator;\n } else if (theseAreOperators !== thisIsOperator) {\n if (!inconsistentOK)\n throw new Error(\"Inconsistent operator: \" +\n JSON.stringify(valueSelector));\n theseAreOperators = false;\n }\n });\n return !!theseAreOperators; // {} has no operators\n};\n\n\n// string can be converted to integer\nisNumericKey = function (s) {\n return /^[0-9]+$/.test(s);\n};\n","// The minimongo selector compiler!\n\n// Terminology:\n// - a \"selector\" is the EJSON object representing a selector\n// - a \"matcher\" is its compiled form (whether a full Minimongo.Matcher\n// object or one of the component lambdas that matches parts of it)\n// - a \"result object\" is an object with a \"result\" field and maybe\n// distance and arrayIndices.\n// - a \"branched value\" is an object with a \"value\" field and maybe\n// \"dontIterate\" and \"arrayIndices\".\n// - a \"document\" is a top-level object that can be stored in a collection.\n// - a \"lookup function\" is a function that takes in a document and returns\n// an array of \"branched values\".\n// - a \"branched matcher\" maps from an array of branched values to a result\n// object.\n// - an \"element matcher\" maps from a single value to a bool.\n\n// Main entry point.\n// var matcher = new Minimongo.Matcher({a: {$gt: 5}});\n// if (matcher.documentMatches({a: 7})) ...\nMinimongo.Matcher = function (selector) {\n var self = this;\n // A set (object mapping string -> *) of all of the document paths looked\n // at by the selector. Also includes the empty string if it may look at any\n // path (eg, $where).\n self._paths = {};\n // Set to true if compilation finds a $near.\n self._hasGeoQuery = false;\n // Set to true if compilation finds a $where.\n self._hasWhere = false;\n // Set to false if compilation finds anything other than a simple equality or\n // one or more of '$gt', '$gte', '$lt', '$lte', '$ne', '$in', '$nin' used with\n // scalars as operands.\n self._isSimple = true;\n // Set to a dummy document which always matches this Matcher. Or set to null\n // if such document is too hard to find.\n self._matchingDocument = undefined;\n // A clone of the original selector. It may just be a function if the user\n // passed in a function; otherwise is definitely an object (eg, IDs are\n // translated into {_id: ID} first. Used by canBecomeTrueByModifier and\n // Sorter._useWithMatcher.\n self._selector = null;\n self._docMatcher = self._compileSelector(selector);\n};\n\n_.extend(Minimongo.Matcher.prototype, {\n documentMatches: function (doc) {\n if (!doc || typeof doc !== \"object\") {\n throw Error(\"documentMatches needs a document\");\n }\n return this._docMatcher(doc);\n },\n hasGeoQuery: function () {\n return this._hasGeoQuery;\n },\n hasWhere: function () {\n return this._hasWhere;\n },\n isSimple: function () {\n return this._isSimple;\n },\n\n // Given a selector, return a function that takes one argument, a\n // document. It returns a result object.\n _compileSelector: function (selector) {\n var self = this;\n // you can pass a literal function instead of a selector\n if (selector instanceof Function) {\n self._isSimple = false;\n self._selector = selector;\n self._recordPathUsed('');\n return function (doc) {\n return {result: !!selector.call(doc)};\n };\n }\n\n // shorthand -- scalars match _id\n if (LocalCollection._selectorIsId(selector)) {\n self._selector = {_id: selector};\n self._recordPathUsed('_id');\n return function (doc) {\n return {result: EJSON.equals(doc._id, selector)};\n };\n }\n\n // protect against dangerous selectors. falsey and {_id: falsey} are both\n // likely programmer error, and not what you want, particularly for\n // destructive operations.\n if (!selector || (('_id' in selector) && !selector._id)) {\n self._isSimple = false;\n return nothingMatcher;\n }\n\n // Top level can't be an array or true or binary.\n if (typeof(selector) === 'boolean' || isArray(selector) ||\n EJSON.isBinary(selector))\n throw new Error(\"Invalid selector: \" + selector);\n\n self._selector = EJSON.clone(selector);\n return compileDocumentSelector(selector, self, {isRoot: true});\n },\n _recordPathUsed: function (path) {\n this._paths[path] = true;\n },\n // Returns a list of key paths the given selector is looking for. It includes\n // the empty string if there is a $where.\n _getPaths: function () {\n return _.keys(this._paths);\n }\n});\n\n\n// Takes in a selector that could match a full document (eg, the original\n// selector). Returns a function mapping document->result object.\n//\n// matcher is the Matcher object we are compiling.\n//\n// If this is the root document selector (ie, not wrapped in $and or the like),\n// then isRoot is true. (This is used by $near.)\nvar compileDocumentSelector = function (docSelector, matcher, options) {\n options = options || {};\n var docMatchers = [];\n _.each(docSelector, function (subSelector, key) {\n if (key.substr(0, 1) === '$') {\n // Outer operators are either logical operators (they recurse back into\n // this function), or $where.\n if (!_.has(LOGICAL_OPERATORS, key))\n throw new Error(\"Unrecognized logical operator: \" + key);\n matcher._isSimple = false;\n docMatchers.push(LOGICAL_OPERATORS[key](subSelector, matcher,\n options.inElemMatch));\n } else {\n // Record this path, but only if we aren't in an elemMatcher, since in an\n // elemMatch this is a path inside an object in an array, not in the doc\n // root.\n if (!options.inElemMatch)\n matcher._recordPathUsed(key);\n var lookUpByIndex = makeLookupFunction(key);\n var valueMatcher =\n compileValueSelector(subSelector, matcher, options.isRoot);\n docMatchers.push(function (doc) {\n var branchValues = lookUpByIndex(doc);\n return valueMatcher(branchValues);\n });\n }\n });\n\n return andDocumentMatchers(docMatchers);\n};\n\n// Takes in a selector that could match a key-indexed value in a document; eg,\n// {$gt: 5, $lt: 9}, or a regular expression, or any non-expression object (to\n// indicate equality). Returns a branched matcher: a function mapping\n// [branched value]->result object.\nvar compileValueSelector = function (valueSelector, matcher, isRoot) {\n if (valueSelector instanceof RegExp) {\n matcher._isSimple = false;\n return convertElementMatcherToBranchedMatcher(\n regexpElementMatcher(valueSelector));\n } else if (isOperatorObject(valueSelector)) {\n return operatorBranchedMatcher(valueSelector, matcher, isRoot);\n } else {\n return convertElementMatcherToBranchedMatcher(\n equalityElementMatcher(valueSelector));\n }\n};\n\n// Given an element matcher (which evaluates a single value), returns a branched\n// value (which evaluates the element matcher on all the branches and returns a\n// more structured return value possibly including arrayIndices).\nvar convertElementMatcherToBranchedMatcher = function (\n elementMatcher, options) {\n options = options || {};\n return function (branches) {\n var expanded = branches;\n if (!options.dontExpandLeafArrays) {\n expanded = expandArraysInBranches(\n branches, options.dontIncludeLeafArrays);\n }\n var ret = {};\n ret.result = _.any(expanded, function (element) {\n var matched = elementMatcher(element.value);\n\n // Special case for $elemMatch: it means \"true, and use this as an array\n // index if I didn't already have one\".\n if (typeof matched === 'number') {\n // XXX This code dates from when we only stored a single array index\n // (for the outermost array). Should we be also including deeper array\n // indices from the $elemMatch match?\n if (!element.arrayIndices)\n element.arrayIndices = [matched];\n matched = true;\n }\n\n // If some element matched, and it's tagged with array indices, include\n // those indices in our result object.\n if (matched && element.arrayIndices)\n ret.arrayIndices = element.arrayIndices;\n\n return matched;\n });\n return ret;\n };\n};\n\n// Takes a RegExp object and returns an element matcher.\nregexpElementMatcher = function (regexp) {\n return function (value) {\n if (value instanceof RegExp) {\n // Comparing two regexps means seeing if the regexps are identical\n // (really!). Underscore knows how.\n return _.isEqual(value, regexp);\n }\n // Regexps only work against strings.\n if (typeof value !== 'string')\n return false;\n\n // Reset regexp's state to avoid inconsistent matching for objects with the\n // same value on consecutive calls of regexp.test. This happens only if the\n // regexp has the 'g' flag. Also note that ES6 introduces a new flag 'y' for\n // which we should *not* change the lastIndex but MongoDB doesn't support\n // either of these flags.\n regexp.lastIndex = 0;\n\n return regexp.test(value);\n };\n};\n\n// Takes something that is not an operator object and returns an element matcher\n// for equality with that thing.\nequalityElementMatcher = function (elementSelector) {\n if (isOperatorObject(elementSelector))\n throw Error(\"Can't create equalityValueSelector for operator object\");\n\n // Special-case: null and undefined are equal (if you got undefined in there\n // somewhere, or if you got it due to some branch being non-existent in the\n // weird special case), even though they aren't with EJSON.equals.\n if (elementSelector == null) { // undefined or null\n return function (value) {\n return value == null; // undefined or null\n };\n }\n\n return function (value) {\n return LocalCollection._f._equal(elementSelector, value);\n };\n};\n\n// Takes an operator object (an object with $ keys) and returns a branched\n// matcher for it.\nvar operatorBranchedMatcher = function (valueSelector, matcher, isRoot) {\n // Each valueSelector works separately on the various branches. So one\n // operator can match one branch and another can match another branch. This\n // is OK.\n\n var operatorMatchers = [];\n _.each(valueSelector, function (operand, operator) {\n // XXX we should actually implement $eq, which is new in 2.6\n var simpleRange = _.contains(['$lt', '$lte', '$gt', '$gte'], operator) &&\n _.isNumber(operand);\n var simpleInequality = operator === '$ne' && !_.isObject(operand);\n var simpleInclusion = _.contains(['$in', '$nin'], operator) &&\n _.isArray(operand) && !_.any(operand, _.isObject);\n\n if (! (operator === '$eq' || simpleRange ||\n simpleInclusion || simpleInequality)) {\n matcher._isSimple = false;\n }\n\n if (_.has(VALUE_OPERATORS, operator)) {\n operatorMatchers.push(\n VALUE_OPERATORS[operator](operand, valueSelector, matcher, isRoot));\n } else if (_.has(ELEMENT_OPERATORS, operator)) {\n var options = ELEMENT_OPERATORS[operator];\n operatorMatchers.push(\n convertElementMatcherToBranchedMatcher(\n options.compileElementSelector(\n operand, valueSelector, matcher),\n options));\n } else {\n throw new Error(\"Unrecognized operator: \" + operator);\n }\n });\n\n return andBranchedMatchers(operatorMatchers);\n};\n\nvar compileArrayOfDocumentSelectors = function (\n selectors, matcher, inElemMatch) {\n if (!isArray(selectors) || _.isEmpty(selectors))\n throw Error(\"$and/$or/$nor must be nonempty array\");\n return _.map(selectors, function (subSelector) {\n if (!isPlainObject(subSelector))\n throw Error(\"$or/$and/$nor entries need to be full objects\");\n return compileDocumentSelector(\n subSelector, matcher, {inElemMatch: inElemMatch});\n });\n};\n\n// Operators that appear at the top level of a document selector.\nvar LOGICAL_OPERATORS = {\n $and: function (subSelector, matcher, inElemMatch) {\n var matchers = compileArrayOfDocumentSelectors(\n subSelector, matcher, inElemMatch);\n return andDocumentMatchers(matchers);\n },\n\n $or: function (subSelector, matcher, inElemMatch) {\n var matchers = compileArrayOfDocumentSelectors(\n subSelector, matcher, inElemMatch);\n\n // Special case: if there is only one matcher, use it directly, *preserving*\n // any arrayIndices it returns.\n if (matchers.length === 1)\n return matchers[0];\n\n return function (doc) {\n var result = _.any(matchers, function (f) {\n return f(doc).result;\n });\n // $or does NOT set arrayIndices when it has multiple\n // sub-expressions. (Tested against MongoDB.)\n return {result: result};\n };\n },\n\n $nor: function (subSelector, matcher, inElemMatch) {\n var matchers = compileArrayOfDocumentSelectors(\n subSelector, matcher, inElemMatch);\n return function (doc) {\n var result = _.all(matchers, function (f) {\n return !f(doc).result;\n });\n // Never set arrayIndices, because we only match if nothing in particular\n // \"matched\" (and because this is consistent with MongoDB).\n return {result: result};\n };\n },\n\n $where: function (selectorValue, matcher) {\n // Record that *any* path may be used.\n matcher._recordPathUsed('');\n matcher._hasWhere = true;\n if (!(selectorValue instanceof Function)) {\n // XXX MongoDB seems to have more complex logic to decide where or or not\n // to add \"return\"; not sure exactly what it is.\n selectorValue = Function(\"obj\", \"return \" + selectorValue);\n }\n return function (doc) {\n // We make the document available as both `this` and `obj`.\n // XXX not sure what we should do if this throws\n return {result: selectorValue.call(doc, doc)};\n };\n },\n\n // This is just used as a comment in the query (in MongoDB, it also ends up in\n // query logs); it has no effect on the actual selection.\n $comment: function () {\n return function () {\n return {result: true};\n };\n }\n};\n\n// Returns a branched matcher that matches iff the given matcher does not.\n// Note that this implicitly \"deMorganizes\" the wrapped function. ie, it\n// means that ALL branch values need to fail to match innerBranchedMatcher.\nvar invertBranchedMatcher = function (branchedMatcher) {\n return function (branchValues) {\n var invertMe = branchedMatcher(branchValues);\n // We explicitly choose to strip arrayIndices here: it doesn't make sense to\n // say \"update the array element that does not match something\", at least\n // in mongo-land.\n return {result: !invertMe.result};\n };\n};\n\n// Operators that (unlike LOGICAL_OPERATORS) pertain to individual paths in a\n// document, but (unlike ELEMENT_OPERATORS) do not have a simple definition as\n// \"match each branched value independently and combine with\n// convertElementMatcherToBranchedMatcher\".\nvar VALUE_OPERATORS = {\n $not: function (operand, valueSelector, matcher) {\n return invertBranchedMatcher(compileValueSelector(operand, matcher));\n },\n $ne: function (operand) {\n return invertBranchedMatcher(convertElementMatcherToBranchedMatcher(\n equalityElementMatcher(operand)));\n },\n $nin: function (operand) {\n return invertBranchedMatcher(convertElementMatcherToBranchedMatcher(\n ELEMENT_OPERATORS.$in.compileElementSelector(operand)));\n },\n $exists: function (operand) {\n var exists = convertElementMatcherToBranchedMatcher(function (value) {\n return value !== undefined;\n });\n return operand ? exists : invertBranchedMatcher(exists);\n },\n // $options just provides options for $regex; its logic is inside $regex\n $options: function (operand, valueSelector) {\n if (!_.has(valueSelector, '$regex'))\n throw Error(\"$options needs a $regex\");\n return everythingMatcher;\n },\n // $maxDistance is basically an argument to $near\n $maxDistance: function (operand, valueSelector) {\n if (!valueSelector.$near)\n throw Error(\"$maxDistance needs a $near\");\n return everythingMatcher;\n },\n $all: function (operand, valueSelector, matcher) {\n if (!isArray(operand))\n throw Error(\"$all requires array\");\n // Not sure why, but this seems to be what MongoDB does.\n if (_.isEmpty(operand))\n return nothingMatcher;\n\n var branchedMatchers = [];\n _.each(operand, function (criterion) {\n // XXX handle $all/$elemMatch combination\n if (isOperatorObject(criterion))\n throw Error(\"no $ expressions in $all\");\n // This is always a regexp or equality selector.\n branchedMatchers.push(compileValueSelector(criterion, matcher));\n });\n // andBranchedMatchers does NOT require all selectors to return true on the\n // SAME branch.\n return andBranchedMatchers(branchedMatchers);\n },\n $near: function (operand, valueSelector, matcher, isRoot) {\n if (!isRoot)\n throw Error(\"$near can't be inside another $ operator\");\n matcher._hasGeoQuery = true;\n\n // There are two kinds of geodata in MongoDB: coordinate pairs and\n // GeoJSON. They use different distance metrics, too. GeoJSON queries are\n // marked with a $geometry property.\n\n var maxDistance, point, distance;\n if (isPlainObject(operand) && _.has(operand, '$geometry')) {\n // GeoJSON \"2dsphere\" mode.\n maxDistance = operand.$maxDistance;\n point = operand.$geometry;\n distance = function (value) {\n // XXX: for now, we don't calculate the actual distance between, say,\n // polygon and circle. If people care about this use-case it will get\n // a priority.\n if (!value || !value.type)\n return null;\n if (value.type === \"Point\") {\n return GeoJSON.pointDistance(point, value);\n } else {\n return GeoJSON.geometryWithinRadius(value, point, maxDistance)\n ? 0 : maxDistance + 1;\n }\n };\n } else {\n maxDistance = valueSelector.$maxDistance;\n if (!isArray(operand) && !isPlainObject(operand))\n throw Error(\"$near argument must be coordinate pair or GeoJSON\");\n point = pointToArray(operand);\n distance = function (value) {\n if (!isArray(value) && !isPlainObject(value))\n return null;\n return distanceCoordinatePairs(point, value);\n };\n }\n\n return function (branchedValues) {\n // There might be multiple points in the document that match the given\n // field. Only one of them needs to be within $maxDistance, but we need to\n // evaluate all of them and use the nearest one for the implicit sort\n // specifier. (That's why we can't just use ELEMENT_OPERATORS here.)\n //\n // Note: This differs from MongoDB's implementation, where a document will\n // actually show up *multiple times* in the result set, with one entry for\n // each within-$maxDistance branching point.\n branchedValues = expandArraysInBranches(branchedValues);\n var result = {result: false};\n _.each(branchedValues, function (branch) {\n var curDistance = distance(branch.value);\n // Skip branches that aren't real points or are too far away.\n if (curDistance === null || curDistance > maxDistance)\n return;\n // Skip anything that's a tie.\n if (result.distance !== undefined && result.distance <= curDistance)\n return;\n result.result = true;\n result.distance = curDistance;\n if (!branch.arrayIndices)\n delete result.arrayIndices;\n else\n result.arrayIndices = branch.arrayIndices;\n });\n return result;\n };\n }\n};\n\n// Helpers for $near.\nvar distanceCoordinatePairs = function (a, b) {\n a = pointToArray(a);\n b = pointToArray(b);\n var x = a[0] - b[0];\n var y = a[1] - b[1];\n if (_.isNaN(x) || _.isNaN(y))\n return null;\n return Math.sqrt(x * x + y * y);\n};\n// Makes sure we get 2 elements array and assume the first one to be x and\n// the second one to y no matter what user passes.\n// In case user passes { lon: x, lat: y } returns [x, y]\nvar pointToArray = function (point) {\n return _.map(point, _.identity);\n};\n\n// Helper for $lt/$gt/$lte/$gte.\nvar makeInequality = function (cmpValueComparator) {\n return {\n compileElementSelector: function (operand) {\n // Arrays never compare false with non-arrays for any inequality.\n // XXX This was behavior we observed in pre-release MongoDB 2.5, but\n // it seems to have been reverted.\n // See https://jira.mongodb.org/browse/SERVER-11444\n if (isArray(operand)) {\n return function () {\n return false;\n };\n }\n\n // Special case: consider undefined and null the same (so true with\n // $gte/$lte).\n if (operand === undefined)\n operand = null;\n\n var operandType = LocalCollection._f._type(operand);\n\n return function (value) {\n if (value === undefined)\n value = null;\n // Comparisons are never true among things of different type (except\n // null vs undefined).\n if (LocalCollection._f._type(value) !== operandType)\n return false;\n return cmpValueComparator(LocalCollection._f._cmp(value, operand));\n };\n }\n };\n};\n\n// Each element selector contains:\n// - compileElementSelector, a function with args:\n// - operand - the \"right hand side\" of the operator\n// - valueSelector - the \"context\" for the operator (so that $regex can find\n// $options)\n// - matcher - the Matcher this is going into (so that $elemMatch can compile\n// more things)\n// returning a function mapping a single value to bool.\n// - dontExpandLeafArrays, a bool which prevents expandArraysInBranches from\n// being called\n// - dontIncludeLeafArrays, a bool which causes an argument to be passed to\n// expandArraysInBranches if it is called\nELEMENT_OPERATORS = {\n $lt: makeInequality(function (cmpValue) {\n return cmpValue < 0;\n }),\n $gt: makeInequality(function (cmpValue) {\n return cmpValue > 0;\n }),\n $lte: makeInequality(function (cmpValue) {\n return cmpValue <= 0;\n }),\n $gte: makeInequality(function (cmpValue) {\n return cmpValue >= 0;\n }),\n $mod: {\n compileElementSelector: function (operand) {\n if (!(isArray(operand) && operand.length === 2\n && typeof(operand[0]) === 'number'\n && typeof(operand[1]) === 'number')) {\n throw Error(\"argument to $mod must be an array of two numbers\");\n }\n // XXX could require to be ints or round or something\n var divisor = operand[0];\n var remainder = operand[1];\n return function (value) {\n return typeof value === 'number' && value % divisor === remainder;\n };\n }\n },\n $in: {\n compileElementSelector: function (operand) {\n if (!isArray(operand))\n throw Error(\"$in needs an array\");\n\n var elementMatchers = [];\n _.each(operand, function (option) {\n if (option instanceof RegExp)\n elementMatchers.push(regexpElementMatcher(option));\n else if (isOperatorObject(option))\n throw Error(\"cannot nest $ under $in\");\n else\n elementMatchers.push(equalityElementMatcher(option));\n });\n\n return function (value) {\n // Allow {a: {$in: [null]}} to match when 'a' does not exist.\n if (value === undefined)\n value = null;\n return _.any(elementMatchers, function (e) {\n return e(value);\n });\n };\n }\n },\n $size: {\n // {a: [[5, 5]]} must match {a: {$size: 1}} but not {a: {$size: 2}}, so we\n // don't want to consider the element [5,5] in the leaf array [[5,5]] as a\n // possible value.\n dontExpandLeafArrays: true,\n compileElementSelector: function (operand) {\n if (typeof operand === 'string') {\n // Don't ask me why, but by experimentation, this seems to be what Mongo\n // does.\n operand = 0;\n } else if (typeof operand !== 'number') {\n throw Error(\"$size needs a number\");\n }\n return function (value) {\n return isArray(value) && value.length === operand;\n };\n }\n },\n $type: {\n // {a: [5]} must not match {a: {$type: 4}} (4 means array), but it should\n // match {a: {$type: 1}} (1 means number), and {a: [[5]]} must match {$a:\n // {$type: 4}}. Thus, when we see a leaf array, we *should* expand it but\n // should *not* include it itself.\n dontIncludeLeafArrays: true,\n compileElementSelector: function (operand) {\n if (typeof operand !== 'number')\n throw Error(\"$type needs a number\");\n return function (value) {\n return value !== undefined\n && LocalCollection._f._type(value) === operand;\n };\n }\n },\n $regex: {\n compileElementSelector: function (operand, valueSelector) {\n if (!(typeof operand === 'string' || operand instanceof RegExp))\n throw Error(\"$regex has to be a string or RegExp\");\n\n var regexp;\n if (valueSelector.$options !== undefined) {\n // Options passed in $options (even the empty string) always overrides\n // options in the RegExp object itself. (See also\n // Mongo.Collection._rewriteSelector.)\n\n // Be clear that we only support the JS-supported options, not extended\n // ones (eg, Mongo supports x and s). Ideally we would implement x and s\n // by transforming the regexp, but not today...\n if (/[^gim]/.test(valueSelector.$options))\n throw new Error(\"Only the i, m, and g regexp options are supported\");\n\n var regexSource = operand instanceof RegExp ? operand.source : operand;\n regexp = new RegExp(regexSource, valueSelector.$options);\n } else if (operand instanceof RegExp) {\n regexp = operand;\n } else {\n regexp = new RegExp(operand);\n }\n return regexpElementMatcher(regexp);\n }\n },\n $elemMatch: {\n dontExpandLeafArrays: true,\n compileElementSelector: function (operand, valueSelector, matcher) {\n if (!isPlainObject(operand))\n throw Error(\"$elemMatch need an object\");\n\n var subMatcher, isDocMatcher;\n if (isOperatorObject(operand, true)) {\n subMatcher = compileValueSelector(operand, matcher);\n isDocMatcher = false;\n } else {\n // This is NOT the same as compileValueSelector(operand), and not just\n // because of the slightly different calling convention.\n // {$elemMatch: {x: 3}} means \"an element has a field x:3\", not\n // \"consists only of a field x:3\". Also, regexps and sub-$ are allowed.\n subMatcher = compileDocumentSelector(operand, matcher,\n {inElemMatch: true});\n isDocMatcher = true;\n }\n\n return function (value) {\n if (!isArray(value))\n return false;\n for (var i = 0; i < value.length; ++i) {\n var arrayElement = value[i];\n var arg;\n if (isDocMatcher) {\n // We can only match {$elemMatch: {b: 3}} against objects.\n // (We can also match against arrays, if there's numeric indices,\n // eg {$elemMatch: {'0.b': 3}} or {$elemMatch: {0: 3}}.)\n if (!isPlainObject(arrayElement) && !isArray(arrayElement))\n return false;\n arg = arrayElement;\n } else {\n // dontIterate ensures that {a: {$elemMatch: {$gt: 5}}} matches\n // {a: [8]} but not {a: [[8]]}\n arg = [{value: arrayElement, dontIterate: true}];\n }\n // XXX support $near in $elemMatch by propagating $distance?\n if (subMatcher(arg).result)\n return i; // specially understood to mean \"use as arrayIndices\"\n }\n return false;\n };\n }\n }\n};\n\n// makeLookupFunction(key) returns a lookup function.\n//\n// A lookup function takes in a document and returns an array of matching\n// branches. If no arrays are found while looking up the key, this array will\n// have exactly one branches (possibly 'undefined', if some segment of the key\n// was not found).\n//\n// If arrays are found in the middle, this can have more than one element, since\n// we \"branch\". When we \"branch\", if there are more key segments to look up,\n// then we only pursue branches that are plain objects (not arrays or scalars).\n// This means we can actually end up with no branches!\n//\n// We do *NOT* branch on arrays that are found at the end (ie, at the last\n// dotted member of the key). We just return that array; if you want to\n// effectively \"branch\" over the array's values, post-process the lookup\n// function with expandArraysInBranches.\n//\n// Each branch is an object with keys:\n// - value: the value at the branch\n// - dontIterate: an optional bool; if true, it means that 'value' is an array\n// that expandArraysInBranches should NOT expand. This specifically happens\n// when there is a numeric index in the key, and ensures the\n// perhaps-surprising MongoDB behavior where {'a.0': 5} does NOT\n// match {a: [[5]]}.\n// - arrayIndices: if any array indexing was done during lookup (either due to\n// explicit numeric indices or implicit branching), this will be an array of\n// the array indices used, from outermost to innermost; it is falsey or\n// absent if no array index is used. If an explicit numeric index is used,\n// the index will be followed in arrayIndices by the string 'x'.\n//\n// Note: arrayIndices is used for two purposes. First, it is used to\n// implement the '$' modifier feature, which only ever looks at its first\n// element.\n//\n// Second, it is used for sort key generation, which needs to be able to tell\n// the difference between different paths. Moreover, it needs to\n// differentiate between explicit and implicit branching, which is why\n// there's the somewhat hacky 'x' entry: this means that explicit and\n// implicit array lookups will have different full arrayIndices paths. (That\n// code only requires that different paths have different arrayIndices; it\n// doesn't actually \"parse\" arrayIndices. As an alternative, arrayIndices\n// could contain objects with flags like \"implicit\", but I think that only\n// makes the code surrounding them more complex.)\n//\n// (By the way, this field ends up getting passed around a lot without\n// cloning, so never mutate any arrayIndices field/var in this package!)\n//\n//\n// At the top level, you may only pass in a plain object or array.\n//\n// See the test 'minimongo - lookup' for some examples of what lookup functions\n// return.\nmakeLookupFunction = function (key, options) {\n options = options || {};\n var parts = key.split('.');\n var firstPart = parts.length ? parts[0] : '';\n var firstPartIsNumeric = isNumericKey(firstPart);\n var nextPartIsNumeric = parts.length >= 2 && isNumericKey(parts[1]);\n var lookupRest;\n if (parts.length > 1) {\n lookupRest = makeLookupFunction(parts.slice(1).join('.'));\n }\n\n var omitUnnecessaryFields = function (retVal) {\n if (!retVal.dontIterate)\n delete retVal.dontIterate;\n if (retVal.arrayIndices && !retVal.arrayIndices.length)\n delete retVal.arrayIndices;\n return retVal;\n };\n\n // Doc will always be a plain object or an array.\n // apply an explicit numeric index, an array.\n return function (doc, arrayIndices) {\n if (!arrayIndices)\n arrayIndices = [];\n\n if (isArray(doc)) {\n // If we're being asked to do an invalid lookup into an array (non-integer\n // or out-of-bounds), return no results (which is different from returning\n // a single undefined result, in that `null` equality checks won't match).\n if (!(firstPartIsNumeric && firstPart < doc.length))\n return [];\n\n // Remember that we used this array index. Include an 'x' to indicate that\n // the previous index came from being considered as an explicit array\n // index (not branching).\n arrayIndices = arrayIndices.concat(+firstPart, 'x');\n }\n\n // Do our first lookup.\n var firstLevel = doc[firstPart];\n\n // If there is no deeper to dig, return what we found.\n //\n // If what we found is an array, most value selectors will choose to treat\n // the elements of the array as matchable values in their own right, but\n // that's done outside of the lookup function. (Exceptions to this are $size\n // and stuff relating to $elemMatch. eg, {a: {$size: 2}} does not match {a:\n // [[1, 2]]}.)\n //\n // That said, if we just did an *explicit* array lookup (on doc) to find\n // firstLevel, and firstLevel is an array too, we do NOT want value\n // selectors to iterate over it. eg, {'a.0': 5} does not match {a: [[5]]}.\n // So in that case, we mark the return value as \"don't iterate\".\n if (!lookupRest) {\n return [omitUnnecessaryFields({\n value: firstLevel,\n dontIterate: isArray(doc) && isArray(firstLevel),\n arrayIndices: arrayIndices})];\n }\n\n // We need to dig deeper. But if we can't, because what we've found is not\n // an array or plain object, we're done. If we just did a numeric index into\n // an array, we return nothing here (this is a change in Mongo 2.5 from\n // Mongo 2.4, where {'a.0.b': null} stopped matching {a: [5]}). Otherwise,\n // return a single `undefined` (which can, for example, match via equality\n // with `null`).\n if (!isIndexable(firstLevel)) {\n if (isArray(doc))\n return [];\n return [omitUnnecessaryFields({value: undefined,\n arrayIndices: arrayIndices})];\n }\n\n var result = [];\n var appendToResult = function (more) {\n Array.prototype.push.apply(result, more);\n };\n\n // Dig deeper: look up the rest of the parts on whatever we've found.\n // (lookupRest is smart enough to not try to do invalid lookups into\n // firstLevel if it's an array.)\n appendToResult(lookupRest(firstLevel, arrayIndices));\n\n // If we found an array, then in *addition* to potentially treating the next\n // part as a literal integer lookup, we should also \"branch\": try to look up\n // the rest of the parts on each array element in parallel.\n //\n // In this case, we *only* dig deeper into array elements that are plain\n // objects. (Recall that we only got this far if we have further to dig.)\n // This makes sense: we certainly don't dig deeper into non-indexable\n // objects. And it would be weird to dig into an array: it's simpler to have\n // a rule that explicit integer indexes only apply to an outer array, not to\n // an array you find after a branching search.\n //\n // In the special case of a numeric part in a *sort selector* (not a query\n // selector), we skip the branching: we ONLY allow the numeric part to mean\n // \"look up this index\" in that case, not \"also look up this index in all\n // the elements of the array\".\n if (isArray(firstLevel) && !(nextPartIsNumeric && options.forSort)) {\n _.each(firstLevel, function (branch, arrayIndex) {\n if (isPlainObject(branch)) {\n appendToResult(lookupRest(\n branch,\n arrayIndices.concat(arrayIndex)));\n }\n });\n }\n\n return result;\n };\n};\nMinimongoTest.makeLookupFunction = makeLookupFunction;\n\nexpandArraysInBranches = function (branches, skipTheArrays) {\n var branchesOut = [];\n _.each(branches, function (branch) {\n var thisIsArray = isArray(branch.value);\n // We include the branch itself, *UNLESS* we it's an array that we're going\n // to iterate and we're told to skip arrays. (That's right, we include some\n // arrays even skipTheArrays is true: these are arrays that were found via\n // explicit numerical indices.)\n if (!(skipTheArrays && thisIsArray && !branch.dontIterate)) {\n branchesOut.push({\n value: branch.value,\n arrayIndices: branch.arrayIndices\n });\n }\n if (thisIsArray && !branch.dontIterate) {\n _.each(branch.value, function (leaf, i) {\n branchesOut.push({\n value: leaf,\n arrayIndices: (branch.arrayIndices || []).concat(i)\n });\n });\n }\n });\n return branchesOut;\n};\n\nvar nothingMatcher = function (docOrBranchedValues) {\n return {result: false};\n};\n\nvar everythingMatcher = function (docOrBranchedValues) {\n return {result: true};\n};\n\n\n// NB: We are cheating and using this function to implement \"AND\" for both\n// \"document matchers\" and \"branched matchers\". They both return result objects\n// but the argument is different: for the former it's a whole doc, whereas for\n// the latter it's an array of \"branched values\".\nvar andSomeMatchers = function (subMatchers) {\n if (subMatchers.length === 0)\n return everythingMatcher;\n if (subMatchers.length === 1)\n return subMatchers[0];\n\n return function (docOrBranches) {\n var ret = {};\n ret.result = _.all(subMatchers, function (f) {\n var subResult = f(docOrBranches);\n // Copy a 'distance' number out of the first sub-matcher that has\n // one. Yes, this means that if there are multiple $near fields in a\n // query, something arbitrary happens; this appears to be consistent with\n // Mongo.\n if (subResult.result && subResult.distance !== undefined\n && ret.distance === undefined) {\n ret.distance = subResult.distance;\n }\n // Similarly, propagate arrayIndices from sub-matchers... but to match\n // MongoDB behavior, this time the *last* sub-matcher with arrayIndices\n // wins.\n if (subResult.result && subResult.arrayIndices) {\n ret.arrayIndices = subResult.arrayIndices;\n }\n return subResult.result;\n });\n\n // If we didn't actually match, forget any extra metadata we came up with.\n if (!ret.result) {\n delete ret.distance;\n delete ret.arrayIndices;\n }\n return ret;\n };\n};\n\nvar andDocumentMatchers = andSomeMatchers;\nvar andBranchedMatchers = andSomeMatchers;\n\n\n// helpers used by compiled selector code\nLocalCollection._f = {\n // XXX for _all and _in, consider building 'inquery' at compile time..\n\n _type: function (v) {\n if (typeof v === \"number\")\n return 1;\n if (typeof v === \"string\")\n return 2;\n if (typeof v === \"boolean\")\n return 8;\n if (isArray(v))\n return 4;\n if (v === null)\n return 10;\n if (v instanceof RegExp)\n // note that typeof(/x/) === \"object\"\n return 11;\n if (typeof v === \"function\")\n return 13;\n if (v instanceof Date)\n return 9;\n if (EJSON.isBinary(v))\n return 5;\n if (v instanceof LocalCollection._ObjectID)\n return 7;\n return 3; // object\n\n // XXX support some/all of these:\n // 14, symbol\n // 15, javascript code with scope\n // 16, 18: 32-bit/64-bit integer\n // 17, timestamp\n // 255, minkey\n // 127, maxkey\n },\n\n // deep equality test: use for literal document and array matches\n _equal: function (a, b) {\n return EJSON.equals(a, b, {keyOrderSensitive: true});\n },\n\n // maps a type code to a value that can be used to sort values of\n // different types\n _typeorder: function (t) {\n // http://www.mongodb.org/display/DOCS/What+is+the+Compare+Order+for+BSON+Types\n // XXX what is the correct sort position for Javascript code?\n // ('100' in the matrix below)\n // XXX minkey/maxkey\n return [-1, // (not a type)\n 1, // number\n 2, // string\n 3, // object\n 4, // array\n 5, // binary\n -1, // deprecated\n 6, // ObjectID\n 7, // bool\n 8, // Date\n 0, // null\n 9, // RegExp\n -1, // deprecated\n 100, // JS code\n 2, // deprecated (symbol)\n 100, // JS code\n 1, // 32-bit int\n 8, // Mongo timestamp\n 1 // 64-bit int\n ][t];\n },\n\n // compare two values of unknown type according to BSON ordering\n // semantics. (as an extension, consider 'undefined' to be less than\n // any other value.) return negative if a is less, positive if b is\n // less, or 0 if equal\n _cmp: function (a, b) {\n if (a === undefined)\n return b === undefined ? 0 : -1;\n if (b === undefined)\n return 1;\n var ta = LocalCollection._f._type(a);\n var tb = LocalCollection._f._type(b);\n var oa = LocalCollection._f._typeorder(ta);\n var ob = LocalCollection._f._typeorder(tb);\n if (oa !== ob)\n return oa < ob ? -1 : 1;\n if (ta !== tb)\n // XXX need to implement this if we implement Symbol or integers, or\n // Timestamp\n throw Error(\"Missing type coercion logic in _cmp\");\n if (ta === 7) { // ObjectID\n // Convert to string.\n ta = tb = 2;\n a = a.toHexString();\n b = b.toHexString();\n }\n if (ta === 9) { // Date\n // Convert to millis.\n ta = tb = 1;\n a = a.getTime();\n b = b.getTime();\n }\n\n if (ta === 1) // double\n return a - b;\n if (tb === 2) // string\n return a < b ? -1 : (a === b ? 0 : 1);\n if (ta === 3) { // Object\n // this could be much more efficient in the expected case ...\n var to_array = function (obj) {\n var ret = [];\n for (var key in obj) {\n ret.push(key);\n ret.push(obj[key]);\n }\n return ret;\n };\n return LocalCollection._f._cmp(to_array(a), to_array(b));\n }\n if (ta === 4) { // Array\n for (var i = 0; ; i++) {\n if (i === a.length)\n return (i === b.length) ? 0 : -1;\n if (i === b.length)\n return 1;\n var s = LocalCollection._f._cmp(a[i], b[i]);\n if (s !== 0)\n return s;\n }\n }\n if (ta === 5) { // binary\n // Surprisingly, a small binary blob is always less than a large one in\n // Mongo.\n if (a.length !== b.length)\n return a.length - b.length;\n for (i = 0; i < a.length; i++) {\n if (a[i] < b[i])\n return -1;\n if (a[i] > b[i])\n return 1;\n }\n return 0;\n }\n if (ta === 8) { // boolean\n if (a) return b ? 0 : 1;\n return b ? -1 : 0;\n }\n if (ta === 10) // null\n return 0;\n if (ta === 11) // regexp\n throw Error(\"Sorting not supported on regular expression\"); // XXX\n // 13: javascript code\n // 14: symbol\n // 15: javascript code with scope\n // 16: 32-bit integer\n // 17: timestamp\n // 18: 64-bit integer\n // 255: minkey\n // 127: maxkey\n if (ta === 13) // javascript code\n throw Error(\"Sorting not supported on Javascript code\"); // XXX\n throw Error(\"Unknown type to sort\");\n }\n};\n\n// Oddball function used by upsert.\nLocalCollection._removeDollarOperators = function (selector) {\n var selectorDoc = {};\n for (var k in selector)\n if (k.substr(0, 1) !== '$')\n selectorDoc[k] = selector[k];\n return selectorDoc;\n};\n","// Give a sort spec, which can be in any of these forms:\n// {\"key1\": 1, \"key2\": -1}\n// [[\"key1\", \"asc\"], [\"key2\", \"desc\"]]\n// [\"key1\", [\"key2\", \"desc\"]]\n//\n// (.. with the first form being dependent on the key enumeration\n// behavior of your javascript VM, which usually does what you mean in\n// this case if the key names don't look like integers ..)\n//\n// return a function that takes two objects, and returns -1 if the\n// first object comes first in order, 1 if the second object comes\n// first, or 0 if neither object comes before the other.\n\nMinimongo.Sorter = function (spec, options) {\n var self = this;\n options = options || {};\n\n self._sortSpecParts = [];\n\n var addSpecPart = function (path, ascending) {\n if (!path)\n throw Error(\"sort keys must be non-empty\");\n if (path.charAt(0) === '$')\n throw Error(\"unsupported sort key: \" + path);\n self._sortSpecParts.push({\n path: path,\n lookup: makeLookupFunction(path, {forSort: true}),\n ascending: ascending\n });\n };\n\n if (spec instanceof Array) {\n for (var i = 0; i < spec.length; i++) {\n if (typeof spec[i] === \"string\") {\n addSpecPart(spec[i], true);\n } else {\n addSpecPart(spec[i][0], spec[i][1] !== \"desc\");\n }\n }\n } else if (typeof spec === \"object\") {\n _.each(spec, function (value, key) {\n addSpecPart(key, value >= 0);\n });\n } else {\n throw Error(\"Bad sort specification: \" + JSON.stringify(spec));\n }\n\n // To implement affectedByModifier, we piggy-back on top of Matcher's\n // affectedByModifier code; we create a selector that is affected by the same\n // modifiers as this sort order. This is only implemented on the server.\n if (self.affectedByModifier) {\n var selector = {};\n _.each(self._sortSpecParts, function (spec) {\n selector[spec.path] = 1;\n });\n self._selectorForAffectedByModifier = new Minimongo.Matcher(selector);\n }\n\n self._keyComparator = composeComparators(\n _.map(self._sortSpecParts, function (spec, i) {\n return self._keyFieldComparator(i);\n }));\n\n // If you specify a matcher for this Sorter, _keyFilter may be set to a\n // function which selects whether or not a given \"sort key\" (tuple of values\n // for the different sort spec fields) is compatible with the selector.\n self._keyFilter = null;\n options.matcher && self._useWithMatcher(options.matcher);\n};\n\n// In addition to these methods, sorter_project.js defines combineIntoProjection\n// on the server only.\n_.extend(Minimongo.Sorter.prototype, {\n getComparator: function (options) {\n var self = this;\n\n // If we have no distances, just use the comparator from the source\n // specification (which defaults to \"everything is equal\".\n if (!options || !options.distances) {\n return self._getBaseComparator();\n }\n\n var distances = options.distances;\n\n // Return a comparator which first tries the sort specification, and if that\n // says \"it's equal\", breaks ties using $near distances.\n return composeComparators([self._getBaseComparator(), function (a, b) {\n if (!distances.has(a._id))\n throw Error(\"Missing distance for \" + a._id);\n if (!distances.has(b._id))\n throw Error(\"Missing distance for \" + b._id);\n return distances.get(a._id) - distances.get(b._id);\n }]);\n },\n\n _getPaths: function () {\n var self = this;\n return _.pluck(self._sortSpecParts, 'path');\n },\n\n // Finds the minimum key from the doc, according to the sort specs. (We say\n // \"minimum\" here but this is with respect to the sort spec, so \"descending\"\n // sort fields mean we're finding the max for that field.)\n //\n // Note that this is NOT \"find the minimum value of the first field, the\n // minimum value of the second field, etc\"... it's \"choose the\n // lexicographically minimum value of the key vector, allowing only keys which\n // you can find along the same paths\". ie, for a doc {a: [{x: 0, y: 5}, {x:\n // 1, y: 3}]} with sort spec {'a.x': 1, 'a.y': 1}, the only keys are [0,5] and\n // [1,3], and the minimum key is [0,5]; notably, [0,3] is NOT a key.\n _getMinKeyFromDoc: function (doc) {\n var self = this;\n var minKey = null;\n\n self._generateKeysFromDoc(doc, function (key) {\n if (!self._keyCompatibleWithSelector(key))\n return;\n\n if (minKey === null) {\n minKey = key;\n return;\n }\n if (self._compareKeys(key, minKey) < 0) {\n minKey = key;\n }\n });\n\n // This could happen if our key filter somehow filters out all the keys even\n // though somehow the selector matches.\n if (minKey === null)\n throw Error(\"sort selector found no keys in doc?\");\n return minKey;\n },\n\n _keyCompatibleWithSelector: function (key) {\n var self = this;\n return !self._keyFilter || self._keyFilter(key);\n },\n\n // Iterates over each possible \"key\" from doc (ie, over each branch), calling\n // 'cb' with the key.\n _generateKeysFromDoc: function (doc, cb) {\n var self = this;\n\n if (self._sortSpecParts.length === 0)\n throw new Error(\"can't generate keys without a spec\");\n\n // maps index -> ({'' -> value} or {path -> value})\n var valuesByIndexAndPath = [];\n\n var pathFromIndices = function (indices) {\n return indices.join(',') + ',';\n };\n\n var knownPaths = null;\n\n _.each(self._sortSpecParts, function (spec, whichField) {\n // Expand any leaf arrays that we find, and ignore those arrays\n // themselves. (We never sort based on an array itself.)\n var branches = expandArraysInBranches(spec.lookup(doc), true);\n\n // If there are no values for a key (eg, key goes to an empty array),\n // pretend we found one null value.\n if (!branches.length)\n branches = [{value: null}];\n\n var usedPaths = false;\n valuesByIndexAndPath[whichField] = {};\n _.each(branches, function (branch) {\n if (!branch.arrayIndices) {\n // If there are no array indices for a branch, then it must be the\n // only branch, because the only thing that produces multiple branches\n // is the use of arrays.\n if (branches.length > 1)\n throw Error(\"multiple branches but no array used?\");\n valuesByIndexAndPath[whichField][''] = branch.value;\n return;\n }\n\n usedPaths = true;\n var path = pathFromIndices(branch.arrayIndices);\n if (_.has(valuesByIndexAndPath[whichField], path))\n throw Error(\"duplicate path: \" + path);\n valuesByIndexAndPath[whichField][path] = branch.value;\n\n // If two sort fields both go into arrays, they have to go into the\n // exact same arrays and we have to find the same paths. This is\n // roughly the same condition that makes MongoDB throw this strange\n // error message. eg, the main thing is that if sort spec is {a: 1,\n // b:1} then a and b cannot both be arrays.\n //\n // (In MongoDB it seems to be OK to have {a: 1, 'a.x.y': 1} where 'a'\n // and 'a.x.y' are both arrays, but we don't allow this for now.\n // #NestedArraySort\n // XXX achieve full compatibility here\n if (knownPaths && !_.has(knownPaths, path)) {\n throw Error(\"cannot index parallel arrays\");\n }\n });\n\n if (knownPaths) {\n // Similarly to above, paths must match everywhere, unless this is a\n // non-array field.\n if (!_.has(valuesByIndexAndPath[whichField], '') &&\n _.size(knownPaths) !== _.size(valuesByIndexAndPath[whichField])) {\n throw Error(\"cannot index parallel arrays!\");\n }\n } else if (usedPaths) {\n knownPaths = {};\n _.each(valuesByIndexAndPath[whichField], function (x, path) {\n knownPaths[path] = true;\n });\n }\n });\n\n if (!knownPaths) {\n // Easy case: no use of arrays.\n var soleKey = _.map(valuesByIndexAndPath, function (values) {\n if (!_.has(values, ''))\n throw Error(\"no value in sole key case?\");\n return values[''];\n });\n cb(soleKey);\n return;\n }\n\n _.each(knownPaths, function (x, path) {\n var key = _.map(valuesByIndexAndPath, function (values) {\n if (_.has(values, ''))\n return values[''];\n if (!_.has(values, path))\n throw Error(\"missing path?\");\n return values[path];\n });\n cb(key);\n });\n },\n\n // Takes in two keys: arrays whose lengths match the number of spec\n // parts. Returns negative, 0, or positive based on using the sort spec to\n // compare fields.\n _compareKeys: function (key1, key2) {\n var self = this;\n if (key1.length !== self._sortSpecParts.length ||\n key2.length !== self._sortSpecParts.length) {\n throw Error(\"Key has wrong length\");\n }\n\n return self._keyComparator(key1, key2);\n },\n\n // Given an index 'i', returns a comparator that compares two key arrays based\n // on field 'i'.\n _keyFieldComparator: function (i) {\n var self = this;\n var invert = !self._sortSpecParts[i].ascending;\n return function (key1, key2) {\n var compare = LocalCollection._f._cmp(key1[i], key2[i]);\n if (invert)\n compare = -compare;\n return compare;\n };\n },\n\n // Returns a comparator that represents the sort specification (but not\n // including a possible geoquery distance tie-breaker).\n _getBaseComparator: function () {\n var self = this;\n\n // If we're only sorting on geoquery distance and no specs, just say\n // everything is equal.\n if (!self._sortSpecParts.length) {\n return function (doc1, doc2) {\n return 0;\n };\n }\n\n return function (doc1, doc2) {\n var key1 = self._getMinKeyFromDoc(doc1);\n var key2 = self._getMinKeyFromDoc(doc2);\n return self._compareKeys(key1, key2);\n };\n },\n\n // In MongoDB, if you have documents\n // {_id: 'x', a: [1, 10]} and\n // {_id: 'y', a: [5, 15]},\n // then C.find({}, {sort: {a: 1}}) puts x before y (1 comes before 5).\n // But C.find({a: {$gt: 3}}, {sort: {a: 1}}) puts y before x (1 does not\n // match the selector, and 5 comes before 10).\n //\n // The way this works is pretty subtle! For example, if the documents\n // are instead {_id: 'x', a: [{x: 1}, {x: 10}]}) and\n // {_id: 'y', a: [{x: 5}, {x: 15}]}),\n // then C.find({'a.x': {$gt: 3}}, {sort: {'a.x': 1}}) and\n // C.find({a: {$elemMatch: {x: {$gt: 3}}}}, {sort: {'a.x': 1}})\n // both follow this rule (y before x). (ie, you do have to apply this\n // through $elemMatch.)\n //\n // So if you pass a matcher to this sorter's constructor, we will attempt to\n // skip sort keys that don't match the selector. The logic here is pretty\n // subtle and undocumented; we've gotten as close as we can figure out based\n // on our understanding of Mongo's behavior.\n _useWithMatcher: function (matcher) {\n var self = this;\n\n if (self._keyFilter)\n throw Error(\"called _useWithMatcher twice?\");\n\n // If we are only sorting by distance, then we're not going to bother to\n // build a key filter.\n // XXX figure out how geoqueries interact with this stuff\n if (_.isEmpty(self._sortSpecParts))\n return;\n\n var selector = matcher._selector;\n\n // If the user just passed a literal function to find(), then we can't get a\n // key filter from it.\n if (selector instanceof Function)\n return;\n\n var constraintsByPath = {};\n _.each(self._sortSpecParts, function (spec, i) {\n constraintsByPath[spec.path] = [];\n });\n\n _.each(selector, function (subSelector, key) {\n // XXX support $and and $or\n\n var constraints = constraintsByPath[key];\n if (!constraints)\n return;\n\n // XXX it looks like the real MongoDB implementation isn't \"does the\n // regexp match\" but \"does the value fall into a range named by the\n // literal prefix of the regexp\", ie \"foo\" in /^foo(bar|baz)+/ But\n // \"does the regexp match\" is a good approximation.\n if (subSelector instanceof RegExp) {\n // As far as we can tell, using either of the options that both we and\n // MongoDB support ('i' and 'm') disables use of the key filter. This\n // makes sense: MongoDB mostly appears to be calculating ranges of an\n // index to use, which means it only cares about regexps that match\n // one range (with a literal prefix), and both 'i' and 'm' prevent the\n // literal prefix of the regexp from actually meaning one range.\n if (subSelector.ignoreCase || subSelector.multiline)\n return;\n constraints.push(regexpElementMatcher(subSelector));\n return;\n }\n\n if (isOperatorObject(subSelector)) {\n _.each(subSelector, function (operand, operator) {\n if (_.contains(['$lt', '$lte', '$gt', '$gte'], operator)) {\n // XXX this depends on us knowing that these operators don't use any\n // of the arguments to compileElementSelector other than operand.\n constraints.push(\n ELEMENT_OPERATORS[operator].compileElementSelector(operand));\n }\n\n // See comments in the RegExp block above.\n if (operator === '$regex' && !subSelector.$options) {\n constraints.push(\n ELEMENT_OPERATORS.$regex.compileElementSelector(\n operand, subSelector));\n }\n\n // XXX support {$exists: true}, $mod, $type, $in, $elemMatch\n });\n return;\n }\n\n // OK, it's an equality thing.\n constraints.push(equalityElementMatcher(subSelector));\n });\n\n // It appears that the first sort field is treated differently from the\n // others; we shouldn't create a key filter unless the first sort field is\n // restricted, though after that point we can restrict the other sort fields\n // or not as we wish.\n if (_.isEmpty(constraintsByPath[self._sortSpecParts[0].path]))\n return;\n\n self._keyFilter = function (key) {\n return _.all(self._sortSpecParts, function (specPart, index) {\n return _.all(constraintsByPath[specPart.path], function (f) {\n return f(key[index]);\n });\n });\n };\n }\n});\n\n// Given an array of comparators\n// (functions (a,b)->(negative or positive or zero)), returns a single\n// comparator which uses each comparator in order and returns the first\n// non-zero value.\nvar composeComparators = function (comparatorArray) {\n return function (a, b) {\n for (var i = 0; i < comparatorArray.length; ++i) {\n var compare = comparatorArray[i](a, b);\n if (compare !== 0)\n return compare;\n }\n return 0;\n };\n};\n","// Knows how to compile a fields projection to a predicate function.\n// @returns - Function: a closure that filters out an object according to the\n// fields projection rules:\n// @param obj - Object: MongoDB-styled document\n// @returns - Object: a document with the fields filtered out\n// according to projection rules. Doesn't retain subfields\n// of passed argument.\nLocalCollection._compileProjection = function (fields) {\n LocalCollection._checkSupportedProjection(fields);\n\n var _idProjection = _.isUndefined(fields._id) ? true : fields._id;\n var details = projectionDetails(fields);\n\n // returns transformed doc according to ruleTree\n var transform = function (doc, ruleTree) {\n // Special case for \"sets\"\n if (_.isArray(doc))\n return _.map(doc, function (subdoc) { return transform(subdoc, ruleTree); });\n\n var res = details.including ? {} : EJSON.clone(doc);\n _.each(ruleTree, function (rule, key) {\n if (!_.has(doc, key))\n return;\n if (_.isObject(rule)) {\n // For sub-objects/subsets we branch\n if (_.isObject(doc[key]))\n res[key] = transform(doc[key], rule);\n // Otherwise we don't even touch this subfield\n } else if (details.including)\n res[key] = EJSON.clone(doc[key]);\n else\n delete res[key];\n });\n\n return res;\n };\n\n return function (obj) {\n var res = transform(obj, details.tree);\n\n if (_idProjection && _.has(obj, '_id'))\n res._id = obj._id;\n if (!_idProjection && _.has(res, '_id'))\n delete res._id;\n return res;\n };\n};\n\n// Traverses the keys of passed projection and constructs a tree where all\n// leaves are either all True or all False\n// @returns Object:\n// - tree - Object - tree representation of keys involved in projection\n// (exception for '_id' as it is a special case handled separately)\n// - including - Boolean - \"take only certain fields\" type of projection\nprojectionDetails = function (fields) {\n // Find the non-_id keys (_id is handled specially because it is included unless\n // explicitly excluded). Sort the keys, so that our code to detect overlaps\n // like 'foo' and 'foo.bar' can assume that 'foo' comes first.\n var fieldsKeys = _.keys(fields).sort();\n\n // If there are other rules other than '_id', treat '_id' differently in a\n // separate case. If '_id' is the only rule, use it to understand if it is\n // including/excluding projection.\n if (fieldsKeys.length > 0 && !(fieldsKeys.length === 1 && fieldsKeys[0] === '_id'))\n fieldsKeys = _.reject(fieldsKeys, function (key) { return key === '_id'; });\n\n var including = null; // Unknown\n\n _.each(fieldsKeys, function (keyPath) {\n var rule = !!fields[keyPath];\n if (including === null)\n including = rule;\n if (including !== rule)\n // This error message is copies from MongoDB shell\n throw MinimongoError(\"You cannot currently mix including and excluding fields.\");\n });\n\n\n var projectionRulesTree = pathsToTree(\n fieldsKeys,\n function (path) { return including; },\n function (node, path, fullPath) {\n // Check passed projection fields' keys: If you have two rules such as\n // 'foo.bar' and 'foo.bar.baz', then the result becomes ambiguous. If\n // that happens, there is a probability you are doing something wrong,\n // framework should notify you about such mistake earlier on cursor\n // compilation step than later during runtime. Note, that real mongo\n // doesn't do anything about it and the later rule appears in projection\n // project, more priority it takes.\n //\n // Example, assume following in mongo shell:\n // > db.coll.insert({ a: { b: 23, c: 44 } })\n // > db.coll.find({}, { 'a': 1, 'a.b': 1 })\n // { \"_id\" : ObjectId(\"520bfe456024608e8ef24af3\"), \"a\" : { \"b\" : 23 } }\n // > db.coll.find({}, { 'a.b': 1, 'a': 1 })\n // { \"_id\" : ObjectId(\"520bfe456024608e8ef24af3\"), \"a\" : { \"b\" : 23, \"c\" : 44 } }\n //\n // Note, how second time the return set of keys is different.\n\n var currentPath = fullPath;\n var anotherPath = path;\n throw MinimongoError(\"both \" + currentPath + \" and \" + anotherPath +\n \" found in fields option, using both of them may trigger \" +\n \"unexpected behavior. Did you mean to use only one of them?\");\n });\n\n return {\n tree: projectionRulesTree,\n including: including\n };\n};\n\n// paths - Array: list of mongo style paths\n// newLeafFn - Function: of form function(path) should return a scalar value to\n// put into list created for that path\n// conflictFn - Function: of form function(node, path, fullPath) is called\n// when building a tree path for 'fullPath' node on\n// 'path' was already a leaf with a value. Must return a\n// conflict resolution.\n// initial tree - Optional Object: starting tree.\n// @returns - Object: tree represented as a set of nested objects\npathsToTree = function (paths, newLeafFn, conflictFn, tree) {\n tree = tree || {};\n _.each(paths, function (keyPath) {\n var treePos = tree;\n var pathArr = keyPath.split('.');\n\n // use _.all just for iteration with break\n var success = _.all(pathArr.slice(0, -1), function (key, idx) {\n if (!_.has(treePos, key))\n treePos[key] = {};\n else if (!_.isObject(treePos[key])) {\n treePos[key] = conflictFn(treePos[key],\n pathArr.slice(0, idx + 1).join('.'),\n keyPath);\n // break out of loop if we are failing for this path\n if (!_.isObject(treePos[key]))\n return false;\n }\n\n treePos = treePos[key];\n return true;\n });\n\n if (success) {\n var lastKey = _.last(pathArr);\n if (!_.has(treePos, lastKey))\n treePos[lastKey] = newLeafFn(keyPath);\n else\n treePos[lastKey] = conflictFn(treePos[lastKey], keyPath, keyPath);\n }\n });\n\n return tree;\n};\n\nLocalCollection._checkSupportedProjection = function (fields) {\n if (!_.isObject(fields) || _.isArray(fields))\n throw MinimongoError(\"fields option must be an object\");\n\n _.each(fields, function (val, keyPath) {\n if (_.contains(keyPath.split('.'), '$'))\n throw MinimongoError(\"Minimongo doesn't support $ operator in projections yet.\");\n if (_.indexOf([1, 0, true, false], val) === -1)\n throw MinimongoError(\"Projection values should be one of 1, 0, true, or false\");\n });\n};\n\n","// XXX need a strategy for passing the binding of $ into this\n// function, from the compiled selector\n//\n// maybe just {key.up.to.just.before.dollarsign: array_index}\n//\n// XXX atomicity: if one modification fails, do we roll back the whole\n// change?\n//\n// options:\n// - isInsert is set when _modify is being called to compute the document to\n// insert as part of an upsert operation. We use this primarily to figure\n// out when to set the fields in $setOnInsert, if present.\nLocalCollection._modify = function (doc, mod, options) {\n options = options || {};\n if (!isPlainObject(mod))\n throw MinimongoError(\"Modifier must be an object\");\n var isModifier = isOperatorObject(mod);\n\n var newDoc;\n\n if (!isModifier) {\n if (mod._id && !EJSON.equals(doc._id, mod._id))\n throw MinimongoError(\"Cannot change the _id of a document\");\n\n // replace the whole document\n for (var k in mod) {\n if (/\\./.test(k))\n throw MinimongoError(\n \"When replacing document, field name may not contain '.'\");\n }\n newDoc = mod;\n } else {\n // apply modifiers to the doc.\n newDoc = EJSON.clone(doc);\n\n _.each(mod, function (operand, op) {\n var modFunc = MODIFIERS[op];\n // Treat $setOnInsert as $set if this is an insert.\n if (options.isInsert && op === '$setOnInsert')\n modFunc = MODIFIERS['$set'];\n if (!modFunc)\n throw MinimongoError(\"Invalid modifier specified \" + op);\n _.each(operand, function (arg, keypath) {\n if (keypath === '') {\n throw MinimongoError(\"An empty update path is not valid.\");\n }\n\n if (keypath === '_id') {\n throw MinimongoError(\"Mod on _id not allowed\");\n }\n\n var keyparts = keypath.split('.');\n\n if (! _.all(keyparts, _.identity)) {\n throw MinimongoError(\n \"The update path '\" + keypath +\n \"' contains an empty field name, which is not allowed.\");\n }\n\n var noCreate = _.has(NO_CREATE_MODIFIERS, op);\n var forbidArray = (op === \"$rename\");\n var target = findModTarget(newDoc, keyparts, {\n noCreate: NO_CREATE_MODIFIERS[op],\n forbidArray: (op === \"$rename\"),\n arrayIndices: options.arrayIndices\n });\n var field = keyparts.pop();\n modFunc(target, field, arg, keypath, newDoc);\n });\n });\n }\n\n // move new document into place.\n _.each(_.keys(doc), function (k) {\n // Note: this used to be for (var k in doc) however, this does not\n // work right in Opera. Deleting from a doc while iterating over it\n // would sometimes cause opera to skip some keys.\n if (k !== '_id')\n delete doc[k];\n });\n _.each(newDoc, function (v, k) {\n doc[k] = v;\n });\n};\n\n// for a.b.c.2.d.e, keyparts should be ['a', 'b', 'c', '2', 'd', 'e'],\n// and then you would operate on the 'e' property of the returned\n// object.\n//\n// if options.noCreate is falsey, creates intermediate levels of\n// structure as necessary, like mkdir -p (and raises an exception if\n// that would mean giving a non-numeric property to an array.) if\n// options.noCreate is true, return undefined instead.\n//\n// may modify the last element of keyparts to signal to the caller that it needs\n// to use a different value to index into the returned object (for example,\n// ['a', '01'] -> ['a', 1]).\n//\n// if forbidArray is true, return null if the keypath goes through an array.\n//\n// if options.arrayIndices is set, use its first element for the (first) '$' in\n// the path.\nvar findModTarget = function (doc, keyparts, options) {\n options = options || {};\n var usedArrayIndex = false;\n for (var i = 0; i < keyparts.length; i++) {\n var last = (i === keyparts.length - 1);\n var keypart = keyparts[i];\n var indexable = isIndexable(doc);\n if (!indexable) {\n if (options.noCreate)\n return undefined;\n var e = MinimongoError(\n \"cannot use the part '\" + keypart + \"' to traverse \" + doc);\n e.setPropertyError = true;\n throw e;\n }\n if (doc instanceof Array) {\n if (options.forbidArray)\n return null;\n if (keypart === '$') {\n if (usedArrayIndex)\n throw MinimongoError(\"Too many positional (i.e. '$') elements\");\n if (!options.arrayIndices || !options.arrayIndices.length) {\n throw MinimongoError(\"The positional operator did not find the \" +\n \"match needed from the query\");\n }\n keypart = options.arrayIndices[0];\n usedArrayIndex = true;\n } else if (isNumericKey(keypart)) {\n keypart = parseInt(keypart);\n } else {\n if (options.noCreate)\n return undefined;\n throw MinimongoError(\n \"can't append to array using string field name [\"\n + keypart + \"]\");\n }\n if (last)\n // handle 'a.01'\n keyparts[i] = keypart;\n if (options.noCreate && keypart >= doc.length)\n return undefined;\n while (doc.length < keypart)\n doc.push(null);\n if (!last) {\n if (doc.length === keypart)\n doc.push({});\n else if (typeof doc[keypart] !== \"object\")\n throw MinimongoError(\"can't modify field '\" + keyparts[i + 1] +\n \"' of list value \" + JSON.stringify(doc[keypart]));\n }\n } else {\n if (keypart.length && keypart.substr(0, 1) === '$')\n throw MinimongoError(\"can't set field named \" + keypart);\n if (!(keypart in doc)) {\n if (options.noCreate)\n return undefined;\n if (!last)\n doc[keypart] = {};\n }\n }\n\n if (last)\n return doc;\n doc = doc[keypart];\n }\n\n // notreached\n};\n\nvar NO_CREATE_MODIFIERS = {\n $unset: true,\n $pop: true,\n $rename: true,\n $pull: true,\n $pullAll: true\n};\n\nvar MODIFIERS = {\n $inc: function (target, field, arg) {\n if (typeof arg !== \"number\")\n throw MinimongoError(\"Modifier $inc allowed for numbers only\");\n if (field in target) {\n if (typeof target[field] !== \"number\")\n throw MinimongoError(\"Cannot apply $inc modifier to non-number\");\n target[field] += arg;\n } else {\n target[field] = arg;\n }\n },\n $set: function (target, field, arg) {\n if (!_.isObject(target)) { // not an array or an object\n var e = MinimongoError(\"Cannot set property on non-object field\");\n e.setPropertyError = true;\n throw e;\n }\n if (target === null) {\n var e = MinimongoError(\"Cannot set property on null\");\n e.setPropertyError = true;\n throw e;\n }\n target[field] = EJSON.clone(arg);\n },\n $setOnInsert: function (target, field, arg) {\n // converted to `$set` in `_modify`\n },\n $unset: function (target, field, arg) {\n if (target !== undefined) {\n if (target instanceof Array) {\n if (field in target)\n target[field] = null;\n } else\n delete target[field];\n }\n },\n $push: function (target, field, arg) {\n if (target[field] === undefined)\n target[field] = [];\n if (!(target[field] instanceof Array))\n throw MinimongoError(\"Cannot apply $push modifier to non-array\");\n\n if (!(arg && arg.$each)) {\n // Simple mode: not $each\n target[field].push(EJSON.clone(arg));\n return;\n }\n\n // Fancy mode: $each (and maybe $slice and $sort)\n var toPush = arg.$each;\n if (!(toPush instanceof Array))\n throw MinimongoError(\"$each must be an array\");\n\n // Parse $slice.\n var slice = undefined;\n if ('$slice' in arg) {\n if (typeof arg.$slice !== \"number\")\n throw MinimongoError(\"$slice must be a numeric value\");\n // XXX should check to make sure integer\n if (arg.$slice > 0)\n throw MinimongoError(\"$slice in $push must be zero or negative\");\n slice = arg.$slice;\n }\n\n // Parse $sort.\n var sortFunction = undefined;\n if (arg.$sort) {\n if (slice === undefined)\n throw MinimongoError(\"$sort requires $slice to be present\");\n // XXX this allows us to use a $sort whose value is an array, but that's\n // actually an extension of the Node driver, so it won't work\n // server-side. Could be confusing!\n // XXX is it correct that we don't do geo-stuff here?\n sortFunction = new Minimongo.Sorter(arg.$sort).getComparator();\n for (var i = 0; i < toPush.length; i++) {\n if (LocalCollection._f._type(toPush[i]) !== 3) {\n throw MinimongoError(\"$push like modifiers using $sort \" +\n \"require all elements to be objects\");\n }\n }\n }\n\n // Actually push.\n for (var j = 0; j < toPush.length; j++)\n target[field].push(EJSON.clone(toPush[j]));\n\n // Actually sort.\n if (sortFunction)\n target[field].sort(sortFunction);\n\n // Actually slice.\n if (slice !== undefined) {\n if (slice === 0)\n target[field] = []; // differs from Array.slice!\n else\n target[field] = target[field].slice(slice);\n }\n },\n $pushAll: function (target, field, arg) {\n if (!(typeof arg === \"object\" && arg instanceof Array))\n throw MinimongoError(\"Modifier $pushAll/pullAll allowed for arrays only\");\n var x = target[field];\n if (x === undefined)\n target[field] = arg;\n else if (!(x instanceof Array))\n throw MinimongoError(\"Cannot apply $pushAll modifier to non-array\");\n else {\n for (var i = 0; i < arg.length; i++)\n x.push(arg[i]);\n }\n },\n $addToSet: function (target, field, arg) {\n var isEach = false;\n if (typeof arg === \"object\") {\n //check if first key is '$each'\n for (var k in arg) {\n if (k === \"$each\")\n isEach = true;\n break;\n }\n }\n var values = isEach ? arg[\"$each\"] : [arg];\n var x = target[field];\n if (x === undefined)\n target[field] = values;\n else if (!(x instanceof Array))\n throw MinimongoError(\"Cannot apply $addToSet modifier to non-array\");\n else {\n _.each(values, function (value) {\n for (var i = 0; i < x.length; i++)\n if (LocalCollection._f._equal(value, x[i]))\n return;\n x.push(EJSON.clone(value));\n });\n }\n },\n $pop: function (target, field, arg) {\n if (target === undefined)\n return;\n var x = target[field];\n if (x === undefined)\n return;\n else if (!(x instanceof Array))\n throw MinimongoError(\"Cannot apply $pop modifier to non-array\");\n else {\n if (typeof arg === 'number' && arg < 0)\n x.splice(0, 1);\n else\n x.pop();\n }\n },\n $pull: function (target, field, arg) {\n if (target === undefined)\n return;\n var x = target[field];\n if (x === undefined)\n return;\n else if (!(x instanceof Array))\n throw MinimongoError(\"Cannot apply $pull/pullAll modifier to non-array\");\n else {\n var out = [];\n if (typeof arg === \"object\" && !(arg instanceof Array)) {\n // XXX would be much nicer to compile this once, rather than\n // for each document we modify.. but usually we're not\n // modifying that many documents, so we'll let it slide for\n // now\n\n // XXX Minimongo.Matcher isn't up for the job, because we need\n // to permit stuff like {$pull: {a: {$gt: 4}}}.. something\n // like {$gt: 4} is not normally a complete selector.\n // same issue as $elemMatch possibly?\n var matcher = new Minimongo.Matcher(arg);\n for (var i = 0; i < x.length; i++)\n if (!matcher.documentMatches(x[i]).result)\n out.push(x[i]);\n } else {\n for (var i = 0; i < x.length; i++)\n if (!LocalCollection._f._equal(x[i], arg))\n out.push(x[i]);\n }\n target[field] = out;\n }\n },\n $pullAll: function (target, field, arg) {\n if (!(typeof arg === \"object\" && arg instanceof Array))\n throw MinimongoError(\"Modifier $pushAll/pullAll allowed for arrays only\");\n if (target === undefined)\n return;\n var x = target[field];\n if (x === undefined)\n return;\n else if (!(x instanceof Array))\n throw MinimongoError(\"Cannot apply $pull/pullAll modifier to non-array\");\n else {\n var out = [];\n for (var i = 0; i < x.length; i++) {\n var exclude = false;\n for (var j = 0; j < arg.length; j++) {\n if (LocalCollection._f._equal(x[i], arg[j])) {\n exclude = true;\n break;\n }\n }\n if (!exclude)\n out.push(x[i]);\n }\n target[field] = out;\n }\n },\n $rename: function (target, field, arg, keypath, doc) {\n if (keypath === arg)\n // no idea why mongo has this restriction..\n throw MinimongoError(\"$rename source must differ from target\");\n if (target === null)\n throw MinimongoError(\"$rename source field invalid\");\n if (typeof arg !== \"string\")\n throw MinimongoError(\"$rename target must be a string\");\n if (target === undefined)\n return;\n var v = target[field];\n delete target[field];\n\n var keyparts = arg.split('.');\n var target2 = findModTarget(doc, keyparts, {forbidArray: true});\n if (target2 === null)\n throw MinimongoError(\"$rename target field invalid\");\n var field2 = keyparts.pop();\n target2[field2] = v;\n },\n $bit: function (target, field, arg) {\n // XXX mongo only supports $bit on integers, and we only support\n // native javascript numbers (doubles) so far, so we can't support $bit\n throw MinimongoError(\"$bit is not supported\");\n }\n};\n","// ordered: bool.\n// old_results and new_results: collections of documents.\n// if ordered, they are arrays.\n// if unordered, they are IdMaps\nLocalCollection._diffQueryChanges = function (ordered, oldResults, newResults,\n observer, options) {\n if (ordered)\n LocalCollection._diffQueryOrderedChanges(\n oldResults, newResults, observer, options);\n else\n LocalCollection._diffQueryUnorderedChanges(\n oldResults, newResults, observer, options);\n};\n\nLocalCollection._diffQueryUnorderedChanges = function (oldResults, newResults,\n observer, options) {\n options = options || {};\n var projectionFn = options.projectionFn || EJSON.clone;\n\n if (observer.movedBefore) {\n throw new Error(\"_diffQueryUnordered called with a movedBefore observer!\");\n }\n\n newResults.forEach(function (newDoc, id) {\n var oldDoc = oldResults.get(id);\n if (oldDoc) {\n if (observer.changed && !EJSON.equals(oldDoc, newDoc)) {\n var projectedNew = projectionFn(newDoc);\n var projectedOld = projectionFn(oldDoc);\n var changedFields =\n LocalCollection._makeChangedFields(projectedNew, projectedOld);\n if (! _.isEmpty(changedFields)) {\n observer.changed(id, changedFields);\n }\n }\n } else if (observer.added) {\n var fields = projectionFn(newDoc);\n delete fields._id;\n observer.added(newDoc._id, fields);\n }\n });\n\n if (observer.removed) {\n oldResults.forEach(function (oldDoc, id) {\n if (!newResults.has(id))\n observer.removed(id);\n });\n }\n};\n\n\nLocalCollection._diffQueryOrderedChanges = function (old_results, new_results,\n observer, options) {\n options = options || {};\n var projectionFn = options.projectionFn || EJSON.clone;\n\n var new_presence_of_id = {};\n _.each(new_results, function (doc) {\n if (new_presence_of_id[doc._id])\n Meteor._debug(\"Duplicate _id in new_results\");\n new_presence_of_id[doc._id] = true;\n });\n\n var old_index_of_id = {};\n _.each(old_results, function (doc, i) {\n if (doc._id in old_index_of_id)\n Meteor._debug(\"Duplicate _id in old_results\");\n old_index_of_id[doc._id] = i;\n });\n\n // ALGORITHM:\n //\n // To determine which docs should be considered \"moved\" (and which\n // merely change position because of other docs moving) we run\n // a \"longest common subsequence\" (LCS) algorithm. The LCS of the\n // old doc IDs and the new doc IDs gives the docs that should NOT be\n // considered moved.\n\n // To actually call the appropriate callbacks to get from the old state to the\n // new state:\n\n // First, we call removed() on all the items that only appear in the old\n // state.\n\n // Then, once we have the items that should not move, we walk through the new\n // results array group-by-group, where a \"group\" is a set of items that have\n // moved, anchored on the end by an item that should not move. One by one, we\n // move each of those elements into place \"before\" the anchoring end-of-group\n // item, and fire changed events on them if necessary. Then we fire a changed\n // event on the anchor, and move on to the next group. There is always at\n // least one group; the last group is anchored by a virtual \"null\" id at the\n // end.\n\n // Asymptotically: O(N k) where k is number of ops, or potentially\n // O(N log N) if inner loop of LCS were made to be binary search.\n\n\n //////// LCS (longest common sequence, with respect to _id)\n // (see Wikipedia article on Longest Increasing Subsequence,\n // where the LIS is taken of the sequence of old indices of the\n // docs in new_results)\n //\n // unmoved: the output of the algorithm; members of the LCS,\n // in the form of indices into new_results\n var unmoved = [];\n // max_seq_len: length of LCS found so far\n var max_seq_len = 0;\n // seq_ends[i]: the index into new_results of the last doc in a\n // common subsequence of length of i+1 <= max_seq_len\n var N = new_results.length;\n var seq_ends = new Array(N);\n // ptrs: the common subsequence ending with new_results[n] extends\n // a common subsequence ending with new_results[ptr[n]], unless\n // ptr[n] is -1.\n var ptrs = new Array(N);\n // virtual sequence of old indices of new results\n var old_idx_seq = function(i_new) {\n return old_index_of_id[new_results[i_new]._id];\n };\n // for each item in new_results, use it to extend a common subsequence\n // of length j <= max_seq_len\n for(var i=0; i 0) {\n if (old_idx_seq(seq_ends[j-1]) < old_idx_seq(i))\n break;\n j--;\n }\n\n ptrs[i] = (j === 0 ? -1 : seq_ends[j-1]);\n seq_ends[j] = i;\n if (j+1 > max_seq_len)\n max_seq_len = j+1;\n }\n }\n\n // pull out the LCS/LIS into unmoved\n var idx = (max_seq_len === 0 ? -1 : seq_ends[max_seq_len-1]);\n while (idx >= 0) {\n unmoved.push(idx);\n idx = ptrs[idx];\n }\n // the unmoved item list is built backwards, so fix that\n unmoved.reverse();\n\n // the last group is always anchored by the end of the result list, which is\n // an id of \"null\"\n unmoved.push(new_results.length);\n\n _.each(old_results, function (doc) {\n if (!new_presence_of_id[doc._id])\n observer.removed && observer.removed(doc._id);\n });\n // for each group of things in the new_results that is anchored by an unmoved\n // element, iterate through the things before it.\n var startOfGroup = 0;\n _.each(unmoved, function (endOfGroup) {\n var groupId = new_results[endOfGroup] ? new_results[endOfGroup]._id : null;\n var oldDoc, newDoc, fields, projectedNew, projectedOld;\n for (var i = startOfGroup; i < endOfGroup; i++) {\n newDoc = new_results[i];\n if (!_.has(old_index_of_id, newDoc._id)) {\n fields = projectionFn(newDoc);\n delete fields._id;\n observer.addedBefore && observer.addedBefore(newDoc._id, fields, groupId);\n observer.added && observer.added(newDoc._id, fields);\n } else {\n // moved\n oldDoc = old_results[old_index_of_id[newDoc._id]];\n projectedNew = projectionFn(newDoc);\n projectedOld = projectionFn(oldDoc);\n fields = LocalCollection._makeChangedFields(projectedNew, projectedOld);\n if (!_.isEmpty(fields)) {\n observer.changed && observer.changed(newDoc._id, fields);\n }\n observer.movedBefore && observer.movedBefore(newDoc._id, groupId);\n }\n }\n if (groupId) {\n newDoc = new_results[endOfGroup];\n oldDoc = old_results[old_index_of_id[newDoc._id]];\n projectedNew = projectionFn(newDoc);\n projectedOld = projectionFn(oldDoc);\n fields = LocalCollection._makeChangedFields(projectedNew, projectedOld);\n if (!_.isEmpty(fields)) {\n observer.changed && observer.changed(newDoc._id, fields);\n }\n }\n startOfGroup = endOfGroup+1;\n });\n\n\n};\n\n\n// General helper for diff-ing two objects.\n// callbacks is an object like so:\n// { leftOnly: function (key, leftValue) {...},\n// rightOnly: function (key, rightValue) {...},\n// both: function (key, leftValue, rightValue) {...},\n// }\nLocalCollection._diffObjects = function (left, right, callbacks) {\n _.each(left, function (leftValue, key) {\n if (_.has(right, key))\n callbacks.both && callbacks.both(key, leftValue, right[key]);\n else\n callbacks.leftOnly && callbacks.leftOnly(key, leftValue);\n });\n if (callbacks.rightOnly) {\n _.each(right, function(rightValue, key) {\n if (!_.has(left, key))\n callbacks.rightOnly(key, rightValue);\n });\n }\n};\n","LocalCollection._IdMap = function () {\n var self = this;\n IdMap.call(self, LocalCollection._idStringify, LocalCollection._idParse);\n};\n\nMeteor._inherits(LocalCollection._IdMap, IdMap);\n\n","// XXX maybe move these into another ObserveHelpers package or something\n\n// _CachingChangeObserver is an object which receives observeChanges callbacks\n// and keeps a cache of the current cursor state up to date in self.docs. Users\n// of this class should read the docs field but not modify it. You should pass\n// the \"applyChange\" field as the callbacks to the underlying observeChanges\n// call. Optionally, you can specify your own observeChanges callbacks which are\n// invoked immediately before the docs field is updated; this object is made\n// available as `this` to those callbacks.\nLocalCollection._CachingChangeObserver = function (options) {\n var self = this;\n options = options || {};\n\n var orderedFromCallbacks = options.callbacks &&\n LocalCollection._observeChangesCallbacksAreOrdered(options.callbacks);\n if (_.has(options, 'ordered')) {\n self.ordered = options.ordered;\n if (options.callbacks && options.ordered !== orderedFromCallbacks)\n throw Error(\"ordered option doesn't match callbacks\");\n } else if (options.callbacks) {\n self.ordered = orderedFromCallbacks;\n } else {\n throw Error(\"must provide ordered or callbacks\");\n }\n var callbacks = options.callbacks || {};\n\n if (self.ordered) {\n self.docs = new OrderedDict(LocalCollection._idStringify);\n self.applyChange = {\n addedBefore: function (id, fields, before) {\n var doc = EJSON.clone(fields);\n doc._id = id;\n callbacks.addedBefore && callbacks.addedBefore.call(\n self, id, fields, before);\n // This line triggers if we provide added with movedBefore.\n callbacks.added && callbacks.added.call(self, id, fields);\n // XXX could `before` be a falsy ID? Technically\n // idStringify seems to allow for them -- though\n // OrderedDict won't call stringify on a falsy arg.\n self.docs.putBefore(id, doc, before || null);\n },\n movedBefore: function (id, before) {\n var doc = self.docs.get(id);\n callbacks.movedBefore && callbacks.movedBefore.call(self, id, before);\n self.docs.moveBefore(id, before || null);\n }\n };\n } else {\n self.docs = new LocalCollection._IdMap;\n self.applyChange = {\n added: function (id, fields) {\n var doc = EJSON.clone(fields);\n callbacks.added && callbacks.added.call(self, id, fields);\n doc._id = id;\n self.docs.set(id, doc);\n }\n };\n }\n\n // The methods in _IdMap and OrderedDict used by these callbacks are\n // identical.\n self.applyChange.changed = function (id, fields) {\n var doc = self.docs.get(id);\n if (!doc)\n throw new Error(\"Unknown id for changed: \" + id);\n callbacks.changed && callbacks.changed.call(\n self, id, EJSON.clone(fields));\n LocalCollection._applyChanges(doc, fields);\n };\n self.applyChange.removed = function (id) {\n callbacks.removed && callbacks.removed.call(self, id);\n self.docs.remove(id);\n };\n};\n\nLocalCollection._observeFromObserveChanges = function (cursor, observeCallbacks) {\n var transform = cursor.getTransform() || function (doc) {return doc;};\n var suppressed = !!observeCallbacks._suppress_initial;\n\n var observeChangesCallbacks;\n if (LocalCollection._observeCallbacksAreOrdered(observeCallbacks)) {\n // The \"_no_indices\" option sets all index arguments to -1 and skips the\n // linear scans required to generate them. This lets observers that don't\n // need absolute indices benefit from the other features of this API --\n // relative order, transforms, and applyChanges -- without the speed hit.\n var indices = !observeCallbacks._no_indices;\n observeChangesCallbacks = {\n addedBefore: function (id, fields, before) {\n var self = this;\n if (suppressed || !(observeCallbacks.addedAt || observeCallbacks.added))\n return;\n var doc = transform(_.extend(fields, {_id: id}));\n if (observeCallbacks.addedAt) {\n var index = indices\n ? (before ? self.docs.indexOf(before) : self.docs.size()) : -1;\n observeCallbacks.addedAt(doc, index, before);\n } else {\n observeCallbacks.added(doc);\n }\n },\n changed: function (id, fields) {\n var self = this;\n if (!(observeCallbacks.changedAt || observeCallbacks.changed))\n return;\n var doc = EJSON.clone(self.docs.get(id));\n if (!doc)\n throw new Error(\"Unknown id for changed: \" + id);\n var oldDoc = transform(EJSON.clone(doc));\n LocalCollection._applyChanges(doc, fields);\n doc = transform(doc);\n if (observeCallbacks.changedAt) {\n var index = indices ? self.docs.indexOf(id) : -1;\n observeCallbacks.changedAt(doc, oldDoc, index);\n } else {\n observeCallbacks.changed(doc, oldDoc);\n }\n },\n movedBefore: function (id, before) {\n var self = this;\n if (!observeCallbacks.movedTo)\n return;\n var from = indices ? self.docs.indexOf(id) : -1;\n\n var to = indices\n ? (before ? self.docs.indexOf(before) : self.docs.size()) : -1;\n // When not moving backwards, adjust for the fact that removing the\n // document slides everything back one slot.\n if (to > from)\n --to;\n observeCallbacks.movedTo(transform(EJSON.clone(self.docs.get(id))),\n from, to, before || null);\n },\n removed: function (id) {\n var self = this;\n if (!(observeCallbacks.removedAt || observeCallbacks.removed))\n return;\n // technically maybe there should be an EJSON.clone here, but it's about\n // to be removed from self.docs!\n var doc = transform(self.docs.get(id));\n if (observeCallbacks.removedAt) {\n var index = indices ? self.docs.indexOf(id) : -1;\n observeCallbacks.removedAt(doc, index);\n } else {\n observeCallbacks.removed(doc);\n }\n }\n };\n } else {\n observeChangesCallbacks = {\n added: function (id, fields) {\n if (!suppressed && observeCallbacks.added) {\n var doc = _.extend(fields, {_id: id});\n observeCallbacks.added(transform(doc));\n }\n },\n changed: function (id, fields) {\n var self = this;\n if (observeCallbacks.changed) {\n var oldDoc = self.docs.get(id);\n var doc = EJSON.clone(oldDoc);\n LocalCollection._applyChanges(doc, fields);\n observeCallbacks.changed(transform(doc),\n transform(EJSON.clone(oldDoc)));\n }\n },\n removed: function (id) {\n var self = this;\n if (observeCallbacks.removed) {\n observeCallbacks.removed(transform(self.docs.get(id)));\n }\n }\n };\n }\n\n var changeObserver = new LocalCollection._CachingChangeObserver(\n {callbacks: observeChangesCallbacks});\n var handle = cursor.observeChanges(changeObserver.applyChange);\n suppressed = false;\n\n return handle;\n};\n","LocalCollection._looksLikeObjectID = function (str) {\n return str.length === 24 && str.match(/^[0-9a-f]*$/);\n};\n\nLocalCollection._ObjectID = function (hexString) {\n //random-based impl of Mongo ObjectID\n var self = this;\n if (hexString) {\n hexString = hexString.toLowerCase();\n if (!LocalCollection._looksLikeObjectID(hexString)) {\n throw new Error(\"Invalid hexadecimal string for creating an ObjectID\");\n }\n // meant to work with _.isEqual(), which relies on structural equality\n self._str = hexString;\n } else {\n self._str = Random.hexString(24);\n }\n};\n\nLocalCollection._ObjectID.prototype.toString = function () {\n var self = this;\n return \"ObjectID(\\\"\" + self._str + \"\\\")\";\n};\n\nLocalCollection._ObjectID.prototype.equals = function (other) {\n var self = this;\n return other instanceof LocalCollection._ObjectID &&\n self.valueOf() === other.valueOf();\n};\n\nLocalCollection._ObjectID.prototype.clone = function () {\n var self = this;\n return new LocalCollection._ObjectID(self._str);\n};\n\nLocalCollection._ObjectID.prototype.typeName = function() {\n return \"oid\";\n};\n\nLocalCollection._ObjectID.prototype.getTimestamp = function() {\n var self = this;\n return parseInt(self._str.substr(0, 8), 16);\n};\n\nLocalCollection._ObjectID.prototype.valueOf =\n LocalCollection._ObjectID.prototype.toJSONValue =\n LocalCollection._ObjectID.prototype.toHexString =\n function () { return this._str; };\n\n// Is this selector just shorthand for lookup by _id?\nLocalCollection._selectorIsId = function (selector) {\n return (typeof selector === \"string\") ||\n (typeof selector === \"number\") ||\n selector instanceof LocalCollection._ObjectID;\n};\n\n// Is the selector just lookup by _id (shorthand or not)?\nLocalCollection._selectorIsIdPerhapsAsObject = function (selector) {\n return LocalCollection._selectorIsId(selector) ||\n (selector && typeof selector === \"object\" &&\n selector._id && LocalCollection._selectorIsId(selector._id) &&\n _.size(selector) === 1);\n};\n\n// If this is a selector which explicitly constrains the match by ID to a finite\n// number of documents, returns a list of their IDs. Otherwise returns\n// null. Note that the selector may have other restrictions so it may not even\n// match those document! We care about $in and $and since those are generated\n// access-controlled update and remove.\nLocalCollection._idsMatchedBySelector = function (selector) {\n // Is the selector just an ID?\n if (LocalCollection._selectorIsId(selector))\n return [selector];\n if (!selector)\n return null;\n\n // Do we have an _id clause?\n if (_.has(selector, '_id')) {\n // Is the _id clause just an ID?\n if (LocalCollection._selectorIsId(selector._id))\n return [selector._id];\n // Is the _id clause {_id: {$in: [\"x\", \"y\", \"z\"]}}?\n if (selector._id && selector._id.$in\n && _.isArray(selector._id.$in)\n && !_.isEmpty(selector._id.$in)\n && _.all(selector._id.$in, LocalCollection._selectorIsId)) {\n return selector._id.$in;\n }\n return null;\n }\n\n // If this is a top-level $and, and any of the clauses constrain their\n // documents, then the whole selector is constrained by any one clause's\n // constraint. (Well, by their intersection, but that seems unlikely.)\n if (selector.$and && _.isArray(selector.$and)) {\n for (var i = 0; i < selector.$and.length; ++i) {\n var subIds = LocalCollection._idsMatchedBySelector(selector.$and[i]);\n if (subIds)\n return subIds;\n }\n }\n\n return null;\n};\n\nEJSON.addType(\"oid\", function (str) {\n return new LocalCollection._ObjectID(str);\n});\n","// Knows how to combine a mongo selector and a fields projection to a new fields\n// projection taking into account active fields from the passed selector.\n// @returns Object - projection object (same as fields option of mongo cursor)\nMinimongo.Matcher.prototype.combineIntoProjection = function (projection) {\n var self = this;\n var selectorPaths = Minimongo._pathsElidingNumericKeys(self._getPaths());\n\n // Special case for $where operator in the selector - projection should depend\n // on all fields of the document. getSelectorPaths returns a list of paths\n // selector depends on. If one of the paths is '' (empty string) representing\n // the root or the whole document, complete projection should be returned.\n if (_.contains(selectorPaths, ''))\n return {};\n\n return combineImportantPathsIntoProjection(selectorPaths, projection);\n};\n\nMinimongo._pathsElidingNumericKeys = function (paths) {\n var self = this;\n return _.map(paths, function (path) {\n return _.reject(path.split('.'), isNumericKey).join('.');\n });\n};\n\ncombineImportantPathsIntoProjection = function (paths, projection) {\n var prjDetails = projectionDetails(projection);\n var tree = prjDetails.tree;\n var mergedProjection = {};\n\n // merge the paths to include\n tree = pathsToTree(paths,\n function (path) { return true; },\n function (node, path, fullPath) { return true; },\n tree);\n mergedProjection = treeToPaths(tree);\n if (prjDetails.including) {\n // both selector and projection are pointing on fields to include\n // so we can just return the merged tree\n return mergedProjection;\n } else {\n // selector is pointing at fields to include\n // projection is pointing at fields to exclude\n // make sure we don't exclude important paths\n var mergedExclProjection = {};\n _.each(mergedProjection, function (incl, path) {\n if (!incl)\n mergedExclProjection[path] = false;\n });\n\n return mergedExclProjection;\n }\n};\n\n// Returns a set of key paths similar to\n// { 'foo.bar': 1, 'a.b.c': 1 }\nvar treeToPaths = function (tree, prefix) {\n prefix = prefix || '';\n var result = {};\n\n _.each(tree, function (val, key) {\n if (_.isObject(val))\n _.extend(result, treeToPaths(val, prefix + key + '.'));\n else\n result[prefix + key] = val;\n });\n\n return result;\n};\n\n","// Returns true if the modifier applied to some document may change the result\n// of matching the document by selector\n// The modifier is always in a form of Object:\n// - $set\n// - 'a.b.22.z': value\n// - 'foo.bar': 42\n// - $unset\n// - 'abc.d': 1\nMinimongo.Matcher.prototype.affectedByModifier = function (modifier) {\n var self = this;\n // safe check for $set/$unset being objects\n modifier = _.extend({ $set: {}, $unset: {} }, modifier);\n var modifiedPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset));\n var meaningfulPaths = self._getPaths();\n\n return _.any(modifiedPaths, function (path) {\n var mod = path.split('.');\n return _.any(meaningfulPaths, function (meaningfulPath) {\n var sel = meaningfulPath.split('.');\n var i = 0, j = 0;\n\n while (i < sel.length && j < mod.length) {\n if (isNumericKey(sel[i]) && isNumericKey(mod[j])) {\n // foo.4.bar selector affected by foo.4 modifier\n // foo.3.bar selector unaffected by foo.4 modifier\n if (sel[i] === mod[j])\n i++, j++;\n else\n return false;\n } else if (isNumericKey(sel[i])) {\n // foo.4.bar selector unaffected by foo.bar modifier\n return false;\n } else if (isNumericKey(mod[j])) {\n j++;\n } else if (sel[i] === mod[j])\n i++, j++;\n else\n return false;\n }\n\n // One is a prefix of another, taking numeric fields into account\n return true;\n });\n });\n};\n\n// Minimongo.Sorter gets a similar method, which delegates to a Matcher it made\n// for this exact purpose.\nMinimongo.Sorter.prototype.affectedByModifier = function (modifier) {\n var self = this;\n return self._selectorForAffectedByModifier.affectedByModifier(modifier);\n};\n\n// @param modifier - Object: MongoDB-styled modifier with `$set`s and `$unsets`\n// only. (assumed to come from oplog)\n// @returns - Boolean: if after applying the modifier, selector can start\n// accepting the modified value.\n// NOTE: assumes that document affected by modifier didn't match this Matcher\n// before, so if modifier can't convince selector in a positive change it would\n// stay 'false'.\n// Currently doesn't support $-operators and numeric indices precisely.\nMinimongo.Matcher.prototype.canBecomeTrueByModifier = function (modifier) {\n var self = this;\n if (!this.affectedByModifier(modifier))\n return false;\n\n modifier = _.extend({$set:{}, $unset:{}}, modifier);\n var modifierPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset));\n\n if (!self.isSimple())\n return true;\n\n if (_.any(self._getPaths(), pathHasNumericKeys) ||\n _.any(modifierPaths, pathHasNumericKeys))\n return true;\n\n // check if there is a $set or $unset that indicates something is an\n // object rather than a scalar in the actual object where we saw $-operator\n // NOTE: it is correct since we allow only scalars in $-operators\n // Example: for selector {'a.b': {$gt: 5}} the modifier {'a.b.c':7} would\n // definitely set the result to false as 'a.b' appears to be an object.\n var expectedScalarIsObject = _.any(self._selector, function (sel, path) {\n if (! isOperatorObject(sel))\n return false;\n return _.any(modifierPaths, function (modifierPath) {\n return startsWith(modifierPath, path + '.');\n });\n });\n\n if (expectedScalarIsObject)\n return false;\n\n // See if we can apply the modifier on the ideally matching object. If it\n // still matches the selector, then the modifier could have turned the real\n // object in the database into something matching.\n var matchingDocument = EJSON.clone(self.matchingDocument());\n\n // The selector is too complex, anything can happen.\n if (matchingDocument === null)\n return true;\n\n try {\n LocalCollection._modify(matchingDocument, modifier);\n } catch (e) {\n // Couldn't set a property on a field which is a scalar or null in the\n // selector.\n // Example:\n // real document: { 'a.b': 3 }\n // selector: { 'a': 12 }\n // converted selector (ideal document): { 'a': 12 }\n // modifier: { $set: { 'a.b': 4 } }\n // We don't know what real document was like but from the error raised by\n // $set on a scalar field we can reason that the structure of real document\n // is completely different.\n if (e.name === \"MinimongoError\" && e.setPropertyError)\n return false;\n throw e;\n }\n\n return self.documentMatches(matchingDocument).result;\n};\n\n// Returns an object that would match the selector if possible or null if the\n// selector is too complex for us to analyze\n// { 'a.b': { ans: 42 }, 'foo.bar': null, 'foo.baz': \"something\" }\n// => { a: { b: { ans: 42 } }, foo: { bar: null, baz: \"something\" } }\nMinimongo.Matcher.prototype.matchingDocument = function () {\n var self = this;\n\n // check if it was computed before\n if (self._matchingDocument !== undefined)\n return self._matchingDocument;\n\n // If the analysis of this selector is too hard for our implementation\n // fallback to \"YES\"\n var fallback = false;\n self._matchingDocument = pathsToTree(self._getPaths(),\n function (path) {\n var valueSelector = self._selector[path];\n if (isOperatorObject(valueSelector)) {\n // if there is a strict equality, there is a good\n // chance we can use one of those as \"matching\"\n // dummy value\n if (valueSelector.$in) {\n var matcher = new Minimongo.Matcher({ placeholder: valueSelector });\n\n // Return anything from $in that matches the whole selector for this\n // path. If nothing matches, returns `undefined` as nothing can make\n // this selector into `true`.\n return _.find(valueSelector.$in, function (x) {\n return matcher.documentMatches({ placeholder: x }).result;\n });\n } else if (onlyContainsKeys(valueSelector, ['$gt', '$gte', '$lt', '$lte'])) {\n var lowerBound = -Infinity, upperBound = Infinity;\n _.each(['$lte', '$lt'], function (op) {\n if (_.has(valueSelector, op) && valueSelector[op] < upperBound)\n upperBound = valueSelector[op];\n });\n _.each(['$gte', '$gt'], function (op) {\n if (_.has(valueSelector, op) && valueSelector[op] > lowerBound)\n lowerBound = valueSelector[op];\n });\n\n var middle = (lowerBound + upperBound) / 2;\n var matcher = new Minimongo.Matcher({ placeholder: valueSelector });\n if (!matcher.documentMatches({ placeholder: middle }).result &&\n (middle === lowerBound || middle === upperBound))\n fallback = true;\n\n return middle;\n } else if (onlyContainsKeys(valueSelector, ['$nin',' $ne'])) {\n // Since self._isSimple makes sure $nin and $ne are not combined with\n // objects or arrays, we can confidently return an empty object as it\n // never matches any scalar.\n return {};\n } else {\n fallback = true;\n }\n }\n return self._selector[path];\n },\n _.identity /*conflict resolution is no resolution*/);\n\n if (fallback)\n self._matchingDocument = null;\n\n return self._matchingDocument;\n};\n\nvar getPaths = function (sel) {\n return _.keys(new Minimongo.Matcher(sel)._paths);\n return _.chain(sel).map(function (v, k) {\n // we don't know how to handle $where because it can be anything\n if (k === \"$where\")\n return ''; // matches everything\n // we branch from $or/$and/$nor operator\n if (_.contains(['$or', '$and', '$nor'], k))\n return _.map(v, getPaths);\n // the value is a literal or some comparison operator\n return k;\n }).flatten().uniq().value();\n};\n\n// A helper to ensure object has only certain keys\nvar onlyContainsKeys = function (obj, keys) {\n return _.all(obj, function (v, k) {\n return _.contains(keys, k);\n });\n};\n\nvar pathHasNumericKeys = function (path) {\n return _.any(path.split('.'), isNumericKey);\n}\n\n// XXX from Underscore.String (http://epeli.github.com/underscore.string/)\nvar startsWith = function(str, starts) {\n return str.length >= starts.length &&\n str.substring(0, starts.length) === starts;\n};\n\n","Minimongo.Sorter.prototype.combineIntoProjection = function (projection) {\n var self = this;\n var specPaths = Minimongo._pathsElidingNumericKeys(self._getPaths());\n return combineImportantPathsIntoProjection(specPaths, projection);\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js b/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js deleted file mode 100644 index 538d574..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js +++ /dev/null @@ -1,3249 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - -/* Package-scope variables */ -var moment; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/momentjs:moment/moment.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -//! moment.js // 1 -//! version : 2.10.6 // 2 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors // 3 -//! license : MIT // 4 -//! momentjs.com // 5 - // 6 -(function (global, factory) { // 7 - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : // 8 - typeof define === 'function' && define.amd ? define(factory) : // 9 - global.moment = factory() // 10 -}(this, function () { 'use strict'; // 11 - // 12 - var hookCallback; // 13 - // 14 - function utils_hooks__hooks () { // 15 - return hookCallback.apply(null, arguments); // 16 - } // 17 - // 18 - // This is done to register the method called with moment() // 19 - // without creating circular dependencies. // 20 - function setHookCallback (callback) { // 21 - hookCallback = callback; // 22 - } // 23 - // 24 - function isArray(input) { // 25 - return Object.prototype.toString.call(input) === '[object Array]'; // 26 - } // 27 - // 28 - function isDate(input) { // 29 - return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; // 30 - } // 31 - // 32 - function map(arr, fn) { // 33 - var res = [], i; // 34 - for (i = 0; i < arr.length; ++i) { // 35 - res.push(fn(arr[i], i)); // 36 - } // 37 - return res; // 38 - } // 39 - // 40 - function hasOwnProp(a, b) { // 41 - return Object.prototype.hasOwnProperty.call(a, b); // 42 - } // 43 - // 44 - function extend(a, b) { // 45 - for (var i in b) { // 46 - if (hasOwnProp(b, i)) { // 47 - a[i] = b[i]; // 48 - } // 49 - } // 50 - // 51 - if (hasOwnProp(b, 'toString')) { // 52 - a.toString = b.toString; // 53 - } // 54 - // 55 - if (hasOwnProp(b, 'valueOf')) { // 56 - a.valueOf = b.valueOf; // 57 - } // 58 - // 59 - return a; // 60 - } // 61 - // 62 - function create_utc__createUTC (input, format, locale, strict) { // 63 - return createLocalOrUTC(input, format, locale, strict, true).utc(); // 64 - } // 65 - // 66 - function defaultParsingFlags() { // 67 - // We need to deep clone this object. // 68 - return { // 69 - empty : false, // 70 - unusedTokens : [], // 71 - unusedInput : [], // 72 - overflow : -2, // 73 - charsLeftOver : 0, // 74 - nullInput : false, // 75 - invalidMonth : null, // 76 - invalidFormat : false, // 77 - userInvalidated : false, // 78 - iso : false // 79 - }; // 80 - } // 81 - // 82 - function getParsingFlags(m) { // 83 - if (m._pf == null) { // 84 - m._pf = defaultParsingFlags(); // 85 - } // 86 - return m._pf; // 87 - } // 88 - // 89 - function valid__isValid(m) { // 90 - if (m._isValid == null) { // 91 - var flags = getParsingFlags(m); // 92 - m._isValid = !isNaN(m._d.getTime()) && // 93 - flags.overflow < 0 && // 94 - !flags.empty && // 95 - !flags.invalidMonth && // 96 - !flags.invalidWeekday && // 97 - !flags.nullInput && // 98 - !flags.invalidFormat && // 99 - !flags.userInvalidated; // 100 - // 101 - if (m._strict) { // 102 - m._isValid = m._isValid && // 103 - flags.charsLeftOver === 0 && // 104 - flags.unusedTokens.length === 0 && // 105 - flags.bigHour === undefined; // 106 - } // 107 - } // 108 - return m._isValid; // 109 - } // 110 - // 111 - function valid__createInvalid (flags) { // 112 - var m = create_utc__createUTC(NaN); // 113 - if (flags != null) { // 114 - extend(getParsingFlags(m), flags); // 115 - } // 116 - else { // 117 - getParsingFlags(m).userInvalidated = true; // 118 - } // 119 - // 120 - return m; // 121 - } // 122 - // 123 - var momentProperties = utils_hooks__hooks.momentProperties = []; // 124 - // 125 - function copyConfig(to, from) { // 126 - var i, prop, val; // 127 - // 128 - if (typeof from._isAMomentObject !== 'undefined') { // 129 - to._isAMomentObject = from._isAMomentObject; // 130 - } // 131 - if (typeof from._i !== 'undefined') { // 132 - to._i = from._i; // 133 - } // 134 - if (typeof from._f !== 'undefined') { // 135 - to._f = from._f; // 136 - } // 137 - if (typeof from._l !== 'undefined') { // 138 - to._l = from._l; // 139 - } // 140 - if (typeof from._strict !== 'undefined') { // 141 - to._strict = from._strict; // 142 - } // 143 - if (typeof from._tzm !== 'undefined') { // 144 - to._tzm = from._tzm; // 145 - } // 146 - if (typeof from._isUTC !== 'undefined') { // 147 - to._isUTC = from._isUTC; // 148 - } // 149 - if (typeof from._offset !== 'undefined') { // 150 - to._offset = from._offset; // 151 - } // 152 - if (typeof from._pf !== 'undefined') { // 153 - to._pf = getParsingFlags(from); // 154 - } // 155 - if (typeof from._locale !== 'undefined') { // 156 - to._locale = from._locale; // 157 - } // 158 - // 159 - if (momentProperties.length > 0) { // 160 - for (i in momentProperties) { // 161 - prop = momentProperties[i]; // 162 - val = from[prop]; // 163 - if (typeof val !== 'undefined') { // 164 - to[prop] = val; // 165 - } // 166 - } // 167 - } // 168 - // 169 - return to; // 170 - } // 171 - // 172 - var updateInProgress = false; // 173 - // 174 - // Moment prototype object // 175 - function Moment(config) { // 176 - copyConfig(this, config); // 177 - this._d = new Date(config._d != null ? config._d.getTime() : NaN); // 178 - // Prevent infinite loop in case updateOffset creates new moment // 179 - // objects. // 180 - if (updateInProgress === false) { // 181 - updateInProgress = true; // 182 - utils_hooks__hooks.updateOffset(this); // 183 - updateInProgress = false; // 184 - } // 185 - } // 186 - // 187 - function isMoment (obj) { // 188 - return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); // 189 - } // 190 - // 191 - function absFloor (number) { // 192 - if (number < 0) { // 193 - return Math.ceil(number); // 194 - } else { // 195 - return Math.floor(number); // 196 - } // 197 - } // 198 - // 199 - function toInt(argumentForCoercion) { // 200 - var coercedNumber = +argumentForCoercion, // 201 - value = 0; // 202 - // 203 - if (coercedNumber !== 0 && isFinite(coercedNumber)) { // 204 - value = absFloor(coercedNumber); // 205 - } // 206 - // 207 - return value; // 208 - } // 209 - // 210 - function compareArrays(array1, array2, dontConvert) { // 211 - var len = Math.min(array1.length, array2.length), // 212 - lengthDiff = Math.abs(array1.length - array2.length), // 213 - diffs = 0, // 214 - i; // 215 - for (i = 0; i < len; i++) { // 216 - if ((dontConvert && array1[i] !== array2[i]) || // 217 - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { // 218 - diffs++; // 219 - } // 220 - } // 221 - return diffs + lengthDiff; // 222 - } // 223 - // 224 - function Locale() { // 225 - } // 226 - // 227 - var locales = {}; // 228 - var globalLocale; // 229 - // 230 - function normalizeLocale(key) { // 231 - return key ? key.toLowerCase().replace('_', '-') : key; // 232 - } // 233 - // 234 - // pick the locale from the array // 235 - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each // 236 - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { // 238 - var i = 0, j, next, locale, split; // 239 - // 240 - while (i < names.length) { // 241 - split = normalizeLocale(names[i]).split('-'); // 242 - j = split.length; // 243 - next = normalizeLocale(names[i + 1]); // 244 - next = next ? next.split('-') : null; // 245 - while (j > 0) { // 246 - locale = loadLocale(split.slice(0, j).join('-')); // 247 - if (locale) { // 248 - return locale; // 249 - } // 250 - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { // 251 - //the next array item is better than a shallower substring of this one // 252 - break; // 253 - } // 254 - j--; // 255 - } // 256 - i++; // 257 - } // 258 - return null; // 259 - } // 260 - // 261 - function loadLocale(name) { // 262 - var oldLocale = null; // 263 - // TODO: Find a better way to register and load all the locales in Node // 264 - if (!locales[name] && typeof module !== 'undefined' && // 265 - module && module.exports) { // 266 - try { // 267 - oldLocale = globalLocale._abbr; // 268 - require('./locale/' + name); // 269 - // because defineLocale currently also sets the global locale, we // 270 - // want to undo that for lazy loaded locales // 271 - locale_locales__getSetGlobalLocale(oldLocale); // 272 - } catch (e) { } // 273 - } // 274 - return locales[name]; // 275 - } // 276 - // 277 - // This function will load locale and then set the global locale. If // 278 - // no arguments are passed in, it will simply return the current global // 279 - // locale key. // 280 - function locale_locales__getSetGlobalLocale (key, values) { // 281 - var data; // 282 - if (key) { // 283 - if (typeof values === 'undefined') { // 284 - data = locale_locales__getLocale(key); // 285 - } // 286 - else { // 287 - data = defineLocale(key, values); // 288 - } // 289 - // 290 - if (data) { // 291 - // moment.duration._locale = moment._locale = data; // 292 - globalLocale = data; // 293 - } // 294 - } // 295 - // 296 - return globalLocale._abbr; // 297 - } // 298 - // 299 - function defineLocale (name, values) { // 300 - if (values !== null) { // 301 - values.abbr = name; // 302 - locales[name] = locales[name] || new Locale(); // 303 - locales[name].set(values); // 304 - // 305 - // backwards compat for now: also set the locale // 306 - locale_locales__getSetGlobalLocale(name); // 307 - // 308 - return locales[name]; // 309 - } else { // 310 - // useful for testing // 311 - delete locales[name]; // 312 - return null; // 313 - } // 314 - } // 315 - // 316 - // returns locale data // 317 - function locale_locales__getLocale (key) { // 318 - var locale; // 319 - // 320 - if (key && key._locale && key._locale._abbr) { // 321 - key = key._locale._abbr; // 322 - } // 323 - // 324 - if (!key) { // 325 - return globalLocale; // 326 - } // 327 - // 328 - if (!isArray(key)) { // 329 - //short-circuit everything else // 330 - locale = loadLocale(key); // 331 - if (locale) { // 332 - return locale; // 333 - } // 334 - key = [key]; // 335 - } // 336 - // 337 - return chooseLocale(key); // 338 - } // 339 - // 340 - var aliases = {}; // 341 - // 342 - function addUnitAlias (unit, shorthand) { // 343 - var lowerCase = unit.toLowerCase(); // 344 - aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; // 345 - } // 346 - // 347 - function normalizeUnits(units) { // 348 - return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; // 349 - } // 350 - // 351 - function normalizeObjectUnits(inputObject) { // 352 - var normalizedInput = {}, // 353 - normalizedProp, // 354 - prop; // 355 - // 356 - for (prop in inputObject) { // 357 - if (hasOwnProp(inputObject, prop)) { // 358 - normalizedProp = normalizeUnits(prop); // 359 - if (normalizedProp) { // 360 - normalizedInput[normalizedProp] = inputObject[prop]; // 361 - } // 362 - } // 363 - } // 364 - // 365 - return normalizedInput; // 366 - } // 367 - // 368 - function makeGetSet (unit, keepTime) { // 369 - return function (value) { // 370 - if (value != null) { // 371 - get_set__set(this, unit, value); // 372 - utils_hooks__hooks.updateOffset(this, keepTime); // 373 - return this; // 374 - } else { // 375 - return get_set__get(this, unit); // 376 - } // 377 - }; // 378 - } // 379 - // 380 - function get_set__get (mom, unit) { // 381 - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); // 382 - } // 383 - // 384 - function get_set__set (mom, unit, value) { // 385 - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); // 386 - } // 387 - // 388 - // MOMENTS // 389 - // 390 - function getSet (units, value) { // 391 - var unit; // 392 - if (typeof units === 'object') { // 393 - for (unit in units) { // 394 - this.set(unit, units[unit]); // 395 - } // 396 - } else { // 397 - units = normalizeUnits(units); // 398 - if (typeof this[units] === 'function') { // 399 - return this[units](value); // 400 - } // 401 - } // 402 - return this; // 403 - } // 404 - // 405 - function zeroFill(number, targetLength, forceSign) { // 406 - var absNumber = '' + Math.abs(number), // 407 - zerosToFill = targetLength - absNumber.length, // 408 - sign = number >= 0; // 409 - return (sign ? (forceSign ? '+' : '') : '-') + // 410 - Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; // 411 - } // 412 - // 413 - var formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; - // 415 - var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; // 416 - // 417 - var formatFunctions = {}; // 418 - // 419 - var formatTokenFunctions = {}; // 420 - // 421 - // token: 'M' // 422 - // padded: ['MM', 2] // 423 - // ordinal: 'Mo' // 424 - // callback: function () { this.month() + 1 } // 425 - function addFormatToken (token, padded, ordinal, callback) { // 426 - var func = callback; // 427 - if (typeof callback === 'string') { // 428 - func = function () { // 429 - return this[callback](); // 430 - }; // 431 - } // 432 - if (token) { // 433 - formatTokenFunctions[token] = func; // 434 - } // 435 - if (padded) { // 436 - formatTokenFunctions[padded[0]] = function () { // 437 - return zeroFill(func.apply(this, arguments), padded[1], padded[2]); // 438 - }; // 439 - } // 440 - if (ordinal) { // 441 - formatTokenFunctions[ordinal] = function () { // 442 - return this.localeData().ordinal(func.apply(this, arguments), token); // 443 - }; // 444 - } // 445 - } // 446 - // 447 - function removeFormattingTokens(input) { // 448 - if (input.match(/\[[\s\S]/)) { // 449 - return input.replace(/^\[|\]$/g, ''); // 450 - } // 451 - return input.replace(/\\/g, ''); // 452 - } // 453 - // 454 - function makeFormatFunction(format) { // 455 - var array = format.match(formattingTokens), i, length; // 456 - // 457 - for (i = 0, length = array.length; i < length; i++) { // 458 - if (formatTokenFunctions[array[i]]) { // 459 - array[i] = formatTokenFunctions[array[i]]; // 460 - } else { // 461 - array[i] = removeFormattingTokens(array[i]); // 462 - } // 463 - } // 464 - // 465 - return function (mom) { // 466 - var output = ''; // 467 - for (i = 0; i < length; i++) { // 468 - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; // 469 - } // 470 - return output; // 471 - }; // 472 - } // 473 - // 474 - // format date using native date object // 475 - function formatMoment(m, format) { // 476 - if (!m.isValid()) { // 477 - return m.localeData().invalidDate(); // 478 - } // 479 - // 480 - format = expandFormat(format, m.localeData()); // 481 - formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); // 482 - // 483 - return formatFunctions[format](m); // 484 - } // 485 - // 486 - function expandFormat(format, locale) { // 487 - var i = 5; // 488 - // 489 - function replaceLongDateFormatTokens(input) { // 490 - return locale.longDateFormat(input) || input; // 491 - } // 492 - // 493 - localFormattingTokens.lastIndex = 0; // 494 - while (i >= 0 && localFormattingTokens.test(format)) { // 495 - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); // 496 - localFormattingTokens.lastIndex = 0; // 497 - i -= 1; // 498 - } // 499 - // 500 - return format; // 501 - } // 502 - // 503 - var match1 = /\d/; // 0 - 9 // 504 - var match2 = /\d\d/; // 00 - 99 // 505 - var match3 = /\d{3}/; // 000 - 999 // 506 - var match4 = /\d{4}/; // 0000 - 9999 // 507 - var match6 = /[+-]?\d{6}/; // -999999 - 999999 // 508 - var match1to2 = /\d\d?/; // 0 - 99 // 509 - var match1to3 = /\d{1,3}/; // 0 - 999 // 510 - var match1to4 = /\d{1,4}/; // 0 - 9999 // 511 - var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 // 512 - // 513 - var matchUnsigned = /\d+/; // 0 - inf // 514 - var matchSigned = /[+-]?\d+/; // -inf - inf // 515 - // 516 - var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z // 517 - // 518 - var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 // 519 - // 520 - // any word (or two) characters or numbers including two/three word month in arabic. // 521 - var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; - // 523 - var regexes = {}; // 524 - // 525 - function isFunction (sth) { // 526 - // https://github.com/moment/moment/issues/2325 // 527 - return typeof sth === 'function' && // 528 - Object.prototype.toString.call(sth) === '[object Function]'; // 529 - } // 530 - // 531 - // 532 - function addRegexToken (token, regex, strictRegex) { // 533 - regexes[token] = isFunction(regex) ? regex : function (isStrict) { // 534 - return (isStrict && strictRegex) ? strictRegex : regex; // 535 - }; // 536 - } // 537 - // 538 - function getParseRegexForToken (token, config) { // 539 - if (!hasOwnProp(regexes, token)) { // 540 - return new RegExp(unescapeFormat(token)); // 541 - } // 542 - // 543 - return regexes[token](config._strict, config._locale); // 544 - } // 545 - // 546 - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript // 547 - function unescapeFormat(s) { // 548 - return s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { // 549 - return p1 || p2 || p3 || p4; // 550 - }).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); // 551 - } // 552 - // 553 - var tokens = {}; // 554 - // 555 - function addParseToken (token, callback) { // 556 - var i, func = callback; // 557 - if (typeof token === 'string') { // 558 - token = [token]; // 559 - } // 560 - if (typeof callback === 'number') { // 561 - func = function (input, array) { // 562 - array[callback] = toInt(input); // 563 - }; // 564 - } // 565 - for (i = 0; i < token.length; i++) { // 566 - tokens[token[i]] = func; // 567 - } // 568 - } // 569 - // 570 - function addWeekParseToken (token, callback) { // 571 - addParseToken(token, function (input, array, config, token) { // 572 - config._w = config._w || {}; // 573 - callback(input, config._w, config, token); // 574 - }); // 575 - } // 576 - // 577 - function addTimeToArrayFromToken(token, input, config) { // 578 - if (input != null && hasOwnProp(tokens, token)) { // 579 - tokens[token](input, config._a, config, token); // 580 - } // 581 - } // 582 - // 583 - var YEAR = 0; // 584 - var MONTH = 1; // 585 - var DATE = 2; // 586 - var HOUR = 3; // 587 - var MINUTE = 4; // 588 - var SECOND = 5; // 589 - var MILLISECOND = 6; // 590 - // 591 - function daysInMonth(year, month) { // 592 - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); // 593 - } // 594 - // 595 - // FORMATTING // 596 - // 597 - addFormatToken('M', ['MM', 2], 'Mo', function () { // 598 - return this.month() + 1; // 599 - }); // 600 - // 601 - addFormatToken('MMM', 0, 0, function (format) { // 602 - return this.localeData().monthsShort(this, format); // 603 - }); // 604 - // 605 - addFormatToken('MMMM', 0, 0, function (format) { // 606 - return this.localeData().months(this, format); // 607 - }); // 608 - // 609 - // ALIASES // 610 - // 611 - addUnitAlias('month', 'M'); // 612 - // 613 - // PARSING // 614 - // 615 - addRegexToken('M', match1to2); // 616 - addRegexToken('MM', match1to2, match2); // 617 - addRegexToken('MMM', matchWord); // 618 - addRegexToken('MMMM', matchWord); // 619 - // 620 - addParseToken(['M', 'MM'], function (input, array) { // 621 - array[MONTH] = toInt(input) - 1; // 622 - }); // 623 - // 624 - addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { // 625 - var month = config._locale.monthsParse(input, token, config._strict); // 626 - // if we didn't find a month name, mark the date as invalid. // 627 - if (month != null) { // 628 - array[MONTH] = month; // 629 - } else { // 630 - getParsingFlags(config).invalidMonth = input; // 631 - } // 632 - }); // 633 - // 634 - // LOCALES // 635 - // 636 - var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); - function localeMonths (m) { // 638 - return this._months[m.month()]; // 639 - } // 640 - // 641 - var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); // 642 - function localeMonthsShort (m) { // 643 - return this._monthsShort[m.month()]; // 644 - } // 645 - // 646 - function localeMonthsParse (monthName, format, strict) { // 647 - var i, mom, regex; // 648 - // 649 - if (!this._monthsParse) { // 650 - this._monthsParse = []; // 651 - this._longMonthsParse = []; // 652 - this._shortMonthsParse = []; // 653 - } // 654 - // 655 - for (i = 0; i < 12; i++) { // 656 - // make the regex if we don't have it already // 657 - mom = create_utc__createUTC([2000, i]); // 658 - if (strict && !this._longMonthsParse[i]) { // 659 - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); // 660 - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); // 661 - } // 662 - if (!strict && !this._monthsParse[i]) { // 663 - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); // 664 - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); // 665 - } // 666 - // test the regex // 667 - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { // 668 - return i; // 669 - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { // 670 - return i; // 671 - } else if (!strict && this._monthsParse[i].test(monthName)) { // 672 - return i; // 673 - } // 674 - } // 675 - } // 676 - // 677 - // MOMENTS // 678 - // 679 - function setMonth (mom, value) { // 680 - var dayOfMonth; // 681 - // 682 - // TODO: Move this out of here! // 683 - if (typeof value === 'string') { // 684 - value = mom.localeData().monthsParse(value); // 685 - // TODO: Another silent failure? // 686 - if (typeof value !== 'number') { // 687 - return mom; // 688 - } // 689 - } // 690 - // 691 - dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); // 692 - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); // 693 - return mom; // 694 - } // 695 - // 696 - function getSetMonth (value) { // 697 - if (value != null) { // 698 - setMonth(this, value); // 699 - utils_hooks__hooks.updateOffset(this, true); // 700 - return this; // 701 - } else { // 702 - return get_set__get(this, 'Month'); // 703 - } // 704 - } // 705 - // 706 - function getDaysInMonth () { // 707 - return daysInMonth(this.year(), this.month()); // 708 - } // 709 - // 710 - function checkOverflow (m) { // 711 - var overflow; // 712 - var a = m._a; // 713 - // 714 - if (a && getParsingFlags(m).overflow === -2) { // 715 - overflow = // 716 - a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : // 717 - a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : // 718 - a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : - a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : // 720 - a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : // 721 - a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : // 722 - -1; // 723 - // 724 - if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { // 725 - overflow = DATE; // 726 - } // 727 - // 728 - getParsingFlags(m).overflow = overflow; // 729 - } // 730 - // 731 - return m; // 732 - } // 733 - // 734 - function warn(msg) { // 735 - if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); // 737 - } // 738 - } // 739 - // 740 - function deprecate(msg, fn) { // 741 - var firstTime = true; // 742 - // 743 - return extend(function () { // 744 - if (firstTime) { // 745 - warn(msg + '\n' + (new Error()).stack); // 746 - firstTime = false; // 747 - } // 748 - return fn.apply(this, arguments); // 749 - }, fn); // 750 - } // 751 - // 752 - var deprecations = {}; // 753 - // 754 - function deprecateSimple(name, msg) { // 755 - if (!deprecations[name]) { // 756 - warn(msg); // 757 - deprecations[name] = true; // 758 - } // 759 - } // 760 - // 761 - utils_hooks__hooks.suppressDeprecationWarnings = false; // 762 - // 763 - var from_string__isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; - // 765 - var isoDates = [ // 766 - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], // 767 - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], // 768 - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], // 769 - ['GGGG-[W]WW', /\d{4}-W\d{2}/], // 770 - ['YYYY-DDD', /\d{4}-\d{3}/] // 771 - ]; // 772 - // 773 - // iso time formats and regexes // 774 - var isoTimes = [ // 775 - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], // 776 - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], // 777 - ['HH:mm', /(T| )\d\d:\d\d/], // 778 - ['HH', /(T| )\d\d/] // 779 - ]; // 780 - // 781 - var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // 782 - // 783 - // date from iso format // 784 - function configFromISO(config) { // 785 - var i, l, // 786 - string = config._i, // 787 - match = from_string__isoRegex.exec(string); // 788 - // 789 - if (match) { // 790 - getParsingFlags(config).iso = true; // 791 - for (i = 0, l = isoDates.length; i < l; i++) { // 792 - if (isoDates[i][1].exec(string)) { // 793 - config._f = isoDates[i][0]; // 794 - break; // 795 - } // 796 - } // 797 - for (i = 0, l = isoTimes.length; i < l; i++) { // 798 - if (isoTimes[i][1].exec(string)) { // 799 - // match[6] should be 'T' or space // 800 - config._f += (match[6] || ' ') + isoTimes[i][0]; // 801 - break; // 802 - } // 803 - } // 804 - if (string.match(matchOffset)) { // 805 - config._f += 'Z'; // 806 - } // 807 - configFromStringAndFormat(config); // 808 - } else { // 809 - config._isValid = false; // 810 - } // 811 - } // 812 - // 813 - // date from iso format or fallback // 814 - function configFromString(config) { // 815 - var matched = aspNetJsonRegex.exec(config._i); // 816 - // 817 - if (matched !== null) { // 818 - config._d = new Date(+matched[1]); // 819 - return; // 820 - } // 821 - // 822 - configFromISO(config); // 823 - if (config._isValid === false) { // 824 - delete config._isValid; // 825 - utils_hooks__hooks.createFromInputFallback(config); // 826 - } // 827 - } // 828 - // 829 - utils_hooks__hooks.createFromInputFallback = deprecate( // 830 - 'moment construction falls back to js Date. This is ' + // 831 - 'discouraged and will be removed in upcoming major ' + // 832 - 'release. Please refer to ' + // 833 - 'https://github.com/moment/moment/issues/1407 for more info.', // 834 - function (config) { // 835 - config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); // 836 - } // 837 - ); // 838 - // 839 - function createDate (y, m, d, h, M, s, ms) { // 840 - //can't just apply() to create a date: // 841 - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); // 843 - // 844 - //the date constructor doesn't accept years < 1970 // 845 - if (y < 1970) { // 846 - date.setFullYear(y); // 847 - } // 848 - return date; // 849 - } // 850 - // 851 - function createUTCDate (y) { // 852 - var date = new Date(Date.UTC.apply(null, arguments)); // 853 - if (y < 1970) { // 854 - date.setUTCFullYear(y); // 855 - } // 856 - return date; // 857 - } // 858 - // 859 - addFormatToken(0, ['YY', 2], 0, function () { // 860 - return this.year() % 100; // 861 - }); // 862 - // 863 - addFormatToken(0, ['YYYY', 4], 0, 'year'); // 864 - addFormatToken(0, ['YYYYY', 5], 0, 'year'); // 865 - addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // 866 - // 867 - // ALIASES // 868 - // 869 - addUnitAlias('year', 'y'); // 870 - // 871 - // PARSING // 872 - // 873 - addRegexToken('Y', matchSigned); // 874 - addRegexToken('YY', match1to2, match2); // 875 - addRegexToken('YYYY', match1to4, match4); // 876 - addRegexToken('YYYYY', match1to6, match6); // 877 - addRegexToken('YYYYYY', match1to6, match6); // 878 - // 879 - addParseToken(['YYYYY', 'YYYYYY'], YEAR); // 880 - addParseToken('YYYY', function (input, array) { // 881 - array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input); // 882 - }); // 883 - addParseToken('YY', function (input, array) { // 884 - array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input); // 885 - }); // 886 - // 887 - // HELPERS // 888 - // 889 - function daysInYear(year) { // 890 - return isLeapYear(year) ? 366 : 365; // 891 - } // 892 - // 893 - function isLeapYear(year) { // 894 - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; // 895 - } // 896 - // 897 - // HOOKS // 898 - // 899 - utils_hooks__hooks.parseTwoDigitYear = function (input) { // 900 - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); // 901 - }; // 902 - // 903 - // MOMENTS // 904 - // 905 - var getSetYear = makeGetSet('FullYear', false); // 906 - // 907 - function getIsLeapYear () { // 908 - return isLeapYear(this.year()); // 909 - } // 910 - // 911 - addFormatToken('w', ['ww', 2], 'wo', 'week'); // 912 - addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // 913 - // 914 - // ALIASES // 915 - // 916 - addUnitAlias('week', 'w'); // 917 - addUnitAlias('isoWeek', 'W'); // 918 - // 919 - // PARSING // 920 - // 921 - addRegexToken('w', match1to2); // 922 - addRegexToken('ww', match1to2, match2); // 923 - addRegexToken('W', match1to2); // 924 - addRegexToken('WW', match1to2, match2); // 925 - // 926 - addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { // 927 - week[token.substr(0, 1)] = toInt(input); // 928 - }); // 929 - // 930 - // HELPERS // 931 - // 932 - // firstDayOfWeek 0 = sun, 6 = sat // 933 - // the day of the week that starts the week // 934 - // (usually sunday or monday) // 935 - // firstDayOfWeekOfYear 0 = sun, 6 = sat // 936 - // the first week is the week that contains the first // 937 - // of this day of the week // 938 - // (eg. ISO weeks use thursday (4)) // 939 - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { // 940 - var end = firstDayOfWeekOfYear - firstDayOfWeek, // 941 - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), // 942 - adjustedMoment; // 943 - // 944 - // 945 - if (daysToDayOfWeek > end) { // 946 - daysToDayOfWeek -= 7; // 947 - } // 948 - // 949 - if (daysToDayOfWeek < end - 7) { // 950 - daysToDayOfWeek += 7; // 951 - } // 952 - // 953 - adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, 'd'); // 954 - return { // 955 - week: Math.ceil(adjustedMoment.dayOfYear() / 7), // 956 - year: adjustedMoment.year() // 957 - }; // 958 - } // 959 - // 960 - // LOCALES // 961 - // 962 - function localeWeek (mom) { // 963 - return weekOfYear(mom, this._week.dow, this._week.doy).week; // 964 - } // 965 - // 966 - var defaultLocaleWeek = { // 967 - dow : 0, // Sunday is the first day of the week. // 968 - doy : 6 // The week that contains Jan 1st is the first week of the year. // 969 - }; // 970 - // 971 - function localeFirstDayOfWeek () { // 972 - return this._week.dow; // 973 - } // 974 - // 975 - function localeFirstDayOfYear () { // 976 - return this._week.doy; // 977 - } // 978 - // 979 - // MOMENTS // 980 - // 981 - function getSetWeek (input) { // 982 - var week = this.localeData().week(this); // 983 - return input == null ? week : this.add((input - week) * 7, 'd'); // 984 - } // 985 - // 986 - function getSetISOWeek (input) { // 987 - var week = weekOfYear(this, 1, 4).week; // 988 - return input == null ? week : this.add((input - week) * 7, 'd'); // 989 - } // 990 - // 991 - addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // 992 - // 993 - // ALIASES // 994 - // 995 - addUnitAlias('dayOfYear', 'DDD'); // 996 - // 997 - // PARSING // 998 - // 999 - addRegexToken('DDD', match1to3); // 1000 - addRegexToken('DDDD', match3); // 1001 - addParseToken(['DDD', 'DDDD'], function (input, array, config) { // 1002 - config._dayOfYear = toInt(input); // 1003 - }); // 1004 - // 1005 - // HELPERS // 1006 - // 1007 - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday // 1008 - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { // 1009 - var week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear; - if (d < firstDayOfWeek) { // 1011 - d += 7; // 1012 - } // 1013 - // 1014 - weekday = weekday != null ? 1 * weekday : firstDayOfWeek; // 1015 - // 1016 - dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday; // 1017 - // 1018 - return { // 1019 - year: dayOfYear > 0 ? year : year - 1, // 1020 - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear // 1021 - }; // 1022 - } // 1023 - // 1024 - // MOMENTS // 1025 - // 1026 - function getSetDayOfYear (input) { // 1027 - var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; // 1028 - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); // 1029 - } // 1030 - // 1031 - // Pick the first defined of two or three arguments. // 1032 - function defaults(a, b, c) { // 1033 - if (a != null) { // 1034 - return a; // 1035 - } // 1036 - if (b != null) { // 1037 - return b; // 1038 - } // 1039 - return c; // 1040 - } // 1041 - // 1042 - function currentDateArray(config) { // 1043 - var now = new Date(); // 1044 - if (config._useUTC) { // 1045 - return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()]; // 1046 - } // 1047 - return [now.getFullYear(), now.getMonth(), now.getDate()]; // 1048 - } // 1049 - // 1050 - // convert an array to a date. // 1051 - // the array should mirror the parameters below // 1052 - // note: all values past the year are optional and will default to the lowest possible value. // 1053 - // [year, month, day , hour, minute, second, millisecond] // 1054 - function configFromArray (config) { // 1055 - var i, date, input = [], currentDate, yearToUse; // 1056 - // 1057 - if (config._d) { // 1058 - return; // 1059 - } // 1060 - // 1061 - currentDate = currentDateArray(config); // 1062 - // 1063 - //compute day of the year from weeks and weekdays // 1064 - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { // 1065 - dayOfYearFromWeekInfo(config); // 1066 - } // 1067 - // 1068 - //if the day of the year is set, figure out what it is // 1069 - if (config._dayOfYear) { // 1070 - yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); // 1071 - // 1072 - if (config._dayOfYear > daysInYear(yearToUse)) { // 1073 - getParsingFlags(config)._overflowDayOfYear = true; // 1074 - } // 1075 - // 1076 - date = createUTCDate(yearToUse, 0, config._dayOfYear); // 1077 - config._a[MONTH] = date.getUTCMonth(); // 1078 - config._a[DATE] = date.getUTCDate(); // 1079 - } // 1080 - // 1081 - // Default to current date. // 1082 - // * if no year, month, day of month are given, default to today // 1083 - // * if day of month is given, default month and year // 1084 - // * if month is given, default only year // 1085 - // * if year is given, don't default anything // 1086 - for (i = 0; i < 3 && config._a[i] == null; ++i) { // 1087 - config._a[i] = input[i] = currentDate[i]; // 1088 - } // 1089 - // 1090 - // Zero out whatever was not defaulted, including time // 1091 - for (; i < 7; i++) { // 1092 - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; // 1093 - } // 1094 - // 1095 - // Check for 24:00:00.000 // 1096 - if (config._a[HOUR] === 24 && // 1097 - config._a[MINUTE] === 0 && // 1098 - config._a[SECOND] === 0 && // 1099 - config._a[MILLISECOND] === 0) { // 1100 - config._nextDay = true; // 1101 - config._a[HOUR] = 0; // 1102 - } // 1103 - // 1104 - config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); // 1105 - // Apply timezone offset from input. The actual utcOffset can be changed // 1106 - // with parseZone. // 1107 - if (config._tzm != null) { // 1108 - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); // 1109 - } // 1110 - // 1111 - if (config._nextDay) { // 1112 - config._a[HOUR] = 24; // 1113 - } // 1114 - } // 1115 - // 1116 - function dayOfYearFromWeekInfo(config) { // 1117 - var w, weekYear, week, weekday, dow, doy, temp; // 1118 - // 1119 - w = config._w; // 1120 - if (w.GG != null || w.W != null || w.E != null) { // 1121 - dow = 1; // 1122 - doy = 4; // 1123 - // 1124 - // TODO: We need to take the current isoWeekYear, but that depends on // 1125 - // how we interpret now (local, utc, fixed offset). So create // 1126 - // a now version of current config (take local/utc/offset flags, and // 1127 - // create now). // 1128 - weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year); // 1129 - week = defaults(w.W, 1); // 1130 - weekday = defaults(w.E, 1); // 1131 - } else { // 1132 - dow = config._locale._week.dow; // 1133 - doy = config._locale._week.doy; // 1134 - // 1135 - weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year); // 1136 - week = defaults(w.w, 1); // 1137 - // 1138 - if (w.d != null) { // 1139 - // weekday -- low day numbers are considered next week // 1140 - weekday = w.d; // 1141 - if (weekday < dow) { // 1142 - ++week; // 1143 - } // 1144 - } else if (w.e != null) { // 1145 - // local weekday -- counting starts from begining of week // 1146 - weekday = w.e + dow; // 1147 - } else { // 1148 - // default to begining of week // 1149 - weekday = dow; // 1150 - } // 1151 - } // 1152 - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); // 1153 - // 1154 - config._a[YEAR] = temp.year; // 1155 - config._dayOfYear = temp.dayOfYear; // 1156 - } // 1157 - // 1158 - utils_hooks__hooks.ISO_8601 = function () {}; // 1159 - // 1160 - // date from string and format string // 1161 - function configFromStringAndFormat(config) { // 1162 - // TODO: Move this to another part of the creation flow to prevent circular deps // 1163 - if (config._f === utils_hooks__hooks.ISO_8601) { // 1164 - configFromISO(config); // 1165 - return; // 1166 - } // 1167 - // 1168 - config._a = []; // 1169 - getParsingFlags(config).empty = true; // 1170 - // 1171 - // This array is used to make a Date, either with `new Date` or `Date.UTC` // 1172 - var string = '' + config._i, // 1173 - i, parsedInput, tokens, token, skipped, // 1174 - stringLength = string.length, // 1175 - totalParsedInputLength = 0; // 1176 - // 1177 - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; // 1178 - // 1179 - for (i = 0; i < tokens.length; i++) { // 1180 - token = tokens[i]; // 1181 - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // 1182 - if (parsedInput) { // 1183 - skipped = string.substr(0, string.indexOf(parsedInput)); // 1184 - if (skipped.length > 0) { // 1185 - getParsingFlags(config).unusedInput.push(skipped); // 1186 - } // 1187 - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); // 1188 - totalParsedInputLength += parsedInput.length; // 1189 - } // 1190 - // don't parse if it's not a known token // 1191 - if (formatTokenFunctions[token]) { // 1192 - if (parsedInput) { // 1193 - getParsingFlags(config).empty = false; // 1194 - } // 1195 - else { // 1196 - getParsingFlags(config).unusedTokens.push(token); // 1197 - } // 1198 - addTimeToArrayFromToken(token, parsedInput, config); // 1199 - } // 1200 - else if (config._strict && !parsedInput) { // 1201 - getParsingFlags(config).unusedTokens.push(token); // 1202 - } // 1203 - } // 1204 - // 1205 - // add remaining unparsed input length to the string // 1206 - getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; // 1207 - if (string.length > 0) { // 1208 - getParsingFlags(config).unusedInput.push(string); // 1209 - } // 1210 - // 1211 - // clear _12h flag if hour is <= 12 // 1212 - if (getParsingFlags(config).bigHour === true && // 1213 - config._a[HOUR] <= 12 && // 1214 - config._a[HOUR] > 0) { // 1215 - getParsingFlags(config).bigHour = undefined; // 1216 - } // 1217 - // handle meridiem // 1218 - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); // 1219 - // 1220 - configFromArray(config); // 1221 - checkOverflow(config); // 1222 - } // 1223 - // 1224 - // 1225 - function meridiemFixWrap (locale, hour, meridiem) { // 1226 - var isPm; // 1227 - // 1228 - if (meridiem == null) { // 1229 - // nothing to do // 1230 - return hour; // 1231 - } // 1232 - if (locale.meridiemHour != null) { // 1233 - return locale.meridiemHour(hour, meridiem); // 1234 - } else if (locale.isPM != null) { // 1235 - // Fallback // 1236 - isPm = locale.isPM(meridiem); // 1237 - if (isPm && hour < 12) { // 1238 - hour += 12; // 1239 - } // 1240 - if (!isPm && hour === 12) { // 1241 - hour = 0; // 1242 - } // 1243 - return hour; // 1244 - } else { // 1245 - // this is not supposed to happen // 1246 - return hour; // 1247 - } // 1248 - } // 1249 - // 1250 - function configFromStringAndArray(config) { // 1251 - var tempConfig, // 1252 - bestMoment, // 1253 - // 1254 - scoreToBeat, // 1255 - i, // 1256 - currentScore; // 1257 - // 1258 - if (config._f.length === 0) { // 1259 - getParsingFlags(config).invalidFormat = true; // 1260 - config._d = new Date(NaN); // 1261 - return; // 1262 - } // 1263 - // 1264 - for (i = 0; i < config._f.length; i++) { // 1265 - currentScore = 0; // 1266 - tempConfig = copyConfig({}, config); // 1267 - if (config._useUTC != null) { // 1268 - tempConfig._useUTC = config._useUTC; // 1269 - } // 1270 - tempConfig._f = config._f[i]; // 1271 - configFromStringAndFormat(tempConfig); // 1272 - // 1273 - if (!valid__isValid(tempConfig)) { // 1274 - continue; // 1275 - } // 1276 - // 1277 - // if there is any input that was not parsed add a penalty for that format // 1278 - currentScore += getParsingFlags(tempConfig).charsLeftOver; // 1279 - // 1280 - //or tokens // 1281 - currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; // 1282 - // 1283 - getParsingFlags(tempConfig).score = currentScore; // 1284 - // 1285 - if (scoreToBeat == null || currentScore < scoreToBeat) { // 1286 - scoreToBeat = currentScore; // 1287 - bestMoment = tempConfig; // 1288 - } // 1289 - } // 1290 - // 1291 - extend(config, bestMoment || tempConfig); // 1292 - } // 1293 - // 1294 - function configFromObject(config) { // 1295 - if (config._d) { // 1296 - return; // 1297 - } // 1298 - // 1299 - var i = normalizeObjectUnits(config._i); // 1300 - config._a = [i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond]; // 1301 - // 1302 - configFromArray(config); // 1303 - } // 1304 - // 1305 - function createFromConfig (config) { // 1306 - var res = new Moment(checkOverflow(prepareConfig(config))); // 1307 - if (res._nextDay) { // 1308 - // Adding is smart enough around DST // 1309 - res.add(1, 'd'); // 1310 - res._nextDay = undefined; // 1311 - } // 1312 - // 1313 - return res; // 1314 - } // 1315 - // 1316 - function prepareConfig (config) { // 1317 - var input = config._i, // 1318 - format = config._f; // 1319 - // 1320 - config._locale = config._locale || locale_locales__getLocale(config._l); // 1321 - // 1322 - if (input === null || (format === undefined && input === '')) { // 1323 - return valid__createInvalid({nullInput: true}); // 1324 - } // 1325 - // 1326 - if (typeof input === 'string') { // 1327 - config._i = input = config._locale.preparse(input); // 1328 - } // 1329 - // 1330 - if (isMoment(input)) { // 1331 - return new Moment(checkOverflow(input)); // 1332 - } else if (isArray(format)) { // 1333 - configFromStringAndArray(config); // 1334 - } else if (format) { // 1335 - configFromStringAndFormat(config); // 1336 - } else if (isDate(input)) { // 1337 - config._d = input; // 1338 - } else { // 1339 - configFromInput(config); // 1340 - } // 1341 - // 1342 - return config; // 1343 - } // 1344 - // 1345 - function configFromInput(config) { // 1346 - var input = config._i; // 1347 - if (input === undefined) { // 1348 - config._d = new Date(); // 1349 - } else if (isDate(input)) { // 1350 - config._d = new Date(+input); // 1351 - } else if (typeof input === 'string') { // 1352 - configFromString(config); // 1353 - } else if (isArray(input)) { // 1354 - config._a = map(input.slice(0), function (obj) { // 1355 - return parseInt(obj, 10); // 1356 - }); // 1357 - configFromArray(config); // 1358 - } else if (typeof(input) === 'object') { // 1359 - configFromObject(config); // 1360 - } else if (typeof(input) === 'number') { // 1361 - // from milliseconds // 1362 - config._d = new Date(input); // 1363 - } else { // 1364 - utils_hooks__hooks.createFromInputFallback(config); // 1365 - } // 1366 - } // 1367 - // 1368 - function createLocalOrUTC (input, format, locale, strict, isUTC) { // 1369 - var c = {}; // 1370 - // 1371 - if (typeof(locale) === 'boolean') { // 1372 - strict = locale; // 1373 - locale = undefined; // 1374 - } // 1375 - // object construction must be done this way. // 1376 - // https://github.com/moment/moment/issues/1423 // 1377 - c._isAMomentObject = true; // 1378 - c._useUTC = c._isUTC = isUTC; // 1379 - c._l = locale; // 1380 - c._i = input; // 1381 - c._f = format; // 1382 - c._strict = strict; // 1383 - // 1384 - return createFromConfig(c); // 1385 - } // 1386 - // 1387 - function local__createLocal (input, format, locale, strict) { // 1388 - return createLocalOrUTC(input, format, locale, strict, false); // 1389 - } // 1390 - // 1391 - var prototypeMin = deprecate( // 1392 - 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', // 1393 - function () { // 1394 - var other = local__createLocal.apply(null, arguments); // 1395 - return other < this ? this : other; // 1396 - } // 1397 - ); // 1398 - // 1399 - var prototypeMax = deprecate( // 1400 - 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', // 1401 - function () { // 1402 - var other = local__createLocal.apply(null, arguments); // 1403 - return other > this ? this : other; // 1404 - } // 1405 - ); // 1406 - // 1407 - // Pick a moment m from moments so that m[fn](other) is true for all // 1408 - // other. This relies on the function fn to be transitive. // 1409 - // // 1410 - // moments should either be an array of moment objects or an array, whose // 1411 - // first element is an array of moment objects. // 1412 - function pickBy(fn, moments) { // 1413 - var res, i; // 1414 - if (moments.length === 1 && isArray(moments[0])) { // 1415 - moments = moments[0]; // 1416 - } // 1417 - if (!moments.length) { // 1418 - return local__createLocal(); // 1419 - } // 1420 - res = moments[0]; // 1421 - for (i = 1; i < moments.length; ++i) { // 1422 - if (!moments[i].isValid() || moments[i][fn](res)) { // 1423 - res = moments[i]; // 1424 - } // 1425 - } // 1426 - return res; // 1427 - } // 1428 - // 1429 - // TODO: Use [].sort instead? // 1430 - function min () { // 1431 - var args = [].slice.call(arguments, 0); // 1432 - // 1433 - return pickBy('isBefore', args); // 1434 - } // 1435 - // 1436 - function max () { // 1437 - var args = [].slice.call(arguments, 0); // 1438 - // 1439 - return pickBy('isAfter', args); // 1440 - } // 1441 - // 1442 - function Duration (duration) { // 1443 - var normalizedInput = normalizeObjectUnits(duration), // 1444 - years = normalizedInput.year || 0, // 1445 - quarters = normalizedInput.quarter || 0, // 1446 - months = normalizedInput.month || 0, // 1447 - weeks = normalizedInput.week || 0, // 1448 - days = normalizedInput.day || 0, // 1449 - hours = normalizedInput.hour || 0, // 1450 - minutes = normalizedInput.minute || 0, // 1451 - seconds = normalizedInput.second || 0, // 1452 - milliseconds = normalizedInput.millisecond || 0; // 1453 - // 1454 - // representation for dateAddRemove // 1455 - this._milliseconds = +milliseconds + // 1456 - seconds * 1e3 + // 1000 // 1457 - minutes * 6e4 + // 1000 * 60 // 1458 - hours * 36e5; // 1000 * 60 * 60 // 1459 - // Because of dateAddRemove treats 24 hours as different from a // 1460 - // day when working around DST, we need to store them separately // 1461 - this._days = +days + // 1462 - weeks * 7; // 1463 - // It is impossible translate months into days without knowing // 1464 - // which months you are are talking about, so we have to store // 1465 - // it separately. // 1466 - this._months = +months + // 1467 - quarters * 3 + // 1468 - years * 12; // 1469 - // 1470 - this._data = {}; // 1471 - // 1472 - this._locale = locale_locales__getLocale(); // 1473 - // 1474 - this._bubble(); // 1475 - } // 1476 - // 1477 - function isDuration (obj) { // 1478 - return obj instanceof Duration; // 1479 - } // 1480 - // 1481 - function offset (token, separator) { // 1482 - addFormatToken(token, 0, 0, function () { // 1483 - var offset = this.utcOffset(); // 1484 - var sign = '+'; // 1485 - if (offset < 0) { // 1486 - offset = -offset; // 1487 - sign = '-'; // 1488 - } // 1489 - return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); // 1490 - }); // 1491 - } // 1492 - // 1493 - offset('Z', ':'); // 1494 - offset('ZZ', ''); // 1495 - // 1496 - // PARSING // 1497 - // 1498 - addRegexToken('Z', matchOffset); // 1499 - addRegexToken('ZZ', matchOffset); // 1500 - addParseToken(['Z', 'ZZ'], function (input, array, config) { // 1501 - config._useUTC = true; // 1502 - config._tzm = offsetFromString(input); // 1503 - }); // 1504 - // 1505 - // HELPERS // 1506 - // 1507 - // timezone chunker // 1508 - // '+10:00' > ['10', '00'] // 1509 - // '-1530' > ['-15', '30'] // 1510 - var chunkOffset = /([\+\-]|\d\d)/gi; // 1511 - // 1512 - function offsetFromString(string) { // 1513 - var matches = ((string || '').match(matchOffset) || []); // 1514 - var chunk = matches[matches.length - 1] || []; // 1515 - var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; // 1516 - var minutes = +(parts[1] * 60) + toInt(parts[2]); // 1517 - // 1518 - return parts[0] === '+' ? minutes : -minutes; // 1519 - } // 1520 - // 1521 - // Return a moment from input, that is local/utc/zone equivalent to model. // 1522 - function cloneWithOffset(input, model) { // 1523 - var res, diff; // 1524 - if (model._isUTC) { // 1525 - res = model.clone(); // 1526 - diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res); // 1527 - // Use low-level api, because this fn is low-level api. // 1528 - res._d.setTime(+res._d + diff); // 1529 - utils_hooks__hooks.updateOffset(res, false); // 1530 - return res; // 1531 - } else { // 1532 - return local__createLocal(input).local(); // 1533 - } // 1534 - } // 1535 - // 1536 - function getDateOffset (m) { // 1537 - // On Firefox.24 Date#getTimezoneOffset returns a floating point. // 1538 - // https://github.com/moment/moment/pull/1871 // 1539 - return -Math.round(m._d.getTimezoneOffset() / 15) * 15; // 1540 - } // 1541 - // 1542 - // HOOKS // 1543 - // 1544 - // This function will be called whenever a moment is mutated. // 1545 - // It is intended to keep the offset in sync with the timezone. // 1546 - utils_hooks__hooks.updateOffset = function () {}; // 1547 - // 1548 - // MOMENTS // 1549 - // 1550 - // keepLocalTime = true means only change the timezone, without // 1551 - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> // 1552 - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset // 1553 - // +0200, so we adjust the time as needed, to be valid. // 1554 - // // 1555 - // Keeping the time actually adds/subtracts (one hour) // 1556 - // from the actual represented time. That is why we call updateOffset // 1557 - // a second time. In case it wants us to change the offset again // 1558 - // _changeInProgress == true case, then we have to adjust, because // 1559 - // there is no such time in the given timezone. // 1560 - function getSetOffset (input, keepLocalTime) { // 1561 - var offset = this._offset || 0, // 1562 - localAdjust; // 1563 - if (input != null) { // 1564 - if (typeof input === 'string') { // 1565 - input = offsetFromString(input); // 1566 - } // 1567 - if (Math.abs(input) < 16) { // 1568 - input = input * 60; // 1569 - } // 1570 - if (!this._isUTC && keepLocalTime) { // 1571 - localAdjust = getDateOffset(this); // 1572 - } // 1573 - this._offset = input; // 1574 - this._isUTC = true; // 1575 - if (localAdjust != null) { // 1576 - this.add(localAdjust, 'm'); // 1577 - } // 1578 - if (offset !== input) { // 1579 - if (!keepLocalTime || this._changeInProgress) { // 1580 - add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false); // 1581 - } else if (!this._changeInProgress) { // 1582 - this._changeInProgress = true; // 1583 - utils_hooks__hooks.updateOffset(this, true); // 1584 - this._changeInProgress = null; // 1585 - } // 1586 - } // 1587 - return this; // 1588 - } else { // 1589 - return this._isUTC ? offset : getDateOffset(this); // 1590 - } // 1591 - } // 1592 - // 1593 - function getSetZone (input, keepLocalTime) { // 1594 - if (input != null) { // 1595 - if (typeof input !== 'string') { // 1596 - input = -input; // 1597 - } // 1598 - // 1599 - this.utcOffset(input, keepLocalTime); // 1600 - // 1601 - return this; // 1602 - } else { // 1603 - return -this.utcOffset(); // 1604 - } // 1605 - } // 1606 - // 1607 - function setOffsetToUTC (keepLocalTime) { // 1608 - return this.utcOffset(0, keepLocalTime); // 1609 - } // 1610 - // 1611 - function setOffsetToLocal (keepLocalTime) { // 1612 - if (this._isUTC) { // 1613 - this.utcOffset(0, keepLocalTime); // 1614 - this._isUTC = false; // 1615 - // 1616 - if (keepLocalTime) { // 1617 - this.subtract(getDateOffset(this), 'm'); // 1618 - } // 1619 - } // 1620 - return this; // 1621 - } // 1622 - // 1623 - function setOffsetToParsedOffset () { // 1624 - if (this._tzm) { // 1625 - this.utcOffset(this._tzm); // 1626 - } else if (typeof this._i === 'string') { // 1627 - this.utcOffset(offsetFromString(this._i)); // 1628 - } // 1629 - return this; // 1630 - } // 1631 - // 1632 - function hasAlignedHourOffset (input) { // 1633 - input = input ? local__createLocal(input).utcOffset() : 0; // 1634 - // 1635 - return (this.utcOffset() - input) % 60 === 0; // 1636 - } // 1637 - // 1638 - function isDaylightSavingTime () { // 1639 - return ( // 1640 - this.utcOffset() > this.clone().month(0).utcOffset() || // 1641 - this.utcOffset() > this.clone().month(5).utcOffset() // 1642 - ); // 1643 - } // 1644 - // 1645 - function isDaylightSavingTimeShifted () { // 1646 - if (typeof this._isDSTShifted !== 'undefined') { // 1647 - return this._isDSTShifted; // 1648 - } // 1649 - // 1650 - var c = {}; // 1651 - // 1652 - copyConfig(c, this); // 1653 - c = prepareConfig(c); // 1654 - // 1655 - if (c._a) { // 1656 - var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a); // 1657 - this._isDSTShifted = this.isValid() && // 1658 - compareArrays(c._a, other.toArray()) > 0; // 1659 - } else { // 1660 - this._isDSTShifted = false; // 1661 - } // 1662 - // 1663 - return this._isDSTShifted; // 1664 - } // 1665 - // 1666 - function isLocal () { // 1667 - return !this._isUTC; // 1668 - } // 1669 - // 1670 - function isUtcOffset () { // 1671 - return this._isUTC; // 1672 - } // 1673 - // 1674 - function isUtc () { // 1675 - return this._isUTC && this._offset === 0; // 1676 - } // 1677 - // 1678 - var aspNetRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/; // 1679 - // 1680 - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html // 1681 - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere // 1682 - var create__isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/; - // 1684 - function create__createDuration (input, key) { // 1685 - var duration = input, // 1686 - // matching against regexp is expensive, do it on demand // 1687 - match = null, // 1688 - sign, // 1689 - ret, // 1690 - diffRes; // 1691 - // 1692 - if (isDuration(input)) { // 1693 - duration = { // 1694 - ms : input._milliseconds, // 1695 - d : input._days, // 1696 - M : input._months // 1697 - }; // 1698 - } else if (typeof input === 'number') { // 1699 - duration = {}; // 1700 - if (key) { // 1701 - duration[key] = input; // 1702 - } else { // 1703 - duration.milliseconds = input; // 1704 - } // 1705 - } else if (!!(match = aspNetRegex.exec(input))) { // 1706 - sign = (match[1] === '-') ? -1 : 1; // 1707 - duration = { // 1708 - y : 0, // 1709 - d : toInt(match[DATE]) * sign, // 1710 - h : toInt(match[HOUR]) * sign, // 1711 - m : toInt(match[MINUTE]) * sign, // 1712 - s : toInt(match[SECOND]) * sign, // 1713 - ms : toInt(match[MILLISECOND]) * sign // 1714 - }; // 1715 - } else if (!!(match = create__isoRegex.exec(input))) { // 1716 - sign = (match[1] === '-') ? -1 : 1; // 1717 - duration = { // 1718 - y : parseIso(match[2], sign), // 1719 - M : parseIso(match[3], sign), // 1720 - d : parseIso(match[4], sign), // 1721 - h : parseIso(match[5], sign), // 1722 - m : parseIso(match[6], sign), // 1723 - s : parseIso(match[7], sign), // 1724 - w : parseIso(match[8], sign) // 1725 - }; // 1726 - } else if (duration == null) {// checks for null or undefined // 1727 - duration = {}; // 1728 - } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { // 1729 - diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to)); // 1730 - // 1731 - duration = {}; // 1732 - duration.ms = diffRes.milliseconds; // 1733 - duration.M = diffRes.months; // 1734 - } // 1735 - // 1736 - ret = new Duration(duration); // 1737 - // 1738 - if (isDuration(input) && hasOwnProp(input, '_locale')) { // 1739 - ret._locale = input._locale; // 1740 - } // 1741 - // 1742 - return ret; // 1743 - } // 1744 - // 1745 - create__createDuration.fn = Duration.prototype; // 1746 - // 1747 - function parseIso (inp, sign) { // 1748 - // We'd normally use ~~inp for this, but unfortunately it also // 1749 - // converts floats to ints. // 1750 - // inp may be undefined, so careful calling replace on it. // 1751 - var res = inp && parseFloat(inp.replace(',', '.')); // 1752 - // apply sign while we're at it // 1753 - return (isNaN(res) ? 0 : res) * sign; // 1754 - } // 1755 - // 1756 - function positiveMomentsDifference(base, other) { // 1757 - var res = {milliseconds: 0, months: 0}; // 1758 - // 1759 - res.months = other.month() - base.month() + // 1760 - (other.year() - base.year()) * 12; // 1761 - if (base.clone().add(res.months, 'M').isAfter(other)) { // 1762 - --res.months; // 1763 - } // 1764 - // 1765 - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); // 1766 - // 1767 - return res; // 1768 - } // 1769 - // 1770 - function momentsDifference(base, other) { // 1771 - var res; // 1772 - other = cloneWithOffset(other, base); // 1773 - if (base.isBefore(other)) { // 1774 - res = positiveMomentsDifference(base, other); // 1775 - } else { // 1776 - res = positiveMomentsDifference(other, base); // 1777 - res.milliseconds = -res.milliseconds; // 1778 - res.months = -res.months; // 1779 - } // 1780 - // 1781 - return res; // 1782 - } // 1783 - // 1784 - function createAdder(direction, name) { // 1785 - return function (val, period) { // 1786 - var dur, tmp; // 1787 - //invert the arguments, but complain about it // 1788 - if (period !== null && !isNaN(+period)) { // 1789 - deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); - tmp = val; val = period; period = tmp; // 1791 - } // 1792 - // 1793 - val = typeof val === 'string' ? +val : val; // 1794 - dur = create__createDuration(val, period); // 1795 - add_subtract__addSubtract(this, dur, direction); // 1796 - return this; // 1797 - }; // 1798 - } // 1799 - // 1800 - function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) { // 1801 - var milliseconds = duration._milliseconds, // 1802 - days = duration._days, // 1803 - months = duration._months; // 1804 - updateOffset = updateOffset == null ? true : updateOffset; // 1805 - // 1806 - if (milliseconds) { // 1807 - mom._d.setTime(+mom._d + milliseconds * isAdding); // 1808 - } // 1809 - if (days) { // 1810 - get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding); // 1811 - } // 1812 - if (months) { // 1813 - setMonth(mom, get_set__get(mom, 'Month') + months * isAdding); // 1814 - } // 1815 - if (updateOffset) { // 1816 - utils_hooks__hooks.updateOffset(mom, days || months); // 1817 - } // 1818 - } // 1819 - // 1820 - var add_subtract__add = createAdder(1, 'add'); // 1821 - var add_subtract__subtract = createAdder(-1, 'subtract'); // 1822 - // 1823 - function moment_calendar__calendar (time, formats) { // 1824 - // We want to compare the start of today, vs this. // 1825 - // Getting start-of-today depends on whether we're local/utc/offset or not. // 1826 - var now = time || local__createLocal(), // 1827 - sod = cloneWithOffset(now, this).startOf('day'), // 1828 - diff = this.diff(sod, 'days', true), // 1829 - format = diff < -6 ? 'sameElse' : // 1830 - diff < -1 ? 'lastWeek' : // 1831 - diff < 0 ? 'lastDay' : // 1832 - diff < 1 ? 'sameDay' : // 1833 - diff < 2 ? 'nextDay' : // 1834 - diff < 7 ? 'nextWeek' : 'sameElse'; // 1835 - return this.format(formats && formats[format] || this.localeData().calendar(format, this, local__createLocal(now))); - } // 1837 - // 1838 - function clone () { // 1839 - return new Moment(this); // 1840 - } // 1841 - // 1842 - function isAfter (input, units) { // 1843 - var inputMs; // 1844 - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); // 1845 - if (units === 'millisecond') { // 1846 - input = isMoment(input) ? input : local__createLocal(input); // 1847 - return +this > +input; // 1848 - } else { // 1849 - inputMs = isMoment(input) ? +input : +local__createLocal(input); // 1850 - return inputMs < +this.clone().startOf(units); // 1851 - } // 1852 - } // 1853 - // 1854 - function isBefore (input, units) { // 1855 - var inputMs; // 1856 - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); // 1857 - if (units === 'millisecond') { // 1858 - input = isMoment(input) ? input : local__createLocal(input); // 1859 - return +this < +input; // 1860 - } else { // 1861 - inputMs = isMoment(input) ? +input : +local__createLocal(input); // 1862 - return +this.clone().endOf(units) < inputMs; // 1863 - } // 1864 - } // 1865 - // 1866 - function isBetween (from, to, units) { // 1867 - return this.isAfter(from, units) && this.isBefore(to, units); // 1868 - } // 1869 - // 1870 - function isSame (input, units) { // 1871 - var inputMs; // 1872 - units = normalizeUnits(units || 'millisecond'); // 1873 - if (units === 'millisecond') { // 1874 - input = isMoment(input) ? input : local__createLocal(input); // 1875 - return +this === +input; // 1876 - } else { // 1877 - inputMs = +local__createLocal(input); // 1878 - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); // 1879 - } // 1880 - } // 1881 - // 1882 - function diff (input, units, asFloat) { // 1883 - var that = cloneWithOffset(input, this), // 1884 - zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4, // 1885 - delta, output; // 1886 - // 1887 - units = normalizeUnits(units); // 1888 - // 1889 - if (units === 'year' || units === 'month' || units === 'quarter') { // 1890 - output = monthDiff(this, that); // 1891 - if (units === 'quarter') { // 1892 - output = output / 3; // 1893 - } else if (units === 'year') { // 1894 - output = output / 12; // 1895 - } // 1896 - } else { // 1897 - delta = this - that; // 1898 - output = units === 'second' ? delta / 1e3 : // 1000 // 1899 - units === 'minute' ? delta / 6e4 : // 1000 * 60 // 1900 - units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60 // 1901 - units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst // 1902 - units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst // 1903 - delta; // 1904 - } // 1905 - return asFloat ? output : absFloor(output); // 1906 - } // 1907 - // 1908 - function monthDiff (a, b) { // 1909 - // difference in months // 1910 - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), // 1911 - // b is in (anchor - 1 month, anchor + 1 month) // 1912 - anchor = a.clone().add(wholeMonthDiff, 'months'), // 1913 - anchor2, adjust; // 1914 - // 1915 - if (b - anchor < 0) { // 1916 - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // 1917 - // linear across the month // 1918 - adjust = (b - anchor) / (anchor - anchor2); // 1919 - } else { // 1920 - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // 1921 - // linear across the month // 1922 - adjust = (b - anchor) / (anchor2 - anchor); // 1923 - } // 1924 - // 1925 - return -(wholeMonthDiff + adjust); // 1926 - } // 1927 - // 1928 - utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; // 1929 - // 1930 - function toString () { // 1931 - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); // 1932 - } // 1933 - // 1934 - function moment_format__toISOString () { // 1935 - var m = this.clone().utc(); // 1936 - if (0 < m.year() && m.year() <= 9999) { // 1937 - if ('function' === typeof Date.prototype.toISOString) { // 1938 - // native implementation is ~50x faster, use it when we can // 1939 - return this.toDate().toISOString(); // 1940 - } else { // 1941 - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); // 1942 - } // 1943 - } else { // 1944 - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); // 1945 - } // 1946 - } // 1947 - // 1948 - function format (inputString) { // 1949 - var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat); // 1950 - return this.localeData().postformat(output); // 1951 - } // 1952 - // 1953 - function from (time, withoutSuffix) { // 1954 - if (!this.isValid()) { // 1955 - return this.localeData().invalidDate(); // 1956 - } // 1957 - return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); // 1958 - } // 1959 - // 1960 - function fromNow (withoutSuffix) { // 1961 - return this.from(local__createLocal(), withoutSuffix); // 1962 - } // 1963 - // 1964 - function to (time, withoutSuffix) { // 1965 - if (!this.isValid()) { // 1966 - return this.localeData().invalidDate(); // 1967 - } // 1968 - return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix); // 1969 - } // 1970 - // 1971 - function toNow (withoutSuffix) { // 1972 - return this.to(local__createLocal(), withoutSuffix); // 1973 - } // 1974 - // 1975 - function locale (key) { // 1976 - var newLocaleData; // 1977 - // 1978 - if (key === undefined) { // 1979 - return this._locale._abbr; // 1980 - } else { // 1981 - newLocaleData = locale_locales__getLocale(key); // 1982 - if (newLocaleData != null) { // 1983 - this._locale = newLocaleData; // 1984 - } // 1985 - return this; // 1986 - } // 1987 - } // 1988 - // 1989 - var lang = deprecate( // 1990 - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { // 1992 - if (key === undefined) { // 1993 - return this.localeData(); // 1994 - } else { // 1995 - return this.locale(key); // 1996 - } // 1997 - } // 1998 - ); // 1999 - // 2000 - function localeData () { // 2001 - return this._locale; // 2002 - } // 2003 - // 2004 - function startOf (units) { // 2005 - units = normalizeUnits(units); // 2006 - // the following switch intentionally omits break keywords // 2007 - // to utilize falling through the cases. // 2008 - switch (units) { // 2009 - case 'year': // 2010 - this.month(0); // 2011 - /* falls through */ // 2012 - case 'quarter': // 2013 - case 'month': // 2014 - this.date(1); // 2015 - /* falls through */ // 2016 - case 'week': // 2017 - case 'isoWeek': // 2018 - case 'day': // 2019 - this.hours(0); // 2020 - /* falls through */ // 2021 - case 'hour': // 2022 - this.minutes(0); // 2023 - /* falls through */ // 2024 - case 'minute': // 2025 - this.seconds(0); // 2026 - /* falls through */ // 2027 - case 'second': // 2028 - this.milliseconds(0); // 2029 - } // 2030 - // 2031 - // weeks are a special case // 2032 - if (units === 'week') { // 2033 - this.weekday(0); // 2034 - } // 2035 - if (units === 'isoWeek') { // 2036 - this.isoWeekday(1); // 2037 - } // 2038 - // 2039 - // quarters are also special // 2040 - if (units === 'quarter') { // 2041 - this.month(Math.floor(this.month() / 3) * 3); // 2042 - } // 2043 - // 2044 - return this; // 2045 - } // 2046 - // 2047 - function endOf (units) { // 2048 - units = normalizeUnits(units); // 2049 - if (units === undefined || units === 'millisecond') { // 2050 - return this; // 2051 - } // 2052 - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); // 2053 - } // 2054 - // 2055 - function to_type__valueOf () { // 2056 - return +this._d - ((this._offset || 0) * 60000); // 2057 - } // 2058 - // 2059 - function unix () { // 2060 - return Math.floor(+this / 1000); // 2061 - } // 2062 - // 2063 - function toDate () { // 2064 - return this._offset ? new Date(+this) : this._d; // 2065 - } // 2066 - // 2067 - function toArray () { // 2068 - var m = this; // 2069 - return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; // 2070 - } // 2071 - // 2072 - function toObject () { // 2073 - var m = this; // 2074 - return { // 2075 - years: m.year(), // 2076 - months: m.month(), // 2077 - date: m.date(), // 2078 - hours: m.hours(), // 2079 - minutes: m.minutes(), // 2080 - seconds: m.seconds(), // 2081 - milliseconds: m.milliseconds() // 2082 - }; // 2083 - } // 2084 - // 2085 - function moment_valid__isValid () { // 2086 - return valid__isValid(this); // 2087 - } // 2088 - // 2089 - function parsingFlags () { // 2090 - return extend({}, getParsingFlags(this)); // 2091 - } // 2092 - // 2093 - function invalidAt () { // 2094 - return getParsingFlags(this).overflow; // 2095 - } // 2096 - // 2097 - addFormatToken(0, ['gg', 2], 0, function () { // 2098 - return this.weekYear() % 100; // 2099 - }); // 2100 - // 2101 - addFormatToken(0, ['GG', 2], 0, function () { // 2102 - return this.isoWeekYear() % 100; // 2103 - }); // 2104 - // 2105 - function addWeekYearFormatToken (token, getter) { // 2106 - addFormatToken(0, [token, token.length], 0, getter); // 2107 - } // 2108 - // 2109 - addWeekYearFormatToken('gggg', 'weekYear'); // 2110 - addWeekYearFormatToken('ggggg', 'weekYear'); // 2111 - addWeekYearFormatToken('GGGG', 'isoWeekYear'); // 2112 - addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // 2113 - // 2114 - // ALIASES // 2115 - // 2116 - addUnitAlias('weekYear', 'gg'); // 2117 - addUnitAlias('isoWeekYear', 'GG'); // 2118 - // 2119 - // PARSING // 2120 - // 2121 - addRegexToken('G', matchSigned); // 2122 - addRegexToken('g', matchSigned); // 2123 - addRegexToken('GG', match1to2, match2); // 2124 - addRegexToken('gg', match1to2, match2); // 2125 - addRegexToken('GGGG', match1to4, match4); // 2126 - addRegexToken('gggg', match1to4, match4); // 2127 - addRegexToken('GGGGG', match1to6, match6); // 2128 - addRegexToken('ggggg', match1to6, match6); // 2129 - // 2130 - addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { // 2131 - week[token.substr(0, 2)] = toInt(input); // 2132 - }); // 2133 - // 2134 - addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { // 2135 - week[token] = utils_hooks__hooks.parseTwoDigitYear(input); // 2136 - }); // 2137 - // 2138 - // HELPERS // 2139 - // 2140 - function weeksInYear(year, dow, doy) { // 2141 - return weekOfYear(local__createLocal([year, 11, 31 + dow - doy]), dow, doy).week; // 2142 - } // 2143 - // 2144 - // MOMENTS // 2145 - // 2146 - function getSetWeekYear (input) { // 2147 - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; // 2148 - return input == null ? year : this.add((input - year), 'y'); // 2149 - } // 2150 - // 2151 - function getSetISOWeekYear (input) { // 2152 - var year = weekOfYear(this, 1, 4).year; // 2153 - return input == null ? year : this.add((input - year), 'y'); // 2154 - } // 2155 - // 2156 - function getISOWeeksInYear () { // 2157 - return weeksInYear(this.year(), 1, 4); // 2158 - } // 2159 - // 2160 - function getWeeksInYear () { // 2161 - var weekInfo = this.localeData()._week; // 2162 - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); // 2163 - } // 2164 - // 2165 - addFormatToken('Q', 0, 0, 'quarter'); // 2166 - // 2167 - // ALIASES // 2168 - // 2169 - addUnitAlias('quarter', 'Q'); // 2170 - // 2171 - // PARSING // 2172 - // 2173 - addRegexToken('Q', match1); // 2174 - addParseToken('Q', function (input, array) { // 2175 - array[MONTH] = (toInt(input) - 1) * 3; // 2176 - }); // 2177 - // 2178 - // MOMENTS // 2179 - // 2180 - function getSetQuarter (input) { // 2181 - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); // 2182 - } // 2183 - // 2184 - addFormatToken('D', ['DD', 2], 'Do', 'date'); // 2185 - // 2186 - // ALIASES // 2187 - // 2188 - addUnitAlias('date', 'D'); // 2189 - // 2190 - // PARSING // 2191 - // 2192 - addRegexToken('D', match1to2); // 2193 - addRegexToken('DD', match1to2, match2); // 2194 - addRegexToken('Do', function (isStrict, locale) { // 2195 - return isStrict ? locale._ordinalParse : locale._ordinalParseLenient; // 2196 - }); // 2197 - // 2198 - addParseToken(['D', 'DD'], DATE); // 2199 - addParseToken('Do', function (input, array) { // 2200 - array[DATE] = toInt(input.match(match1to2)[0], 10); // 2201 - }); // 2202 - // 2203 - // MOMENTS // 2204 - // 2205 - var getSetDayOfMonth = makeGetSet('Date', true); // 2206 - // 2207 - addFormatToken('d', 0, 'do', 'day'); // 2208 - // 2209 - addFormatToken('dd', 0, 0, function (format) { // 2210 - return this.localeData().weekdaysMin(this, format); // 2211 - }); // 2212 - // 2213 - addFormatToken('ddd', 0, 0, function (format) { // 2214 - return this.localeData().weekdaysShort(this, format); // 2215 - }); // 2216 - // 2217 - addFormatToken('dddd', 0, 0, function (format) { // 2218 - return this.localeData().weekdays(this, format); // 2219 - }); // 2220 - // 2221 - addFormatToken('e', 0, 0, 'weekday'); // 2222 - addFormatToken('E', 0, 0, 'isoWeekday'); // 2223 - // 2224 - // ALIASES // 2225 - // 2226 - addUnitAlias('day', 'd'); // 2227 - addUnitAlias('weekday', 'e'); // 2228 - addUnitAlias('isoWeekday', 'E'); // 2229 - // 2230 - // PARSING // 2231 - // 2232 - addRegexToken('d', match1to2); // 2233 - addRegexToken('e', match1to2); // 2234 - addRegexToken('E', match1to2); // 2235 - addRegexToken('dd', matchWord); // 2236 - addRegexToken('ddd', matchWord); // 2237 - addRegexToken('dddd', matchWord); // 2238 - // 2239 - addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config) { // 2240 - var weekday = config._locale.weekdaysParse(input); // 2241 - // if we didn't get a weekday name, mark the date as invalid // 2242 - if (weekday != null) { // 2243 - week.d = weekday; // 2244 - } else { // 2245 - getParsingFlags(config).invalidWeekday = input; // 2246 - } // 2247 - }); // 2248 - // 2249 - addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { // 2250 - week[token] = toInt(input); // 2251 - }); // 2252 - // 2253 - // HELPERS // 2254 - // 2255 - function parseWeekday(input, locale) { // 2256 - if (typeof input !== 'string') { // 2257 - return input; // 2258 - } // 2259 - // 2260 - if (!isNaN(input)) { // 2261 - return parseInt(input, 10); // 2262 - } // 2263 - // 2264 - input = locale.weekdaysParse(input); // 2265 - if (typeof input === 'number') { // 2266 - return input; // 2267 - } // 2268 - // 2269 - return null; // 2270 - } // 2271 - // 2272 - // LOCALES // 2273 - // 2274 - var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); // 2275 - function localeWeekdays (m) { // 2276 - return this._weekdays[m.day()]; // 2277 - } // 2278 - // 2279 - var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); // 2280 - function localeWeekdaysShort (m) { // 2281 - return this._weekdaysShort[m.day()]; // 2282 - } // 2283 - // 2284 - var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); // 2285 - function localeWeekdaysMin (m) { // 2286 - return this._weekdaysMin[m.day()]; // 2287 - } // 2288 - // 2289 - function localeWeekdaysParse (weekdayName) { // 2290 - var i, mom, regex; // 2291 - // 2292 - this._weekdaysParse = this._weekdaysParse || []; // 2293 - // 2294 - for (i = 0; i < 7; i++) { // 2295 - // make the regex if we don't have it already // 2296 - if (!this._weekdaysParse[i]) { // 2297 - mom = local__createLocal([2000, 1]).day(i); // 2298 - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); // 2300 - } // 2301 - // test the regex // 2302 - if (this._weekdaysParse[i].test(weekdayName)) { // 2303 - return i; // 2304 - } // 2305 - } // 2306 - } // 2307 - // 2308 - // MOMENTS // 2309 - // 2310 - function getSetDayOfWeek (input) { // 2311 - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); // 2312 - if (input != null) { // 2313 - input = parseWeekday(input, this.localeData()); // 2314 - return this.add(input - day, 'd'); // 2315 - } else { // 2316 - return day; // 2317 - } // 2318 - } // 2319 - // 2320 - function getSetLocaleDayOfWeek (input) { // 2321 - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; // 2322 - return input == null ? weekday : this.add(input - weekday, 'd'); // 2323 - } // 2324 - // 2325 - function getSetISODayOfWeek (input) { // 2326 - // behaves the same as moment#day except // 2327 - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) // 2328 - // as a setter, sunday should belong to the previous week. // 2329 - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); // 2330 - } // 2331 - // 2332 - addFormatToken('H', ['HH', 2], 0, 'hour'); // 2333 - addFormatToken('h', ['hh', 2], 0, function () { // 2334 - return this.hours() % 12 || 12; // 2335 - }); // 2336 - // 2337 - function meridiem (token, lowercase) { // 2338 - addFormatToken(token, 0, 0, function () { // 2339 - return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); // 2340 - }); // 2341 - } // 2342 - // 2343 - meridiem('a', true); // 2344 - meridiem('A', false); // 2345 - // 2346 - // ALIASES // 2347 - // 2348 - addUnitAlias('hour', 'h'); // 2349 - // 2350 - // PARSING // 2351 - // 2352 - function matchMeridiem (isStrict, locale) { // 2353 - return locale._meridiemParse; // 2354 - } // 2355 - // 2356 - addRegexToken('a', matchMeridiem); // 2357 - addRegexToken('A', matchMeridiem); // 2358 - addRegexToken('H', match1to2); // 2359 - addRegexToken('h', match1to2); // 2360 - addRegexToken('HH', match1to2, match2); // 2361 - addRegexToken('hh', match1to2, match2); // 2362 - // 2363 - addParseToken(['H', 'HH'], HOUR); // 2364 - addParseToken(['a', 'A'], function (input, array, config) { // 2365 - config._isPm = config._locale.isPM(input); // 2366 - config._meridiem = input; // 2367 - }); // 2368 - addParseToken(['h', 'hh'], function (input, array, config) { // 2369 - array[HOUR] = toInt(input); // 2370 - getParsingFlags(config).bigHour = true; // 2371 - }); // 2372 - // 2373 - // LOCALES // 2374 - // 2375 - function localeIsPM (input) { // 2376 - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays // 2377 - // Using charAt should be more compatible. // 2378 - return ((input + '').toLowerCase().charAt(0) === 'p'); // 2379 - } // 2380 - // 2381 - var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; // 2382 - function localeMeridiem (hours, minutes, isLower) { // 2383 - if (hours > 11) { // 2384 - return isLower ? 'pm' : 'PM'; // 2385 - } else { // 2386 - return isLower ? 'am' : 'AM'; // 2387 - } // 2388 - } // 2389 - // 2390 - // 2391 - // MOMENTS // 2392 - // 2393 - // Setting the hour should keep the time, because the user explicitly // 2394 - // specified which hour he wants. So trying to maintain the same hour (in // 2395 - // a new timezone) makes sense. Adding/subtracting hours does not follow // 2396 - // this rule. // 2397 - var getSetHour = makeGetSet('Hours', true); // 2398 - // 2399 - addFormatToken('m', ['mm', 2], 0, 'minute'); // 2400 - // 2401 - // ALIASES // 2402 - // 2403 - addUnitAlias('minute', 'm'); // 2404 - // 2405 - // PARSING // 2406 - // 2407 - addRegexToken('m', match1to2); // 2408 - addRegexToken('mm', match1to2, match2); // 2409 - addParseToken(['m', 'mm'], MINUTE); // 2410 - // 2411 - // MOMENTS // 2412 - // 2413 - var getSetMinute = makeGetSet('Minutes', false); // 2414 - // 2415 - addFormatToken('s', ['ss', 2], 0, 'second'); // 2416 - // 2417 - // ALIASES // 2418 - // 2419 - addUnitAlias('second', 's'); // 2420 - // 2421 - // PARSING // 2422 - // 2423 - addRegexToken('s', match1to2); // 2424 - addRegexToken('ss', match1to2, match2); // 2425 - addParseToken(['s', 'ss'], SECOND); // 2426 - // 2427 - // MOMENTS // 2428 - // 2429 - var getSetSecond = makeGetSet('Seconds', false); // 2430 - // 2431 - addFormatToken('S', 0, 0, function () { // 2432 - return ~~(this.millisecond() / 100); // 2433 - }); // 2434 - // 2435 - addFormatToken(0, ['SS', 2], 0, function () { // 2436 - return ~~(this.millisecond() / 10); // 2437 - }); // 2438 - // 2439 - addFormatToken(0, ['SSS', 3], 0, 'millisecond'); // 2440 - addFormatToken(0, ['SSSS', 4], 0, function () { // 2441 - return this.millisecond() * 10; // 2442 - }); // 2443 - addFormatToken(0, ['SSSSS', 5], 0, function () { // 2444 - return this.millisecond() * 100; // 2445 - }); // 2446 - addFormatToken(0, ['SSSSSS', 6], 0, function () { // 2447 - return this.millisecond() * 1000; // 2448 - }); // 2449 - addFormatToken(0, ['SSSSSSS', 7], 0, function () { // 2450 - return this.millisecond() * 10000; // 2451 - }); // 2452 - addFormatToken(0, ['SSSSSSSS', 8], 0, function () { // 2453 - return this.millisecond() * 100000; // 2454 - }); // 2455 - addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { // 2456 - return this.millisecond() * 1000000; // 2457 - }); // 2458 - // 2459 - // 2460 - // ALIASES // 2461 - // 2462 - addUnitAlias('millisecond', 'ms'); // 2463 - // 2464 - // PARSING // 2465 - // 2466 - addRegexToken('S', match1to3, match1); // 2467 - addRegexToken('SS', match1to3, match2); // 2468 - addRegexToken('SSS', match1to3, match3); // 2469 - // 2470 - var token; // 2471 - for (token = 'SSSS'; token.length <= 9; token += 'S') { // 2472 - addRegexToken(token, matchUnsigned); // 2473 - } // 2474 - // 2475 - function parseMs(input, array) { // 2476 - array[MILLISECOND] = toInt(('0.' + input) * 1000); // 2477 - } // 2478 - // 2479 - for (token = 'S'; token.length <= 9; token += 'S') { // 2480 - addParseToken(token, parseMs); // 2481 - } // 2482 - // MOMENTS // 2483 - // 2484 - var getSetMillisecond = makeGetSet('Milliseconds', false); // 2485 - // 2486 - addFormatToken('z', 0, 0, 'zoneAbbr'); // 2487 - addFormatToken('zz', 0, 0, 'zoneName'); // 2488 - // 2489 - // MOMENTS // 2490 - // 2491 - function getZoneAbbr () { // 2492 - return this._isUTC ? 'UTC' : ''; // 2493 - } // 2494 - // 2495 - function getZoneName () { // 2496 - return this._isUTC ? 'Coordinated Universal Time' : ''; // 2497 - } // 2498 - // 2499 - var momentPrototype__proto = Moment.prototype; // 2500 - // 2501 - momentPrototype__proto.add = add_subtract__add; // 2502 - momentPrototype__proto.calendar = moment_calendar__calendar; // 2503 - momentPrototype__proto.clone = clone; // 2504 - momentPrototype__proto.diff = diff; // 2505 - momentPrototype__proto.endOf = endOf; // 2506 - momentPrototype__proto.format = format; // 2507 - momentPrototype__proto.from = from; // 2508 - momentPrototype__proto.fromNow = fromNow; // 2509 - momentPrototype__proto.to = to; // 2510 - momentPrototype__proto.toNow = toNow; // 2511 - momentPrototype__proto.get = getSet; // 2512 - momentPrototype__proto.invalidAt = invalidAt; // 2513 - momentPrototype__proto.isAfter = isAfter; // 2514 - momentPrototype__proto.isBefore = isBefore; // 2515 - momentPrototype__proto.isBetween = isBetween; // 2516 - momentPrototype__proto.isSame = isSame; // 2517 - momentPrototype__proto.isValid = moment_valid__isValid; // 2518 - momentPrototype__proto.lang = lang; // 2519 - momentPrototype__proto.locale = locale; // 2520 - momentPrototype__proto.localeData = localeData; // 2521 - momentPrototype__proto.max = prototypeMax; // 2522 - momentPrototype__proto.min = prototypeMin; // 2523 - momentPrototype__proto.parsingFlags = parsingFlags; // 2524 - momentPrototype__proto.set = getSet; // 2525 - momentPrototype__proto.startOf = startOf; // 2526 - momentPrototype__proto.subtract = add_subtract__subtract; // 2527 - momentPrototype__proto.toArray = toArray; // 2528 - momentPrototype__proto.toObject = toObject; // 2529 - momentPrototype__proto.toDate = toDate; // 2530 - momentPrototype__proto.toISOString = moment_format__toISOString; // 2531 - momentPrototype__proto.toJSON = moment_format__toISOString; // 2532 - momentPrototype__proto.toString = toString; // 2533 - momentPrototype__proto.unix = unix; // 2534 - momentPrototype__proto.valueOf = to_type__valueOf; // 2535 - // 2536 - // Year // 2537 - momentPrototype__proto.year = getSetYear; // 2538 - momentPrototype__proto.isLeapYear = getIsLeapYear; // 2539 - // 2540 - // Week Year // 2541 - momentPrototype__proto.weekYear = getSetWeekYear; // 2542 - momentPrototype__proto.isoWeekYear = getSetISOWeekYear; // 2543 - // 2544 - // Quarter // 2545 - momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter; // 2546 - // 2547 - // Month // 2548 - momentPrototype__proto.month = getSetMonth; // 2549 - momentPrototype__proto.daysInMonth = getDaysInMonth; // 2550 - // 2551 - // Week // 2552 - momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek; // 2553 - momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek; // 2554 - momentPrototype__proto.weeksInYear = getWeeksInYear; // 2555 - momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear; // 2556 - // 2557 - // Day // 2558 - momentPrototype__proto.date = getSetDayOfMonth; // 2559 - momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek; // 2560 - momentPrototype__proto.weekday = getSetLocaleDayOfWeek; // 2561 - momentPrototype__proto.isoWeekday = getSetISODayOfWeek; // 2562 - momentPrototype__proto.dayOfYear = getSetDayOfYear; // 2563 - // 2564 - // Hour // 2565 - momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour; // 2566 - // 2567 - // Minute // 2568 - momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute; // 2569 - // 2570 - // Second // 2571 - momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond; // 2572 - // 2573 - // Millisecond // 2574 - momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond; // 2575 - // 2576 - // Offset // 2577 - momentPrototype__proto.utcOffset = getSetOffset; // 2578 - momentPrototype__proto.utc = setOffsetToUTC; // 2579 - momentPrototype__proto.local = setOffsetToLocal; // 2580 - momentPrototype__proto.parseZone = setOffsetToParsedOffset; // 2581 - momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset; // 2582 - momentPrototype__proto.isDST = isDaylightSavingTime; // 2583 - momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted; // 2584 - momentPrototype__proto.isLocal = isLocal; // 2585 - momentPrototype__proto.isUtcOffset = isUtcOffset; // 2586 - momentPrototype__proto.isUtc = isUtc; // 2587 - momentPrototype__proto.isUTC = isUtc; // 2588 - // 2589 - // Timezone // 2590 - momentPrototype__proto.zoneAbbr = getZoneAbbr; // 2591 - momentPrototype__proto.zoneName = getZoneName; // 2592 - // 2593 - // Deprecations // 2594 - momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); // 2595 - momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); // 2596 - momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); // 2597 - momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone); - // 2599 - var momentPrototype = momentPrototype__proto; // 2600 - // 2601 - function moment__createUnix (input) { // 2602 - return local__createLocal(input * 1000); // 2603 - } // 2604 - // 2605 - function moment__createInZone () { // 2606 - return local__createLocal.apply(null, arguments).parseZone(); // 2607 - } // 2608 - // 2609 - var defaultCalendar = { // 2610 - sameDay : '[Today at] LT', // 2611 - nextDay : '[Tomorrow at] LT', // 2612 - nextWeek : 'dddd [at] LT', // 2613 - lastDay : '[Yesterday at] LT', // 2614 - lastWeek : '[Last] dddd [at] LT', // 2615 - sameElse : 'L' // 2616 - }; // 2617 - // 2618 - function locale_calendar__calendar (key, mom, now) { // 2619 - var output = this._calendar[key]; // 2620 - return typeof output === 'function' ? output.call(mom, now) : output; // 2621 - } // 2622 - // 2623 - var defaultLongDateFormat = { // 2624 - LTS : 'h:mm:ss A', // 2625 - LT : 'h:mm A', // 2626 - L : 'MM/DD/YYYY', // 2627 - LL : 'MMMM D, YYYY', // 2628 - LLL : 'MMMM D, YYYY h:mm A', // 2629 - LLLL : 'dddd, MMMM D, YYYY h:mm A' // 2630 - }; // 2631 - // 2632 - function longDateFormat (key) { // 2633 - var format = this._longDateFormat[key], // 2634 - formatUpper = this._longDateFormat[key.toUpperCase()]; // 2635 - // 2636 - if (format || !formatUpper) { // 2637 - return format; // 2638 - } // 2639 - // 2640 - this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { // 2641 - return val.slice(1); // 2642 - }); // 2643 - // 2644 - return this._longDateFormat[key]; // 2645 - } // 2646 - // 2647 - var defaultInvalidDate = 'Invalid date'; // 2648 - // 2649 - function invalidDate () { // 2650 - return this._invalidDate; // 2651 - } // 2652 - // 2653 - var defaultOrdinal = '%d'; // 2654 - var defaultOrdinalParse = /\d{1,2}/; // 2655 - // 2656 - function ordinal (number) { // 2657 - return this._ordinal.replace('%d', number); // 2658 - } // 2659 - // 2660 - function preParsePostFormat (string) { // 2661 - return string; // 2662 - } // 2663 - // 2664 - var defaultRelativeTime = { // 2665 - future : 'in %s', // 2666 - past : '%s ago', // 2667 - s : 'a few seconds', // 2668 - m : 'a minute', // 2669 - mm : '%d minutes', // 2670 - h : 'an hour', // 2671 - hh : '%d hours', // 2672 - d : 'a day', // 2673 - dd : '%d days', // 2674 - M : 'a month', // 2675 - MM : '%d months', // 2676 - y : 'a year', // 2677 - yy : '%d years' // 2678 - }; // 2679 - // 2680 - function relative__relativeTime (number, withoutSuffix, string, isFuture) { // 2681 - var output = this._relativeTime[string]; // 2682 - return (typeof output === 'function') ? // 2683 - output(number, withoutSuffix, string, isFuture) : // 2684 - output.replace(/%d/i, number); // 2685 - } // 2686 - // 2687 - function pastFuture (diff, output) { // 2688 - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; // 2689 - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); // 2690 - } // 2691 - // 2692 - function locale_set__set (config) { // 2693 - var prop, i; // 2694 - for (i in config) { // 2695 - prop = config[i]; // 2696 - if (typeof prop === 'function') { // 2697 - this[i] = prop; // 2698 - } else { // 2699 - this['_' + i] = prop; // 2700 - } // 2701 - } // 2702 - // Lenient ordinal parsing accepts just a number in addition to // 2703 - // number + (possibly) stuff coming from _ordinalParseLenient. // 2704 - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source); // 2705 - } // 2706 - // 2707 - var prototype__proto = Locale.prototype; // 2708 - // 2709 - prototype__proto._calendar = defaultCalendar; // 2710 - prototype__proto.calendar = locale_calendar__calendar; // 2711 - prototype__proto._longDateFormat = defaultLongDateFormat; // 2712 - prototype__proto.longDateFormat = longDateFormat; // 2713 - prototype__proto._invalidDate = defaultInvalidDate; // 2714 - prototype__proto.invalidDate = invalidDate; // 2715 - prototype__proto._ordinal = defaultOrdinal; // 2716 - prototype__proto.ordinal = ordinal; // 2717 - prototype__proto._ordinalParse = defaultOrdinalParse; // 2718 - prototype__proto.preparse = preParsePostFormat; // 2719 - prototype__proto.postformat = preParsePostFormat; // 2720 - prototype__proto._relativeTime = defaultRelativeTime; // 2721 - prototype__proto.relativeTime = relative__relativeTime; // 2722 - prototype__proto.pastFuture = pastFuture; // 2723 - prototype__proto.set = locale_set__set; // 2724 - // 2725 - // Month // 2726 - prototype__proto.months = localeMonths; // 2727 - prototype__proto._months = defaultLocaleMonths; // 2728 - prototype__proto.monthsShort = localeMonthsShort; // 2729 - prototype__proto._monthsShort = defaultLocaleMonthsShort; // 2730 - prototype__proto.monthsParse = localeMonthsParse; // 2731 - // 2732 - // Week // 2733 - prototype__proto.week = localeWeek; // 2734 - prototype__proto._week = defaultLocaleWeek; // 2735 - prototype__proto.firstDayOfYear = localeFirstDayOfYear; // 2736 - prototype__proto.firstDayOfWeek = localeFirstDayOfWeek; // 2737 - // 2738 - // Day of Week // 2739 - prototype__proto.weekdays = localeWeekdays; // 2740 - prototype__proto._weekdays = defaultLocaleWeekdays; // 2741 - prototype__proto.weekdaysMin = localeWeekdaysMin; // 2742 - prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin; // 2743 - prototype__proto.weekdaysShort = localeWeekdaysShort; // 2744 - prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort; // 2745 - prototype__proto.weekdaysParse = localeWeekdaysParse; // 2746 - // 2747 - // Hours // 2748 - prototype__proto.isPM = localeIsPM; // 2749 - prototype__proto._meridiemParse = defaultLocaleMeridiemParse; // 2750 - prototype__proto.meridiem = localeMeridiem; // 2751 - // 2752 - function lists__get (format, index, field, setter) { // 2753 - var locale = locale_locales__getLocale(); // 2754 - var utc = create_utc__createUTC().set(setter, index); // 2755 - return locale[field](utc, format); // 2756 - } // 2757 - // 2758 - function list (format, index, field, count, setter) { // 2759 - if (typeof format === 'number') { // 2760 - index = format; // 2761 - format = undefined; // 2762 - } // 2763 - // 2764 - format = format || ''; // 2765 - // 2766 - if (index != null) { // 2767 - return lists__get(format, index, field, setter); // 2768 - } // 2769 - // 2770 - var i; // 2771 - var out = []; // 2772 - for (i = 0; i < count; i++) { // 2773 - out[i] = lists__get(format, i, field, setter); // 2774 - } // 2775 - return out; // 2776 - } // 2777 - // 2778 - function lists__listMonths (format, index) { // 2779 - return list(format, index, 'months', 12, 'month'); // 2780 - } // 2781 - // 2782 - function lists__listMonthsShort (format, index) { // 2783 - return list(format, index, 'monthsShort', 12, 'month'); // 2784 - } // 2785 - // 2786 - function lists__listWeekdays (format, index) { // 2787 - return list(format, index, 'weekdays', 7, 'day'); // 2788 - } // 2789 - // 2790 - function lists__listWeekdaysShort (format, index) { // 2791 - return list(format, index, 'weekdaysShort', 7, 'day'); // 2792 - } // 2793 - // 2794 - function lists__listWeekdaysMin (format, index) { // 2795 - return list(format, index, 'weekdaysMin', 7, 'day'); // 2796 - } // 2797 - // 2798 - locale_locales__getSetGlobalLocale('en', { // 2799 - ordinalParse: /\d{1,2}(th|st|nd|rd)/, // 2800 - ordinal : function (number) { // 2801 - var b = number % 10, // 2802 - output = (toInt(number % 100 / 10) === 1) ? 'th' : // 2803 - (b === 1) ? 'st' : // 2804 - (b === 2) ? 'nd' : // 2805 - (b === 3) ? 'rd' : 'th'; // 2806 - return number + output; // 2807 - } // 2808 - }); // 2809 - // 2810 - // Side effect imports // 2811 - utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale); - utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale); - // 2814 - var mathAbs = Math.abs; // 2815 - // 2816 - function duration_abs__abs () { // 2817 - var data = this._data; // 2818 - // 2819 - this._milliseconds = mathAbs(this._milliseconds); // 2820 - this._days = mathAbs(this._days); // 2821 - this._months = mathAbs(this._months); // 2822 - // 2823 - data.milliseconds = mathAbs(data.milliseconds); // 2824 - data.seconds = mathAbs(data.seconds); // 2825 - data.minutes = mathAbs(data.minutes); // 2826 - data.hours = mathAbs(data.hours); // 2827 - data.months = mathAbs(data.months); // 2828 - data.years = mathAbs(data.years); // 2829 - // 2830 - return this; // 2831 - } // 2832 - // 2833 - function duration_add_subtract__addSubtract (duration, input, value, direction) { // 2834 - var other = create__createDuration(input, value); // 2835 - // 2836 - duration._milliseconds += direction * other._milliseconds; // 2837 - duration._days += direction * other._days; // 2838 - duration._months += direction * other._months; // 2839 - // 2840 - return duration._bubble(); // 2841 - } // 2842 - // 2843 - // supports only 2.0-style add(1, 's') or add(duration) // 2844 - function duration_add_subtract__add (input, value) { // 2845 - return duration_add_subtract__addSubtract(this, input, value, 1); // 2846 - } // 2847 - // 2848 - // supports only 2.0-style subtract(1, 's') or subtract(duration) // 2849 - function duration_add_subtract__subtract (input, value) { // 2850 - return duration_add_subtract__addSubtract(this, input, value, -1); // 2851 - } // 2852 - // 2853 - function absCeil (number) { // 2854 - if (number < 0) { // 2855 - return Math.floor(number); // 2856 - } else { // 2857 - return Math.ceil(number); // 2858 - } // 2859 - } // 2860 - // 2861 - function bubble () { // 2862 - var milliseconds = this._milliseconds; // 2863 - var days = this._days; // 2864 - var months = this._months; // 2865 - var data = this._data; // 2866 - var seconds, minutes, hours, years, monthsFromDays; // 2867 - // 2868 - // if we have a mix of positive and negative values, bubble down first // 2869 - // check: https://github.com/moment/moment/issues/2166 // 2870 - if (!((milliseconds >= 0 && days >= 0 && months >= 0) || // 2871 - (milliseconds <= 0 && days <= 0 && months <= 0))) { // 2872 - milliseconds += absCeil(monthsToDays(months) + days) * 864e5; // 2873 - days = 0; // 2874 - months = 0; // 2875 - } // 2876 - // 2877 - // The following code bubbles up values, see the tests for // 2878 - // examples of what that means. // 2879 - data.milliseconds = milliseconds % 1000; // 2880 - // 2881 - seconds = absFloor(milliseconds / 1000); // 2882 - data.seconds = seconds % 60; // 2883 - // 2884 - minutes = absFloor(seconds / 60); // 2885 - data.minutes = minutes % 60; // 2886 - // 2887 - hours = absFloor(minutes / 60); // 2888 - data.hours = hours % 24; // 2889 - // 2890 - days += absFloor(hours / 24); // 2891 - // 2892 - // convert days to months // 2893 - monthsFromDays = absFloor(daysToMonths(days)); // 2894 - months += monthsFromDays; // 2895 - days -= absCeil(monthsToDays(monthsFromDays)); // 2896 - // 2897 - // 12 months -> 1 year // 2898 - years = absFloor(months / 12); // 2899 - months %= 12; // 2900 - // 2901 - data.days = days; // 2902 - data.months = months; // 2903 - data.years = years; // 2904 - // 2905 - return this; // 2906 - } // 2907 - // 2908 - function daysToMonths (days) { // 2909 - // 400 years have 146097 days (taking into account leap year rules) // 2910 - // 400 years have 12 months === 4800 // 2911 - return days * 4800 / 146097; // 2912 - } // 2913 - // 2914 - function monthsToDays (months) { // 2915 - // the reverse of daysToMonths // 2916 - return months * 146097 / 4800; // 2917 - } // 2918 - // 2919 - function as (units) { // 2920 - var days; // 2921 - var months; // 2922 - var milliseconds = this._milliseconds; // 2923 - // 2924 - units = normalizeUnits(units); // 2925 - // 2926 - if (units === 'month' || units === 'year') { // 2927 - days = this._days + milliseconds / 864e5; // 2928 - months = this._months + daysToMonths(days); // 2929 - return units === 'month' ? months : months / 12; // 2930 - } else { // 2931 - // handle milliseconds separately because of floating point math errors (issue #1867) // 2932 - days = this._days + Math.round(monthsToDays(this._months)); // 2933 - switch (units) { // 2934 - case 'week' : return days / 7 + milliseconds / 6048e5; // 2935 - case 'day' : return days + milliseconds / 864e5; // 2936 - case 'hour' : return days * 24 + milliseconds / 36e5; // 2937 - case 'minute' : return days * 1440 + milliseconds / 6e4; // 2938 - case 'second' : return days * 86400 + milliseconds / 1000; // 2939 - // Math.floor prevents floating point math errors here // 2940 - case 'millisecond': return Math.floor(days * 864e5) + milliseconds; // 2941 - default: throw new Error('Unknown unit ' + units); // 2942 - } // 2943 - } // 2944 - } // 2945 - // 2946 - // TODO: Use this.as('ms')? // 2947 - function duration_as__valueOf () { // 2948 - return ( // 2949 - this._milliseconds + // 2950 - this._days * 864e5 + // 2951 - (this._months % 12) * 2592e6 + // 2952 - toInt(this._months / 12) * 31536e6 // 2953 - ); // 2954 - } // 2955 - // 2956 - function makeAs (alias) { // 2957 - return function () { // 2958 - return this.as(alias); // 2959 - }; // 2960 - } // 2961 - // 2962 - var asMilliseconds = makeAs('ms'); // 2963 - var asSeconds = makeAs('s'); // 2964 - var asMinutes = makeAs('m'); // 2965 - var asHours = makeAs('h'); // 2966 - var asDays = makeAs('d'); // 2967 - var asWeeks = makeAs('w'); // 2968 - var asMonths = makeAs('M'); // 2969 - var asYears = makeAs('y'); // 2970 - // 2971 - function duration_get__get (units) { // 2972 - units = normalizeUnits(units); // 2973 - return this[units + 's'](); // 2974 - } // 2975 - // 2976 - function makeGetter(name) { // 2977 - return function () { // 2978 - return this._data[name]; // 2979 - }; // 2980 - } // 2981 - // 2982 - var milliseconds = makeGetter('milliseconds'); // 2983 - var seconds = makeGetter('seconds'); // 2984 - var minutes = makeGetter('minutes'); // 2985 - var hours = makeGetter('hours'); // 2986 - var days = makeGetter('days'); // 2987 - var months = makeGetter('months'); // 2988 - var years = makeGetter('years'); // 2989 - // 2990 - function weeks () { // 2991 - return absFloor(this.days() / 7); // 2992 - } // 2993 - // 2994 - var round = Math.round; // 2995 - var thresholds = { // 2996 - s: 45, // seconds to minute // 2997 - m: 45, // minutes to hour // 2998 - h: 22, // hours to day // 2999 - d: 26, // days to month // 3000 - M: 11 // months to year // 3001 - }; // 3002 - // 3003 - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize // 3004 - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { // 3005 - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); // 3006 - } // 3007 - // 3008 - function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) { // 3009 - var duration = create__createDuration(posNegDuration).abs(); // 3010 - var seconds = round(duration.as('s')); // 3011 - var minutes = round(duration.as('m')); // 3012 - var hours = round(duration.as('h')); // 3013 - var days = round(duration.as('d')); // 3014 - var months = round(duration.as('M')); // 3015 - var years = round(duration.as('y')); // 3016 - // 3017 - var a = seconds < thresholds.s && ['s', seconds] || // 3018 - minutes === 1 && ['m'] || // 3019 - minutes < thresholds.m && ['mm', minutes] || // 3020 - hours === 1 && ['h'] || // 3021 - hours < thresholds.h && ['hh', hours] || // 3022 - days === 1 && ['d'] || // 3023 - days < thresholds.d && ['dd', days] || // 3024 - months === 1 && ['M'] || // 3025 - months < thresholds.M && ['MM', months] || // 3026 - years === 1 && ['y'] || ['yy', years]; // 3027 - // 3028 - a[2] = withoutSuffix; // 3029 - a[3] = +posNegDuration > 0; // 3030 - a[4] = locale; // 3031 - return substituteTimeAgo.apply(null, a); // 3032 - } // 3033 - // 3034 - // This function allows you to set a threshold for relative time strings // 3035 - function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) { // 3036 - if (thresholds[threshold] === undefined) { // 3037 - return false; // 3038 - } // 3039 - if (limit === undefined) { // 3040 - return thresholds[threshold]; // 3041 - } // 3042 - thresholds[threshold] = limit; // 3043 - return true; // 3044 - } // 3045 - // 3046 - function humanize (withSuffix) { // 3047 - var locale = this.localeData(); // 3048 - var output = duration_humanize__relativeTime(this, !withSuffix, locale); // 3049 - // 3050 - if (withSuffix) { // 3051 - output = locale.pastFuture(+this, output); // 3052 - } // 3053 - // 3054 - return locale.postformat(output); // 3055 - } // 3056 - // 3057 - var iso_string__abs = Math.abs; // 3058 - // 3059 - function iso_string__toISOString() { // 3060 - // for ISO strings we do not use the normal bubbling rules: // 3061 - // * milliseconds bubble up until they become hours // 3062 - // * days do not bubble at all // 3063 - // * months bubble up until they become years // 3064 - // This is because there is no context-free conversion between hours and days // 3065 - // (think of clock changes) // 3066 - // and also not between days and months (28-31 days per month) // 3067 - var seconds = iso_string__abs(this._milliseconds) / 1000; // 3068 - var days = iso_string__abs(this._days); // 3069 - var months = iso_string__abs(this._months); // 3070 - var minutes, hours, years; // 3071 - // 3072 - // 3600 seconds -> 60 minutes -> 1 hour // 3073 - minutes = absFloor(seconds / 60); // 3074 - hours = absFloor(minutes / 60); // 3075 - seconds %= 60; // 3076 - minutes %= 60; // 3077 - // 3078 - // 12 months -> 1 year // 3079 - years = absFloor(months / 12); // 3080 - months %= 12; // 3081 - // 3082 - // 3083 - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js // 3084 - var Y = years; // 3085 - var M = months; // 3086 - var D = days; // 3087 - var h = hours; // 3088 - var m = minutes; // 3089 - var s = seconds; // 3090 - var total = this.asSeconds(); // 3091 - // 3092 - if (!total) { // 3093 - // this is the same as C#'s (Noda) and python (isodate)... // 3094 - // but not other JS (goog.date) // 3095 - return 'P0D'; // 3096 - } // 3097 - // 3098 - return (total < 0 ? '-' : '') + // 3099 - 'P' + // 3100 - (Y ? Y + 'Y' : '') + // 3101 - (M ? M + 'M' : '') + // 3102 - (D ? D + 'D' : '') + // 3103 - ((h || m || s) ? 'T' : '') + // 3104 - (h ? h + 'H' : '') + // 3105 - (m ? m + 'M' : '') + // 3106 - (s ? s + 'S' : ''); // 3107 - } // 3108 - // 3109 - var duration_prototype__proto = Duration.prototype; // 3110 - // 3111 - duration_prototype__proto.abs = duration_abs__abs; // 3112 - duration_prototype__proto.add = duration_add_subtract__add; // 3113 - duration_prototype__proto.subtract = duration_add_subtract__subtract; // 3114 - duration_prototype__proto.as = as; // 3115 - duration_prototype__proto.asMilliseconds = asMilliseconds; // 3116 - duration_prototype__proto.asSeconds = asSeconds; // 3117 - duration_prototype__proto.asMinutes = asMinutes; // 3118 - duration_prototype__proto.asHours = asHours; // 3119 - duration_prototype__proto.asDays = asDays; // 3120 - duration_prototype__proto.asWeeks = asWeeks; // 3121 - duration_prototype__proto.asMonths = asMonths; // 3122 - duration_prototype__proto.asYears = asYears; // 3123 - duration_prototype__proto.valueOf = duration_as__valueOf; // 3124 - duration_prototype__proto._bubble = bubble; // 3125 - duration_prototype__proto.get = duration_get__get; // 3126 - duration_prototype__proto.milliseconds = milliseconds; // 3127 - duration_prototype__proto.seconds = seconds; // 3128 - duration_prototype__proto.minutes = minutes; // 3129 - duration_prototype__proto.hours = hours; // 3130 - duration_prototype__proto.days = days; // 3131 - duration_prototype__proto.weeks = weeks; // 3132 - duration_prototype__proto.months = months; // 3133 - duration_prototype__proto.years = years; // 3134 - duration_prototype__proto.humanize = humanize; // 3135 - duration_prototype__proto.toISOString = iso_string__toISOString; // 3136 - duration_prototype__proto.toString = iso_string__toISOString; // 3137 - duration_prototype__proto.toJSON = iso_string__toISOString; // 3138 - duration_prototype__proto.locale = locale; // 3139 - duration_prototype__proto.localeData = localeData; // 3140 - // 3141 - // Deprecations // 3142 - duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString); - duration_prototype__proto.lang = lang; // 3144 - // 3145 - // Side effect imports // 3146 - // 3147 - addFormatToken('X', 0, 0, 'unix'); // 3148 - addFormatToken('x', 0, 0, 'valueOf'); // 3149 - // 3150 - // PARSING // 3151 - // 3152 - addRegexToken('x', matchSigned); // 3153 - addRegexToken('X', matchTimestamp); // 3154 - addParseToken('X', function (input, array, config) { // 3155 - config._d = new Date(parseFloat(input, 10) * 1000); // 3156 - }); // 3157 - addParseToken('x', function (input, array, config) { // 3158 - config._d = new Date(toInt(input)); // 3159 - }); // 3160 - // 3161 - // Side effect imports // 3162 - // 3163 - // 3164 - utils_hooks__hooks.version = '2.10.6'; // 3165 - // 3166 - setHookCallback(local__createLocal); // 3167 - // 3168 - utils_hooks__hooks.fn = momentPrototype; // 3169 - utils_hooks__hooks.min = min; // 3170 - utils_hooks__hooks.max = max; // 3171 - utils_hooks__hooks.utc = create_utc__createUTC; // 3172 - utils_hooks__hooks.unix = moment__createUnix; // 3173 - utils_hooks__hooks.months = lists__listMonths; // 3174 - utils_hooks__hooks.isDate = isDate; // 3175 - utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale; // 3176 - utils_hooks__hooks.invalid = valid__createInvalid; // 3177 - utils_hooks__hooks.duration = create__createDuration; // 3178 - utils_hooks__hooks.isMoment = isMoment; // 3179 - utils_hooks__hooks.weekdays = lists__listWeekdays; // 3180 - utils_hooks__hooks.parseZone = moment__createInZone; // 3181 - utils_hooks__hooks.localeData = locale_locales__getLocale; // 3182 - utils_hooks__hooks.isDuration = isDuration; // 3183 - utils_hooks__hooks.monthsShort = lists__listMonthsShort; // 3184 - utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin; // 3185 - utils_hooks__hooks.defineLocale = defineLocale; // 3186 - utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort; // 3187 - utils_hooks__hooks.normalizeUnits = normalizeUnits; // 3188 - utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold; // 3189 - // 3190 - var _moment = utils_hooks__hooks; // 3191 - // 3192 - return _moment; // 3193 - // 3194 -})); // 3195 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/momentjs:moment/meteor/export.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// moment.js makes `moment` global on the window (or global) object, while Meteor expects a file-scoped global variable -moment = this.moment; // 2 -try { // 3 - delete this.moment; // 4 -} catch (e) { // 5 -} // 6 - // 7 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['momentjs:moment'] = { - moment: moment -}; - -})(); - -//# sourceMappingURL=momentjs_moment.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js.map b/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js.map deleted file mode 100644 index c3cf5d0..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["momentjs:moment/moment.js","momentjs:moment/meteor/export.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,a;AACA,oB;AACA,8D;AACA,iB;AACA,gB;;AAEA,6B;AACA,+F;AACA,kE;AACA,6B;AACA,mC;;AAEA,qB;;AAEA,oC;AACA,mD;AACA,K;;AAEA,+D;AACA,8C;AACA,yC;AACA,gC;AACA,K;;AAEA,6B;AACA,0E;AACA,K;;AAEA,4B;AACA,kG;AACA,K;;AAEA,2B;AACA,wB;AACA,0C;AACA,oC;AACA,S;AACA,mB;AACA,K;;AAEA,+B;AACA,0D;AACA,K;;AAEA,2B;AACA,0B;AACA,mC;AACA,4B;AACA,a;AACA,S;;AAEA,wC;AACA,oC;AACA,S;;AAEA,uC;AACA,kC;AACA,S;;AAEA,iB;AACA,K;;AAEA,oE;AACA,2E;AACA,K;;AAEA,oC;AACA,6C;AACA,gB;AACA,oC;AACA,iC;AACA,iC;AACA,iC;AACA,gC;AACA,oC;AACA,mC;AACA,oC;AACA,oC;AACA,mC;AACA,U;AACA,K;;AAEA,iC;AACA,4B;AACA,0C;AACA,S;AACA,qB;AACA,K;;AAEA,gC;AACA,iC;AACA,2C;AACA,kD;AACA,qC;AACA,+B;AACA,sC;AACA,wC;AACA,mC;AACA,uC;AACA,uC;;AAEA,4B;AACA,0C;AACA,gD;AACA,sD;AACA,gD;AACA,a;AACA,S;AACA,0B;AACA,K;;AAEA,2C;AACA,2C;AACA,4B;AACA,8C;AACA,S;AACA,c;AACA,sD;AACA,S;;AAEA,iB;AACA,K;;AAEA,oE;;AAEA,mC;AACA,yB;;AAEA,2D;AACA,wD;AACA,S;AACA,6C;AACA,4B;AACA,S;AACA,6C;AACA,4B;AACA,S;AACA,6C;AACA,4B;AACA,S;AACA,kD;AACA,sC;AACA,S;AACA,+C;AACA,gC;AACA,S;AACA,iD;AACA,oC;AACA,S;AACA,kD;AACA,sC;AACA,S;AACA,8C;AACA,2C;AACA,S;AACA,kD;AACA,sC;AACA,S;;AAEA,0C;AACA,yC;AACA,2C;AACA,iC;AACA,iD;AACA,mC;AACA,iB;AACA,a;AACA,S;;AAEA,kB;AACA,K;;AAEA,iC;;AAEA,8B;AACA,6B;AACA,iC;AACA,0E;AACA,wE;AACA,mB;AACA,yC;AACA,oC;AACA,kD;AACA,qC;AACA,S;AACA,K;;AAEA,6B;AACA,sF;AACA,K;;AAEA,gC;AACA,yB;AACA,qC;AACA,gB;AACA,sC;AACA,S;AACA,K;;AAEA,yC;AACA,iD;AACA,sB;;AAEA,6D;AACA,4C;AACA,S;;AAEA,qB;AACA,K;;AAEA,yD;AACA,yD;AACA,iE;AACA,sB;AACA,c;AACA,mC;AACA,2D;AACA,0E;AACA,wB;AACA,a;AACA,S;AACA,kC;AACA,K;;AAEA,uB;AACA,K;;AAEA,qB;AACA,qB;;AAEA,mC;AACA,+D;AACA,K;;AAEA,qC;AACA,gG;AACA,mI;AACA,kC;AACA,0C;;AAEA,kC;AACA,yD;AACA,6B;AACA,iD;AACA,iD;AACA,2B;AACA,iE;AACA,6B;AACA,kC;AACA,iB;AACA,4F;AACA,0F;AACA,0B;AACA,iB;AACA,oB;AACA,a;AACA,gB;AACA,S;AACA,oB;AACA,K;;AAEA,+B;AACA,6B;AACA,+E;AACA,8D;AACA,2C;AACA,iB;AACA,+C;AACA,4C;AACA,iF;AACA,4D;AACA,8D;AACA,2B;AACA,S;AACA,6B;AACA,K;;AAEA,yE;AACA,2E;AACA,kB;AACA,+D;AACA,iB;AACA,kB;AACA,gD;AACA,sD;AACA,a;AACA,kB;AACA,iD;AACA,a;;AAEA,uB;AACA,mE;AACA,oC;AACA,a;AACA,S;;AAEA,kC;AACA,K;;AAEA,0C;AACA,8B;AACA,+B;AACA,0D;AACA,sC;;AAEA,4D;AACA,qD;;AAEA,iC;AACA,gB;AACA,iC;AACA,iC;AACA,wB;AACA,S;AACA,K;;AAEA,0B;AACA,8C;AACA,mB;;AAEA,sD;AACA,oC;AACA,S;;AAEA,mB;AACA,gC;AACA,S;;AAEA,4B;AACA,2C;AACA,qC;AACA,yB;AACA,8B;AACA,a;AACA,wB;AACA,S;;AAEA,iC;AACA,K;;AAEA,qB;;AAEA,6C;AACA,2C;AACA,kF;AACA,K;;AAEA,oC;AACA,sG;AACA,K;;AAEA,gD;AACA,iC;AACA,2B;AACA,iB;;AAEA,mC;AACA,gD;AACA,sD;AACA,qC;AACA,wE;AACA,iB;AACA,a;AACA,S;;AAEA,+B;AACA,K;;AAEA,0C;AACA,iC;AACA,gC;AACA,gD;AACA,gE;AACA,4B;AACA,oB;AACA,gD;AACA,a;AACA,U;AACA,K;;AAEA,uC;AACA,kE;AACA,K;;AAEA,8C;AACA,uE;AACA,K;;AAEA,c;;AAEA,oC;AACA,iB;AACA,wC;AACA,iC;AACA,4C;AACA,a;AACA,gB;AACA,0C;AACA,oD;AACA,0C;AACA,a;AACA,S;AACA,oB;AACA,K;;AAEA,wD;AACA,8C;AACA,0D;AACA,+B;AACA,sD;AACA,oF;AACA,K;;AAEA,gM;;AAEA,6E;;AAEA,6B;;AAEA,kC;;AAEA,oB;AACA,0B;AACA,qB;AACA,iD;AACA,gE;AACA,4B;AACA,2C;AACA,gC;AACA,wC;AACA,c;AACA,S;AACA,oB;AACA,+C;AACA,S;AACA,qB;AACA,2D;AACA,mF;AACA,c;AACA,S;AACA,sB;AACA,yD;AACA,qF;AACA,c;AACA,S;AACA,K;;AAEA,4C;AACA,sC;AACA,iD;AACA,S;AACA,wC;AACA,K;;AAEA,yC;AACA,8D;;AAEA,6D;AACA,iD;AACA,0D;AACA,oB;AACA,4D;AACA,a;AACA,S;;AAEA,+B;AACA,4B;AACA,0C;AACA,+F;AACA,a;AACA,0B;AACA,U;AACA,K;;AAEA,2C;AACA,sC;AACA,2B;AACA,gD;AACA,S;;AAEA,sD;AACA,wF;;AAEA,0C;AACA,K;;AAEA,2C;AACA,kB;;AAEA,qD;AACA,yD;AACA,S;;AAEA,4C;AACA,8D;AACA,wF;AACA,gD;AACA,mB;AACA,S;;AAEA,sB;AACA,K;;AAEA,wD;AACA,yD;AACA,0D;AACA,2D;AACA,6D;AACA,yD;AACA,0D;AACA,2D;AACA,6D;;AAEA,0D;AACA,0D;;AAEA,gF;;AAEA,2E;;AAEA,wF;AACA,uI;;AAEA,qB;;AAEA,+B;AACA,uD;AACA,2C;AACA,wE;AACA,K;;;AAGA,wD;AACA,0E;AACA,mE;AACA,U;AACA,K;;AAEA,oD;AACA,0C;AACA,qD;AACA,S;;AAEA,8D;AACA,K;;AAEA,2G;AACA,gC;AACA,sH;AACA,wC;AACA,qD;AACA,K;;AAEA,oB;;AAEA,8C;AACA,+B;AACA,wC;AACA,4B;AACA,S;AACA,2C;AACA,4C;AACA,+C;AACA,c;AACA,S;AACA,4C;AACA,oC;AACA,S;AACA,K;;AAEA,kD;AACA,qE;AACA,wC;AACA,sD;AACA,W;AACA,K;;AAEA,4D;AACA,yD;AACA,2D;AACA,S;AACA,K;;AAEA,iB;AACA,kB;AACA,iB;AACA,iB;AACA,mB;AACA,mB;AACA,wB;;AAEA,uC;AACA,mE;AACA,K;;AAEA,iB;;AAEA,sD;AACA,gC;AACA,O;;AAEA,mD;AACA,2D;AACA,O;;AAEA,oD;AACA,sD;AACA,O;;AAEA,c;;AAEA,+B;;AAEA,c;;AAEA,qC;AACA,6C;AACA,qC;AACA,qC;;AAEA,wD;AACA,wC;AACA,O;;AAEA,2E;AACA,6E;AACA,oE;AACA,4B;AACA,iC;AACA,gB;AACA,yD;AACA,S;AACA,O;;AAEA,c;;AAEA,iI;AACA,+B;AACA,uC;AACA,K;;AAEA,gG;AACA,oC;AACA,4C;AACA,K;;AAEA,4D;AACA,0B;;AAEA,iC;AACA,mC;AACA,uC;AACA,wC;AACA,S;;AAEA,kC;AACA,yD;AACA,mD;AACA,sD;AACA,8G;AACA,oH;AACA,a;AACA,mD;AACA,sF;AACA,+E;AACA,a;AACA,6B;AACA,0F;AACA,yB;AACA,iG;AACA,yB;AACA,yE;AACA,yB;AACA,a;AACA,S;AACA,K;;AAEA,c;;AAEA,oC;AACA,uB;;AAEA,uC;AACA,wC;AACA,wD;AACA,4C;AACA,4C;AACA,2B;AACA,a;AACA,S;;AAEA,0E;AACA,+E;AACA,mB;AACA,K;;AAEA,kC;AACA,4B;AACA,kC;AACA,wD;AACA,wB;AACA,gB;AACA,+C;AACA,S;AACA,K;;AAEA,gC;AACA,sD;AACA,K;;AAEA,gC;AACA,qB;AACA,qB;;AAEA,sD;AACA,sB;AACA,oE;AACA,8F;AACA,sJ;AACA,qE;AACA,qE;AACA,0E;AACA,mB;;AAEA,gG;AACA,gC;AACA,a;;AAEA,mD;AACA,S;;AAEA,iB;AACA,K;;AAEA,wB;AACA,yH;AACA,wD;AACA,S;AACA,K;;AAEA,iC;AACA,6B;;AAEA,mC;AACA,4B;AACA,uD;AACA,kC;AACA,a;AACA,6C;AACA,e;AACA,K;;AAEA,0B;;AAEA,yC;AACA,kC;AACA,sB;AACA,sC;AACA,S;AACA,K;;AAEA,2D;;AAEA,4K;;AAEA,oB;AACA,kD;AACA,4C;AACA,4C;AACA,uC;AACA,mC;AACA,M;;AAEA,mC;AACA,oB;AACA,sD;AACA,4C;AACA,oC;AACA,2B;AACA,M;;AAEA,gD;;AAEA,2B;AACA,oC;AACA,iB;AACA,+B;AACA,uD;;AAEA,oB;AACA,+C;AACA,0D;AACA,kD;AACA,+C;AACA,0B;AACA,iB;AACA,a;AACA,0D;AACA,kD;AACA,sD;AACA,oE;AACA,0B;AACA,iB;AACA,a;AACA,4C;AACA,iC;AACA,a;AACA,8C;AACA,gB;AACA,oC;AACA,S;AACA,K;;AAEA,uC;AACA,uC;AACA,sD;;AAEA,+B;AACA,8C;AACA,mB;AACA,S;;AAEA,8B;AACA,wC;AACA,mC;AACA,+D;AACA,S;AACA,K;;AAEA,2D;AACA,+D;AACA,8D;AACA,qC;AACA,sE;AACA,2B;AACA,6E;AACA,S;AACA,M;;AAEA,gD;AACA,8C;AACA,4H;AACA,kD;;AAEA,0D;AACA,uB;AACA,gC;AACA,S;AACA,oB;AACA,K;;AAEA,gC;AACA,6D;AACA,uB;AACA,mC;AACA,S;AACA,oB;AACA,K;;AAEA,iD;AACA,iC;AACA,O;;AAEA,sD;AACA,sD;AACA,sD;;AAEA,c;;AAEA,8B;;AAEA,c;;AAEA,yC;AACA,+C;AACA,+C;AACA,+C;AACA,+C;;AAEA,6C;AACA,mD;AACA,sG;AACA,O;AACA,iD;AACA,kE;AACA,O;;AAEA,c;;AAEA,+B;AACA,4C;AACA,K;;AAEA,+B;AACA,wE;AACA,K;;AAEA,Y;;AAEA,6D;AACA,gE;AACA,M;;AAEA,c;;AAEA,mD;;AAEA,+B;AACA,uC;AACA,K;;AAEA,iD;AACA,oD;;AAEA,c;;AAEA,8B;AACA,iC;;AAEA,c;;AAEA,mC;AACA,2C;AACA,mC;AACA,2C;;AAEA,qF;AACA,gD;AACA,O;;AAEA,c;;AAEA,4C;AACA,oE;AACA,sD;AACA,4C;AACA,8E;AACA,mD;AACA,4D;AACA,oE;AACA,wD;AACA,+D;AACA,2B;;;AAGA,oC;AACA,iC;AACA,S;;AAEA,wC;AACA,iC;AACA,S;;AAEA,2E;AACA,gB;AACA,4D;AACA,uC;AACA,U;AACA,K;;AAEA,c;;AAEA,+B;AACA,oE;AACA,K;;AAEA,6B;AACA,wD;AACA,iF;AACA,M;;AAEA,sC;AACA,8B;AACA,K;;AAEA,sC;AACA,8B;AACA,K;;AAEA,c;;AAEA,iC;AACA,gD;AACA,wE;AACA,K;;AAEA,oC;AACA,+C;AACA,wE;AACA,K;;AAEA,4D;;AAEA,c;;AAEA,qC;;AAEA,c;;AAEA,qC;AACA,kC;AACA,oE;AACA,yC;AACA,O;;AAEA,c;;AAEA,6G;AACA,4F;AACA,+I;AACA,iC;AACA,mB;AACA,S;;AAEA,iE;;AAEA,gE;;AAEA,gB;AACA,kD;AACA,oF;AACA,U;AACA,K;;AAEA,c;;AAEA,sC;AACA,6G;AACA,8E;AACA,K;;AAEA,wD;AACA,gC;AACA,wB;AACA,qB;AACA,S;AACA,wB;AACA,qB;AACA,S;AACA,iB;AACA,K;;AAEA,uC;AACA,6B;AACA,6B;AACA,+E;AACA,S;AACA,kE;AACA,K;;AAEA,kC;AACA,mD;AACA,iG;AACA,6D;AACA,uC;AACA,wD;;AAEA,wB;AACA,mB;AACA,S;;AAEA,+C;;AAEA,yD;AACA,+E;AACA,0C;AACA,S;;AAEA,8D;AACA,gC;AACA,qE;;AAEA,4D;AACA,kE;AACA,a;;AAEA,kE;AACA,kD;AACA,gD;AACA,S;;AAEA,mC;AACA,wE;AACA,6D;AACA,iD;AACA,qD;AACA,yD;AACA,qD;AACA,S;;AAEA,8D;AACA,4B;AACA,gG;AACA,S;;AAEA,iC;AACA,qC;AACA,0C;AACA,0C;AACA,+C;AACA,mC;AACA,gC;AACA,S;;AAEA,qF;AACA,gF;AACA,0B;AACA,kC;AACA,6E;AACA,S;;AAEA,8B;AACA,iC;AACA,S;AACA,K;;AAEA,4C;AACA,uD;;AAEA,sB;AACA,yD;AACA,oB;AACA,oB;;AAEA,iF;AACA,yE;AACA,gF;AACA,2B;AACA,oG;AACA,oC;AACA,uC;AACA,gB;AACA,2C;AACA,2C;;AAEA,wG;AACA,oC;;AAEA,8B;AACA,sE;AACA,8B;AACA,oC;AACA,2B;AACA,iB;AACA,qC;AACA,yE;AACA,oC;AACA,oB;AACA,8C;AACA,8B;AACA,a;AACA,S;AACA,qE;;AAEA,oC;AACA,2C;AACA,K;;AAEA,iD;;AAEA,yC;AACA,gD;AACA,wF;AACA,wD;AACA,kC;AACA,mB;AACA,S;;AAEA,uB;AACA,6C;;AAEA,kF;AACA,oC;AACA,mD;AACA,yC;AACA,uC;;AAEA,uF;;AAEA,6C;AACA,8B;AACA,wF;AACA,8B;AACA,wE;AACA,yC;AACA,sE;AACA,iB;AACA,wF;AACA,6D;AACA,a;AACA,oD;AACA,8C;AACA,kC;AACA,0D;AACA,iB;AACA,sB;AACA,qE;AACA,iB;AACA,oE;AACA,a;AACA,sD;AACA,iE;AACA,a;AACA,S;;AAEA,4D;AACA,sF;AACA,gC;AACA,6D;AACA,S;;AAEA,2C;AACA,uD;AACA,wC;AACA,sC;AACA,wD;AACA,S;AACA,0B;AACA,6F;;AAEA,gC;AACA,8B;AACA,K;;;AAGA,uD;AACA,iB;;AAEA,+B;AACA,4B;AACA,wB;AACA,S;AACA,0C;AACA,uD;AACA,yC;AACA,uB;AACA,yC;AACA,oC;AACA,2B;AACA,a;AACA,uC;AACA,yB;AACA,a;AACA,wB;AACA,gB;AACA,6C;AACA,wB;AACA,S;AACA,K;;AAEA,+C;AACA,uB;AACA,uB;;AAEA,wB;AACA,c;AACA,yB;;AAEA,qC;AACA,yD;AACA,sC;AACA,mB;AACA,S;;AAEA,gD;AACA,6B;AACA,gD;AACA,yC;AACA,oD;AACA,a;AACA,yC;AACA,kD;;AAEA,8C;AACA,yB;AACA,a;;AAEA,sF;AACA,sE;;AAEA,uB;AACA,iF;;AAEA,6D;;AAEA,oE;AACA,2C;AACA,wC;AACA,a;AACA,S;;AAEA,iD;AACA,K;;AAEA,uC;AACA,wB;AACA,mB;AACA,S;;AAEA,gD;AACA,kG;;AAEA,gC;AACA,K;;AAEA,wC;AACA,mE;AACA,2B;AACA,gD;AACA,4B;AACA,qC;AACA,S;;AAEA,mB;AACA,K;;AAEA,qC;AACA,8B;AACA,+B;;AAEA,gF;;AAEA,uE;AACA,2D;AACA,S;;AAEA,wC;AACA,+D;AACA,S;;AAEA,8B;AACA,oD;AACA,qC;AACA,6C;AACA,4B;AACA,8C;AACA,mC;AACA,8B;AACA,gB;AACA,oC;AACA,S;;AAEA,sB;AACA,K;;AAEA,sC;AACA,8B;AACA,kC;AACA,mC;AACA,mC;AACA,yC;AACA,+C;AACA,qC;AACA,oC;AACA,4D;AACA,yC;AACA,e;AACA,oC;AACA,gD;AACA,qC;AACA,gD;AACA,gC;AACA,wC;AACA,gB;AACA,+D;AACA,S;AACA,K;;AAEA,sE;AACA,mB;;AAEA,2C;AACA,4B;AACA,+B;AACA,S;AACA,qD;AACA,uD;AACA,kC;AACA,qC;AACA,sB;AACA,qB;AACA,sB;AACA,2B;;AAEA,mC;AACA,K;;AAEA,iE;AACA,sE;AACA,K;;AAEA,iC;AACA,4G;AACA,sB;AACA,mE;AACA,gD;AACA,U;AACA,O;;AAEA,iC;AACA,2G;AACA,qB;AACA,kE;AACA,+C;AACA,S;AACA,M;;AAEA,wE;AACA,8D;AACA,M;AACA,6E;AACA,mD;AACA,kC;AACA,mB;AACA,0D;AACA,iC;AACA,S;AACA,8B;AACA,wC;AACA,S;AACA,yB;AACA,8C;AACA,+D;AACA,iC;AACA,a;AACA,S;AACA,mB;AACA,K;;AAEA,iC;AACA,qB;AACA,+C;;AAEA,wC;AACA,K;;AAEA,qB;AACA,+C;;AAEA,uC;AACA,K;;AAEA,kC;AACA,6D;AACA,8C;AACA,oD;AACA,gD;AACA,8C;AACA,4C;AACA,8C;AACA,kD;AACA,kD;AACA,4D;;AAEA,2C;AACA,4C;AACA,mC;AACA,wC;AACA,2C;AACA,uE;AACA,wE;AACA,4B;AACA,sB;AACA,sE;AACA,sE;AACA,yB;AACA,gC;AACA,0B;AACA,uB;;AAEA,wB;;AAEA,mD;;AAEA,uB;AACA,K;;AAEA,+B;AACA,uC;AACA,K;;AAEA,wC;AACA,iD;AACA,0C;AACA,2B;AACA,6B;AACA,iC;AACA,2B;AACA,a;AACA,kG;AACA,W;AACA,K;;AAEA,qB;AACA,qB;;AAEA,c;;AAEA,qC;AACA,qC;AACA,gE;AACA,8B;AACA,8C;AACA,O;;AAEA,c;;AAEA,uB;AACA,+B;AACA,+B;AACA,wC;;AAEA,uC;AACA,gE;AACA,wD;AACA,qE;AACA,yD;;AAEA,qD;AACA,K;;AAEA,8E;AACA,4C;AACA,sB;AACA,2B;AACA,gC;AACA,qG;AACA,mE;AACA,2C;AACA,wD;AACA,uB;AACA,gB;AACA,qD;AACA,S;AACA,K;;AAEA,gC;AACA,yE;AACA,qD;AACA,+D;AACA,K;;AAEA,Y;;AAEA,iE;AACA,mE;AACA,qD;;AAEA,c;;AAEA,mE;AACA,2E;AACA,0E;AACA,2D;AACA,M;AACA,0D;AACA,yE;AACA,oE;AACA,sE;AACA,mD;AACA,kD;AACA,uC;AACA,wB;AACA,4B;AACA,4C;AACA,gD;AACA,a;AACA,uC;AACA,mC;AACA,a;AACA,gD;AACA,kD;AACA,a;AACA,iC;AACA,+B;AACA,sC;AACA,2C;AACA,a;AACA,mC;AACA,+D;AACA,2G;AACA,qD;AACA,kD;AACA,gE;AACA,kD;AACA,iB;AACA,a;AACA,wB;AACA,gB;AACA,8D;AACA,S;AACA,K;;AAEA,gD;AACA,4B;AACA,4C;AACA,+B;AACA,a;;AAEA,iD;;AAEA,wB;AACA,gB;AACA,qC;AACA,S;AACA,K;;AAEA,6C;AACA,gD;AACA,K;;AAEA,+C;AACA,0B;AACA,6C;AACA,gC;;AAEA,gC;AACA,wD;AACA,a;AACA,S;AACA,oB;AACA,K;;AAEA,yC;AACA,wB;AACA,sC;AACA,iD;AACA,sD;AACA,S;AACA,oB;AACA,K;;AAEA,2C;AACA,kE;;AAEA,qD;AACA,K;;AAEA,sC;AACA,gB;AACA,mE;AACA,gE;AACA,U;AACA,K;;AAEA,6C;AACA,wD;AACA,sC;AACA,S;;AAEA,mB;;AAEA,4B;AACA,6B;;AAEA,mB;AACA,0F;AACA,kD;AACA,yD;AACA,gB;AACA,uC;AACA,S;;AAEA,kC;AACA,K;;AAEA,yB;AACA,4B;AACA,K;;AAEA,6B;AACA,2B;AACA,K;;AAEA,uB;AACA,iD;AACA,K;;AAEA,6E;;AAEA,gG;AACA,gF;AACA,2J;;AAEA,kD;AACA,6B;AACA,oE;AACA,yB;AACA,iB;AACA,gB;AACA,oB;;AAEA,gC;AACA,wB;AACA,yC;AACA,iC;AACA,kC;AACA,c;AACA,+C;AACA,0B;AACA,sB;AACA,sC;AACA,oB;AACA,8C;AACA,a;AACA,yD;AACA,+C;AACA,wB;AACA,uB;AACA,sD;AACA,sD;AACA,sD;AACA,sD;AACA,qD;AACA,c;AACA,8D;AACA,+C;AACA,wB;AACA,6C;AACA,6C;AACA,6C;AACA,6C;AACA,6C;AACA,6C;AACA,4C;AACA,c;AACA,qE;AACA,0B;AACA,8F;AACA,4G;;AAEA,0B;AACA,+C;AACA,wC;AACA,S;;AAEA,qC;;AAEA,gE;AACA,wC;AACA,S;;AAEA,mB;AACA,K;;AAEA,mD;;AAEA,mC;AACA,sE;AACA,mC;AACA,kE;AACA,2D;AACA,uC;AACA,6C;AACA,K;;AAEA,qD;AACA,+C;;AAEA,mD;AACA,8C;AACA,+D;AACA,yB;AACA,S;;AAEA,yE;;AAEA,mB;AACA,K;;AAEA,6C;AACA,gB;AACA,6C;AACA,mC;AACA,yD;AACA,gB;AACA,yD;AACA,iD;AACA,qC;AACA,S;;AAEA,mB;AACA,K;;AAEA,2C;AACA,uC;AACA,yB;AACA,yD;AACA,qD;AACA,iJ;AACA,sD;AACA,a;;AAEA,uD;AACA,sD;AACA,4D;AACA,wB;AACA,U;AACA,K;;AAEA,gF;AACA,kD;AACA,kC;AACA,sC;AACA,kE;;AAEA,2B;AACA,8D;AACA,S;AACA,mB;AACA,mF;AACA,S;AACA,qB;AACA,0E;AACA,S;AACA,2B;AACA,iE;AACA,S;AACA,K;;AAEA,uD;AACA,6D;;AAEA,wD;AACA,0D;AACA,mF;AACA,+C;AACA,4D;AACA,gD;AACA,6C;AACA,wC;AACA,sC;AACA,sC;AACA,sC;AACA,mD;AACA,4H;AACA,K;;AAEA,uB;AACA,gC;AACA,K;;AAEA,qC;AACA,oB;AACA,qF;AACA,sC;AACA,wE;AACA,kC;AACA,gB;AACA,4E;AACA,0D;AACA,S;AACA,K;;AAEA,sC;AACA,oB;AACA,qF;AACA,sC;AACA,wE;AACA,kC;AACA,gB;AACA,4E;AACA,wD;AACA,S;AACA,K;;AAEA,0C;AACA,qE;AACA,K;;AAEA,oC;AACA,oB;AACA,uD;AACA,sC;AACA,wE;AACA,oC;AACA,gB;AACA,iD;AACA,wG;AACA,S;AACA,K;;AAEA,2C;AACA,gD;AACA,oE;AACA,0B;;AAEA,sC;;AAEA,2E;AACA,2C;AACA,sC;AACA,oC;AACA,0C;AACA,qC;AACA,a;AACA,gB;AACA,gC;AACA,+D;AACA,+D;AACA,mE;AACA,kG;AACA,wG;AACA,sB;AACA,S;AACA,mD;AACA,K;;AAEA,+B;AACA,+B;AACA,oF;AACA,2D;AACA,6D;AACA,4B;;AAEA,6B;AACA,kE;AACA,sC;AACA,uD;AACA,gB;AACA,kE;AACA,sC;AACA,uD;AACA,S;;AAEA,0C;AACA,K;;AAEA,8D;;AAEA,0B;AACA,oF;AACA,K;;AAEA,4C;AACA,mC;AACA,+C;AACA,mE;AACA,2E;AACA,mD;AACA,oB;AACA,uE;AACA,a;AACA,gB;AACA,qE;AACA,S;AACA,K;;AAEA,mC;AACA,yF;AACA,oD;AACA,K;;AAEA,yC;AACA,8B;AACA,mD;AACA,S;AACA,6G;AACA,K;;AAEA,sC;AACA,8D;AACA,K;;AAEA,uC;AACA,8B;AACA,mD;AACA,S;AACA,6G;AACA,K;;AAEA,oC;AACA,4D;AACA,K;;AAEA,2B;AACA,0B;;AAEA,gC;AACA,sC;AACA,gB;AACA,2D;AACA,wC;AACA,6C;AACA,a;AACA,wB;AACA,S;AACA,K;;AAEA,yB;AACA,0J;AACA,wB;AACA,oC;AACA,yC;AACA,oB;AACA,wC;AACA,a;AACA,S;AACA,M;;AAEA,4B;AACA,4B;AACA,K;;AAEA,8B;AACA,sC;AACA,kE;AACA,gD;AACA,wB;AACA,oB;AACA,0B;AACA,+B;AACA,uB;AACA,qB;AACA,yB;AACA,+B;AACA,oB;AACA,uB;AACA,mB;AACA,0B;AACA,+B;AACA,oB;AACA,4B;AACA,+B;AACA,sB;AACA,4B;AACA,+B;AACA,sB;AACA,iC;AACA,S;;AAEA,mC;AACA,+B;AACA,4B;AACA,S;AACA,kC;AACA,+B;AACA,S;;AAEA,oC;AACA,kC;AACA,yD;AACA,S;;AAEA,oB;AACA,K;;AAEA,4B;AACA,sC;AACA,6D;AACA,wB;AACA,S;AACA,oG;AACA,K;;AAEA,kC;AACA,wD;AACA,K;;AAEA,sB;AACA,wC;AACA,K;;AAEA,wB;AACA,wD;AACA,K;;AAEA,yB;AACA,qB;AACA,kG;AACA,K;;AAEA,0B;AACA,qB;AACA,gB;AACA,4B;AACA,8B;AACA,2B;AACA,6B;AACA,iC;AACA,iC;AACA,0C;AACA,U;AACA,K;;AAEA,uC;AACA,oC;AACA,K;;AAEA,8B;AACA,iD;AACA,K;;AAEA,2B;AACA,8C;AACA,K;;AAEA,iD;AACA,qC;AACA,O;;AAEA,iD;AACA,wC;AACA,O;;AAEA,qD;AACA,4D;AACA,K;;AAEA,mD;AACA,mD;AACA,mD;AACA,mD;;AAEA,c;;AAEA,mC;AACA,sC;;AAEA,c;;AAEA,yC;AACA,yC;AACA,+C;AACA,+C;AACA,+C;AACA,+C;AACA,+C;AACA,+C;;AAEA,iG;AACA,gD;AACA,O;;AAEA,2E;AACA,kE;AACA,O;;AAEA,c;;AAEA,0C;AACA,yF;AACA,K;;AAEA,c;;AAEA,qC;AACA,mG;AACA,oE;AACA,K;;AAEA,wC;AACA,+C;AACA,oE;AACA,K;;AAEA,mC;AACA,8C;AACA,K;;AAEA,gC;AACA,+C;AACA,oE;AACA,K;;AAEA,yC;;AAEA,c;;AAEA,iC;;AAEA,c;;AAEA,+B;AACA,gD;AACA,8C;AACA,O;;AAEA,c;;AAEA,oC;AACA,kH;AACA,K;;AAEA,iD;;AAEA,c;;AAEA,8B;;AAEA,c;;AAEA,mC;AACA,2C;AACA,qD;AACA,6E;AACA,O;;AAEA,qC;AACA,iD;AACA,2D;AACA,O;;AAEA,c;;AAEA,oD;;AAEA,wC;;AAEA,kD;AACA,2D;AACA,O;;AAEA,mD;AACA,6D;AACA,O;;AAEA,oD;AACA,wD;AACA,O;;AAEA,yC;AACA,4C;;AAEA,c;;AAEA,6B;AACA,iC;AACA,oC;;AAEA,c;;AAEA,qC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;;AAEA,6E;AACA,0D;AACA,oE;AACA,8B;AACA,6B;AACA,gB;AACA,2D;AACA,S;AACA,O;;AAEA,8E;AACA,mC;AACA,O;;AAEA,c;;AAEA,0C;AACA,wC;AACA,yB;AACA,S;;AAEA,4B;AACA,uC;AACA,S;;AAEA,4C;AACA,wC;AACA,yB;AACA,S;;AAEA,oB;AACA,K;;AAEA,c;;AAEA,sG;AACA,iC;AACA,uC;AACA,K;;AAEA,8E;AACA,sC;AACA,4C;AACA,K;;AAEA,qE;AACA,oC;AACA,0C;AACA,K;;AAEA,gD;AACA,0B;;AAEA,wD;;AAEA,iC;AACA,yD;AACA,0C;AACA,2D;AACA,6H;AACA,iF;AACA,a;AACA,6B;AACA,2D;AACA,yB;AACA,a;AACA,S;AACA,K;;AAEA,c;;AAEA,sC;AACA,uE;AACA,4B;AACA,2D;AACA,8C;AACA,gB;AACA,uB;AACA,S;AACA,K;;AAEA,4C;AACA,yE;AACA,wE;AACA,K;;AAEA,yC;AACA,gD;AACA,yE;AACA,kE;AACA,8F;AACA,K;;AAEA,8C;AACA,mD;AACA,uC;AACA,O;;AAEA,0C;AACA,iD;AACA,uF;AACA,W;AACA,K;;AAEA,wB;AACA,yB;;AAEA,c;;AAEA,8B;;AAEA,c;;AAEA,+C;AACA,qC;AACA,K;;AAEA,uC;AACA,uC;AACA,mC;AACA,mC;AACA,2C;AACA,2C;;AAEA,qC;AACA,+D;AACA,kD;AACA,iC;AACA,O;AACA,gE;AACA,mC;AACA,+C;AACA,O;;AAEA,c;;AAEA,iC;AACA,0F;AACA,kD;AACA,8D;AACA,K;;AAEA,qD;AACA,uD;AACA,yB;AACA,yC;AACA,gB;AACA,yC;AACA,S;AACA,K;;;AAGA,c;;AAEA,yE;AACA,6E;AACA,4E;AACA,iB;AACA,+C;;AAEA,gD;;AAEA,c;;AAEA,gC;;AAEA,c;;AAEA,mC;AACA,2C;AACA,uC;;AAEA,c;;AAEA,oD;;AAEA,gD;;AAEA,c;;AAEA,gC;;AAEA,c;;AAEA,mC;AACA,2C;AACA,uC;;AAEA,c;;AAEA,oD;;AAEA,2C;AACA,4C;AACA,O;;AAEA,iD;AACA,2C;AACA,O;;AAEA,oD;AACA,mD;AACA,uC;AACA,O;AACA,oD;AACA,wC;AACA,O;AACA,qD;AACA,yC;AACA,O;AACA,sD;AACA,0C;AACA,O;AACA,uD;AACA,2C;AACA,O;AACA,wD;AACA,4C;AACA,O;;;AAGA,c;;AAEA,sC;;AAEA,c;;AAEA,6C;AACA,6C;AACA,6C;;AAEA,c;AACA,2D;AACA,4C;AACA,K;;AAEA,oC;AACA,0D;AACA,K;;AAEA,wD;AACA,sC;AACA,K;AACA,c;;AAEA,8D;;AAEA,2C;AACA,2C;;AAEA,c;;AAEA,6B;AACA,wC;AACA,K;;AAEA,6B;AACA,+D;AACA,K;;AAEA,kD;;AAEA,4D;AACA,oE;AACA,gD;AACA,+C;AACA,gD;AACA,iD;AACA,+C;AACA,kD;AACA,6C;AACA,gD;AACA,iD;AACA,oD;AACA,kD;AACA,mD;AACA,oD;AACA,iD;AACA,gE;AACA,+C;AACA,iD;AACA,qD;AACA,uD;AACA,uD;AACA,uD;AACA,iD;AACA,kD;AACA,iE;AACA,kD;AACA,mD;AACA,iD;AACA,qE;AACA,qE;AACA,mD;AACA,+C;AACA,2D;;AAEA,W;AACA,mD;AACA,sD;;AAEA,gB;AACA,wD;AACA,2D;;AAEA,c;AACA,qF;;AAEA,Y;AACA,qD;AACA,wD;;AAEA,W;AACA,6F;AACA,gG;AACA,2D;AACA,8D;;AAEA,U;AACA,yD;AACA,kG;AACA,8D;AACA,2D;AACA,wD;;AAEA,W;AACA,4E;;AAEA,a;AACA,kF;;AAEA,a;AACA,kF;;AAEA,kB;AACA,iG;;AAEA,a;AACA,+D;AACA,iE;AACA,mE;AACA,0E;AACA,uE;AACA,uE;AACA,8E;AACA,0D;AACA,8D;AACA,wD;AACA,wD;;AAEA,e;AACA,kD;AACA,kD;;AAEA,mB;AACA,mH;AACA,+G;AACA,4G;AACA,uK;;AAEA,iD;;AAEA,yC;AACA,gD;AACA,K;;AAEA,sC;AACA,qE;AACA,K;;AAEA,2B;AACA,kC;AACA,qC;AACA,kC;AACA,sC;AACA,yC;AACA,sB;AACA,M;;AAEA,wD;AACA,yC;AACA,6E;AACA,K;;AAEA,iC;AACA,2B;AACA,wB;AACA,4B;AACA,8B;AACA,qC;AACA,0C;AACA,M;;AAEA,mC;AACA,+C;AACA,kE;;AAEA,qC;AACA,0B;AACA,S;;AAEA,4F;AACA,gC;AACA,W;;AAEA,yC;AACA,K;;AAEA,4C;;AAEA,6B;AACA,iC;AACA,K;;AAEA,8B;AACA,wC;;AAEA,+B;AACA,mD;AACA,K;;AAEA,0C;AACA,sB;AACA,K;;AAEA,+B;AACA,yB;AACA,0B;AACA,6B;AACA,wB;AACA,0B;AACA,uB;AACA,wB;AACA,qB;AACA,uB;AACA,uB;AACA,yB;AACA,sB;AACA,uB;AACA,M;;AAEA,+E;AACA,gD;AACA,+C;AACA,6D;AACA,0C;AACA,K;;AAEA,wC;AACA,sE;AACA,6F;AACA,K;;AAEA,uC;AACA,oB;AACA,2B;AACA,6B;AACA,6C;AACA,+B;AACA,oB;AACA,qC;AACA,a;AACA,S;AACA,uE;AACA,sE;AACA,qG;AACA,K;;AAEA,4C;;AAEA,uD;AACA,iE;AACA,6D;AACA,sD;AACA,0D;AACA,mD;AACA,sD;AACA,+C;AACA,2D;AACA,0D;AACA,0D;AACA,2D;AACA,8D;AACA,kD;AACA,uD;;AAEA,Y;AACA,wD;AACA,wD;AACA,6D;AACA,6D;AACA,6D;;AAEA,W;AACA,uC;AACA,+C;AACA,2D;AACA,2D;;AAEA,kB;AACA,4D;AACA,4D;AACA,+D;AACA,+D;AACA,iE;AACA,iE;AACA,iE;;AAEA,Y;AACA,uC;AACA,iE;AACA,+C;;AAEA,wD;AACA,iD;AACA,6D;AACA,0C;AACA,K;;AAEA,yD;AACA,yC;AACA,2B;AACA,+B;AACA,S;;AAEA,8B;;AAEA,4B;AACA,4D;AACA,S;;AAEA,c;AACA,qB;AACA,qC;AACA,0D;AACA,S;AACA,mB;AACA,K;;AAEA,gD;AACA,0D;AACA,K;;AAEA,qD;AACA,+D;AACA,K;;AAEA,kD;AACA,yD;AACA,K;;AAEA,uD;AACA,8D;AACA,K;;AAEA,qD;AACA,4D;AACA,K;;AAEA,8C;AACA,6C;AACA,qC;AACA,gC;AACA,kE;AACA,kC;AACA,kC;AACA,wC;AACA,mC;AACA,S;AACA,O;;AAEA,0B;AACA,qI;AACA,wI;;AAEA,2B;;AAEA,mC;AACA,wC;;AAEA,yD;AACA,iD;AACA,mD;;AAEA,wD;AACA,mD;AACA,mD;AACA,iD;AACA,kD;AACA,iD;;AAEA,oB;AACA,K;;AAEA,qF;AACA,yD;;AAEA,kE;AACA,0D;AACA,4D;;AAEA,kC;AACA,K;;AAEA,2D;AACA,wD;AACA,yE;AACA,K;;AAEA,qE;AACA,6D;AACA,0E;AACA,K;;AAEA,+B;AACA,yB;AACA,sC;AACA,gB;AACA,qC;AACA,S;AACA,K;;AAEA,wB;AACA,8C;AACA,sC;AACA,wC;AACA,sC;AACA,2D;;AAEA,8E;AACA,8D;AACA,gE;AACA,mE;AACA,yE;AACA,qB;AACA,uB;AACA,S;;AAEA,kE;AACA,uC;AACA,gD;;AAEA,0D;AACA,yC;;AAEA,mD;AACA,yC;;AAEA,mD;AACA,uC;;AAEA,qC;;AAEA,iC;AACA,sD;AACA,iC;AACA,sD;;AAEA,8B;AACA,sC;AACA,qB;;AAEA,2B;AACA,6B;AACA,4B;;AAEA,oB;AACA,K;;AAEA,kC;AACA,2E;AACA,4C;AACA,oC;AACA,K;;AAEA,oC;AACA,sC;AACA,sC;AACA,K;;AAEA,yB;AACA,iB;AACA,mB;AACA,8C;;AAEA,sC;;AAEA,oD;AACA,yD;AACA,uD;AACA,4D;AACA,gB;AACA,iG;AACA,uE;AACA,4B;AACA,4E;AACA,2E;AACA,0E;AACA,yE;AACA,0E;AACA,sE;AACA,mF;AACA,kE;AACA,a;AACA,S;AACA,K;;AAEA,+B;AACA,sC;AACA,gB;AACA,gC;AACA,gC;AACA,0C;AACA,8C;AACA,U;AACA,K;;AAEA,6B;AACA,4B;AACA,kC;AACA,U;AACA,K;;AAEA,sC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;AACA,qC;;AAEA,wC;AACA,sC;AACA,mC;AACA,K;;AAEA,+B;AACA,4B;AACA,oC;AACA,U;AACA,K;;AAEA,kD;AACA,6C;AACA,6C;AACA,2C;AACA,0C;AACA,4C;AACA,2C;;AAEA,uB;AACA,yC;AACA,K;;AAEA,2B;AACA,sB;AACA,oC;AACA,kC;AACA,+B;AACA,gC;AACA,iC;AACA,M;;AAEA,6F;AACA,iF;AACA,mF;AACA,K;;AAEA,sF;AACA,oE;AACA,+C;AACA,+C;AACA,+C;AACA,+C;AACA,+C;AACA,+C;;AAEA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,4D;AACA,2E;;AAEA,6B;AACA,mC;AACA,sB;AACA,gD;AACA,K;;AAEA,4E;AACA,gF;AACA,kD;AACA,yB;AACA,S;AACA,kC;AACA,yC;AACA,S;AACA,sC;AACA,oB;AACA,K;;AAEA,oC;AACA,uC;AACA,gF;;AAEA,yB;AACA,sD;AACA,S;;AAEA,yC;AACA,K;;AAEA,mC;;AAEA,wC;AACA,mE;AACA,4D;AACA,uC;AACA,sD;AACA,qF;AACA,mC;AACA,sE;AACA,iE;AACA,uD;AACA,yD;AACA,kC;;AAEA,+C;AACA,mD;AACA,mD;AACA,sB;AACA,sB;;AAEA,8B;AACA,uC;AACA,qB;;;AAGA,uG;AACA,sB;AACA,uB;AACA,qB;AACA,sB;AACA,wB;AACA,wB;AACA,qC;;AAEA,qB;AACA,sE;AACA,2C;AACA,yB;AACA,S;;AAEA,uC;AACA,iB;AACA,gC;AACA,gC;AACA,gC;AACA,wC;AACA,gC;AACA,gC;AACA,+B;AACA,K;;AAEA,uD;;AAEA,iE;AACA,0E;AACA,+E;AACA,kD;AACA,8D;AACA,yD;AACA,yD;AACA,uD;AACA,sD;AACA,uD;AACA,wD;AACA,uD;AACA,oE;AACA,sD;AACA,iE;AACA,4D;AACA,uD;AACA,uD;AACA,qD;AACA,oD;AACA,qD;AACA,sD;AACA,qD;AACA,wD;AACA,uE;AACA,uE;AACA,uE;AACA,sD;AACA,0D;;AAEA,mB;AACA,sK;AACA,0C;;AAEA,0B;;AAEA,sC;AACA,yC;;AAEA,c;;AAEA,oC;AACA,uC;AACA,wD;AACA,2D;AACA,O;AACA,wD;AACA,2C;AACA,O;;AAEA,0B;;;AAGA,0C;;AAEA,wC;;AAEA,+D;AACA,mD;AACA,mD;AACA,qE;AACA,kE;AACA,iE;AACA,sD;AACA,kF;AACA,oE;AACA,sE;AACA,wD;AACA,mE;AACA,oE;AACA,yE;AACA,0D;AACA,sE;AACA,sE;AACA,4D;AACA,wE;AACA,8D;AACA,8F;;AAEA,qC;;AAEA,mB;;AAEA,I;;;;;;;;;;;;;;;;;;AC1nGA,uH;AACA,qB;AACA,K;AACA,uB;AACA,a;AACA,C","file":"/packages/momentjs_moment.js","sourcesContent":["//! moment.js\n//! version : 2.10.6\n//! authors : Tim Wood, Iskren Chernev, Moment.js contributors\n//! license : MIT\n//! momentjs.com\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n global.moment = factory()\n}(this, function () { 'use strict';\n\n var hookCallback;\n\n function utils_hooks__hooks () {\n return hookCallback.apply(null, arguments);\n }\n\n // This is done to register the method called with moment()\n // without creating circular dependencies.\n function setHookCallback (callback) {\n hookCallback = callback;\n }\n\n function isArray(input) {\n return Object.prototype.toString.call(input) === '[object Array]';\n }\n\n function isDate(input) {\n return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n }\n\n function map(arr, fn) {\n var res = [], i;\n for (i = 0; i < arr.length; ++i) {\n res.push(fn(arr[i], i));\n }\n return res;\n }\n\n function hasOwnProp(a, b) {\n return Object.prototype.hasOwnProperty.call(a, b);\n }\n\n function extend(a, b) {\n for (var i in b) {\n if (hasOwnProp(b, i)) {\n a[i] = b[i];\n }\n }\n\n if (hasOwnProp(b, 'toString')) {\n a.toString = b.toString;\n }\n\n if (hasOwnProp(b, 'valueOf')) {\n a.valueOf = b.valueOf;\n }\n\n return a;\n }\n\n function create_utc__createUTC (input, format, locale, strict) {\n return createLocalOrUTC(input, format, locale, strict, true).utc();\n }\n\n function defaultParsingFlags() {\n // We need to deep clone this object.\n return {\n empty : false,\n unusedTokens : [],\n unusedInput : [],\n overflow : -2,\n charsLeftOver : 0,\n nullInput : false,\n invalidMonth : null,\n invalidFormat : false,\n userInvalidated : false,\n iso : false\n };\n }\n\n function getParsingFlags(m) {\n if (m._pf == null) {\n m._pf = defaultParsingFlags();\n }\n return m._pf;\n }\n\n function valid__isValid(m) {\n if (m._isValid == null) {\n var flags = getParsingFlags(m);\n m._isValid = !isNaN(m._d.getTime()) &&\n flags.overflow < 0 &&\n !flags.empty &&\n !flags.invalidMonth &&\n !flags.invalidWeekday &&\n !flags.nullInput &&\n !flags.invalidFormat &&\n !flags.userInvalidated;\n\n if (m._strict) {\n m._isValid = m._isValid &&\n flags.charsLeftOver === 0 &&\n flags.unusedTokens.length === 0 &&\n flags.bigHour === undefined;\n }\n }\n return m._isValid;\n }\n\n function valid__createInvalid (flags) {\n var m = create_utc__createUTC(NaN);\n if (flags != null) {\n extend(getParsingFlags(m), flags);\n }\n else {\n getParsingFlags(m).userInvalidated = true;\n }\n\n return m;\n }\n\n var momentProperties = utils_hooks__hooks.momentProperties = [];\n\n function copyConfig(to, from) {\n var i, prop, val;\n\n if (typeof from._isAMomentObject !== 'undefined') {\n to._isAMomentObject = from._isAMomentObject;\n }\n if (typeof from._i !== 'undefined') {\n to._i = from._i;\n }\n if (typeof from._f !== 'undefined') {\n to._f = from._f;\n }\n if (typeof from._l !== 'undefined') {\n to._l = from._l;\n }\n if (typeof from._strict !== 'undefined') {\n to._strict = from._strict;\n }\n if (typeof from._tzm !== 'undefined') {\n to._tzm = from._tzm;\n }\n if (typeof from._isUTC !== 'undefined') {\n to._isUTC = from._isUTC;\n }\n if (typeof from._offset !== 'undefined') {\n to._offset = from._offset;\n }\n if (typeof from._pf !== 'undefined') {\n to._pf = getParsingFlags(from);\n }\n if (typeof from._locale !== 'undefined') {\n to._locale = from._locale;\n }\n\n if (momentProperties.length > 0) {\n for (i in momentProperties) {\n prop = momentProperties[i];\n val = from[prop];\n if (typeof val !== 'undefined') {\n to[prop] = val;\n }\n }\n }\n\n return to;\n }\n\n var updateInProgress = false;\n\n // Moment prototype object\n function Moment(config) {\n copyConfig(this, config);\n this._d = new Date(config._d != null ? config._d.getTime() : NaN);\n // Prevent infinite loop in case updateOffset creates new moment\n // objects.\n if (updateInProgress === false) {\n updateInProgress = true;\n utils_hooks__hooks.updateOffset(this);\n updateInProgress = false;\n }\n }\n\n function isMoment (obj) {\n return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);\n }\n\n function absFloor (number) {\n if (number < 0) {\n return Math.ceil(number);\n } else {\n return Math.floor(number);\n }\n }\n\n function toInt(argumentForCoercion) {\n var coercedNumber = +argumentForCoercion,\n value = 0;\n\n if (coercedNumber !== 0 && isFinite(coercedNumber)) {\n value = absFloor(coercedNumber);\n }\n\n return value;\n }\n\n function compareArrays(array1, array2, dontConvert) {\n var len = Math.min(array1.length, array2.length),\n lengthDiff = Math.abs(array1.length - array2.length),\n diffs = 0,\n i;\n for (i = 0; i < len; i++) {\n if ((dontConvert && array1[i] !== array2[i]) ||\n (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {\n diffs++;\n }\n }\n return diffs + lengthDiff;\n }\n\n function Locale() {\n }\n\n var locales = {};\n var globalLocale;\n\n function normalizeLocale(key) {\n return key ? key.toLowerCase().replace('_', '-') : key;\n }\n\n // pick the locale from the array\n // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each\n // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root\n function chooseLocale(names) {\n var i = 0, j, next, locale, split;\n\n while (i < names.length) {\n split = normalizeLocale(names[i]).split('-');\n j = split.length;\n next = normalizeLocale(names[i + 1]);\n next = next ? next.split('-') : null;\n while (j > 0) {\n locale = loadLocale(split.slice(0, j).join('-'));\n if (locale) {\n return locale;\n }\n if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {\n //the next array item is better than a shallower substring of this one\n break;\n }\n j--;\n }\n i++;\n }\n return null;\n }\n\n function loadLocale(name) {\n var oldLocale = null;\n // TODO: Find a better way to register and load all the locales in Node\n if (!locales[name] && typeof module !== 'undefined' &&\n module && module.exports) {\n try {\n oldLocale = globalLocale._abbr;\n require('./locale/' + name);\n // because defineLocale currently also sets the global locale, we\n // want to undo that for lazy loaded locales\n locale_locales__getSetGlobalLocale(oldLocale);\n } catch (e) { }\n }\n return locales[name];\n }\n\n // This function will load locale and then set the global locale. If\n // no arguments are passed in, it will simply return the current global\n // locale key.\n function locale_locales__getSetGlobalLocale (key, values) {\n var data;\n if (key) {\n if (typeof values === 'undefined') {\n data = locale_locales__getLocale(key);\n }\n else {\n data = defineLocale(key, values);\n }\n\n if (data) {\n // moment.duration._locale = moment._locale = data;\n globalLocale = data;\n }\n }\n\n return globalLocale._abbr;\n }\n\n function defineLocale (name, values) {\n if (values !== null) {\n values.abbr = name;\n locales[name] = locales[name] || new Locale();\n locales[name].set(values);\n\n // backwards compat for now: also set the locale\n locale_locales__getSetGlobalLocale(name);\n\n return locales[name];\n } else {\n // useful for testing\n delete locales[name];\n return null;\n }\n }\n\n // returns locale data\n function locale_locales__getLocale (key) {\n var locale;\n\n if (key && key._locale && key._locale._abbr) {\n key = key._locale._abbr;\n }\n\n if (!key) {\n return globalLocale;\n }\n\n if (!isArray(key)) {\n //short-circuit everything else\n locale = loadLocale(key);\n if (locale) {\n return locale;\n }\n key = [key];\n }\n\n return chooseLocale(key);\n }\n\n var aliases = {};\n\n function addUnitAlias (unit, shorthand) {\n var lowerCase = unit.toLowerCase();\n aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;\n }\n\n function normalizeUnits(units) {\n return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;\n }\n\n function normalizeObjectUnits(inputObject) {\n var normalizedInput = {},\n normalizedProp,\n prop;\n\n for (prop in inputObject) {\n if (hasOwnProp(inputObject, prop)) {\n normalizedProp = normalizeUnits(prop);\n if (normalizedProp) {\n normalizedInput[normalizedProp] = inputObject[prop];\n }\n }\n }\n\n return normalizedInput;\n }\n\n function makeGetSet (unit, keepTime) {\n return function (value) {\n if (value != null) {\n get_set__set(this, unit, value);\n utils_hooks__hooks.updateOffset(this, keepTime);\n return this;\n } else {\n return get_set__get(this, unit);\n }\n };\n }\n\n function get_set__get (mom, unit) {\n return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();\n }\n\n function get_set__set (mom, unit, value) {\n return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);\n }\n\n // MOMENTS\n\n function getSet (units, value) {\n var unit;\n if (typeof units === 'object') {\n for (unit in units) {\n this.set(unit, units[unit]);\n }\n } else {\n units = normalizeUnits(units);\n if (typeof this[units] === 'function') {\n return this[units](value);\n }\n }\n return this;\n }\n\n function zeroFill(number, targetLength, forceSign) {\n var absNumber = '' + Math.abs(number),\n zerosToFill = targetLength - absNumber.length,\n sign = number >= 0;\n return (sign ? (forceSign ? '+' : '') : '-') +\n Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;\n }\n\n var formattingTokens = /(\\[[^\\[]*\\])|(\\\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;\n\n var localFormattingTokens = /(\\[[^\\[]*\\])|(\\\\)?(LTS|LT|LL?L?L?|l{1,4})/g;\n\n var formatFunctions = {};\n\n var formatTokenFunctions = {};\n\n // token: 'M'\n // padded: ['MM', 2]\n // ordinal: 'Mo'\n // callback: function () { this.month() + 1 }\n function addFormatToken (token, padded, ordinal, callback) {\n var func = callback;\n if (typeof callback === 'string') {\n func = function () {\n return this[callback]();\n };\n }\n if (token) {\n formatTokenFunctions[token] = func;\n }\n if (padded) {\n formatTokenFunctions[padded[0]] = function () {\n return zeroFill(func.apply(this, arguments), padded[1], padded[2]);\n };\n }\n if (ordinal) {\n formatTokenFunctions[ordinal] = function () {\n return this.localeData().ordinal(func.apply(this, arguments), token);\n };\n }\n }\n\n function removeFormattingTokens(input) {\n if (input.match(/\\[[\\s\\S]/)) {\n return input.replace(/^\\[|\\]$/g, '');\n }\n return input.replace(/\\\\/g, '');\n }\n\n function makeFormatFunction(format) {\n var array = format.match(formattingTokens), i, length;\n\n for (i = 0, length = array.length; i < length; i++) {\n if (formatTokenFunctions[array[i]]) {\n array[i] = formatTokenFunctions[array[i]];\n } else {\n array[i] = removeFormattingTokens(array[i]);\n }\n }\n\n return function (mom) {\n var output = '';\n for (i = 0; i < length; i++) {\n output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];\n }\n return output;\n };\n }\n\n // format date using native date object\n function formatMoment(m, format) {\n if (!m.isValid()) {\n return m.localeData().invalidDate();\n }\n\n format = expandFormat(format, m.localeData());\n formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);\n\n return formatFunctions[format](m);\n }\n\n function expandFormat(format, locale) {\n var i = 5;\n\n function replaceLongDateFormatTokens(input) {\n return locale.longDateFormat(input) || input;\n }\n\n localFormattingTokens.lastIndex = 0;\n while (i >= 0 && localFormattingTokens.test(format)) {\n format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);\n localFormattingTokens.lastIndex = 0;\n i -= 1;\n }\n\n return format;\n }\n\n var match1 = /\\d/; // 0 - 9\n var match2 = /\\d\\d/; // 00 - 99\n var match3 = /\\d{3}/; // 000 - 999\n var match4 = /\\d{4}/; // 0000 - 9999\n var match6 = /[+-]?\\d{6}/; // -999999 - 999999\n var match1to2 = /\\d\\d?/; // 0 - 99\n var match1to3 = /\\d{1,3}/; // 0 - 999\n var match1to4 = /\\d{1,4}/; // 0 - 9999\n var match1to6 = /[+-]?\\d{1,6}/; // -999999 - 999999\n\n var matchUnsigned = /\\d+/; // 0 - inf\n var matchSigned = /[+-]?\\d+/; // -inf - inf\n\n var matchOffset = /Z|[+-]\\d\\d:?\\d\\d/gi; // +00:00 -00:00 +0000 -0000 or Z\n\n var matchTimestamp = /[+-]?\\d+(\\.\\d{1,3})?/; // 123456789 123456789.123\n\n // any word (or two) characters or numbers including two/three word month in arabic.\n var matchWord = /[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i;\n\n var regexes = {};\n\n function isFunction (sth) {\n // https://github.com/moment/moment/issues/2325\n return typeof sth === 'function' &&\n Object.prototype.toString.call(sth) === '[object Function]';\n }\n\n\n function addRegexToken (token, regex, strictRegex) {\n regexes[token] = isFunction(regex) ? regex : function (isStrict) {\n return (isStrict && strictRegex) ? strictRegex : regex;\n };\n }\n\n function getParseRegexForToken (token, config) {\n if (!hasOwnProp(regexes, token)) {\n return new RegExp(unescapeFormat(token));\n }\n\n return regexes[token](config._strict, config._locale);\n }\n\n // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript\n function unescapeFormat(s) {\n return s.replace('\\\\', '').replace(/\\\\(\\[)|\\\\(\\])|\\[([^\\]\\[]*)\\]|\\\\(.)/g, function (matched, p1, p2, p3, p4) {\n return p1 || p2 || p3 || p4;\n }).replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n }\n\n var tokens = {};\n\n function addParseToken (token, callback) {\n var i, func = callback;\n if (typeof token === 'string') {\n token = [token];\n }\n if (typeof callback === 'number') {\n func = function (input, array) {\n array[callback] = toInt(input);\n };\n }\n for (i = 0; i < token.length; i++) {\n tokens[token[i]] = func;\n }\n }\n\n function addWeekParseToken (token, callback) {\n addParseToken(token, function (input, array, config, token) {\n config._w = config._w || {};\n callback(input, config._w, config, token);\n });\n }\n\n function addTimeToArrayFromToken(token, input, config) {\n if (input != null && hasOwnProp(tokens, token)) {\n tokens[token](input, config._a, config, token);\n }\n }\n\n var YEAR = 0;\n var MONTH = 1;\n var DATE = 2;\n var HOUR = 3;\n var MINUTE = 4;\n var SECOND = 5;\n var MILLISECOND = 6;\n\n function daysInMonth(year, month) {\n return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n }\n\n // FORMATTING\n\n addFormatToken('M', ['MM', 2], 'Mo', function () {\n return this.month() + 1;\n });\n\n addFormatToken('MMM', 0, 0, function (format) {\n return this.localeData().monthsShort(this, format);\n });\n\n addFormatToken('MMMM', 0, 0, function (format) {\n return this.localeData().months(this, format);\n });\n\n // ALIASES\n\n addUnitAlias('month', 'M');\n\n // PARSING\n\n addRegexToken('M', match1to2);\n addRegexToken('MM', match1to2, match2);\n addRegexToken('MMM', matchWord);\n addRegexToken('MMMM', matchWord);\n\n addParseToken(['M', 'MM'], function (input, array) {\n array[MONTH] = toInt(input) - 1;\n });\n\n addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {\n var month = config._locale.monthsParse(input, token, config._strict);\n // if we didn't find a month name, mark the date as invalid.\n if (month != null) {\n array[MONTH] = month;\n } else {\n getParsingFlags(config).invalidMonth = input;\n }\n });\n\n // LOCALES\n\n var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');\n function localeMonths (m) {\n return this._months[m.month()];\n }\n\n var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');\n function localeMonthsShort (m) {\n return this._monthsShort[m.month()];\n }\n\n function localeMonthsParse (monthName, format, strict) {\n var i, mom, regex;\n\n if (!this._monthsParse) {\n this._monthsParse = [];\n this._longMonthsParse = [];\n this._shortMonthsParse = [];\n }\n\n for (i = 0; i < 12; i++) {\n // make the regex if we don't have it already\n mom = create_utc__createUTC([2000, i]);\n if (strict && !this._longMonthsParse[i]) {\n this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');\n this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');\n }\n if (!strict && !this._monthsParse[i]) {\n regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');\n this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');\n }\n // test the regex\n if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {\n return i;\n } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {\n return i;\n } else if (!strict && this._monthsParse[i].test(monthName)) {\n return i;\n }\n }\n }\n\n // MOMENTS\n\n function setMonth (mom, value) {\n var dayOfMonth;\n\n // TODO: Move this out of here!\n if (typeof value === 'string') {\n value = mom.localeData().monthsParse(value);\n // TODO: Another silent failure?\n if (typeof value !== 'number') {\n return mom;\n }\n }\n\n dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));\n mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);\n return mom;\n }\n\n function getSetMonth (value) {\n if (value != null) {\n setMonth(this, value);\n utils_hooks__hooks.updateOffset(this, true);\n return this;\n } else {\n return get_set__get(this, 'Month');\n }\n }\n\n function getDaysInMonth () {\n return daysInMonth(this.year(), this.month());\n }\n\n function checkOverflow (m) {\n var overflow;\n var a = m._a;\n\n if (a && getParsingFlags(m).overflow === -2) {\n overflow =\n a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :\n a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :\n a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :\n a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :\n a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :\n a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :\n -1;\n\n if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {\n overflow = DATE;\n }\n\n getParsingFlags(m).overflow = overflow;\n }\n\n return m;\n }\n\n function warn(msg) {\n if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {\n console.warn('Deprecation warning: ' + msg);\n }\n }\n\n function deprecate(msg, fn) {\n var firstTime = true;\n\n return extend(function () {\n if (firstTime) {\n warn(msg + '\\n' + (new Error()).stack);\n firstTime = false;\n }\n return fn.apply(this, arguments);\n }, fn);\n }\n\n var deprecations = {};\n\n function deprecateSimple(name, msg) {\n if (!deprecations[name]) {\n warn(msg);\n deprecations[name] = true;\n }\n }\n\n utils_hooks__hooks.suppressDeprecationWarnings = false;\n\n var from_string__isoRegex = /^\\s*(?:[+-]\\d{6}|\\d{4})-(?:(\\d\\d-\\d\\d)|(W\\d\\d$)|(W\\d\\d-\\d)|(\\d\\d\\d))((T| )(\\d\\d(:\\d\\d(:\\d\\d(\\.\\d+)?)?)?)?([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?$/;\n\n var isoDates = [\n ['YYYYYY-MM-DD', /[+-]\\d{6}-\\d{2}-\\d{2}/],\n ['YYYY-MM-DD', /\\d{4}-\\d{2}-\\d{2}/],\n ['GGGG-[W]WW-E', /\\d{4}-W\\d{2}-\\d/],\n ['GGGG-[W]WW', /\\d{4}-W\\d{2}/],\n ['YYYY-DDD', /\\d{4}-\\d{3}/]\n ];\n\n // iso time formats and regexes\n var isoTimes = [\n ['HH:mm:ss.SSSS', /(T| )\\d\\d:\\d\\d:\\d\\d\\.\\d+/],\n ['HH:mm:ss', /(T| )\\d\\d:\\d\\d:\\d\\d/],\n ['HH:mm', /(T| )\\d\\d:\\d\\d/],\n ['HH', /(T| )\\d\\d/]\n ];\n\n var aspNetJsonRegex = /^\\/?Date\\((\\-?\\d+)/i;\n\n // date from iso format\n function configFromISO(config) {\n var i, l,\n string = config._i,\n match = from_string__isoRegex.exec(string);\n\n if (match) {\n getParsingFlags(config).iso = true;\n for (i = 0, l = isoDates.length; i < l; i++) {\n if (isoDates[i][1].exec(string)) {\n config._f = isoDates[i][0];\n break;\n }\n }\n for (i = 0, l = isoTimes.length; i < l; i++) {\n if (isoTimes[i][1].exec(string)) {\n // match[6] should be 'T' or space\n config._f += (match[6] || ' ') + isoTimes[i][0];\n break;\n }\n }\n if (string.match(matchOffset)) {\n config._f += 'Z';\n }\n configFromStringAndFormat(config);\n } else {\n config._isValid = false;\n }\n }\n\n // date from iso format or fallback\n function configFromString(config) {\n var matched = aspNetJsonRegex.exec(config._i);\n\n if (matched !== null) {\n config._d = new Date(+matched[1]);\n return;\n }\n\n configFromISO(config);\n if (config._isValid === false) {\n delete config._isValid;\n utils_hooks__hooks.createFromInputFallback(config);\n }\n }\n\n utils_hooks__hooks.createFromInputFallback = deprecate(\n 'moment construction falls back to js Date. This is ' +\n 'discouraged and will be removed in upcoming major ' +\n 'release. Please refer to ' +\n 'https://github.com/moment/moment/issues/1407 for more info.',\n function (config) {\n config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));\n }\n );\n\n function createDate (y, m, d, h, M, s, ms) {\n //can't just apply() to create a date:\n //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply\n var date = new Date(y, m, d, h, M, s, ms);\n\n //the date constructor doesn't accept years < 1970\n if (y < 1970) {\n date.setFullYear(y);\n }\n return date;\n }\n\n function createUTCDate (y) {\n var date = new Date(Date.UTC.apply(null, arguments));\n if (y < 1970) {\n date.setUTCFullYear(y);\n }\n return date;\n }\n\n addFormatToken(0, ['YY', 2], 0, function () {\n return this.year() % 100;\n });\n\n addFormatToken(0, ['YYYY', 4], 0, 'year');\n addFormatToken(0, ['YYYYY', 5], 0, 'year');\n addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');\n\n // ALIASES\n\n addUnitAlias('year', 'y');\n\n // PARSING\n\n addRegexToken('Y', matchSigned);\n addRegexToken('YY', match1to2, match2);\n addRegexToken('YYYY', match1to4, match4);\n addRegexToken('YYYYY', match1to6, match6);\n addRegexToken('YYYYYY', match1to6, match6);\n\n addParseToken(['YYYYY', 'YYYYYY'], YEAR);\n addParseToken('YYYY', function (input, array) {\n array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);\n });\n addParseToken('YY', function (input, array) {\n array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);\n });\n\n // HELPERS\n\n function daysInYear(year) {\n return isLeapYear(year) ? 366 : 365;\n }\n\n function isLeapYear(year) {\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n }\n\n // HOOKS\n\n utils_hooks__hooks.parseTwoDigitYear = function (input) {\n return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);\n };\n\n // MOMENTS\n\n var getSetYear = makeGetSet('FullYear', false);\n\n function getIsLeapYear () {\n return isLeapYear(this.year());\n }\n\n addFormatToken('w', ['ww', 2], 'wo', 'week');\n addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');\n\n // ALIASES\n\n addUnitAlias('week', 'w');\n addUnitAlias('isoWeek', 'W');\n\n // PARSING\n\n addRegexToken('w', match1to2);\n addRegexToken('ww', match1to2, match2);\n addRegexToken('W', match1to2);\n addRegexToken('WW', match1to2, match2);\n\n addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {\n week[token.substr(0, 1)] = toInt(input);\n });\n\n // HELPERS\n\n // firstDayOfWeek 0 = sun, 6 = sat\n // the day of the week that starts the week\n // (usually sunday or monday)\n // firstDayOfWeekOfYear 0 = sun, 6 = sat\n // the first week is the week that contains the first\n // of this day of the week\n // (eg. ISO weeks use thursday (4))\n function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {\n var end = firstDayOfWeekOfYear - firstDayOfWeek,\n daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),\n adjustedMoment;\n\n\n if (daysToDayOfWeek > end) {\n daysToDayOfWeek -= 7;\n }\n\n if (daysToDayOfWeek < end - 7) {\n daysToDayOfWeek += 7;\n }\n\n adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, 'd');\n return {\n week: Math.ceil(adjustedMoment.dayOfYear() / 7),\n year: adjustedMoment.year()\n };\n }\n\n // LOCALES\n\n function localeWeek (mom) {\n return weekOfYear(mom, this._week.dow, this._week.doy).week;\n }\n\n var defaultLocaleWeek = {\n dow : 0, // Sunday is the first day of the week.\n doy : 6 // The week that contains Jan 1st is the first week of the year.\n };\n\n function localeFirstDayOfWeek () {\n return this._week.dow;\n }\n\n function localeFirstDayOfYear () {\n return this._week.doy;\n }\n\n // MOMENTS\n\n function getSetWeek (input) {\n var week = this.localeData().week(this);\n return input == null ? week : this.add((input - week) * 7, 'd');\n }\n\n function getSetISOWeek (input) {\n var week = weekOfYear(this, 1, 4).week;\n return input == null ? week : this.add((input - week) * 7, 'd');\n }\n\n addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');\n\n // ALIASES\n\n addUnitAlias('dayOfYear', 'DDD');\n\n // PARSING\n\n addRegexToken('DDD', match1to3);\n addRegexToken('DDDD', match3);\n addParseToken(['DDD', 'DDDD'], function (input, array, config) {\n config._dayOfYear = toInt(input);\n });\n\n // HELPERS\n\n //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday\n function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {\n var week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear;\n if (d < firstDayOfWeek) {\n d += 7;\n }\n\n weekday = weekday != null ? 1 * weekday : firstDayOfWeek;\n\n dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday;\n\n return {\n year: dayOfYear > 0 ? year : year - 1,\n dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear\n };\n }\n\n // MOMENTS\n\n function getSetDayOfYear (input) {\n var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;\n return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');\n }\n\n // Pick the first defined of two or three arguments.\n function defaults(a, b, c) {\n if (a != null) {\n return a;\n }\n if (b != null) {\n return b;\n }\n return c;\n }\n\n function currentDateArray(config) {\n var now = new Date();\n if (config._useUTC) {\n return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()];\n }\n return [now.getFullYear(), now.getMonth(), now.getDate()];\n }\n\n // convert an array to a date.\n // the array should mirror the parameters below\n // note: all values past the year are optional and will default to the lowest possible value.\n // [year, month, day , hour, minute, second, millisecond]\n function configFromArray (config) {\n var i, date, input = [], currentDate, yearToUse;\n\n if (config._d) {\n return;\n }\n\n currentDate = currentDateArray(config);\n\n //compute day of the year from weeks and weekdays\n if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {\n dayOfYearFromWeekInfo(config);\n }\n\n //if the day of the year is set, figure out what it is\n if (config._dayOfYear) {\n yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);\n\n if (config._dayOfYear > daysInYear(yearToUse)) {\n getParsingFlags(config)._overflowDayOfYear = true;\n }\n\n date = createUTCDate(yearToUse, 0, config._dayOfYear);\n config._a[MONTH] = date.getUTCMonth();\n config._a[DATE] = date.getUTCDate();\n }\n\n // Default to current date.\n // * if no year, month, day of month are given, default to today\n // * if day of month is given, default month and year\n // * if month is given, default only year\n // * if year is given, don't default anything\n for (i = 0; i < 3 && config._a[i] == null; ++i) {\n config._a[i] = input[i] = currentDate[i];\n }\n\n // Zero out whatever was not defaulted, including time\n for (; i < 7; i++) {\n config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];\n }\n\n // Check for 24:00:00.000\n if (config._a[HOUR] === 24 &&\n config._a[MINUTE] === 0 &&\n config._a[SECOND] === 0 &&\n config._a[MILLISECOND] === 0) {\n config._nextDay = true;\n config._a[HOUR] = 0;\n }\n\n config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);\n // Apply timezone offset from input. The actual utcOffset can be changed\n // with parseZone.\n if (config._tzm != null) {\n config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);\n }\n\n if (config._nextDay) {\n config._a[HOUR] = 24;\n }\n }\n\n function dayOfYearFromWeekInfo(config) {\n var w, weekYear, week, weekday, dow, doy, temp;\n\n w = config._w;\n if (w.GG != null || w.W != null || w.E != null) {\n dow = 1;\n doy = 4;\n\n // TODO: We need to take the current isoWeekYear, but that depends on\n // how we interpret now (local, utc, fixed offset). So create\n // a now version of current config (take local/utc/offset flags, and\n // create now).\n weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);\n week = defaults(w.W, 1);\n weekday = defaults(w.E, 1);\n } else {\n dow = config._locale._week.dow;\n doy = config._locale._week.doy;\n\n weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);\n week = defaults(w.w, 1);\n\n if (w.d != null) {\n // weekday -- low day numbers are considered next week\n weekday = w.d;\n if (weekday < dow) {\n ++week;\n }\n } else if (w.e != null) {\n // local weekday -- counting starts from begining of week\n weekday = w.e + dow;\n } else {\n // default to begining of week\n weekday = dow;\n }\n }\n temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);\n\n config._a[YEAR] = temp.year;\n config._dayOfYear = temp.dayOfYear;\n }\n\n utils_hooks__hooks.ISO_8601 = function () {};\n\n // date from string and format string\n function configFromStringAndFormat(config) {\n // TODO: Move this to another part of the creation flow to prevent circular deps\n if (config._f === utils_hooks__hooks.ISO_8601) {\n configFromISO(config);\n return;\n }\n\n config._a = [];\n getParsingFlags(config).empty = true;\n\n // This array is used to make a Date, either with `new Date` or `Date.UTC`\n var string = '' + config._i,\n i, parsedInput, tokens, token, skipped,\n stringLength = string.length,\n totalParsedInputLength = 0;\n\n tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];\n\n for (i = 0; i < tokens.length; i++) {\n token = tokens[i];\n parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];\n if (parsedInput) {\n skipped = string.substr(0, string.indexOf(parsedInput));\n if (skipped.length > 0) {\n getParsingFlags(config).unusedInput.push(skipped);\n }\n string = string.slice(string.indexOf(parsedInput) + parsedInput.length);\n totalParsedInputLength += parsedInput.length;\n }\n // don't parse if it's not a known token\n if (formatTokenFunctions[token]) {\n if (parsedInput) {\n getParsingFlags(config).empty = false;\n }\n else {\n getParsingFlags(config).unusedTokens.push(token);\n }\n addTimeToArrayFromToken(token, parsedInput, config);\n }\n else if (config._strict && !parsedInput) {\n getParsingFlags(config).unusedTokens.push(token);\n }\n }\n\n // add remaining unparsed input length to the string\n getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;\n if (string.length > 0) {\n getParsingFlags(config).unusedInput.push(string);\n }\n\n // clear _12h flag if hour is <= 12\n if (getParsingFlags(config).bigHour === true &&\n config._a[HOUR] <= 12 &&\n config._a[HOUR] > 0) {\n getParsingFlags(config).bigHour = undefined;\n }\n // handle meridiem\n config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);\n\n configFromArray(config);\n checkOverflow(config);\n }\n\n\n function meridiemFixWrap (locale, hour, meridiem) {\n var isPm;\n\n if (meridiem == null) {\n // nothing to do\n return hour;\n }\n if (locale.meridiemHour != null) {\n return locale.meridiemHour(hour, meridiem);\n } else if (locale.isPM != null) {\n // Fallback\n isPm = locale.isPM(meridiem);\n if (isPm && hour < 12) {\n hour += 12;\n }\n if (!isPm && hour === 12) {\n hour = 0;\n }\n return hour;\n } else {\n // this is not supposed to happen\n return hour;\n }\n }\n\n function configFromStringAndArray(config) {\n var tempConfig,\n bestMoment,\n\n scoreToBeat,\n i,\n currentScore;\n\n if (config._f.length === 0) {\n getParsingFlags(config).invalidFormat = true;\n config._d = new Date(NaN);\n return;\n }\n\n for (i = 0; i < config._f.length; i++) {\n currentScore = 0;\n tempConfig = copyConfig({}, config);\n if (config._useUTC != null) {\n tempConfig._useUTC = config._useUTC;\n }\n tempConfig._f = config._f[i];\n configFromStringAndFormat(tempConfig);\n\n if (!valid__isValid(tempConfig)) {\n continue;\n }\n\n // if there is any input that was not parsed add a penalty for that format\n currentScore += getParsingFlags(tempConfig).charsLeftOver;\n\n //or tokens\n currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;\n\n getParsingFlags(tempConfig).score = currentScore;\n\n if (scoreToBeat == null || currentScore < scoreToBeat) {\n scoreToBeat = currentScore;\n bestMoment = tempConfig;\n }\n }\n\n extend(config, bestMoment || tempConfig);\n }\n\n function configFromObject(config) {\n if (config._d) {\n return;\n }\n\n var i = normalizeObjectUnits(config._i);\n config._a = [i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond];\n\n configFromArray(config);\n }\n\n function createFromConfig (config) {\n var res = new Moment(checkOverflow(prepareConfig(config)));\n if (res._nextDay) {\n // Adding is smart enough around DST\n res.add(1, 'd');\n res._nextDay = undefined;\n }\n\n return res;\n }\n\n function prepareConfig (config) {\n var input = config._i,\n format = config._f;\n\n config._locale = config._locale || locale_locales__getLocale(config._l);\n\n if (input === null || (format === undefined && input === '')) {\n return valid__createInvalid({nullInput: true});\n }\n\n if (typeof input === 'string') {\n config._i = input = config._locale.preparse(input);\n }\n\n if (isMoment(input)) {\n return new Moment(checkOverflow(input));\n } else if (isArray(format)) {\n configFromStringAndArray(config);\n } else if (format) {\n configFromStringAndFormat(config);\n } else if (isDate(input)) {\n config._d = input;\n } else {\n configFromInput(config);\n }\n\n return config;\n }\n\n function configFromInput(config) {\n var input = config._i;\n if (input === undefined) {\n config._d = new Date();\n } else if (isDate(input)) {\n config._d = new Date(+input);\n } else if (typeof input === 'string') {\n configFromString(config);\n } else if (isArray(input)) {\n config._a = map(input.slice(0), function (obj) {\n return parseInt(obj, 10);\n });\n configFromArray(config);\n } else if (typeof(input) === 'object') {\n configFromObject(config);\n } else if (typeof(input) === 'number') {\n // from milliseconds\n config._d = new Date(input);\n } else {\n utils_hooks__hooks.createFromInputFallback(config);\n }\n }\n\n function createLocalOrUTC (input, format, locale, strict, isUTC) {\n var c = {};\n\n if (typeof(locale) === 'boolean') {\n strict = locale;\n locale = undefined;\n }\n // object construction must be done this way.\n // https://github.com/moment/moment/issues/1423\n c._isAMomentObject = true;\n c._useUTC = c._isUTC = isUTC;\n c._l = locale;\n c._i = input;\n c._f = format;\n c._strict = strict;\n\n return createFromConfig(c);\n }\n\n function local__createLocal (input, format, locale, strict) {\n return createLocalOrUTC(input, format, locale, strict, false);\n }\n\n var prototypeMin = deprecate(\n 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',\n function () {\n var other = local__createLocal.apply(null, arguments);\n return other < this ? this : other;\n }\n );\n\n var prototypeMax = deprecate(\n 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',\n function () {\n var other = local__createLocal.apply(null, arguments);\n return other > this ? this : other;\n }\n );\n\n // Pick a moment m from moments so that m[fn](other) is true for all\n // other. This relies on the function fn to be transitive.\n //\n // moments should either be an array of moment objects or an array, whose\n // first element is an array of moment objects.\n function pickBy(fn, moments) {\n var res, i;\n if (moments.length === 1 && isArray(moments[0])) {\n moments = moments[0];\n }\n if (!moments.length) {\n return local__createLocal();\n }\n res = moments[0];\n for (i = 1; i < moments.length; ++i) {\n if (!moments[i].isValid() || moments[i][fn](res)) {\n res = moments[i];\n }\n }\n return res;\n }\n\n // TODO: Use [].sort instead?\n function min () {\n var args = [].slice.call(arguments, 0);\n\n return pickBy('isBefore', args);\n }\n\n function max () {\n var args = [].slice.call(arguments, 0);\n\n return pickBy('isAfter', args);\n }\n\n function Duration (duration) {\n var normalizedInput = normalizeObjectUnits(duration),\n years = normalizedInput.year || 0,\n quarters = normalizedInput.quarter || 0,\n months = normalizedInput.month || 0,\n weeks = normalizedInput.week || 0,\n days = normalizedInput.day || 0,\n hours = normalizedInput.hour || 0,\n minutes = normalizedInput.minute || 0,\n seconds = normalizedInput.second || 0,\n milliseconds = normalizedInput.millisecond || 0;\n\n // representation for dateAddRemove\n this._milliseconds = +milliseconds +\n seconds * 1e3 + // 1000\n minutes * 6e4 + // 1000 * 60\n hours * 36e5; // 1000 * 60 * 60\n // Because of dateAddRemove treats 24 hours as different from a\n // day when working around DST, we need to store them separately\n this._days = +days +\n weeks * 7;\n // It is impossible translate months into days without knowing\n // which months you are are talking about, so we have to store\n // it separately.\n this._months = +months +\n quarters * 3 +\n years * 12;\n\n this._data = {};\n\n this._locale = locale_locales__getLocale();\n\n this._bubble();\n }\n\n function isDuration (obj) {\n return obj instanceof Duration;\n }\n\n function offset (token, separator) {\n addFormatToken(token, 0, 0, function () {\n var offset = this.utcOffset();\n var sign = '+';\n if (offset < 0) {\n offset = -offset;\n sign = '-';\n }\n return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);\n });\n }\n\n offset('Z', ':');\n offset('ZZ', '');\n\n // PARSING\n\n addRegexToken('Z', matchOffset);\n addRegexToken('ZZ', matchOffset);\n addParseToken(['Z', 'ZZ'], function (input, array, config) {\n config._useUTC = true;\n config._tzm = offsetFromString(input);\n });\n\n // HELPERS\n\n // timezone chunker\n // '+10:00' > ['10', '00']\n // '-1530' > ['-15', '30']\n var chunkOffset = /([\\+\\-]|\\d\\d)/gi;\n\n function offsetFromString(string) {\n var matches = ((string || '').match(matchOffset) || []);\n var chunk = matches[matches.length - 1] || [];\n var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];\n var minutes = +(parts[1] * 60) + toInt(parts[2]);\n\n return parts[0] === '+' ? minutes : -minutes;\n }\n\n // Return a moment from input, that is local/utc/zone equivalent to model.\n function cloneWithOffset(input, model) {\n var res, diff;\n if (model._isUTC) {\n res = model.clone();\n diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res);\n // Use low-level api, because this fn is low-level api.\n res._d.setTime(+res._d + diff);\n utils_hooks__hooks.updateOffset(res, false);\n return res;\n } else {\n return local__createLocal(input).local();\n }\n }\n\n function getDateOffset (m) {\n // On Firefox.24 Date#getTimezoneOffset returns a floating point.\n // https://github.com/moment/moment/pull/1871\n return -Math.round(m._d.getTimezoneOffset() / 15) * 15;\n }\n\n // HOOKS\n\n // This function will be called whenever a moment is mutated.\n // It is intended to keep the offset in sync with the timezone.\n utils_hooks__hooks.updateOffset = function () {};\n\n // MOMENTS\n\n // keepLocalTime = true means only change the timezone, without\n // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->\n // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset\n // +0200, so we adjust the time as needed, to be valid.\n //\n // Keeping the time actually adds/subtracts (one hour)\n // from the actual represented time. That is why we call updateOffset\n // a second time. In case it wants us to change the offset again\n // _changeInProgress == true case, then we have to adjust, because\n // there is no such time in the given timezone.\n function getSetOffset (input, keepLocalTime) {\n var offset = this._offset || 0,\n localAdjust;\n if (input != null) {\n if (typeof input === 'string') {\n input = offsetFromString(input);\n }\n if (Math.abs(input) < 16) {\n input = input * 60;\n }\n if (!this._isUTC && keepLocalTime) {\n localAdjust = getDateOffset(this);\n }\n this._offset = input;\n this._isUTC = true;\n if (localAdjust != null) {\n this.add(localAdjust, 'm');\n }\n if (offset !== input) {\n if (!keepLocalTime || this._changeInProgress) {\n add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false);\n } else if (!this._changeInProgress) {\n this._changeInProgress = true;\n utils_hooks__hooks.updateOffset(this, true);\n this._changeInProgress = null;\n }\n }\n return this;\n } else {\n return this._isUTC ? offset : getDateOffset(this);\n }\n }\n\n function getSetZone (input, keepLocalTime) {\n if (input != null) {\n if (typeof input !== 'string') {\n input = -input;\n }\n\n this.utcOffset(input, keepLocalTime);\n\n return this;\n } else {\n return -this.utcOffset();\n }\n }\n\n function setOffsetToUTC (keepLocalTime) {\n return this.utcOffset(0, keepLocalTime);\n }\n\n function setOffsetToLocal (keepLocalTime) {\n if (this._isUTC) {\n this.utcOffset(0, keepLocalTime);\n this._isUTC = false;\n\n if (keepLocalTime) {\n this.subtract(getDateOffset(this), 'm');\n }\n }\n return this;\n }\n\n function setOffsetToParsedOffset () {\n if (this._tzm) {\n this.utcOffset(this._tzm);\n } else if (typeof this._i === 'string') {\n this.utcOffset(offsetFromString(this._i));\n }\n return this;\n }\n\n function hasAlignedHourOffset (input) {\n input = input ? local__createLocal(input).utcOffset() : 0;\n\n return (this.utcOffset() - input) % 60 === 0;\n }\n\n function isDaylightSavingTime () {\n return (\n this.utcOffset() > this.clone().month(0).utcOffset() ||\n this.utcOffset() > this.clone().month(5).utcOffset()\n );\n }\n\n function isDaylightSavingTimeShifted () {\n if (typeof this._isDSTShifted !== 'undefined') {\n return this._isDSTShifted;\n }\n\n var c = {};\n\n copyConfig(c, this);\n c = prepareConfig(c);\n\n if (c._a) {\n var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a);\n this._isDSTShifted = this.isValid() &&\n compareArrays(c._a, other.toArray()) > 0;\n } else {\n this._isDSTShifted = false;\n }\n\n return this._isDSTShifted;\n }\n\n function isLocal () {\n return !this._isUTC;\n }\n\n function isUtcOffset () {\n return this._isUTC;\n }\n\n function isUtc () {\n return this._isUTC && this._offset === 0;\n }\n\n var aspNetRegex = /(\\-)?(?:(\\d*)\\.)?(\\d+)\\:(\\d+)(?:\\:(\\d+)\\.?(\\d{3})?)?/;\n\n // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html\n // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere\n var create__isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;\n\n function create__createDuration (input, key) {\n var duration = input,\n // matching against regexp is expensive, do it on demand\n match = null,\n sign,\n ret,\n diffRes;\n\n if (isDuration(input)) {\n duration = {\n ms : input._milliseconds,\n d : input._days,\n M : input._months\n };\n } else if (typeof input === 'number') {\n duration = {};\n if (key) {\n duration[key] = input;\n } else {\n duration.milliseconds = input;\n }\n } else if (!!(match = aspNetRegex.exec(input))) {\n sign = (match[1] === '-') ? -1 : 1;\n duration = {\n y : 0,\n d : toInt(match[DATE]) * sign,\n h : toInt(match[HOUR]) * sign,\n m : toInt(match[MINUTE]) * sign,\n s : toInt(match[SECOND]) * sign,\n ms : toInt(match[MILLISECOND]) * sign\n };\n } else if (!!(match = create__isoRegex.exec(input))) {\n sign = (match[1] === '-') ? -1 : 1;\n duration = {\n y : parseIso(match[2], sign),\n M : parseIso(match[3], sign),\n d : parseIso(match[4], sign),\n h : parseIso(match[5], sign),\n m : parseIso(match[6], sign),\n s : parseIso(match[7], sign),\n w : parseIso(match[8], sign)\n };\n } else if (duration == null) {// checks for null or undefined\n duration = {};\n } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {\n diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));\n\n duration = {};\n duration.ms = diffRes.milliseconds;\n duration.M = diffRes.months;\n }\n\n ret = new Duration(duration);\n\n if (isDuration(input) && hasOwnProp(input, '_locale')) {\n ret._locale = input._locale;\n }\n\n return ret;\n }\n\n create__createDuration.fn = Duration.prototype;\n\n function parseIso (inp, sign) {\n // We'd normally use ~~inp for this, but unfortunately it also\n // converts floats to ints.\n // inp may be undefined, so careful calling replace on it.\n var res = inp && parseFloat(inp.replace(',', '.'));\n // apply sign while we're at it\n return (isNaN(res) ? 0 : res) * sign;\n }\n\n function positiveMomentsDifference(base, other) {\n var res = {milliseconds: 0, months: 0};\n\n res.months = other.month() - base.month() +\n (other.year() - base.year()) * 12;\n if (base.clone().add(res.months, 'M').isAfter(other)) {\n --res.months;\n }\n\n res.milliseconds = +other - +(base.clone().add(res.months, 'M'));\n\n return res;\n }\n\n function momentsDifference(base, other) {\n var res;\n other = cloneWithOffset(other, base);\n if (base.isBefore(other)) {\n res = positiveMomentsDifference(base, other);\n } else {\n res = positiveMomentsDifference(other, base);\n res.milliseconds = -res.milliseconds;\n res.months = -res.months;\n }\n\n return res;\n }\n\n function createAdder(direction, name) {\n return function (val, period) {\n var dur, tmp;\n //invert the arguments, but complain about it\n if (period !== null && !isNaN(+period)) {\n deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');\n tmp = val; val = period; period = tmp;\n }\n\n val = typeof val === 'string' ? +val : val;\n dur = create__createDuration(val, period);\n add_subtract__addSubtract(this, dur, direction);\n return this;\n };\n }\n\n function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) {\n var milliseconds = duration._milliseconds,\n days = duration._days,\n months = duration._months;\n updateOffset = updateOffset == null ? true : updateOffset;\n\n if (milliseconds) {\n mom._d.setTime(+mom._d + milliseconds * isAdding);\n }\n if (days) {\n get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding);\n }\n if (months) {\n setMonth(mom, get_set__get(mom, 'Month') + months * isAdding);\n }\n if (updateOffset) {\n utils_hooks__hooks.updateOffset(mom, days || months);\n }\n }\n\n var add_subtract__add = createAdder(1, 'add');\n var add_subtract__subtract = createAdder(-1, 'subtract');\n\n function moment_calendar__calendar (time, formats) {\n // We want to compare the start of today, vs this.\n // Getting start-of-today depends on whether we're local/utc/offset or not.\n var now = time || local__createLocal(),\n sod = cloneWithOffset(now, this).startOf('day'),\n diff = this.diff(sod, 'days', true),\n format = diff < -6 ? 'sameElse' :\n diff < -1 ? 'lastWeek' :\n diff < 0 ? 'lastDay' :\n diff < 1 ? 'sameDay' :\n diff < 2 ? 'nextDay' :\n diff < 7 ? 'nextWeek' : 'sameElse';\n return this.format(formats && formats[format] || this.localeData().calendar(format, this, local__createLocal(now)));\n }\n\n function clone () {\n return new Moment(this);\n }\n\n function isAfter (input, units) {\n var inputMs;\n units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');\n if (units === 'millisecond') {\n input = isMoment(input) ? input : local__createLocal(input);\n return +this > +input;\n } else {\n inputMs = isMoment(input) ? +input : +local__createLocal(input);\n return inputMs < +this.clone().startOf(units);\n }\n }\n\n function isBefore (input, units) {\n var inputMs;\n units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');\n if (units === 'millisecond') {\n input = isMoment(input) ? input : local__createLocal(input);\n return +this < +input;\n } else {\n inputMs = isMoment(input) ? +input : +local__createLocal(input);\n return +this.clone().endOf(units) < inputMs;\n }\n }\n\n function isBetween (from, to, units) {\n return this.isAfter(from, units) && this.isBefore(to, units);\n }\n\n function isSame (input, units) {\n var inputMs;\n units = normalizeUnits(units || 'millisecond');\n if (units === 'millisecond') {\n input = isMoment(input) ? input : local__createLocal(input);\n return +this === +input;\n } else {\n inputMs = +local__createLocal(input);\n return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));\n }\n }\n\n function diff (input, units, asFloat) {\n var that = cloneWithOffset(input, this),\n zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4,\n delta, output;\n\n units = normalizeUnits(units);\n\n if (units === 'year' || units === 'month' || units === 'quarter') {\n output = monthDiff(this, that);\n if (units === 'quarter') {\n output = output / 3;\n } else if (units === 'year') {\n output = output / 12;\n }\n } else {\n delta = this - that;\n output = units === 'second' ? delta / 1e3 : // 1000\n units === 'minute' ? delta / 6e4 : // 1000 * 60\n units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60\n units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst\n units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst\n delta;\n }\n return asFloat ? output : absFloor(output);\n }\n\n function monthDiff (a, b) {\n // difference in months\n var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),\n // b is in (anchor - 1 month, anchor + 1 month)\n anchor = a.clone().add(wholeMonthDiff, 'months'),\n anchor2, adjust;\n\n if (b - anchor < 0) {\n anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');\n // linear across the month\n adjust = (b - anchor) / (anchor - anchor2);\n } else {\n anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');\n // linear across the month\n adjust = (b - anchor) / (anchor2 - anchor);\n }\n\n return -(wholeMonthDiff + adjust);\n }\n\n utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';\n\n function toString () {\n return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');\n }\n\n function moment_format__toISOString () {\n var m = this.clone().utc();\n if (0 < m.year() && m.year() <= 9999) {\n if ('function' === typeof Date.prototype.toISOString) {\n // native implementation is ~50x faster, use it when we can\n return this.toDate().toISOString();\n } else {\n return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');\n }\n } else {\n return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');\n }\n }\n\n function format (inputString) {\n var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat);\n return this.localeData().postformat(output);\n }\n\n function from (time, withoutSuffix) {\n if (!this.isValid()) {\n return this.localeData().invalidDate();\n }\n return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);\n }\n\n function fromNow (withoutSuffix) {\n return this.from(local__createLocal(), withoutSuffix);\n }\n\n function to (time, withoutSuffix) {\n if (!this.isValid()) {\n return this.localeData().invalidDate();\n }\n return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);\n }\n\n function toNow (withoutSuffix) {\n return this.to(local__createLocal(), withoutSuffix);\n }\n\n function locale (key) {\n var newLocaleData;\n\n if (key === undefined) {\n return this._locale._abbr;\n } else {\n newLocaleData = locale_locales__getLocale(key);\n if (newLocaleData != null) {\n this._locale = newLocaleData;\n }\n return this;\n }\n }\n\n var lang = deprecate(\n 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',\n function (key) {\n if (key === undefined) {\n return this.localeData();\n } else {\n return this.locale(key);\n }\n }\n );\n\n function localeData () {\n return this._locale;\n }\n\n function startOf (units) {\n units = normalizeUnits(units);\n // the following switch intentionally omits break keywords\n // to utilize falling through the cases.\n switch (units) {\n case 'year':\n this.month(0);\n /* falls through */\n case 'quarter':\n case 'month':\n this.date(1);\n /* falls through */\n case 'week':\n case 'isoWeek':\n case 'day':\n this.hours(0);\n /* falls through */\n case 'hour':\n this.minutes(0);\n /* falls through */\n case 'minute':\n this.seconds(0);\n /* falls through */\n case 'second':\n this.milliseconds(0);\n }\n\n // weeks are a special case\n if (units === 'week') {\n this.weekday(0);\n }\n if (units === 'isoWeek') {\n this.isoWeekday(1);\n }\n\n // quarters are also special\n if (units === 'quarter') {\n this.month(Math.floor(this.month() / 3) * 3);\n }\n\n return this;\n }\n\n function endOf (units) {\n units = normalizeUnits(units);\n if (units === undefined || units === 'millisecond') {\n return this;\n }\n return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');\n }\n\n function to_type__valueOf () {\n return +this._d - ((this._offset || 0) * 60000);\n }\n\n function unix () {\n return Math.floor(+this / 1000);\n }\n\n function toDate () {\n return this._offset ? new Date(+this) : this._d;\n }\n\n function toArray () {\n var m = this;\n return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];\n }\n\n function toObject () {\n var m = this;\n return {\n years: m.year(),\n months: m.month(),\n date: m.date(),\n hours: m.hours(),\n minutes: m.minutes(),\n seconds: m.seconds(),\n milliseconds: m.milliseconds()\n };\n }\n\n function moment_valid__isValid () {\n return valid__isValid(this);\n }\n\n function parsingFlags () {\n return extend({}, getParsingFlags(this));\n }\n\n function invalidAt () {\n return getParsingFlags(this).overflow;\n }\n\n addFormatToken(0, ['gg', 2], 0, function () {\n return this.weekYear() % 100;\n });\n\n addFormatToken(0, ['GG', 2], 0, function () {\n return this.isoWeekYear() % 100;\n });\n\n function addWeekYearFormatToken (token, getter) {\n addFormatToken(0, [token, token.length], 0, getter);\n }\n\n addWeekYearFormatToken('gggg', 'weekYear');\n addWeekYearFormatToken('ggggg', 'weekYear');\n addWeekYearFormatToken('GGGG', 'isoWeekYear');\n addWeekYearFormatToken('GGGGG', 'isoWeekYear');\n\n // ALIASES\n\n addUnitAlias('weekYear', 'gg');\n addUnitAlias('isoWeekYear', 'GG');\n\n // PARSING\n\n addRegexToken('G', matchSigned);\n addRegexToken('g', matchSigned);\n addRegexToken('GG', match1to2, match2);\n addRegexToken('gg', match1to2, match2);\n addRegexToken('GGGG', match1to4, match4);\n addRegexToken('gggg', match1to4, match4);\n addRegexToken('GGGGG', match1to6, match6);\n addRegexToken('ggggg', match1to6, match6);\n\n addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {\n week[token.substr(0, 2)] = toInt(input);\n });\n\n addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {\n week[token] = utils_hooks__hooks.parseTwoDigitYear(input);\n });\n\n // HELPERS\n\n function weeksInYear(year, dow, doy) {\n return weekOfYear(local__createLocal([year, 11, 31 + dow - doy]), dow, doy).week;\n }\n\n // MOMENTS\n\n function getSetWeekYear (input) {\n var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year;\n return input == null ? year : this.add((input - year), 'y');\n }\n\n function getSetISOWeekYear (input) {\n var year = weekOfYear(this, 1, 4).year;\n return input == null ? year : this.add((input - year), 'y');\n }\n\n function getISOWeeksInYear () {\n return weeksInYear(this.year(), 1, 4);\n }\n\n function getWeeksInYear () {\n var weekInfo = this.localeData()._week;\n return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);\n }\n\n addFormatToken('Q', 0, 0, 'quarter');\n\n // ALIASES\n\n addUnitAlias('quarter', 'Q');\n\n // PARSING\n\n addRegexToken('Q', match1);\n addParseToken('Q', function (input, array) {\n array[MONTH] = (toInt(input) - 1) * 3;\n });\n\n // MOMENTS\n\n function getSetQuarter (input) {\n return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);\n }\n\n addFormatToken('D', ['DD', 2], 'Do', 'date');\n\n // ALIASES\n\n addUnitAlias('date', 'D');\n\n // PARSING\n\n addRegexToken('D', match1to2);\n addRegexToken('DD', match1to2, match2);\n addRegexToken('Do', function (isStrict, locale) {\n return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;\n });\n\n addParseToken(['D', 'DD'], DATE);\n addParseToken('Do', function (input, array) {\n array[DATE] = toInt(input.match(match1to2)[0], 10);\n });\n\n // MOMENTS\n\n var getSetDayOfMonth = makeGetSet('Date', true);\n\n addFormatToken('d', 0, 'do', 'day');\n\n addFormatToken('dd', 0, 0, function (format) {\n return this.localeData().weekdaysMin(this, format);\n });\n\n addFormatToken('ddd', 0, 0, function (format) {\n return this.localeData().weekdaysShort(this, format);\n });\n\n addFormatToken('dddd', 0, 0, function (format) {\n return this.localeData().weekdays(this, format);\n });\n\n addFormatToken('e', 0, 0, 'weekday');\n addFormatToken('E', 0, 0, 'isoWeekday');\n\n // ALIASES\n\n addUnitAlias('day', 'd');\n addUnitAlias('weekday', 'e');\n addUnitAlias('isoWeekday', 'E');\n\n // PARSING\n\n addRegexToken('d', match1to2);\n addRegexToken('e', match1to2);\n addRegexToken('E', match1to2);\n addRegexToken('dd', matchWord);\n addRegexToken('ddd', matchWord);\n addRegexToken('dddd', matchWord);\n\n addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config) {\n var weekday = config._locale.weekdaysParse(input);\n // if we didn't get a weekday name, mark the date as invalid\n if (weekday != null) {\n week.d = weekday;\n } else {\n getParsingFlags(config).invalidWeekday = input;\n }\n });\n\n addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {\n week[token] = toInt(input);\n });\n\n // HELPERS\n\n function parseWeekday(input, locale) {\n if (typeof input !== 'string') {\n return input;\n }\n\n if (!isNaN(input)) {\n return parseInt(input, 10);\n }\n\n input = locale.weekdaysParse(input);\n if (typeof input === 'number') {\n return input;\n }\n\n return null;\n }\n\n // LOCALES\n\n var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');\n function localeWeekdays (m) {\n return this._weekdays[m.day()];\n }\n\n var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');\n function localeWeekdaysShort (m) {\n return this._weekdaysShort[m.day()];\n }\n\n var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');\n function localeWeekdaysMin (m) {\n return this._weekdaysMin[m.day()];\n }\n\n function localeWeekdaysParse (weekdayName) {\n var i, mom, regex;\n\n this._weekdaysParse = this._weekdaysParse || [];\n\n for (i = 0; i < 7; i++) {\n // make the regex if we don't have it already\n if (!this._weekdaysParse[i]) {\n mom = local__createLocal([2000, 1]).day(i);\n regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');\n this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');\n }\n // test the regex\n if (this._weekdaysParse[i].test(weekdayName)) {\n return i;\n }\n }\n }\n\n // MOMENTS\n\n function getSetDayOfWeek (input) {\n var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();\n if (input != null) {\n input = parseWeekday(input, this.localeData());\n return this.add(input - day, 'd');\n } else {\n return day;\n }\n }\n\n function getSetLocaleDayOfWeek (input) {\n var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;\n return input == null ? weekday : this.add(input - weekday, 'd');\n }\n\n function getSetISODayOfWeek (input) {\n // behaves the same as moment#day except\n // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)\n // as a setter, sunday should belong to the previous week.\n return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);\n }\n\n addFormatToken('H', ['HH', 2], 0, 'hour');\n addFormatToken('h', ['hh', 2], 0, function () {\n return this.hours() % 12 || 12;\n });\n\n function meridiem (token, lowercase) {\n addFormatToken(token, 0, 0, function () {\n return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);\n });\n }\n\n meridiem('a', true);\n meridiem('A', false);\n\n // ALIASES\n\n addUnitAlias('hour', 'h');\n\n // PARSING\n\n function matchMeridiem (isStrict, locale) {\n return locale._meridiemParse;\n }\n\n addRegexToken('a', matchMeridiem);\n addRegexToken('A', matchMeridiem);\n addRegexToken('H', match1to2);\n addRegexToken('h', match1to2);\n addRegexToken('HH', match1to2, match2);\n addRegexToken('hh', match1to2, match2);\n\n addParseToken(['H', 'HH'], HOUR);\n addParseToken(['a', 'A'], function (input, array, config) {\n config._isPm = config._locale.isPM(input);\n config._meridiem = input;\n });\n addParseToken(['h', 'hh'], function (input, array, config) {\n array[HOUR] = toInt(input);\n getParsingFlags(config).bigHour = true;\n });\n\n // LOCALES\n\n function localeIsPM (input) {\n // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays\n // Using charAt should be more compatible.\n return ((input + '').toLowerCase().charAt(0) === 'p');\n }\n\n var defaultLocaleMeridiemParse = /[ap]\\.?m?\\.?/i;\n function localeMeridiem (hours, minutes, isLower) {\n if (hours > 11) {\n return isLower ? 'pm' : 'PM';\n } else {\n return isLower ? 'am' : 'AM';\n }\n }\n\n\n // MOMENTS\n\n // Setting the hour should keep the time, because the user explicitly\n // specified which hour he wants. So trying to maintain the same hour (in\n // a new timezone) makes sense. Adding/subtracting hours does not follow\n // this rule.\n var getSetHour = makeGetSet('Hours', true);\n\n addFormatToken('m', ['mm', 2], 0, 'minute');\n\n // ALIASES\n\n addUnitAlias('minute', 'm');\n\n // PARSING\n\n addRegexToken('m', match1to2);\n addRegexToken('mm', match1to2, match2);\n addParseToken(['m', 'mm'], MINUTE);\n\n // MOMENTS\n\n var getSetMinute = makeGetSet('Minutes', false);\n\n addFormatToken('s', ['ss', 2], 0, 'second');\n\n // ALIASES\n\n addUnitAlias('second', 's');\n\n // PARSING\n\n addRegexToken('s', match1to2);\n addRegexToken('ss', match1to2, match2);\n addParseToken(['s', 'ss'], SECOND);\n\n // MOMENTS\n\n var getSetSecond = makeGetSet('Seconds', false);\n\n addFormatToken('S', 0, 0, function () {\n return ~~(this.millisecond() / 100);\n });\n\n addFormatToken(0, ['SS', 2], 0, function () {\n return ~~(this.millisecond() / 10);\n });\n\n addFormatToken(0, ['SSS', 3], 0, 'millisecond');\n addFormatToken(0, ['SSSS', 4], 0, function () {\n return this.millisecond() * 10;\n });\n addFormatToken(0, ['SSSSS', 5], 0, function () {\n return this.millisecond() * 100;\n });\n addFormatToken(0, ['SSSSSS', 6], 0, function () {\n return this.millisecond() * 1000;\n });\n addFormatToken(0, ['SSSSSSS', 7], 0, function () {\n return this.millisecond() * 10000;\n });\n addFormatToken(0, ['SSSSSSSS', 8], 0, function () {\n return this.millisecond() * 100000;\n });\n addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {\n return this.millisecond() * 1000000;\n });\n\n\n // ALIASES\n\n addUnitAlias('millisecond', 'ms');\n\n // PARSING\n\n addRegexToken('S', match1to3, match1);\n addRegexToken('SS', match1to3, match2);\n addRegexToken('SSS', match1to3, match3);\n\n var token;\n for (token = 'SSSS'; token.length <= 9; token += 'S') {\n addRegexToken(token, matchUnsigned);\n }\n\n function parseMs(input, array) {\n array[MILLISECOND] = toInt(('0.' + input) * 1000);\n }\n\n for (token = 'S'; token.length <= 9; token += 'S') {\n addParseToken(token, parseMs);\n }\n // MOMENTS\n\n var getSetMillisecond = makeGetSet('Milliseconds', false);\n\n addFormatToken('z', 0, 0, 'zoneAbbr');\n addFormatToken('zz', 0, 0, 'zoneName');\n\n // MOMENTS\n\n function getZoneAbbr () {\n return this._isUTC ? 'UTC' : '';\n }\n\n function getZoneName () {\n return this._isUTC ? 'Coordinated Universal Time' : '';\n }\n\n var momentPrototype__proto = Moment.prototype;\n\n momentPrototype__proto.add = add_subtract__add;\n momentPrototype__proto.calendar = moment_calendar__calendar;\n momentPrototype__proto.clone = clone;\n momentPrototype__proto.diff = diff;\n momentPrototype__proto.endOf = endOf;\n momentPrototype__proto.format = format;\n momentPrototype__proto.from = from;\n momentPrototype__proto.fromNow = fromNow;\n momentPrototype__proto.to = to;\n momentPrototype__proto.toNow = toNow;\n momentPrototype__proto.get = getSet;\n momentPrototype__proto.invalidAt = invalidAt;\n momentPrototype__proto.isAfter = isAfter;\n momentPrototype__proto.isBefore = isBefore;\n momentPrototype__proto.isBetween = isBetween;\n momentPrototype__proto.isSame = isSame;\n momentPrototype__proto.isValid = moment_valid__isValid;\n momentPrototype__proto.lang = lang;\n momentPrototype__proto.locale = locale;\n momentPrototype__proto.localeData = localeData;\n momentPrototype__proto.max = prototypeMax;\n momentPrototype__proto.min = prototypeMin;\n momentPrototype__proto.parsingFlags = parsingFlags;\n momentPrototype__proto.set = getSet;\n momentPrototype__proto.startOf = startOf;\n momentPrototype__proto.subtract = add_subtract__subtract;\n momentPrototype__proto.toArray = toArray;\n momentPrototype__proto.toObject = toObject;\n momentPrototype__proto.toDate = toDate;\n momentPrototype__proto.toISOString = moment_format__toISOString;\n momentPrototype__proto.toJSON = moment_format__toISOString;\n momentPrototype__proto.toString = toString;\n momentPrototype__proto.unix = unix;\n momentPrototype__proto.valueOf = to_type__valueOf;\n\n // Year\n momentPrototype__proto.year = getSetYear;\n momentPrototype__proto.isLeapYear = getIsLeapYear;\n\n // Week Year\n momentPrototype__proto.weekYear = getSetWeekYear;\n momentPrototype__proto.isoWeekYear = getSetISOWeekYear;\n\n // Quarter\n momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;\n\n // Month\n momentPrototype__proto.month = getSetMonth;\n momentPrototype__proto.daysInMonth = getDaysInMonth;\n\n // Week\n momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek;\n momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek;\n momentPrototype__proto.weeksInYear = getWeeksInYear;\n momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;\n\n // Day\n momentPrototype__proto.date = getSetDayOfMonth;\n momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek;\n momentPrototype__proto.weekday = getSetLocaleDayOfWeek;\n momentPrototype__proto.isoWeekday = getSetISODayOfWeek;\n momentPrototype__proto.dayOfYear = getSetDayOfYear;\n\n // Hour\n momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;\n\n // Minute\n momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;\n\n // Second\n momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;\n\n // Millisecond\n momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;\n\n // Offset\n momentPrototype__proto.utcOffset = getSetOffset;\n momentPrototype__proto.utc = setOffsetToUTC;\n momentPrototype__proto.local = setOffsetToLocal;\n momentPrototype__proto.parseZone = setOffsetToParsedOffset;\n momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;\n momentPrototype__proto.isDST = isDaylightSavingTime;\n momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted;\n momentPrototype__proto.isLocal = isLocal;\n momentPrototype__proto.isUtcOffset = isUtcOffset;\n momentPrototype__proto.isUtc = isUtc;\n momentPrototype__proto.isUTC = isUtc;\n\n // Timezone\n momentPrototype__proto.zoneAbbr = getZoneAbbr;\n momentPrototype__proto.zoneName = getZoneName;\n\n // Deprecations\n momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);\n momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);\n momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);\n momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone);\n\n var momentPrototype = momentPrototype__proto;\n\n function moment__createUnix (input) {\n return local__createLocal(input * 1000);\n }\n\n function moment__createInZone () {\n return local__createLocal.apply(null, arguments).parseZone();\n }\n\n var defaultCalendar = {\n sameDay : '[Today at] LT',\n nextDay : '[Tomorrow at] LT',\n nextWeek : 'dddd [at] LT',\n lastDay : '[Yesterday at] LT',\n lastWeek : '[Last] dddd [at] LT',\n sameElse : 'L'\n };\n\n function locale_calendar__calendar (key, mom, now) {\n var output = this._calendar[key];\n return typeof output === 'function' ? output.call(mom, now) : output;\n }\n\n var defaultLongDateFormat = {\n LTS : 'h:mm:ss A',\n LT : 'h:mm A',\n L : 'MM/DD/YYYY',\n LL : 'MMMM D, YYYY',\n LLL : 'MMMM D, YYYY h:mm A',\n LLLL : 'dddd, MMMM D, YYYY h:mm A'\n };\n\n function longDateFormat (key) {\n var format = this._longDateFormat[key],\n formatUpper = this._longDateFormat[key.toUpperCase()];\n\n if (format || !formatUpper) {\n return format;\n }\n\n this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {\n return val.slice(1);\n });\n\n return this._longDateFormat[key];\n }\n\n var defaultInvalidDate = 'Invalid date';\n\n function invalidDate () {\n return this._invalidDate;\n }\n\n var defaultOrdinal = '%d';\n var defaultOrdinalParse = /\\d{1,2}/;\n\n function ordinal (number) {\n return this._ordinal.replace('%d', number);\n }\n\n function preParsePostFormat (string) {\n return string;\n }\n\n var defaultRelativeTime = {\n future : 'in %s',\n past : '%s ago',\n s : 'a few seconds',\n m : 'a minute',\n mm : '%d minutes',\n h : 'an hour',\n hh : '%d hours',\n d : 'a day',\n dd : '%d days',\n M : 'a month',\n MM : '%d months',\n y : 'a year',\n yy : '%d years'\n };\n\n function relative__relativeTime (number, withoutSuffix, string, isFuture) {\n var output = this._relativeTime[string];\n return (typeof output === 'function') ?\n output(number, withoutSuffix, string, isFuture) :\n output.replace(/%d/i, number);\n }\n\n function pastFuture (diff, output) {\n var format = this._relativeTime[diff > 0 ? 'future' : 'past'];\n return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);\n }\n\n function locale_set__set (config) {\n var prop, i;\n for (i in config) {\n prop = config[i];\n if (typeof prop === 'function') {\n this[i] = prop;\n } else {\n this['_' + i] = prop;\n }\n }\n // Lenient ordinal parsing accepts just a number in addition to\n // number + (possibly) stuff coming from _ordinalParseLenient.\n this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\\d{1,2}/).source);\n }\n\n var prototype__proto = Locale.prototype;\n\n prototype__proto._calendar = defaultCalendar;\n prototype__proto.calendar = locale_calendar__calendar;\n prototype__proto._longDateFormat = defaultLongDateFormat;\n prototype__proto.longDateFormat = longDateFormat;\n prototype__proto._invalidDate = defaultInvalidDate;\n prototype__proto.invalidDate = invalidDate;\n prototype__proto._ordinal = defaultOrdinal;\n prototype__proto.ordinal = ordinal;\n prototype__proto._ordinalParse = defaultOrdinalParse;\n prototype__proto.preparse = preParsePostFormat;\n prototype__proto.postformat = preParsePostFormat;\n prototype__proto._relativeTime = defaultRelativeTime;\n prototype__proto.relativeTime = relative__relativeTime;\n prototype__proto.pastFuture = pastFuture;\n prototype__proto.set = locale_set__set;\n\n // Month\n prototype__proto.months = localeMonths;\n prototype__proto._months = defaultLocaleMonths;\n prototype__proto.monthsShort = localeMonthsShort;\n prototype__proto._monthsShort = defaultLocaleMonthsShort;\n prototype__proto.monthsParse = localeMonthsParse;\n\n // Week\n prototype__proto.week = localeWeek;\n prototype__proto._week = defaultLocaleWeek;\n prototype__proto.firstDayOfYear = localeFirstDayOfYear;\n prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;\n\n // Day of Week\n prototype__proto.weekdays = localeWeekdays;\n prototype__proto._weekdays = defaultLocaleWeekdays;\n prototype__proto.weekdaysMin = localeWeekdaysMin;\n prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin;\n prototype__proto.weekdaysShort = localeWeekdaysShort;\n prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort;\n prototype__proto.weekdaysParse = localeWeekdaysParse;\n\n // Hours\n prototype__proto.isPM = localeIsPM;\n prototype__proto._meridiemParse = defaultLocaleMeridiemParse;\n prototype__proto.meridiem = localeMeridiem;\n\n function lists__get (format, index, field, setter) {\n var locale = locale_locales__getLocale();\n var utc = create_utc__createUTC().set(setter, index);\n return locale[field](utc, format);\n }\n\n function list (format, index, field, count, setter) {\n if (typeof format === 'number') {\n index = format;\n format = undefined;\n }\n\n format = format || '';\n\n if (index != null) {\n return lists__get(format, index, field, setter);\n }\n\n var i;\n var out = [];\n for (i = 0; i < count; i++) {\n out[i] = lists__get(format, i, field, setter);\n }\n return out;\n }\n\n function lists__listMonths (format, index) {\n return list(format, index, 'months', 12, 'month');\n }\n\n function lists__listMonthsShort (format, index) {\n return list(format, index, 'monthsShort', 12, 'month');\n }\n\n function lists__listWeekdays (format, index) {\n return list(format, index, 'weekdays', 7, 'day');\n }\n\n function lists__listWeekdaysShort (format, index) {\n return list(format, index, 'weekdaysShort', 7, 'day');\n }\n\n function lists__listWeekdaysMin (format, index) {\n return list(format, index, 'weekdaysMin', 7, 'day');\n }\n\n locale_locales__getSetGlobalLocale('en', {\n ordinalParse: /\\d{1,2}(th|st|nd|rd)/,\n ordinal : function (number) {\n var b = number % 10,\n output = (toInt(number % 100 / 10) === 1) ? 'th' :\n (b === 1) ? 'st' :\n (b === 2) ? 'nd' :\n (b === 3) ? 'rd' : 'th';\n return number + output;\n }\n });\n\n // Side effect imports\n utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale);\n utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale);\n\n var mathAbs = Math.abs;\n\n function duration_abs__abs () {\n var data = this._data;\n\n this._milliseconds = mathAbs(this._milliseconds);\n this._days = mathAbs(this._days);\n this._months = mathAbs(this._months);\n\n data.milliseconds = mathAbs(data.milliseconds);\n data.seconds = mathAbs(data.seconds);\n data.minutes = mathAbs(data.minutes);\n data.hours = mathAbs(data.hours);\n data.months = mathAbs(data.months);\n data.years = mathAbs(data.years);\n\n return this;\n }\n\n function duration_add_subtract__addSubtract (duration, input, value, direction) {\n var other = create__createDuration(input, value);\n\n duration._milliseconds += direction * other._milliseconds;\n duration._days += direction * other._days;\n duration._months += direction * other._months;\n\n return duration._bubble();\n }\n\n // supports only 2.0-style add(1, 's') or add(duration)\n function duration_add_subtract__add (input, value) {\n return duration_add_subtract__addSubtract(this, input, value, 1);\n }\n\n // supports only 2.0-style subtract(1, 's') or subtract(duration)\n function duration_add_subtract__subtract (input, value) {\n return duration_add_subtract__addSubtract(this, input, value, -1);\n }\n\n function absCeil (number) {\n if (number < 0) {\n return Math.floor(number);\n } else {\n return Math.ceil(number);\n }\n }\n\n function bubble () {\n var milliseconds = this._milliseconds;\n var days = this._days;\n var months = this._months;\n var data = this._data;\n var seconds, minutes, hours, years, monthsFromDays;\n\n // if we have a mix of positive and negative values, bubble down first\n // check: https://github.com/moment/moment/issues/2166\n if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||\n (milliseconds <= 0 && days <= 0 && months <= 0))) {\n milliseconds += absCeil(monthsToDays(months) + days) * 864e5;\n days = 0;\n months = 0;\n }\n\n // The following code bubbles up values, see the tests for\n // examples of what that means.\n data.milliseconds = milliseconds % 1000;\n\n seconds = absFloor(milliseconds / 1000);\n data.seconds = seconds % 60;\n\n minutes = absFloor(seconds / 60);\n data.minutes = minutes % 60;\n\n hours = absFloor(minutes / 60);\n data.hours = hours % 24;\n\n days += absFloor(hours / 24);\n\n // convert days to months\n monthsFromDays = absFloor(daysToMonths(days));\n months += monthsFromDays;\n days -= absCeil(monthsToDays(monthsFromDays));\n\n // 12 months -> 1 year\n years = absFloor(months / 12);\n months %= 12;\n\n data.days = days;\n data.months = months;\n data.years = years;\n\n return this;\n }\n\n function daysToMonths (days) {\n // 400 years have 146097 days (taking into account leap year rules)\n // 400 years have 12 months === 4800\n return days * 4800 / 146097;\n }\n\n function monthsToDays (months) {\n // the reverse of daysToMonths\n return months * 146097 / 4800;\n }\n\n function as (units) {\n var days;\n var months;\n var milliseconds = this._milliseconds;\n\n units = normalizeUnits(units);\n\n if (units === 'month' || units === 'year') {\n days = this._days + milliseconds / 864e5;\n months = this._months + daysToMonths(days);\n return units === 'month' ? months : months / 12;\n } else {\n // handle milliseconds separately because of floating point math errors (issue #1867)\n days = this._days + Math.round(monthsToDays(this._months));\n switch (units) {\n case 'week' : return days / 7 + milliseconds / 6048e5;\n case 'day' : return days + milliseconds / 864e5;\n case 'hour' : return days * 24 + milliseconds / 36e5;\n case 'minute' : return days * 1440 + milliseconds / 6e4;\n case 'second' : return days * 86400 + milliseconds / 1000;\n // Math.floor prevents floating point math errors here\n case 'millisecond': return Math.floor(days * 864e5) + milliseconds;\n default: throw new Error('Unknown unit ' + units);\n }\n }\n }\n\n // TODO: Use this.as('ms')?\n function duration_as__valueOf () {\n return (\n this._milliseconds +\n this._days * 864e5 +\n (this._months % 12) * 2592e6 +\n toInt(this._months / 12) * 31536e6\n );\n }\n\n function makeAs (alias) {\n return function () {\n return this.as(alias);\n };\n }\n\n var asMilliseconds = makeAs('ms');\n var asSeconds = makeAs('s');\n var asMinutes = makeAs('m');\n var asHours = makeAs('h');\n var asDays = makeAs('d');\n var asWeeks = makeAs('w');\n var asMonths = makeAs('M');\n var asYears = makeAs('y');\n\n function duration_get__get (units) {\n units = normalizeUnits(units);\n return this[units + 's']();\n }\n\n function makeGetter(name) {\n return function () {\n return this._data[name];\n };\n }\n\n var milliseconds = makeGetter('milliseconds');\n var seconds = makeGetter('seconds');\n var minutes = makeGetter('minutes');\n var hours = makeGetter('hours');\n var days = makeGetter('days');\n var months = makeGetter('months');\n var years = makeGetter('years');\n\n function weeks () {\n return absFloor(this.days() / 7);\n }\n\n var round = Math.round;\n var thresholds = {\n s: 45, // seconds to minute\n m: 45, // minutes to hour\n h: 22, // hours to day\n d: 26, // days to month\n M: 11 // months to year\n };\n\n // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize\n function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {\n return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);\n }\n\n function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) {\n var duration = create__createDuration(posNegDuration).abs();\n var seconds = round(duration.as('s'));\n var minutes = round(duration.as('m'));\n var hours = round(duration.as('h'));\n var days = round(duration.as('d'));\n var months = round(duration.as('M'));\n var years = round(duration.as('y'));\n\n var a = seconds < thresholds.s && ['s', seconds] ||\n minutes === 1 && ['m'] ||\n minutes < thresholds.m && ['mm', minutes] ||\n hours === 1 && ['h'] ||\n hours < thresholds.h && ['hh', hours] ||\n days === 1 && ['d'] ||\n days < thresholds.d && ['dd', days] ||\n months === 1 && ['M'] ||\n months < thresholds.M && ['MM', months] ||\n years === 1 && ['y'] || ['yy', years];\n\n a[2] = withoutSuffix;\n a[3] = +posNegDuration > 0;\n a[4] = locale;\n return substituteTimeAgo.apply(null, a);\n }\n\n // This function allows you to set a threshold for relative time strings\n function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) {\n if (thresholds[threshold] === undefined) {\n return false;\n }\n if (limit === undefined) {\n return thresholds[threshold];\n }\n thresholds[threshold] = limit;\n return true;\n }\n\n function humanize (withSuffix) {\n var locale = this.localeData();\n var output = duration_humanize__relativeTime(this, !withSuffix, locale);\n\n if (withSuffix) {\n output = locale.pastFuture(+this, output);\n }\n\n return locale.postformat(output);\n }\n\n var iso_string__abs = Math.abs;\n\n function iso_string__toISOString() {\n // for ISO strings we do not use the normal bubbling rules:\n // * milliseconds bubble up until they become hours\n // * days do not bubble at all\n // * months bubble up until they become years\n // This is because there is no context-free conversion between hours and days\n // (think of clock changes)\n // and also not between days and months (28-31 days per month)\n var seconds = iso_string__abs(this._milliseconds) / 1000;\n var days = iso_string__abs(this._days);\n var months = iso_string__abs(this._months);\n var minutes, hours, years;\n\n // 3600 seconds -> 60 minutes -> 1 hour\n minutes = absFloor(seconds / 60);\n hours = absFloor(minutes / 60);\n seconds %= 60;\n minutes %= 60;\n\n // 12 months -> 1 year\n years = absFloor(months / 12);\n months %= 12;\n\n\n // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js\n var Y = years;\n var M = months;\n var D = days;\n var h = hours;\n var m = minutes;\n var s = seconds;\n var total = this.asSeconds();\n\n if (!total) {\n // this is the same as C#'s (Noda) and python (isodate)...\n // but not other JS (goog.date)\n return 'P0D';\n }\n\n return (total < 0 ? '-' : '') +\n 'P' +\n (Y ? Y + 'Y' : '') +\n (M ? M + 'M' : '') +\n (D ? D + 'D' : '') +\n ((h || m || s) ? 'T' : '') +\n (h ? h + 'H' : '') +\n (m ? m + 'M' : '') +\n (s ? s + 'S' : '');\n }\n\n var duration_prototype__proto = Duration.prototype;\n\n duration_prototype__proto.abs = duration_abs__abs;\n duration_prototype__proto.add = duration_add_subtract__add;\n duration_prototype__proto.subtract = duration_add_subtract__subtract;\n duration_prototype__proto.as = as;\n duration_prototype__proto.asMilliseconds = asMilliseconds;\n duration_prototype__proto.asSeconds = asSeconds;\n duration_prototype__proto.asMinutes = asMinutes;\n duration_prototype__proto.asHours = asHours;\n duration_prototype__proto.asDays = asDays;\n duration_prototype__proto.asWeeks = asWeeks;\n duration_prototype__proto.asMonths = asMonths;\n duration_prototype__proto.asYears = asYears;\n duration_prototype__proto.valueOf = duration_as__valueOf;\n duration_prototype__proto._bubble = bubble;\n duration_prototype__proto.get = duration_get__get;\n duration_prototype__proto.milliseconds = milliseconds;\n duration_prototype__proto.seconds = seconds;\n duration_prototype__proto.minutes = minutes;\n duration_prototype__proto.hours = hours;\n duration_prototype__proto.days = days;\n duration_prototype__proto.weeks = weeks;\n duration_prototype__proto.months = months;\n duration_prototype__proto.years = years;\n duration_prototype__proto.humanize = humanize;\n duration_prototype__proto.toISOString = iso_string__toISOString;\n duration_prototype__proto.toString = iso_string__toISOString;\n duration_prototype__proto.toJSON = iso_string__toISOString;\n duration_prototype__proto.locale = locale;\n duration_prototype__proto.localeData = localeData;\n\n // Deprecations\n duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString);\n duration_prototype__proto.lang = lang;\n\n // Side effect imports\n\n addFormatToken('X', 0, 0, 'unix');\n addFormatToken('x', 0, 0, 'valueOf');\n\n // PARSING\n\n addRegexToken('x', matchSigned);\n addRegexToken('X', matchTimestamp);\n addParseToken('X', function (input, array, config) {\n config._d = new Date(parseFloat(input, 10) * 1000);\n });\n addParseToken('x', function (input, array, config) {\n config._d = new Date(toInt(input));\n });\n\n // Side effect imports\n\n\n utils_hooks__hooks.version = '2.10.6';\n\n setHookCallback(local__createLocal);\n\n utils_hooks__hooks.fn = momentPrototype;\n utils_hooks__hooks.min = min;\n utils_hooks__hooks.max = max;\n utils_hooks__hooks.utc = create_utc__createUTC;\n utils_hooks__hooks.unix = moment__createUnix;\n utils_hooks__hooks.months = lists__listMonths;\n utils_hooks__hooks.isDate = isDate;\n utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale;\n utils_hooks__hooks.invalid = valid__createInvalid;\n utils_hooks__hooks.duration = create__createDuration;\n utils_hooks__hooks.isMoment = isMoment;\n utils_hooks__hooks.weekdays = lists__listWeekdays;\n utils_hooks__hooks.parseZone = moment__createInZone;\n utils_hooks__hooks.localeData = locale_locales__getLocale;\n utils_hooks__hooks.isDuration = isDuration;\n utils_hooks__hooks.monthsShort = lists__listMonthsShort;\n utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin;\n utils_hooks__hooks.defineLocale = defineLocale;\n utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort;\n utils_hooks__hooks.normalizeUnits = normalizeUnits;\n utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;\n\n var _moment = utils_hooks__hooks;\n\n return _moment;\n\n}));","// moment.js makes `moment` global on the window (or global) object, while Meteor expects a file-scoped global variable\nmoment = this.moment;\ntry {\n delete this.moment;\n} catch (e) {\n}\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/mongo.js b/web-app/.meteor/local/build/programs/server/packages/mongo.js deleted file mode 100644 index 61b5da7..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mongo.js +++ /dev/null @@ -1,4491 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Random = Package.random.Random; -var EJSON = Package.ejson.EJSON; -var _ = Package.underscore._; -var LocalCollection = Package.minimongo.LocalCollection; -var Minimongo = Package.minimongo.Minimongo; -var Log = Package.logging.Log; -var DDP = Package.ddp.DDP; -var DDPServer = Package.ddp.DDPServer; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; -var check = Package.check.check; -var Match = Package.check.Match; -var MaxHeap = Package['binary-heap'].MaxHeap; -var MinHeap = Package['binary-heap'].MinHeap; -var MinMaxHeap = Package['binary-heap'].MinMaxHeap; -var Hook = Package['callback-hook'].Hook; - -/* Package-scope variables */ -var MongoInternals, MongoTest, Mongo, MongoConnection, CursorDescription, Cursor, listenAll, forEachTrigger, OPLOG_COLLECTION, idForOp, OplogHandle, ObserveMultiplexer, ObserveHandle, DocFetcher, PollingObserveDriver, OplogObserveDriver, LocalCollectionDriver; - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/mongo_driver.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/** // 1 - * Provide a synchronous Collection API using fibers, backed by // 2 - * MongoDB. This is only for use on the server, and mostly identical // 3 - * to the client API. // 4 - * // 5 - * NOTE: the public API methods must be run within a fiber. If you call // 6 - * these outside of a fiber they will explode! // 7 - */ // 8 - // 9 -var path = Npm.require('path'); // 10 -var MongoDB = Npm.require('mongodb'); // 11 -var Fiber = Npm.require('fibers'); // 12 -var Future = Npm.require(path.join('fibers', 'future')); // 13 - // 14 -MongoInternals = {}; // 15 -MongoTest = {}; // 16 - // 17 -MongoInternals.NpmModules = { // 18 - mongodb: { // 19 - version: Npm.require('mongodb/package.json').version, // 20 - module: MongoDB // 21 - } // 22 -}; // 23 - // 24 -// Older version of what is now available via // 25 -// MongoInternals.NpmModules.mongodb.module. It was never documented, but // 26 -// people do use it. // 27 -// XXX COMPAT WITH 1.0.3.2 // 28 -MongoInternals.NpmModule = MongoDB; // 29 - // 30 -// This is used to add or remove EJSON from the beginning of everything nested // 31 -// inside an EJSON custom type. It should only be called on pure JSON! // 32 -var replaceNames = function (filter, thing) { // 33 - if (typeof thing === "object") { // 34 - if (_.isArray(thing)) { // 35 - return _.map(thing, _.bind(replaceNames, null, filter)); // 36 - } // 37 - var ret = {}; // 38 - _.each(thing, function (value, key) { // 39 - ret[filter(key)] = replaceNames(filter, value); // 40 - }); // 41 - return ret; // 42 - } // 43 - return thing; // 44 -}; // 45 - // 46 -// Ensure that EJSON.clone keeps a Timestamp as a Timestamp (instead of just // 47 -// doing a structural clone). // 48 -// XXX how ok is this? what if there are multiple copies of MongoDB loaded? // 49 -MongoDB.Timestamp.prototype.clone = function () { // 50 - // Timestamps should be immutable. // 51 - return this; // 52 -}; // 53 - // 54 -var makeMongoLegal = function (name) { return "EJSON" + name; }; // 55 -var unmakeMongoLegal = function (name) { return name.substr(5); }; // 56 - // 57 -var replaceMongoAtomWithMeteor = function (document) { // 58 - if (document instanceof MongoDB.Binary) { // 59 - var buffer = document.value(true); // 60 - return new Uint8Array(buffer); // 61 - } // 62 - if (document instanceof MongoDB.ObjectID) { // 63 - return new Mongo.ObjectID(document.toHexString()); // 64 - } // 65 - if (document["EJSON$type"] && document["EJSON$value"] // 66 - && _.size(document) === 2) { // 67 - return EJSON.fromJSONValue(replaceNames(unmakeMongoLegal, document)); // 68 - } // 69 - if (document instanceof MongoDB.Timestamp) { // 70 - // For now, the Meteor representation of a Mongo timestamp type (not a date! // 71 - // this is a weird internal thing used in the oplog!) is the same as the // 72 - // Mongo representation. We need to do this explicitly or else we would do a // 73 - // structural clone and lose the prototype. // 74 - return document; // 75 - } // 76 - return undefined; // 77 -}; // 78 - // 79 -var replaceMeteorAtomWithMongo = function (document) { // 80 - if (EJSON.isBinary(document)) { // 81 - // This does more copies than we'd like, but is necessary because // 82 - // MongoDB.BSON only looks like it takes a Uint8Array (and doesn't actually // 83 - // serialize it correctly). // 84 - return new MongoDB.Binary(new Buffer(document)); // 85 - } // 86 - if (document instanceof Mongo.ObjectID) { // 87 - return new MongoDB.ObjectID(document.toHexString()); // 88 - } // 89 - if (document instanceof MongoDB.Timestamp) { // 90 - // For now, the Meteor representation of a Mongo timestamp type (not a date! // 91 - // this is a weird internal thing used in the oplog!) is the same as the // 92 - // Mongo representation. We need to do this explicitly or else we would do a // 93 - // structural clone and lose the prototype. // 94 - return document; // 95 - } // 96 - if (EJSON._isCustomType(document)) { // 97 - return replaceNames(makeMongoLegal, EJSON.toJSONValue(document)); // 98 - } // 99 - // It is not ordinarily possible to stick dollar-sign keys into mongo // 100 - // so we don't bother checking for things that need escaping at this time. // 101 - return undefined; // 102 -}; // 103 - // 104 -var replaceTypes = function (document, atomTransformer) { // 105 - if (typeof document !== 'object' || document === null) // 106 - return document; // 107 - // 108 - var replacedTopLevelAtom = atomTransformer(document); // 109 - if (replacedTopLevelAtom !== undefined) // 110 - return replacedTopLevelAtom; // 111 - // 112 - var ret = document; // 113 - _.each(document, function (val, key) { // 114 - var valReplaced = replaceTypes(val, atomTransformer); // 115 - if (val !== valReplaced) { // 116 - // Lazy clone. Shallow copy. // 117 - if (ret === document) // 118 - ret = _.clone(document); // 119 - ret[key] = valReplaced; // 120 - } // 121 - }); // 122 - return ret; // 123 -}; // 124 - // 125 - // 126 -MongoConnection = function (url, options) { // 127 - var self = this; // 128 - options = options || {}; // 129 - self._observeMultiplexers = {}; // 130 - self._onFailoverHook = new Hook; // 131 - // 132 - var mongoOptions = {db: {safe: true}, server: {}, replSet: {}}; // 133 - // 134 - // Set autoReconnect to true, unless passed on the URL. Why someone // 135 - // would want to set autoReconnect to false, I'm not really sure, but // 136 - // keeping this for backwards compatibility for now. // 137 - if (!(/[\?&]auto_?[rR]econnect=/.test(url))) { // 138 - mongoOptions.server.auto_reconnect = true; // 139 - } // 140 - // 141 - // Disable the native parser by default, unless specifically enabled // 142 - // in the mongo URL. // 143 - // - The native driver can cause errors which normally would be // 144 - // thrown, caught, and handled into segfaults that take down the // 145 - // whole app. // 146 - // - Binary modules don't yet work when you bundle and move the bundle // 147 - // to a different platform (aka deploy) // 148 - // We should revisit this after binary npm module support lands. // 149 - if (!(/[\?&]native_?[pP]arser=/.test(url))) { // 150 - mongoOptions.db.native_parser = false; // 151 - } // 152 - // 153 - // XXX maybe we should have a better way of allowing users to configure the // 154 - // underlying Mongo driver // 155 - if (_.has(options, 'poolSize')) { // 156 - // If we just set this for "server", replSet will override it. If we just // 157 - // set it for replSet, it will be ignored if we're not using a replSet. // 158 - mongoOptions.server.poolSize = options.poolSize; // 159 - mongoOptions.replSet.poolSize = options.poolSize; // 160 - } // 161 - // 162 - self.db = null; // 163 - // We keep track of the ReplSet's primary, so that we can trigger hooks when // 164 - // it changes. The Node driver's joined callback seems to fire way too // 165 - // often, which is why we need to track it ourselves. // 166 - self._primary = null; // 167 - self._oplogHandle = null; // 168 - self._docFetcher = null; // 169 - // 170 - // 171 - var connectFuture = new Future; // 172 - MongoDB.connect( // 173 - url, // 174 - mongoOptions, // 175 - Meteor.bindEnvironment( // 176 - function (err, db) { // 177 - if (err) { // 178 - throw err; // 179 - } // 180 - // 181 - // First, figure out what the current primary is, if any. // 182 - if (db.serverConfig._state.master) // 183 - self._primary = db.serverConfig._state.master.name; // 184 - db.serverConfig.on( // 185 - 'joined', Meteor.bindEnvironment(function (kind, doc) { // 186 - if (kind === 'primary') { // 187 - if (doc.primary !== self._primary) { // 188 - self._primary = doc.primary; // 189 - self._onFailoverHook.each(function (callback) { // 190 - callback(); // 191 - return true; // 192 - }); // 193 - } // 194 - } else if (doc.me === self._primary) { // 195 - // The thing we thought was primary is now something other than // 196 - // primary. Forget that we thought it was primary. (This means // 197 - // that if a server stops being primary and then starts being // 198 - // primary again without another server becoming primary in the // 199 - // middle, we'll correctly count it as a failover.) // 200 - self._primary = null; // 201 - } // 202 - })); // 203 - // 204 - // Allow the constructor to return. // 205 - connectFuture['return'](db); // 206 - }, // 207 - connectFuture.resolver() // onException // 208 - ) // 209 - ); // 210 - // 211 - // Wait for the connection to be successful; throws on failure. // 212 - self.db = connectFuture.wait(); // 213 - // 214 - if (options.oplogUrl && ! Package['disable-oplog']) { // 215 - self._oplogHandle = new OplogHandle(options.oplogUrl, self.db.databaseName); // 216 - self._docFetcher = new DocFetcher(self); // 217 - } // 218 -}; // 219 - // 220 -MongoConnection.prototype.close = function() { // 221 - var self = this; // 222 - // 223 - if (! self.db) // 224 - throw Error("close called before Connection created?"); // 225 - // 226 - // XXX probably untested // 227 - var oplogHandle = self._oplogHandle; // 228 - self._oplogHandle = null; // 229 - if (oplogHandle) // 230 - oplogHandle.stop(); // 231 - // 232 - // Use Future.wrap so that errors get thrown. This happens to // 233 - // work even outside a fiber since the 'close' method is not // 234 - // actually asynchronous. // 235 - Future.wrap(_.bind(self.db.close, self.db))(true).wait(); // 236 -}; // 237 - // 238 -// Returns the Mongo Collection object; may yield. // 239 -MongoConnection.prototype.rawCollection = function (collectionName) { // 240 - var self = this; // 241 - // 242 - if (! self.db) // 243 - throw Error("rawCollection called before Connection created?"); // 244 - // 245 - var future = new Future; // 246 - self.db.collection(collectionName, future.resolver()); // 247 - return future.wait(); // 248 -}; // 249 - // 250 -MongoConnection.prototype._createCappedCollection = function ( // 251 - collectionName, byteSize, maxDocuments) { // 252 - var self = this; // 253 - // 254 - if (! self.db) // 255 - throw Error("_createCappedCollection called before Connection created?"); // 256 - // 257 - var future = new Future(); // 258 - self.db.createCollection( // 259 - collectionName, // 260 - { capped: true, size: byteSize, max: maxDocuments }, // 261 - future.resolver()); // 262 - future.wait(); // 263 -}; // 264 - // 265 -// This should be called synchronously with a write, to create a // 266 -// transaction on the current write fence, if any. After we can read // 267 -// the write, and after observers have been notified (or at least, // 268 -// after the observer notifiers have added themselves to the write // 269 -// fence), you should call 'committed()' on the object returned. // 270 -MongoConnection.prototype._maybeBeginWrite = function () { // 271 - var self = this; // 272 - var fence = DDPServer._CurrentWriteFence.get(); // 273 - if (fence) // 274 - return fence.beginWrite(); // 275 - else // 276 - return {committed: function () {}}; // 277 -}; // 278 - // 279 -// Internal interface: adds a callback which is called when the Mongo primary // 280 -// changes. Returns a stop handle. // 281 -MongoConnection.prototype._onFailover = function (callback) { // 282 - return this._onFailoverHook.register(callback); // 283 -}; // 284 - // 285 - // 286 -//////////// Public API ////////// // 287 - // 288 -// The write methods block until the database has confirmed the write (it may // 289 -// not be replicated or stable on disk, but one server has confirmed it) if no // 290 -// callback is provided. If a callback is provided, then they call the callback // 291 -// when the write is confirmed. They return nothing on success, and raise an // 292 -// exception on failure. // 293 -// // 294 -// After making a write (with insert, update, remove), observers are // 295 -// notified asynchronously. If you want to receive a callback once all // 296 -// of the observer notifications have landed for your write, do the // 297 -// writes inside a write fence (set DDPServer._CurrentWriteFence to a new // 298 -// _WriteFence, and then set a callback on the write fence.) // 299 -// // 300 -// Since our execution environment is single-threaded, this is // 301 -// well-defined -- a write "has been made" if it's returned, and an // 302 -// observer "has been notified" if its callback has returned. // 303 - // 304 -var writeCallback = function (write, refresh, callback) { // 305 - return function (err, result) { // 306 - if (! err) { // 307 - // XXX We don't have to run this on error, right? // 308 - refresh(); // 309 - } // 310 - write.committed(); // 311 - if (callback) // 312 - callback(err, result); // 313 - else if (err) // 314 - throw err; // 315 - }; // 316 -}; // 317 - // 318 -var bindEnvironmentForWrite = function (callback) { // 319 - return Meteor.bindEnvironment(callback, "Mongo write"); // 320 -}; // 321 - // 322 -MongoConnection.prototype._insert = function (collection_name, document, // 323 - callback) { // 324 - var self = this; // 325 - // 326 - var sendError = function (e) { // 327 - if (callback) // 328 - return callback(e); // 329 - throw e; // 330 - }; // 331 - // 332 - if (collection_name === "___meteor_failure_test_collection") { // 333 - var e = new Error("Failure test"); // 334 - e.expected = true; // 335 - sendError(e); // 336 - return; // 337 - } // 338 - // 339 - if (!(LocalCollection._isPlainObject(document) && // 340 - !EJSON._isCustomType(document))) { // 341 - sendError(new Error( // 342 - "Only plain objects may be inserted into MongoDB")); // 343 - return; // 344 - } // 345 - // 346 - var write = self._maybeBeginWrite(); // 347 - var refresh = function () { // 348 - Meteor.refresh({collection: collection_name, id: document._id }); // 349 - }; // 350 - callback = bindEnvironmentForWrite(writeCallback(write, refresh, callback)); // 351 - try { // 352 - var collection = self.rawCollection(collection_name); // 353 - collection.insert(replaceTypes(document, replaceMeteorAtomWithMongo), // 354 - {safe: true}, callback); // 355 - } catch (e) { // 356 - write.committed(); // 357 - throw e; // 358 - } // 359 -}; // 360 - // 361 -// Cause queries that may be affected by the selector to poll in this write // 362 -// fence. // 363 -MongoConnection.prototype._refresh = function (collectionName, selector) { // 364 - var self = this; // 365 - var refreshKey = {collection: collectionName}; // 366 - // If we know which documents we're removing, don't poll queries that are // 367 - // specific to other documents. (Note that multiple notifications here should // 368 - // not cause multiple polls, since all our listener is doing is enqueueing a // 369 - // poll.) // 370 - var specificIds = LocalCollection._idsMatchedBySelector(selector); // 371 - if (specificIds) { // 372 - _.each(specificIds, function (id) { // 373 - Meteor.refresh(_.extend({id: id}, refreshKey)); // 374 - }); // 375 - } else { // 376 - Meteor.refresh(refreshKey); // 377 - } // 378 -}; // 379 - // 380 -MongoConnection.prototype._remove = function (collection_name, selector, // 381 - callback) { // 382 - var self = this; // 383 - // 384 - if (collection_name === "___meteor_failure_test_collection") { // 385 - var e = new Error("Failure test"); // 386 - e.expected = true; // 387 - if (callback) // 388 - return callback(e); // 389 - else // 390 - throw e; // 391 - } // 392 - // 393 - var write = self._maybeBeginWrite(); // 394 - var refresh = function () { // 395 - self._refresh(collection_name, selector); // 396 - }; // 397 - callback = bindEnvironmentForWrite(writeCallback(write, refresh, callback)); // 398 - // 399 - try { // 400 - var collection = self.rawCollection(collection_name); // 401 - collection.remove(replaceTypes(selector, replaceMeteorAtomWithMongo), // 402 - {safe: true}, callback); // 403 - } catch (e) { // 404 - write.committed(); // 405 - throw e; // 406 - } // 407 -}; // 408 - // 409 -MongoConnection.prototype._dropCollection = function (collectionName, cb) { // 410 - var self = this; // 411 - // 412 - var write = self._maybeBeginWrite(); // 413 - var refresh = function () { // 414 - Meteor.refresh({collection: collectionName, id: null, // 415 - dropCollection: true}); // 416 - }; // 417 - cb = bindEnvironmentForWrite(writeCallback(write, refresh, cb)); // 418 - // 419 - try { // 420 - var collection = self.rawCollection(collectionName); // 421 - collection.drop(cb); // 422 - } catch (e) { // 423 - write.committed(); // 424 - throw e; // 425 - } // 426 -}; // 427 - // 428 -MongoConnection.prototype._update = function (collection_name, selector, mod, // 429 - options, callback) { // 430 - var self = this; // 431 - // 432 - if (! callback && options instanceof Function) { // 433 - callback = options; // 434 - options = null; // 435 - } // 436 - // 437 - if (collection_name === "___meteor_failure_test_collection") { // 438 - var e = new Error("Failure test"); // 439 - e.expected = true; // 440 - if (callback) // 441 - return callback(e); // 442 - else // 443 - throw e; // 444 - } // 445 - // 446 - // explicit safety check. null and undefined can crash the mongo // 447 - // driver. Although the node driver and minimongo do 'support' // 448 - // non-object modifier in that they don't crash, they are not // 449 - // meaningful operations and do not do anything. Defensively throw an // 450 - // error here. // 451 - if (!mod || typeof mod !== 'object') // 452 - throw new Error("Invalid modifier. Modifier must be an object."); // 453 - // 454 - if (!(LocalCollection._isPlainObject(mod) && // 455 - !EJSON._isCustomType(mod))) { // 456 - throw new Error( // 457 - "Only plain objects may be used as replacement" + // 458 - " documents in MongoDB"); // 459 - return; // 460 - } // 461 - // 462 - if (!options) options = {}; // 463 - // 464 - var write = self._maybeBeginWrite(); // 465 - var refresh = function () { // 466 - self._refresh(collection_name, selector); // 467 - }; // 468 - callback = writeCallback(write, refresh, callback); // 469 - try { // 470 - var collection = self.rawCollection(collection_name); // 471 - var mongoOpts = {safe: true}; // 472 - // explictly enumerate options that minimongo supports // 473 - if (options.upsert) mongoOpts.upsert = true; // 474 - if (options.multi) mongoOpts.multi = true; // 475 - // Lets you get a more more full result from MongoDB. Use with caution: // 476 - // might not work with C.upsert (as opposed to C.update({upsert:true}) or // 477 - // with simulated upsert. // 478 - if (options.fullResult) mongoOpts.fullResult = true; // 479 - // 480 - var mongoSelector = replaceTypes(selector, replaceMeteorAtomWithMongo); // 481 - var mongoMod = replaceTypes(mod, replaceMeteorAtomWithMongo); // 482 - // 483 - var isModify = isModificationMod(mongoMod); // 484 - var knownId = selector._id || mod._id; // 485 - // 486 - if (options._forbidReplace && ! isModify) { // 487 - var e = new Error("Invalid modifier. Replacements are forbidden."); // 488 - if (callback) { // 489 - return callback(e); // 490 - } else { // 491 - throw e; // 492 - } // 493 - } // 494 - // 495 - if (options.upsert && (! knownId) && options.insertedId) { // 496 - // XXX If we know we're using Mongo 2.6 (and this isn't a replacement) // 497 - // we should be able to just use $setOnInsert instead of this // 498 - // simulated upsert thing. (We can't use $setOnInsert with // 499 - // replacements because there's nowhere to write it, and $setOnInsert // 500 - // can't set _id on Mongo 2.4.) // 501 - // // 502 - // Also, in the future we could do a real upsert for the mongo id // 503 - // generation case, if the the node mongo driver gives us back the id // 504 - // of the upserted doc (which our current version does not). // 505 - // // 506 - // For more context, see // 507 - // https://github.com/meteor/meteor/issues/2278#issuecomment-64252706 // 508 - simulateUpsertWithInsertedId( // 509 - collection, mongoSelector, mongoMod, // 510 - isModify, options, // 511 - // This callback does not need to be bindEnvironment'ed because // 512 - // simulateUpsertWithInsertedId() wraps it and then passes it through // 513 - // bindEnvironmentForWrite. // 514 - function (err, result) { // 515 - // If we got here via a upsert() call, then options._returnObject will // 516 - // be set and we should return the whole object. Otherwise, we should // 517 - // just return the number of affected docs to match the mongo API. // 518 - if (result && ! options._returnObject) // 519 - callback(err, result.numberAffected); // 520 - else // 521 - callback(err, result); // 522 - } // 523 - ); // 524 - } else { // 525 - collection.update( // 526 - mongoSelector, mongoMod, mongoOpts, // 527 - bindEnvironmentForWrite(function (err, result, extra) { // 528 - if (! err) { // 529 - if (result && options._returnObject) { // 530 - result = { numberAffected: result }; // 531 - // If this was an upsert() call, and we ended up // 532 - // inserting a new doc and we know its id, then // 533 - // return that id as well. // 534 - if (options.upsert && knownId && // 535 - ! extra.updatedExisting) // 536 - result.insertedId = knownId; // 537 - } // 538 - } // 539 - callback(err, result); // 540 - })); // 541 - } // 542 - } catch (e) { // 543 - write.committed(); // 544 - throw e; // 545 - } // 546 -}; // 547 - // 548 -var isModificationMod = function (mod) { // 549 - var isReplace = false; // 550 - var isModify = false; // 551 - for (var k in mod) { // 552 - if (k.substr(0, 1) === '$') { // 553 - isModify = true; // 554 - } else { // 555 - isReplace = true; // 556 - } // 557 - } // 558 - if (isModify && isReplace) { // 559 - throw new Error( // 560 - "Update parameter cannot have both modifier and non-modifier fields."); // 561 - } // 562 - return isModify; // 563 -}; // 564 - // 565 -var NUM_OPTIMISTIC_TRIES = 3; // 566 - // 567 -// exposed for testing // 568 -MongoConnection._isCannotChangeIdError = function (err) { // 569 - // First check for what this error looked like in Mongo 2.4. Either of these // 570 - // checks should work, but just to be safe... // 571 - if (err.code === 13596) // 572 - return true; // 573 - if (err.err.indexOf("cannot change _id of a document") === 0) // 574 - return true; // 575 - // 576 - // Now look for what it looks like in Mongo 2.6. We don't use the error code // 577 - // here, because the error code we observed it producing (16837) appears to be // 578 - // a far more generic error code based on examining the source. // 579 - if (err.err.indexOf("The _id field cannot be changed") === 0) // 580 - return true; // 581 - // 582 - return false; // 583 -}; // 584 - // 585 -var simulateUpsertWithInsertedId = function (collection, selector, mod, // 586 - isModify, options, callback) { // 587 - // STRATEGY: First try doing a plain update. If it affected 0 documents, // 588 - // then without affecting the database, we know we should probably do an // 589 - // insert. We then do a *conditional* insert that will fail in the case // 590 - // of a race condition. This conditional insert is actually an // 591 - // upsert-replace with an _id, which will never successfully update an // 592 - // existing document. If this upsert fails with an error saying it // 593 - // couldn't change an existing _id, then we know an intervening write has // 594 - // caused the query to match something. We go back to step one and repeat. // 595 - // Like all "optimistic write" schemes, we rely on the fact that it's // 596 - // unlikely our writes will continue to be interfered with under normal // 597 - // circumstances (though sufficiently heavy contention with writers // 598 - // disagreeing on the existence of an object will cause writes to fail // 599 - // in theory). // 600 - // 601 - var newDoc; // 602 - // Run this code up front so that it fails fast if someone uses // 603 - // a Mongo update operator we don't support. // 604 - if (isModify) { // 605 - // We've already run replaceTypes/replaceMeteorAtomWithMongo on // 606 - // selector and mod. We assume it doesn't matter, as far as // 607 - // the behavior of modifiers is concerned, whether `_modify` // 608 - // is run on EJSON or on mongo-converted EJSON. // 609 - var selectorDoc = LocalCollection._removeDollarOperators(selector); // 610 - LocalCollection._modify(selectorDoc, mod, {isInsert: true}); // 611 - newDoc = selectorDoc; // 612 - } else { // 613 - newDoc = mod; // 614 - } // 615 - // 616 - var insertedId = options.insertedId; // must exist // 617 - var mongoOptsForUpdate = { // 618 - safe: true, // 619 - multi: options.multi // 620 - }; // 621 - var mongoOptsForInsert = { // 622 - safe: true, // 623 - upsert: true // 624 - }; // 625 - // 626 - var tries = NUM_OPTIMISTIC_TRIES; // 627 - // 628 - var doUpdate = function () { // 629 - tries--; // 630 - if (! tries) { // 631 - callback(new Error("Upsert failed after " + NUM_OPTIMISTIC_TRIES + " tries.")); // 632 - } else { // 633 - collection.update(selector, mod, mongoOptsForUpdate, // 634 - bindEnvironmentForWrite(function (err, result) { // 635 - if (err) // 636 - callback(err); // 637 - else if (result) // 638 - callback(null, { // 639 - numberAffected: result // 640 - }); // 641 - else // 642 - doConditionalInsert(); // 643 - })); // 644 - } // 645 - }; // 646 - // 647 - var doConditionalInsert = function () { // 648 - var replacementWithId = _.extend( // 649 - replaceTypes({_id: insertedId}, replaceMeteorAtomWithMongo), // 650 - newDoc); // 651 - collection.update(selector, replacementWithId, mongoOptsForInsert, // 652 - bindEnvironmentForWrite(function (err, result) { // 653 - if (err) { // 654 - // figure out if this is a // 655 - // "cannot change _id of document" error, and // 656 - // if so, try doUpdate() again, up to 3 times. // 657 - if (MongoConnection._isCannotChangeIdError(err)) { // 658 - doUpdate(); // 659 - } else { // 660 - callback(err); // 661 - } // 662 - } else { // 663 - callback(null, { // 664 - numberAffected: result, // 665 - insertedId: insertedId // 666 - }); // 667 - } // 668 - })); // 669 - }; // 670 - // 671 - doUpdate(); // 672 -}; // 673 - // 674 -_.each(["insert", "update", "remove", "dropCollection"], function (method) { // 675 - MongoConnection.prototype[method] = function (/* arguments */) { // 676 - var self = this; // 677 - return Meteor.wrapAsync(self["_" + method]).apply(self, arguments); // 678 - }; // 679 -}); // 680 - // 681 -// XXX MongoConnection.upsert() does not return the id of the inserted document // 682 -// unless you set it explicitly in the selector or modifier (as a replacement // 683 -// doc). // 684 -MongoConnection.prototype.upsert = function (collectionName, selector, mod, // 685 - options, callback) { // 686 - var self = this; // 687 - if (typeof options === "function" && ! callback) { // 688 - callback = options; // 689 - options = {}; // 690 - } // 691 - // 692 - return self.update(collectionName, selector, mod, // 693 - _.extend({}, options, { // 694 - upsert: true, // 695 - _returnObject: true // 696 - }), callback); // 697 -}; // 698 - // 699 -MongoConnection.prototype.find = function (collectionName, selector, options) { // 700 - var self = this; // 701 - // 702 - if (arguments.length === 1) // 703 - selector = {}; // 704 - // 705 - return new Cursor( // 706 - self, new CursorDescription(collectionName, selector, options)); // 707 -}; // 708 - // 709 -MongoConnection.prototype.findOne = function (collection_name, selector, // 710 - options) { // 711 - var self = this; // 712 - if (arguments.length === 1) // 713 - selector = {}; // 714 - // 715 - options = options || {}; // 716 - options.limit = 1; // 717 - return self.find(collection_name, selector, options).fetch()[0]; // 718 -}; // 719 - // 720 -// We'll actually design an index API later. For now, we just pass through to // 721 -// Mongo's, but make it synchronous. // 722 -MongoConnection.prototype._ensureIndex = function (collectionName, index, // 723 - options) { // 724 - var self = this; // 725 - options = _.extend({safe: true}, options); // 726 - // 727 - // We expect this function to be called at startup, not from within a method, // 728 - // so we don't interact with the write fence. // 729 - var collection = self.rawCollection(collectionName); // 730 - var future = new Future; // 731 - var indexName = collection.ensureIndex(index, options, future.resolver()); // 732 - future.wait(); // 733 -}; // 734 -MongoConnection.prototype._dropIndex = function (collectionName, index) { // 735 - var self = this; // 736 - // 737 - // This function is only used by test code, not within a method, so we don't // 738 - // interact with the write fence. // 739 - var collection = self.rawCollection(collectionName); // 740 - var future = new Future; // 741 - var indexName = collection.dropIndex(index, future.resolver()); // 742 - future.wait(); // 743 -}; // 744 - // 745 -// CURSORS // 746 - // 747 -// There are several classes which relate to cursors: // 748 -// // 749 -// CursorDescription represents the arguments used to construct a cursor: // 750 -// collectionName, selector, and (find) options. Because it is used as a key // 751 -// for cursor de-dup, everything in it should either be JSON-stringifiable or // 752 -// not affect observeChanges output (eg, options.transform functions are not // 753 -// stringifiable but do not affect observeChanges). // 754 -// // 755 -// SynchronousCursor is a wrapper around a MongoDB cursor // 756 -// which includes fully-synchronous versions of forEach, etc. // 757 -// // 758 -// Cursor is the cursor object returned from find(), which implements the // 759 -// documented Mongo.Collection cursor API. It wraps a CursorDescription and a // 760 -// SynchronousCursor (lazily: it doesn't contact Mongo until you call a method // 761 -// like fetch or forEach on it). // 762 -// // 763 -// ObserveHandle is the "observe handle" returned from observeChanges. It has a // 764 -// reference to an ObserveMultiplexer. // 765 -// // 766 -// ObserveMultiplexer allows multiple identical ObserveHandles to be driven by a // 767 -// single observe driver. // 768 -// // 769 -// There are two "observe drivers" which drive ObserveMultiplexers: // 770 -// - PollingObserveDriver caches the results of a query and reruns it when // 771 -// necessary. // 772 -// - OplogObserveDriver follows the Mongo operation log to directly observe // 773 -// database changes. // 774 -// Both implementations follow the same simple interface: when you create them, // 775 -// they start sending observeChanges callbacks (and a ready() invocation) to // 776 -// their ObserveMultiplexer, and you stop them by calling their stop() method. // 777 - // 778 -CursorDescription = function (collectionName, selector, options) { // 779 - var self = this; // 780 - self.collectionName = collectionName; // 781 - self.selector = Mongo.Collection._rewriteSelector(selector); // 782 - self.options = options || {}; // 783 -}; // 784 - // 785 -Cursor = function (mongo, cursorDescription) { // 786 - var self = this; // 787 - // 788 - self._mongo = mongo; // 789 - self._cursorDescription = cursorDescription; // 790 - self._synchronousCursor = null; // 791 -}; // 792 - // 793 -_.each(['forEach', 'map', 'fetch', 'count'], function (method) { // 794 - Cursor.prototype[method] = function () { // 795 - var self = this; // 796 - // 797 - // You can only observe a tailable cursor. // 798 - if (self._cursorDescription.options.tailable) // 799 - throw new Error("Cannot call " + method + " on a tailable cursor"); // 800 - // 801 - if (!self._synchronousCursor) { // 802 - self._synchronousCursor = self._mongo._createSynchronousCursor( // 803 - self._cursorDescription, { // 804 - // Make sure that the "self" argument to forEach/map callbacks is the // 805 - // Cursor, not the SynchronousCursor. // 806 - selfForIteration: self, // 807 - useTransform: true // 808 - }); // 809 - } // 810 - // 811 - return self._synchronousCursor[method].apply( // 812 - self._synchronousCursor, arguments); // 813 - }; // 814 -}); // 815 - // 816 -// Since we don't actually have a "nextObject" interface, there's really no // 817 -// reason to have a "rewind" interface. All it did was make multiple calls // 818 -// to fetch/map/forEach return nothing the second time. // 819 -// XXX COMPAT WITH 0.8.1 // 820 -Cursor.prototype.rewind = function () { // 821 -}; // 822 - // 823 -Cursor.prototype.getTransform = function () { // 824 - return this._cursorDescription.options.transform; // 825 -}; // 826 - // 827 -// When you call Meteor.publish() with a function that returns a Cursor, we need // 828 -// to transmute it into the equivalent subscription. This is the function that // 829 -// does that. // 830 - // 831 -Cursor.prototype._publishCursor = function (sub) { // 832 - var self = this; // 833 - var collection = self._cursorDescription.collectionName; // 834 - return Mongo.Collection._publishCursor(self, sub, collection); // 835 -}; // 836 - // 837 -// Used to guarantee that publish functions return at most one cursor per // 838 -// collection. Private, because we might later have cursors that include // 839 -// documents from multiple collections somehow. // 840 -Cursor.prototype._getCollectionName = function () { // 841 - var self = this; // 842 - return self._cursorDescription.collectionName; // 843 -} // 844 - // 845 -Cursor.prototype.observe = function (callbacks) { // 846 - var self = this; // 847 - return LocalCollection._observeFromObserveChanges(self, callbacks); // 848 -}; // 849 - // 850 -Cursor.prototype.observeChanges = function (callbacks) { // 851 - var self = this; // 852 - var ordered = LocalCollection._observeChangesCallbacksAreOrdered(callbacks); // 853 - return self._mongo._observeChanges( // 854 - self._cursorDescription, ordered, callbacks); // 855 -}; // 856 - // 857 -MongoConnection.prototype._createSynchronousCursor = function( // 858 - cursorDescription, options) { // 859 - var self = this; // 860 - options = _.pick(options || {}, 'selfForIteration', 'useTransform'); // 861 - // 862 - var collection = self.rawCollection(cursorDescription.collectionName); // 863 - var cursorOptions = cursorDescription.options; // 864 - var mongoOptions = { // 865 - sort: cursorOptions.sort, // 866 - limit: cursorOptions.limit, // 867 - skip: cursorOptions.skip // 868 - }; // 869 - // 870 - // Do we want a tailable cursor (which only works on capped collections)? // 871 - if (cursorOptions.tailable) { // 872 - // We want a tailable cursor... // 873 - mongoOptions.tailable = true; // 874 - // ... and for the server to wait a bit if any getMore has no data (rather // 875 - // than making us put the relevant sleeps in the client)... // 876 - mongoOptions.awaitdata = true; // 877 - // ... and to keep querying the server indefinitely rather than just 5 times // 878 - // if there's no more data. // 879 - mongoOptions.numberOfRetries = -1; // 880 - // And if this is on the oplog collection and the cursor specifies a 'ts', // 881 - // then set the undocumented oplog replay flag, which does a special scan to // 882 - // find the first document (instead of creating an index on ts). This is a // 883 - // very hard-coded Mongo flag which only works on the oplog collection and // 884 - // only works with the ts field. // 885 - if (cursorDescription.collectionName === OPLOG_COLLECTION && // 886 - cursorDescription.selector.ts) { // 887 - mongoOptions.oplogReplay = true; // 888 - } // 889 - } // 890 - // 891 - var dbCursor = collection.find( // 892 - replaceTypes(cursorDescription.selector, replaceMeteorAtomWithMongo), // 893 - cursorOptions.fields, mongoOptions); // 894 - // 895 - return new SynchronousCursor(dbCursor, cursorDescription, options); // 896 -}; // 897 - // 898 -var SynchronousCursor = function (dbCursor, cursorDescription, options) { // 899 - var self = this; // 900 - options = _.pick(options || {}, 'selfForIteration', 'useTransform'); // 901 - // 902 - self._dbCursor = dbCursor; // 903 - self._cursorDescription = cursorDescription; // 904 - // The "self" argument passed to forEach/map callbacks. If we're wrapped // 905 - // inside a user-visible Cursor, we want to provide the outer cursor! // 906 - self._selfForIteration = options.selfForIteration || self; // 907 - if (options.useTransform && cursorDescription.options.transform) { // 908 - self._transform = LocalCollection.wrapTransform( // 909 - cursorDescription.options.transform); // 910 - } else { // 911 - self._transform = null; // 912 - } // 913 - // 914 - // Need to specify that the callback is the first argument to nextObject, // 915 - // since otherwise when we try to call it with no args the driver will // 916 - // interpret "undefined" first arg as an options hash and crash. // 917 - self._synchronousNextObject = Future.wrap( // 918 - dbCursor.nextObject.bind(dbCursor), 0); // 919 - self._synchronousCount = Future.wrap(dbCursor.count.bind(dbCursor)); // 920 - self._visitedIds = new LocalCollection._IdMap; // 921 -}; // 922 - // 923 -_.extend(SynchronousCursor.prototype, { // 924 - _nextObject: function () { // 925 - var self = this; // 926 - // 927 - while (true) { // 928 - var doc = self._synchronousNextObject().wait(); // 929 - // 930 - if (!doc) return null; // 931 - doc = replaceTypes(doc, replaceMongoAtomWithMeteor); // 932 - // 933 - if (!self._cursorDescription.options.tailable && _.has(doc, '_id')) { // 934 - // Did Mongo give us duplicate documents in the same cursor? If so, // 935 - // ignore this one. (Do this before the transform, since transform might // 936 - // return some unrelated value.) We don't do this for tailable cursors, // 937 - // because we want to maintain O(1) memory usage. And if there isn't _id // 938 - // for some reason (maybe it's the oplog), then we don't do this either. // 939 - // (Be careful to do this for falsey but existing _id, though.) // 940 - if (self._visitedIds.has(doc._id)) continue; // 941 - self._visitedIds.set(doc._id, true); // 942 - } // 943 - // 944 - if (self._transform) // 945 - doc = self._transform(doc); // 946 - // 947 - return doc; // 948 - } // 949 - }, // 950 - // 951 - forEach: function (callback, thisArg) { // 952 - var self = this; // 953 - // 954 - // Get back to the beginning. // 955 - self._rewind(); // 956 - // 957 - // We implement the loop ourself instead of using self._dbCursor.each, // 958 - // because "each" will call its callback outside of a fiber which makes it // 959 - // much more complex to make this function synchronous. // 960 - var index = 0; // 961 - while (true) { // 962 - var doc = self._nextObject(); // 963 - if (!doc) return; // 964 - callback.call(thisArg, doc, index++, self._selfForIteration); // 965 - } // 966 - }, // 967 - // 968 - // XXX Allow overlapping callback executions if callback yields. // 969 - map: function (callback, thisArg) { // 970 - var self = this; // 971 - var res = []; // 972 - self.forEach(function (doc, index) { // 973 - res.push(callback.call(thisArg, doc, index, self._selfForIteration)); // 974 - }); // 975 - return res; // 976 - }, // 977 - // 978 - _rewind: function () { // 979 - var self = this; // 980 - // 981 - // known to be synchronous // 982 - self._dbCursor.rewind(); // 983 - // 984 - self._visitedIds = new LocalCollection._IdMap; // 985 - }, // 986 - // 987 - // Mostly usable for tailable cursors. // 988 - close: function () { // 989 - var self = this; // 990 - // 991 - self._dbCursor.close(); // 992 - }, // 993 - // 994 - fetch: function () { // 995 - var self = this; // 996 - return self.map(_.identity); // 997 - }, // 998 - // 999 - count: function () { // 1000 - var self = this; // 1001 - return self._synchronousCount().wait(); // 1002 - }, // 1003 - // 1004 - // This method is NOT wrapped in Cursor. // 1005 - getRawObjects: function (ordered) { // 1006 - var self = this; // 1007 - if (ordered) { // 1008 - return self.fetch(); // 1009 - } else { // 1010 - var results = new LocalCollection._IdMap; // 1011 - self.forEach(function (doc) { // 1012 - results.set(doc._id, doc); // 1013 - }); // 1014 - return results; // 1015 - } // 1016 - } // 1017 -}); // 1018 - // 1019 -MongoConnection.prototype.tail = function (cursorDescription, docCallback) { // 1020 - var self = this; // 1021 - if (!cursorDescription.options.tailable) // 1022 - throw new Error("Can only tail a tailable cursor"); // 1023 - // 1024 - var cursor = self._createSynchronousCursor(cursorDescription); // 1025 - // 1026 - var stopped = false; // 1027 - var lastTS = undefined; // 1028 - var loop = function () { // 1029 - while (true) { // 1030 - if (stopped) // 1031 - return; // 1032 - try { // 1033 - var doc = cursor._nextObject(); // 1034 - } catch (err) { // 1035 - // There's no good way to figure out if this was actually an error // 1036 - // from Mongo. Ah well. But either way, we need to retry the cursor // 1037 - // (unless the failure was because the observe got stopped). // 1038 - doc = null; // 1039 - } // 1040 - // Since cursor._nextObject can yield, we need to check again to see if // 1041 - // we've been stopped before calling the callback. // 1042 - if (stopped) // 1043 - return; // 1044 - if (doc) { // 1045 - // If a tailable cursor contains a "ts" field, use it to recreate the // 1046 - // cursor on error. ("ts" is a standard that Mongo uses internally for // 1047 - // the oplog, and there's a special flag that lets you do binary search // 1048 - // on it instead of needing to use an index.) // 1049 - lastTS = doc.ts; // 1050 - docCallback(doc); // 1051 - } else { // 1052 - var newSelector = _.clone(cursorDescription.selector); // 1053 - if (lastTS) { // 1054 - newSelector.ts = {$gt: lastTS}; // 1055 - } // 1056 - cursor = self._createSynchronousCursor(new CursorDescription( // 1057 - cursorDescription.collectionName, // 1058 - newSelector, // 1059 - cursorDescription.options)); // 1060 - // Mongo failover takes many seconds. Retry in a bit. (Without this // 1061 - // setTimeout, we peg the CPU at 100% and never notice the actual // 1062 - // failover. // 1063 - Meteor.setTimeout(loop, 100); // 1064 - break; // 1065 - } // 1066 - } // 1067 - }; // 1068 - // 1069 - Meteor.defer(loop); // 1070 - // 1071 - return { // 1072 - stop: function () { // 1073 - stopped = true; // 1074 - cursor.close(); // 1075 - } // 1076 - }; // 1077 -}; // 1078 - // 1079 -MongoConnection.prototype._observeChanges = function ( // 1080 - cursorDescription, ordered, callbacks) { // 1081 - var self = this; // 1082 - // 1083 - if (cursorDescription.options.tailable) { // 1084 - return self._observeChangesTailable(cursorDescription, ordered, callbacks); // 1085 - } // 1086 - // 1087 - // You may not filter out _id when observing changes, because the id is a core // 1088 - // part of the observeChanges API. // 1089 - if (cursorDescription.options.fields && // 1090 - (cursorDescription.options.fields._id === 0 || // 1091 - cursorDescription.options.fields._id === false)) { // 1092 - throw Error("You may not observe a cursor with {fields: {_id: 0}}"); // 1093 - } // 1094 - // 1095 - var observeKey = JSON.stringify( // 1096 - _.extend({ordered: ordered}, cursorDescription)); // 1097 - // 1098 - var multiplexer, observeDriver; // 1099 - var firstHandle = false; // 1100 - // 1101 - // Find a matching ObserveMultiplexer, or create a new one. This next block is // 1102 - // guaranteed to not yield (and it doesn't call anything that can observe a // 1103 - // new query), so no other calls to this function can interleave with it. // 1104 - Meteor._noYieldsAllowed(function () { // 1105 - if (_.has(self._observeMultiplexers, observeKey)) { // 1106 - multiplexer = self._observeMultiplexers[observeKey]; // 1107 - } else { // 1108 - firstHandle = true; // 1109 - // Create a new ObserveMultiplexer. // 1110 - multiplexer = new ObserveMultiplexer({ // 1111 - ordered: ordered, // 1112 - onStop: function () { // 1113 - delete self._observeMultiplexers[observeKey]; // 1114 - observeDriver.stop(); // 1115 - } // 1116 - }); // 1117 - self._observeMultiplexers[observeKey] = multiplexer; // 1118 - } // 1119 - }); // 1120 - // 1121 - var observeHandle = new ObserveHandle(multiplexer, callbacks); // 1122 - // 1123 - if (firstHandle) { // 1124 - var matcher, sorter; // 1125 - var canUseOplog = _.all([ // 1126 - function () { // 1127 - // At a bare minimum, using the oplog requires us to have an oplog, to // 1128 - // want unordered callbacks, and to not want a callback on the polls // 1129 - // that won't happen. // 1130 - return self._oplogHandle && !ordered && // 1131 - !callbacks._testOnlyPollCallback; // 1132 - }, function () { // 1133 - // We need to be able to compile the selector. Fall back to polling for // 1134 - // some newfangled $selector that minimongo doesn't support yet. // 1135 - try { // 1136 - matcher = new Minimongo.Matcher(cursorDescription.selector); // 1137 - return true; // 1138 - } catch (e) { // 1139 - // XXX make all compilation errors MinimongoError or something // 1140 - // so that this doesn't ignore unrelated exceptions // 1141 - return false; // 1142 - } // 1143 - }, function () { // 1144 - // ... and the selector itself needs to support oplog. // 1145 - return OplogObserveDriver.cursorSupported(cursorDescription, matcher); // 1146 - }, function () { // 1147 - // And we need to be able to compile the sort, if any. eg, can't be // 1148 - // {$natural: 1}. // 1149 - if (!cursorDescription.options.sort) // 1150 - return true; // 1151 - try { // 1152 - sorter = new Minimongo.Sorter(cursorDescription.options.sort, // 1153 - { matcher: matcher }); // 1154 - return true; // 1155 - } catch (e) { // 1156 - // XXX make all compilation errors MinimongoError or something // 1157 - // so that this doesn't ignore unrelated exceptions // 1158 - return false; // 1159 - } // 1160 - }], function (f) { return f(); }); // invoke each function // 1161 - // 1162 - var driverClass = canUseOplog ? OplogObserveDriver : PollingObserveDriver; // 1163 - observeDriver = new driverClass({ // 1164 - cursorDescription: cursorDescription, // 1165 - mongoHandle: self, // 1166 - multiplexer: multiplexer, // 1167 - ordered: ordered, // 1168 - matcher: matcher, // ignored by polling // 1169 - sorter: sorter, // ignored by polling // 1170 - _testOnlyPollCallback: callbacks._testOnlyPollCallback // 1171 - }); // 1172 - // 1173 - // This field is only set for use in tests. // 1174 - multiplexer._observeDriver = observeDriver; // 1175 - } // 1176 - // 1177 - // Blocks until the initial adds have been sent. // 1178 - multiplexer.addHandleAndSendInitialAdds(observeHandle); // 1179 - // 1180 - return observeHandle; // 1181 -}; // 1182 - // 1183 -// Listen for the invalidation messages that will trigger us to poll the // 1184 -// database for changes. If this selector specifies specific IDs, specify them // 1185 -// here, so that updates to different specific IDs don't cause us to poll. // 1186 -// listenCallback is the same kind of (notification, complete) callback passed // 1187 -// to InvalidationCrossbar.listen. // 1188 - // 1189 -listenAll = function (cursorDescription, listenCallback) { // 1190 - var listeners = []; // 1191 - forEachTrigger(cursorDescription, function (trigger) { // 1192 - listeners.push(DDPServer._InvalidationCrossbar.listen( // 1193 - trigger, listenCallback)); // 1194 - }); // 1195 - // 1196 - return { // 1197 - stop: function () { // 1198 - _.each(listeners, function (listener) { // 1199 - listener.stop(); // 1200 - }); // 1201 - } // 1202 - }; // 1203 -}; // 1204 - // 1205 -forEachTrigger = function (cursorDescription, triggerCallback) { // 1206 - var key = {collection: cursorDescription.collectionName}; // 1207 - var specificIds = LocalCollection._idsMatchedBySelector( // 1208 - cursorDescription.selector); // 1209 - if (specificIds) { // 1210 - _.each(specificIds, function (id) { // 1211 - triggerCallback(_.extend({id: id}, key)); // 1212 - }); // 1213 - triggerCallback(_.extend({dropCollection: true, id: null}, key)); // 1214 - } else { // 1215 - triggerCallback(key); // 1216 - } // 1217 -}; // 1218 - // 1219 -// observeChanges for tailable cursors on capped collections. // 1220 -// // 1221 -// Some differences from normal cursors: // 1222 -// - Will never produce anything other than 'added' or 'addedBefore'. If you // 1223 -// do update a document that has already been produced, this will not notice // 1224 -// it. // 1225 -// - If you disconnect and reconnect from Mongo, it will essentially restart // 1226 -// the query, which will lead to duplicate results. This is pretty bad, // 1227 -// but if you include a field called 'ts' which is inserted as // 1228 -// new MongoInternals.MongoTimestamp(0, 0) (which is initialized to the // 1229 -// current Mongo-style timestamp), we'll be able to find the place to // 1230 -// restart properly. (This field is specifically understood by Mongo with an // 1231 -// optimization which allows it to find the right place to start without // 1232 -// an index on ts. It's how the oplog works.) // 1233 -// - No callbacks are triggered synchronously with the call (there's no // 1234 -// differentiation between "initial data" and "later changes"; everything // 1235 -// that matches the query gets sent asynchronously). // 1236 -// - De-duplication is not implemented. // 1237 -// - Does not yet interact with the write fence. Probably, this should work by // 1238 -// ignoring removes (which don't work on capped collections) and updates // 1239 -// (which don't affect tailable cursors), and just keeping track of the ID // 1240 -// of the inserted object, and closing the write fence once you get to that // 1241 -// ID (or timestamp?). This doesn't work well if the document doesn't match // 1242 -// the query, though. On the other hand, the write fence can close // 1243 -// immediately if it does not match the query. So if we trust minimongo // 1244 -// enough to accurately evaluate the query against the write fence, we // 1245 -// should be able to do this... Of course, minimongo doesn't even support // 1246 -// Mongo Timestamps yet. // 1247 -MongoConnection.prototype._observeChangesTailable = function ( // 1248 - cursorDescription, ordered, callbacks) { // 1249 - var self = this; // 1250 - // 1251 - // Tailable cursors only ever call added/addedBefore callbacks, so it's an // 1252 - // error if you didn't provide them. // 1253 - if ((ordered && !callbacks.addedBefore) || // 1254 - (!ordered && !callbacks.added)) { // 1255 - throw new Error("Can't observe an " + (ordered ? "ordered" : "unordered") // 1256 - + " tailable cursor without a " // 1257 - + (ordered ? "addedBefore" : "added") + " callback"); // 1258 - } // 1259 - // 1260 - return self.tail(cursorDescription, function (doc) { // 1261 - var id = doc._id; // 1262 - delete doc._id; // 1263 - // The ts is an implementation detail. Hide it. // 1264 - delete doc.ts; // 1265 - if (ordered) { // 1266 - callbacks.addedBefore(id, doc, null); // 1267 - } else { // 1268 - callbacks.added(id, doc); // 1269 - } // 1270 - }); // 1271 -}; // 1272 - // 1273 -// XXX We probably need to find a better way to expose this. Right now // 1274 -// it's only used by tests, but in fact you need it in normal // 1275 -// operation to interact with capped collections. // 1276 -MongoInternals.MongoTimestamp = MongoDB.Timestamp; // 1277 - // 1278 -MongoInternals.Connection = MongoConnection; // 1279 - // 1280 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/oplog_tailing.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var Future = Npm.require('fibers/future'); // 1 - // 2 -OPLOG_COLLECTION = 'oplog.rs'; // 3 - // 4 -var TOO_FAR_BEHIND = process.env.METEOR_OPLOG_TOO_FAR_BEHIND || 2000; // 5 - // 6 -// Like Perl's quotemeta: quotes all regexp metacharacters. See // 7 -// https://github.com/substack/quotemeta/blob/master/index.js // 8 -// XXX this is duplicated with accounts_server.js // 9 -var quotemeta = function (str) { // 10 - return String(str).replace(/(\W)/g, '\\$1'); // 11 -}; // 12 - // 13 -var showTS = function (ts) { // 14 - return "Timestamp(" + ts.getHighBits() + ", " + ts.getLowBits() + ")"; // 15 -}; // 16 - // 17 -idForOp = function (op) { // 18 - if (op.op === 'd') // 19 - return op.o._id; // 20 - else if (op.op === 'i') // 21 - return op.o._id; // 22 - else if (op.op === 'u') // 23 - return op.o2._id; // 24 - else if (op.op === 'c') // 25 - throw Error("Operator 'c' doesn't supply an object with id: " + // 26 - EJSON.stringify(op)); // 27 - else // 28 - throw Error("Unknown op: " + EJSON.stringify(op)); // 29 -}; // 30 - // 31 -OplogHandle = function (oplogUrl, dbName) { // 32 - var self = this; // 33 - self._oplogUrl = oplogUrl; // 34 - self._dbName = dbName; // 35 - // 36 - self._oplogLastEntryConnection = null; // 37 - self._oplogTailConnection = null; // 38 - self._stopped = false; // 39 - self._tailHandle = null; // 40 - self._readyFuture = new Future(); // 41 - self._crossbar = new DDPServer._Crossbar({ // 42 - factPackage: "mongo-livedata", factName: "oplog-watchers" // 43 - }); // 44 - self._baseOplogSelector = { // 45 - ns: new RegExp('^' + quotemeta(self._dbName) + '\\.'), // 46 - $or: [ // 47 - { op: {$in: ['i', 'u', 'd']} }, // 48 - // If it is not db.collection.drop(), ignore it // 49 - { op: 'c', 'o.drop': { $exists: true } }] // 50 - }; // 51 - // 52 - // Data structures to support waitUntilCaughtUp(). Each oplog entry has a // 53 - // MongoTimestamp object on it (which is not the same as a Date --- it's a // 54 - // combination of time and an incrementing counter; see // 55 - // http://docs.mongodb.org/manual/reference/bson-types/#timestamps). // 56 - // // 57 - // _catchingUpFutures is an array of {ts: MongoTimestamp, future: Future} // 58 - // objects, sorted by ascending timestamp. _lastProcessedTS is the // 59 - // MongoTimestamp of the last oplog entry we've processed. // 60 - // // 61 - // Each time we call waitUntilCaughtUp, we take a peek at the final oplog // 62 - // entry in the db. If we've already processed it (ie, it is not greater than // 63 - // _lastProcessedTS), waitUntilCaughtUp immediately returns. Otherwise, // 64 - // waitUntilCaughtUp makes a new Future and inserts it along with the final // 65 - // timestamp entry that it read, into _catchingUpFutures. waitUntilCaughtUp // 66 - // then waits on that future, which is resolved once _lastProcessedTS is // 67 - // incremented to be past its timestamp by the worker fiber. // 68 - // // 69 - // XXX use a priority queue or something else that's faster than an array // 70 - self._catchingUpFutures = []; // 71 - self._lastProcessedTS = null; // 72 - // 73 - self._onSkippedEntriesHook = new Hook({ // 74 - debugPrintExceptions: "onSkippedEntries callback" // 75 - }); // 76 - // 77 - self._entryQueue = new Meteor._DoubleEndedQueue(); // 78 - self._workerActive = false; // 79 - // 80 - self._startTailing(); // 81 -}; // 82 - // 83 -_.extend(OplogHandle.prototype, { // 84 - stop: function () { // 85 - var self = this; // 86 - if (self._stopped) // 87 - return; // 88 - self._stopped = true; // 89 - if (self._tailHandle) // 90 - self._tailHandle.stop(); // 91 - // XXX should close connections too // 92 - }, // 93 - onOplogEntry: function (trigger, callback) { // 94 - var self = this; // 95 - if (self._stopped) // 96 - throw new Error("Called onOplogEntry on stopped handle!"); // 97 - // 98 - // Calling onOplogEntry requires us to wait for the tailing to be ready. // 99 - self._readyFuture.wait(); // 100 - // 101 - var originalCallback = callback; // 102 - callback = Meteor.bindEnvironment(function (notification) { // 103 - // XXX can we avoid this clone by making oplog.js careful? // 104 - originalCallback(EJSON.clone(notification)); // 105 - }, function (err) { // 106 - Meteor._debug("Error in oplog callback", err.stack); // 107 - }); // 108 - var listenHandle = self._crossbar.listen(trigger, callback); // 109 - return { // 110 - stop: function () { // 111 - listenHandle.stop(); // 112 - } // 113 - }; // 114 - }, // 115 - // Register a callback to be invoked any time we skip oplog entries (eg, // 116 - // because we are too far behind). // 117 - onSkippedEntries: function (callback) { // 118 - var self = this; // 119 - if (self._stopped) // 120 - throw new Error("Called onSkippedEntries on stopped handle!"); // 121 - return self._onSkippedEntriesHook.register(callback); // 122 - }, // 123 - // Calls `callback` once the oplog has been processed up to a point that is // 124 - // roughly "now": specifically, once we've processed all ops that are // 125 - // currently visible. // 126 - // XXX become convinced that this is actually safe even if oplogConnection // 127 - // is some kind of pool // 128 - waitUntilCaughtUp: function () { // 129 - var self = this; // 130 - if (self._stopped) // 131 - throw new Error("Called waitUntilCaughtUp on stopped handle!"); // 132 - // 133 - // Calling waitUntilCaughtUp requries us to wait for the oplog connection to // 134 - // be ready. // 135 - self._readyFuture.wait(); // 136 - // 137 - while (!self._stopped) { // 138 - // We need to make the selector at least as restrictive as the actual // 139 - // tailing selector (ie, we need to specify the DB name) or else we might // 140 - // find a TS that won't show up in the actual tail stream. // 141 - try { // 142 - var lastEntry = self._oplogLastEntryConnection.findOne( // 143 - OPLOG_COLLECTION, self._baseOplogSelector, // 144 - {fields: {ts: 1}, sort: {$natural: -1}}); // 145 - break; // 146 - } catch (e) { // 147 - // During failover (eg) if we get an exception we should log and retry // 148 - // instead of crashing. // 149 - Meteor._debug("Got exception while reading last entry: " + e); // 150 - Meteor._sleepForMs(100); // 151 - } // 152 - } // 153 - // 154 - if (self._stopped) // 155 - return; // 156 - // 157 - if (!lastEntry) { // 158 - // Really, nothing in the oplog? Well, we've processed everything. // 159 - return; // 160 - } // 161 - // 162 - var ts = lastEntry.ts; // 163 - if (!ts) // 164 - throw Error("oplog entry without ts: " + EJSON.stringify(lastEntry)); // 165 - // 166 - if (self._lastProcessedTS && ts.lessThanOrEqual(self._lastProcessedTS)) { // 167 - // We've already caught up to here. // 168 - return; // 169 - } // 170 - // 171 - // 172 - // Insert the future into our list. Almost always, this will be at the end, // 173 - // but it's conceivable that if we fail over from one primary to another, // 174 - // the oplog entries we see will go backwards. // 175 - var insertAfter = self._catchingUpFutures.length; // 176 - while (insertAfter - 1 > 0 // 177 - && self._catchingUpFutures[insertAfter - 1].ts.greaterThan(ts)) { // 178 - insertAfter--; // 179 - } // 180 - var f = new Future; // 181 - self._catchingUpFutures.splice(insertAfter, 0, {ts: ts, future: f}); // 182 - f.wait(); // 183 - }, // 184 - _startTailing: function () { // 185 - var self = this; // 186 - // First, make sure that we're talking to the local database. // 187 - var mongodbUri = Npm.require('mongodb-uri'); // 188 - if (mongodbUri.parse(self._oplogUrl).database !== 'local') { // 189 - throw Error("$MONGO_OPLOG_URL must be set to the 'local' database of " + // 190 - "a Mongo replica set"); // 191 - } // 192 - // 193 - // We make two separate connections to Mongo. The Node Mongo driver // 194 - // implements a naive round-robin connection pool: each "connection" is a // 195 - // pool of several (5 by default) TCP connections, and each request is // 196 - // rotated through the pools. Tailable cursor queries block on the server // 197 - // until there is some data to return (or until a few seconds have // 198 - // passed). So if the connection pool used for tailing cursors is the same // 199 - // pool used for other queries, the other queries will be delayed by seconds // 200 - // 1/5 of the time. // 201 - // // 202 - // The tail connection will only ever be running a single tail command, so // 203 - // it only needs to make one underlying TCP connection. // 204 - self._oplogTailConnection = new MongoConnection( // 205 - self._oplogUrl, {poolSize: 1}); // 206 - // XXX better docs, but: it's to get monotonic results // 207 - // XXX is it safe to say "if there's an in flight query, just use its // 208 - // results"? I don't think so but should consider that // 209 - self._oplogLastEntryConnection = new MongoConnection( // 210 - self._oplogUrl, {poolSize: 1}); // 211 - // 212 - // Now, make sure that there actually is a repl set here. If not, oplog // 213 - // tailing won't ever find anything! // 214 - var f = new Future; // 215 - self._oplogLastEntryConnection.db.admin().command( // 216 - { ismaster: 1 }, f.resolver()); // 217 - var isMasterDoc = f.wait(); // 218 - if (!(isMasterDoc && isMasterDoc.documents && isMasterDoc.documents[0] && // 219 - isMasterDoc.documents[0].setName)) { // 220 - throw Error("$MONGO_OPLOG_URL must be set to the 'local' database of " + // 221 - "a Mongo replica set"); // 222 - } // 223 - // 224 - // Find the last oplog entry. // 225 - var lastOplogEntry = self._oplogLastEntryConnection.findOne( // 226 - OPLOG_COLLECTION, {}, {sort: {$natural: -1}, fields: {ts: 1}}); // 227 - // 228 - var oplogSelector = _.clone(self._baseOplogSelector); // 229 - if (lastOplogEntry) { // 230 - // Start after the last entry that currently exists. // 231 - oplogSelector.ts = {$gt: lastOplogEntry.ts}; // 232 - // If there are any calls to callWhenProcessedLatest before any other // 233 - // oplog entries show up, allow callWhenProcessedLatest to call its // 234 - // callback immediately. // 235 - self._lastProcessedTS = lastOplogEntry.ts; // 236 - } // 237 - // 238 - var cursorDescription = new CursorDescription( // 239 - OPLOG_COLLECTION, oplogSelector, {tailable: true}); // 240 - // 241 - self._tailHandle = self._oplogTailConnection.tail( // 242 - cursorDescription, function (doc) { // 243 - self._entryQueue.push(doc); // 244 - self._maybeStartWorker(); // 245 - } // 246 - ); // 247 - self._readyFuture.return(); // 248 - }, // 249 - // 250 - _maybeStartWorker: function () { // 251 - var self = this; // 252 - if (self._workerActive) // 253 - return; // 254 - self._workerActive = true; // 255 - Meteor.defer(function () { // 256 - try { // 257 - while (! self._stopped && ! self._entryQueue.isEmpty()) { // 258 - // Are we too far behind? Just tell our observers that they need to // 259 - // repoll, and drop our queue. // 260 - if (self._entryQueue.length > TOO_FAR_BEHIND) { // 261 - var lastEntry = self._entryQueue.pop(); // 262 - self._entryQueue.clear(); // 263 - // 264 - self._onSkippedEntriesHook.each(function (callback) { // 265 - callback(); // 266 - return true; // 267 - }); // 268 - // 269 - // Free any waitUntilCaughtUp() calls that were waiting for us to // 270 - // pass something that we just skipped. // 271 - self._setLastProcessedTS(lastEntry.ts); // 272 - continue; // 273 - } // 274 - // 275 - var doc = self._entryQueue.shift(); // 276 - // 277 - if (!(doc.ns && doc.ns.length > self._dbName.length + 1 && // 278 - doc.ns.substr(0, self._dbName.length + 1) === // 279 - (self._dbName + '.'))) { // 280 - throw new Error("Unexpected ns"); // 281 - } // 282 - // 283 - var trigger = {collection: doc.ns.substr(self._dbName.length + 1), // 284 - dropCollection: false, // 285 - op: doc}; // 286 - // 287 - // Is it a special command and the collection name is hidden somewhere // 288 - // in operator? // 289 - if (trigger.collection === "$cmd") { // 290 - trigger.collection = doc.o.drop; // 291 - trigger.dropCollection = true; // 292 - trigger.id = null; // 293 - } else { // 294 - // All other ops have an id. // 295 - trigger.id = idForOp(doc); // 296 - } // 297 - // 298 - self._crossbar.fire(trigger); // 299 - // 300 - // Now that we've processed this operation, process pending // 301 - // sequencers. // 302 - if (!doc.ts) // 303 - throw Error("oplog entry without ts: " + EJSON.stringify(doc)); // 304 - self._setLastProcessedTS(doc.ts); // 305 - } // 306 - } finally { // 307 - self._workerActive = false; // 308 - } // 309 - }); // 310 - }, // 311 - _setLastProcessedTS: function (ts) { // 312 - var self = this; // 313 - self._lastProcessedTS = ts; // 314 - while (!_.isEmpty(self._catchingUpFutures) // 315 - && self._catchingUpFutures[0].ts.lessThanOrEqual( // 316 - self._lastProcessedTS)) { // 317 - var sequencer = self._catchingUpFutures.shift(); // 318 - sequencer.future.return(); // 319 - } // 320 - } // 321 -}); // 322 - // 323 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/observe_multiplex.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var Future = Npm.require('fibers/future'); // 1 - // 2 -ObserveMultiplexer = function (options) { // 3 - var self = this; // 4 - // 5 - if (!options || !_.has(options, 'ordered')) // 6 - throw Error("must specified ordered"); // 7 - // 8 - Package.facts && Package.facts.Facts.incrementServerFact( // 9 - "mongo-livedata", "observe-multiplexers", 1); // 10 - // 11 - self._ordered = options.ordered; // 12 - self._onStop = options.onStop || function () {}; // 13 - self._queue = new Meteor._SynchronousQueue(); // 14 - self._handles = {}; // 15 - self._readyFuture = new Future; // 16 - self._cache = new LocalCollection._CachingChangeObserver({ // 17 - ordered: options.ordered}); // 18 - // Number of addHandleAndSendInitialAdds tasks scheduled but not yet // 19 - // running. removeHandle uses this to know if it's time to call the onStop // 20 - // callback. // 21 - self._addHandleTasksScheduledButNotPerformed = 0; // 22 - // 23 - _.each(self.callbackNames(), function (callbackName) { // 24 - self[callbackName] = function (/* ... */) { // 25 - self._applyCallback(callbackName, _.toArray(arguments)); // 26 - }; // 27 - }); // 28 -}; // 29 - // 30 -_.extend(ObserveMultiplexer.prototype, { // 31 - addHandleAndSendInitialAdds: function (handle) { // 32 - var self = this; // 33 - // 34 - // Check this before calling runTask (even though runTask does the same // 35 - // check) so that we don't leak an ObserveMultiplexer on error by // 36 - // incrementing _addHandleTasksScheduledButNotPerformed and never // 37 - // decrementing it. // 38 - if (!self._queue.safeToRunTask()) // 39 - throw new Error( // 40 - "Can't call observeChanges from an observe callback on the same query"); // 41 - ++self._addHandleTasksScheduledButNotPerformed; // 42 - // 43 - Package.facts && Package.facts.Facts.incrementServerFact( // 44 - "mongo-livedata", "observe-handles", 1); // 45 - // 46 - self._queue.runTask(function () { // 47 - self._handles[handle._id] = handle; // 48 - // Send out whatever adds we have so far (whether or not we the // 49 - // multiplexer is ready). // 50 - self._sendAdds(handle); // 51 - --self._addHandleTasksScheduledButNotPerformed; // 52 - }); // 53 - // *outside* the task, since otherwise we'd deadlock // 54 - self._readyFuture.wait(); // 55 - }, // 56 - // 57 - // Remove an observe handle. If it was the last observe handle, call the // 58 - // onStop callback; you cannot add any more observe handles after this. // 59 - // // 60 - // This is not synchronized with polls and handle additions: this means that // 61 - // you can safely call it from within an observe callback, but it also means // 62 - // that we have to be careful when we iterate over _handles. // 63 - removeHandle: function (id) { // 64 - var self = this; // 65 - // 66 - // This should not be possible: you can only call removeHandle by having // 67 - // access to the ObserveHandle, which isn't returned to user code until the // 68 - // multiplex is ready. // 69 - if (!self._ready()) // 70 - throw new Error("Can't remove handles until the multiplex is ready"); // 71 - // 72 - delete self._handles[id]; // 73 - // 74 - Package.facts && Package.facts.Facts.incrementServerFact( // 75 - "mongo-livedata", "observe-handles", -1); // 76 - // 77 - if (_.isEmpty(self._handles) && // 78 - self._addHandleTasksScheduledButNotPerformed === 0) { // 79 - self._stop(); // 80 - } // 81 - }, // 82 - _stop: function (options) { // 83 - var self = this; // 84 - options = options || {}; // 85 - // 86 - // It shouldn't be possible for us to stop when all our handles still // 87 - // haven't been returned from observeChanges! // 88 - if (! self._ready() && ! options.fromQueryError) // 89 - throw Error("surprising _stop: not ready"); // 90 - // 91 - // Call stop callback (which kills the underlying process which sends us // 92 - // callbacks and removes us from the connection's dictionary). // 93 - self._onStop(); // 94 - Package.facts && Package.facts.Facts.incrementServerFact( // 95 - "mongo-livedata", "observe-multiplexers", -1); // 96 - // 97 - // Cause future addHandleAndSendInitialAdds calls to throw (but the onStop // 98 - // callback should make our connection forget about us). // 99 - self._handles = null; // 100 - }, // 101 - // 102 - // Allows all addHandleAndSendInitialAdds calls to return, once all preceding // 103 - // adds have been processed. Does not block. // 104 - ready: function () { // 105 - var self = this; // 106 - self._queue.queueTask(function () { // 107 - if (self._ready()) // 108 - throw Error("can't make ObserveMultiplex ready twice!"); // 109 - self._readyFuture.return(); // 110 - }); // 111 - }, // 112 - // 113 - // If trying to execute the query results in an error, call this. This is // 114 - // intended for permanent errors, not transient network errors that could be // 115 - // fixed. It should only be called before ready(), because if you called ready // 116 - // that meant that you managed to run the query once. It will stop this // 117 - // ObserveMultiplex and cause addHandleAndSendInitialAdds calls (and thus // 118 - // observeChanges calls) to throw the error. // 119 - queryError: function (err) { // 120 - var self = this; // 121 - self._queue.runTask(function () { // 122 - if (self._ready()) // 123 - throw Error("can't claim query has an error after it worked!"); // 124 - self._stop({fromQueryError: true}); // 125 - self._readyFuture.throw(err); // 126 - }); // 127 - }, // 128 - // 129 - // Calls "cb" once the effects of all "ready", "addHandleAndSendInitialAdds" // 130 - // and observe callbacks which came before this call have been propagated to // 131 - // all handles. "ready" must have already been called on this multiplexer. // 132 - onFlush: function (cb) { // 133 - var self = this; // 134 - self._queue.queueTask(function () { // 135 - if (!self._ready()) // 136 - throw Error("only call onFlush on a multiplexer that will be ready"); // 137 - cb(); // 138 - }); // 139 - }, // 140 - callbackNames: function () { // 141 - var self = this; // 142 - if (self._ordered) // 143 - return ["addedBefore", "changed", "movedBefore", "removed"]; // 144 - else // 145 - return ["added", "changed", "removed"]; // 146 - }, // 147 - _ready: function () { // 148 - return this._readyFuture.isResolved(); // 149 - }, // 150 - _applyCallback: function (callbackName, args) { // 151 - var self = this; // 152 - self._queue.queueTask(function () { // 153 - // If we stopped in the meantime, do nothing. // 154 - if (!self._handles) // 155 - return; // 156 - // 157 - // First, apply the change to the cache. // 158 - // XXX We could make applyChange callbacks promise not to hang on to any // 159 - // state from their arguments (assuming that their supplied callbacks // 160 - // don't) and skip this clone. Currently 'changed' hangs on to state // 161 - // though. // 162 - self._cache.applyChange[callbackName].apply(null, EJSON.clone(args)); // 163 - // 164 - // If we haven't finished the initial adds, then we should only be getting // 165 - // adds. // 166 - if (!self._ready() && // 167 - (callbackName !== 'added' && callbackName !== 'addedBefore')) { // 168 - throw new Error("Got " + callbackName + " during initial adds"); // 169 - } // 170 - // 171 - // Now multiplex the callbacks out to all observe handles. It's OK if // 172 - // these calls yield; since we're inside a task, no other use of our queue // 173 - // can continue until these are done. (But we do have to be careful to not // 174 - // use a handle that got removed, because removeHandle does not use the // 175 - // queue; thus, we iterate over an array of keys that we control.) // 176 - _.each(_.keys(self._handles), function (handleId) { // 177 - var handle = self._handles && self._handles[handleId]; // 178 - if (!handle) // 179 - return; // 180 - var callback = handle['_' + callbackName]; // 181 - // clone arguments so that callbacks can mutate their arguments // 182 - callback && callback.apply(null, EJSON.clone(args)); // 183 - }); // 184 - }); // 185 - }, // 186 - // 187 - // Sends initial adds to a handle. It should only be called from within a task // 188 - // (the task that is processing the addHandleAndSendInitialAdds call). It // 189 - // synchronously invokes the handle's added or addedBefore; there's no need to // 190 - // flush the queue afterwards to ensure that the callbacks get out. // 191 - _sendAdds: function (handle) { // 192 - var self = this; // 193 - if (self._queue.safeToRunTask()) // 194 - throw Error("_sendAdds may only be called from within a task!"); // 195 - var add = self._ordered ? handle._addedBefore : handle._added; // 196 - if (!add) // 197 - return; // 198 - // note: docs may be an _IdMap or an OrderedDict // 199 - self._cache.docs.forEach(function (doc, id) { // 200 - if (!_.has(self._handles, handle._id)) // 201 - throw Error("handle got removed before sending initial adds!"); // 202 - var fields = EJSON.clone(doc); // 203 - delete fields._id; // 204 - if (self._ordered) // 205 - add(id, fields, null); // we're going in order, so add at end // 206 - else // 207 - add(id, fields); // 208 - }); // 209 - } // 210 -}); // 211 - // 212 - // 213 -var nextObserveHandleId = 1; // 214 -ObserveHandle = function (multiplexer, callbacks) { // 215 - var self = this; // 216 - // The end user is only supposed to call stop(). The other fields are // 217 - // accessible to the multiplexer, though. // 218 - self._multiplexer = multiplexer; // 219 - _.each(multiplexer.callbackNames(), function (name) { // 220 - if (callbacks[name]) { // 221 - self['_' + name] = callbacks[name]; // 222 - } else if (name === "addedBefore" && callbacks.added) { // 223 - // Special case: if you specify "added" and "movedBefore", you get an // 224 - // ordered observe where for some reason you don't get ordering data on // 225 - // the adds. I dunno, we wrote tests for it, there must have been a // 226 - // reason. // 227 - self._addedBefore = function (id, fields, before) { // 228 - callbacks.added(id, fields); // 229 - }; // 230 - } // 231 - }); // 232 - self._stopped = false; // 233 - self._id = nextObserveHandleId++; // 234 -}; // 235 -ObserveHandle.prototype.stop = function () { // 236 - var self = this; // 237 - if (self._stopped) // 238 - return; // 239 - self._stopped = true; // 240 - self._multiplexer.removeHandle(self._id); // 241 -}; // 242 - // 243 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/doc_fetcher.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var Fiber = Npm.require('fibers'); // 1 -var Future = Npm.require('fibers/future'); // 2 - // 3 -DocFetcher = function (mongoConnection) { // 4 - var self = this; // 5 - self._mongoConnection = mongoConnection; // 6 - // Map from cache key -> [callback] // 7 - self._callbacksForCacheKey = {}; // 8 -}; // 9 - // 10 -_.extend(DocFetcher.prototype, { // 11 - // Fetches document "id" from collectionName, returning it or null if not // 12 - // found. // 13 - // // 14 - // If you make multiple calls to fetch() with the same cacheKey (a string), // 15 - // DocFetcher may assume that they all return the same document. (It does // 16 - // not check to see if collectionName/id match.) // 17 - // // 18 - // You may assume that callback is never called synchronously (and in fact // 19 - // OplogObserveDriver does so). // 20 - fetch: function (collectionName, id, cacheKey, callback) { // 21 - var self = this; // 22 - // 23 - check(collectionName, String); // 24 - // id is some sort of scalar // 25 - check(cacheKey, String); // 26 - // 27 - // If there's already an in-progress fetch for this cache key, yield until // 28 - // it's done and return whatever it returns. // 29 - if (_.has(self._callbacksForCacheKey, cacheKey)) { // 30 - self._callbacksForCacheKey[cacheKey].push(callback); // 31 - return; // 32 - } // 33 - // 34 - var callbacks = self._callbacksForCacheKey[cacheKey] = [callback]; // 35 - // 36 - Fiber(function () { // 37 - try { // 38 - var doc = self._mongoConnection.findOne( // 39 - collectionName, {_id: id}) || null; // 40 - // Return doc to all relevant callbacks. Note that this array can // 41 - // continue to grow during callback excecution. // 42 - while (!_.isEmpty(callbacks)) { // 43 - // Clone the document so that the various calls to fetch don't return // 44 - // objects that are intertwingled with each other. Clone before // 45 - // popping the future, so that if clone throws, the error gets passed // 46 - // to the next callback. // 47 - var clonedDoc = EJSON.clone(doc); // 48 - callbacks.pop()(null, clonedDoc); // 49 - } // 50 - } catch (e) { // 51 - while (!_.isEmpty(callbacks)) { // 52 - callbacks.pop()(e); // 53 - } // 54 - } finally { // 55 - // XXX consider keeping the doc around for a period of time before // 56 - // removing from the cache // 57 - delete self._callbacksForCacheKey[cacheKey]; // 58 - } // 59 - }).run(); // 60 - } // 61 -}); // 62 - // 63 -MongoTest.DocFetcher = DocFetcher; // 64 - // 65 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/polling_observe_driver.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -PollingObserveDriver = function (options) { // 1 - var self = this; // 2 - // 3 - self._cursorDescription = options.cursorDescription; // 4 - self._mongoHandle = options.mongoHandle; // 5 - self._ordered = options.ordered; // 6 - self._multiplexer = options.multiplexer; // 7 - self._stopCallbacks = []; // 8 - self._stopped = false; // 9 - // 10 - self._synchronousCursor = self._mongoHandle._createSynchronousCursor( // 11 - self._cursorDescription); // 12 - // 13 - // previous results snapshot. on each poll cycle, diffs against // 14 - // results drives the callbacks. // 15 - self._results = null; // 16 - // 17 - // The number of _pollMongo calls that have been added to self._taskQueue but // 18 - // have not started running. Used to make sure we never schedule more than one // 19 - // _pollMongo (other than possibly the one that is currently running). It's // 20 - // also used by _suspendPolling to pretend there's a poll scheduled. Usually, // 21 - // it's either 0 (for "no polls scheduled other than maybe one currently // 22 - // running") or 1 (for "a poll scheduled that isn't running yet"), but it can // 23 - // also be 2 if incremented by _suspendPolling. // 24 - self._pollsScheduledButNotStarted = 0; // 25 - self._pendingWrites = []; // people to notify when polling completes // 26 - // 27 - // Make sure to create a separately throttled function for each // 28 - // PollingObserveDriver object. // 29 - self._ensurePollIsScheduled = _.throttle( // 30 - self._unthrottledEnsurePollIsScheduled, 50 /* ms */); // 31 - // 32 - // XXX figure out if we still need a queue // 33 - self._taskQueue = new Meteor._SynchronousQueue(); // 34 - // 35 - var listenersHandle = listenAll( // 36 - self._cursorDescription, function (notification) { // 37 - // When someone does a transaction that might affect us, schedule a poll // 38 - // of the database. If that transaction happens inside of a write fence, // 39 - // block the fence until we've polled and notified observers. // 40 - var fence = DDPServer._CurrentWriteFence.get(); // 41 - if (fence) // 42 - self._pendingWrites.push(fence.beginWrite()); // 43 - // Ensure a poll is scheduled... but if we already know that one is, // 44 - // don't hit the throttled _ensurePollIsScheduled function (which might // 45 - // lead to us calling it unnecessarily in 50ms). // 46 - if (self._pollsScheduledButNotStarted === 0) // 47 - self._ensurePollIsScheduled(); // 48 - } // 49 - ); // 50 - self._stopCallbacks.push(function () { listenersHandle.stop(); }); // 51 - // 52 - // every once and a while, poll even if we don't think we're dirty, for // 53 - // eventual consistency with database writes from outside the Meteor // 54 - // universe. // 55 - // // 56 - // For testing, there's an undocumented callback argument to observeChanges // 57 - // which disables time-based polling and gets called at the beginning of each // 58 - // poll. // 59 - if (options._testOnlyPollCallback) { // 60 - self._testOnlyPollCallback = options._testOnlyPollCallback; // 61 - } else { // 62 - var intervalHandle = Meteor.setInterval( // 63 - _.bind(self._ensurePollIsScheduled, self), 10 * 1000); // 64 - self._stopCallbacks.push(function () { // 65 - Meteor.clearInterval(intervalHandle); // 66 - }); // 67 - } // 68 - // 69 - // Make sure we actually poll soon! // 70 - self._unthrottledEnsurePollIsScheduled(); // 71 - // 72 - Package.facts && Package.facts.Facts.incrementServerFact( // 73 - "mongo-livedata", "observe-drivers-polling", 1); // 74 -}; // 75 - // 76 -_.extend(PollingObserveDriver.prototype, { // 77 - // This is always called through _.throttle (except once at startup). // 78 - _unthrottledEnsurePollIsScheduled: function () { // 79 - var self = this; // 80 - if (self._pollsScheduledButNotStarted > 0) // 81 - return; // 82 - ++self._pollsScheduledButNotStarted; // 83 - self._taskQueue.queueTask(function () { // 84 - self._pollMongo(); // 85 - }); // 86 - }, // 87 - // 88 - // test-only interface for controlling polling. // 89 - // // 90 - // _suspendPolling blocks until any currently running and scheduled polls are // 91 - // done, and prevents any further polls from being scheduled. (new // 92 - // ObserveHandles can be added and receive their initial added callbacks, // 93 - // though.) // 94 - // // 95 - // _resumePolling immediately polls, and allows further polls to occur. // 96 - _suspendPolling: function() { // 97 - var self = this; // 98 - // Pretend that there's another poll scheduled (which will prevent // 99 - // _ensurePollIsScheduled from queueing any more polls). // 100 - ++self._pollsScheduledButNotStarted; // 101 - // Now block until all currently running or scheduled polls are done. // 102 - self._taskQueue.runTask(function() {}); // 103 - // 104 - // Confirm that there is only one "poll" (the fake one we're pretending to // 105 - // have) scheduled. // 106 - if (self._pollsScheduledButNotStarted !== 1) // 107 - throw new Error("_pollsScheduledButNotStarted is " + // 108 - self._pollsScheduledButNotStarted); // 109 - }, // 110 - _resumePolling: function() { // 111 - var self = this; // 112 - // We should be in the same state as in the end of _suspendPolling. // 113 - if (self._pollsScheduledButNotStarted !== 1) // 114 - throw new Error("_pollsScheduledButNotStarted is " + // 115 - self._pollsScheduledButNotStarted); // 116 - // Run a poll synchronously (which will counteract the // 117 - // ++_pollsScheduledButNotStarted from _suspendPolling). // 118 - self._taskQueue.runTask(function () { // 119 - self._pollMongo(); // 120 - }); // 121 - }, // 122 - // 123 - _pollMongo: function () { // 124 - var self = this; // 125 - --self._pollsScheduledButNotStarted; // 126 - // 127 - if (self._stopped) // 128 - return; // 129 - // 130 - var first = false; // 131 - var oldResults = self._results; // 132 - if (!oldResults) { // 133 - first = true; // 134 - // XXX maybe use OrderedDict instead? // 135 - oldResults = self._ordered ? [] : new LocalCollection._IdMap; // 136 - } // 137 - // 138 - self._testOnlyPollCallback && self._testOnlyPollCallback(); // 139 - // 140 - // Save the list of pending writes which this round will commit. // 141 - var writesForCycle = self._pendingWrites; // 142 - self._pendingWrites = []; // 143 - // 144 - // Get the new query results. (This yields.) // 145 - try { // 146 - var newResults = self._synchronousCursor.getRawObjects(self._ordered); // 147 - } catch (e) { // 148 - if (first && typeof(e.code) === 'number') { // 149 - // This is an error document sent to us by mongod, not a connection // 150 - // error generated by the client. And we've never seen this query work // 151 - // successfully. Probably it's a bad selector or something, so we should // 152 - // NOT retry. Instead, we should halt the observe (which ends up calling // 153 - // `stop` on us). // 154 - self._multiplexer.queryError( // 155 - new Error( // 156 - "Exception while polling query " + // 157 - JSON.stringify(self._cursorDescription) + ": " + e.message)); // 158 - return; // 159 - } // 160 - // 161 - // getRawObjects can throw if we're having trouble talking to the // 162 - // database. That's fine --- we will repoll later anyway. But we should // 163 - // make sure not to lose track of this cycle's writes. // 164 - // (It also can throw if there's just something invalid about this query; // 165 - // unfortunately the ObserveDriver API doesn't provide a good way to // 166 - // "cancel" the observe from the inside in this case. // 167 - Array.prototype.push.apply(self._pendingWrites, writesForCycle); // 168 - Meteor._debug("Exception while polling query " + // 169 - JSON.stringify(self._cursorDescription) + ": " + e.stack); // 170 - return; // 171 - } // 172 - // 173 - // Run diffs. // 174 - if (!self._stopped) { // 175 - LocalCollection._diffQueryChanges( // 176 - self._ordered, oldResults, newResults, self._multiplexer); // 177 - } // 178 - // 179 - // Signals the multiplexer to allow all observeChanges calls that share this // 180 - // multiplexer to return. (This happens asynchronously, via the // 181 - // multiplexer's queue.) // 182 - if (first) // 183 - self._multiplexer.ready(); // 184 - // 185 - // Replace self._results atomically. (This assignment is what makes `first` // 186 - // stay through on the next cycle, so we've waited until after we've // 187 - // committed to ready-ing the multiplexer.) // 188 - self._results = newResults; // 189 - // 190 - // Once the ObserveMultiplexer has processed everything we've done in this // 191 - // round, mark all the writes which existed before this call as // 192 - // commmitted. (If new writes have shown up in the meantime, there'll // 193 - // already be another _pollMongo task scheduled.) // 194 - self._multiplexer.onFlush(function () { // 195 - _.each(writesForCycle, function (w) { // 196 - w.committed(); // 197 - }); // 198 - }); // 199 - }, // 200 - // 201 - stop: function () { // 202 - var self = this; // 203 - self._stopped = true; // 204 - _.each(self._stopCallbacks, function (c) { c(); }); // 205 - // Release any write fences that are waiting on us. // 206 - _.each(self._pendingWrites, function (w) { // 207 - w.committed(); // 208 - }); // 209 - Package.facts && Package.facts.Facts.incrementServerFact( // 210 - "mongo-livedata", "observe-drivers-polling", -1); // 211 - } // 212 -}); // 213 - // 214 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/oplog_observe_driver.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -var Fiber = Npm.require('fibers'); // 1 -var Future = Npm.require('fibers/future'); // 2 - // 3 -var PHASE = { // 4 - QUERYING: "QUERYING", // 5 - FETCHING: "FETCHING", // 6 - STEADY: "STEADY" // 7 -}; // 8 - // 9 -// Exception thrown by _needToPollQuery which unrolls the stack up to the // 10 -// enclosing call to finishIfNeedToPollQuery. // 11 -var SwitchedToQuery = function () {}; // 12 -var finishIfNeedToPollQuery = function (f) { // 13 - return function () { // 14 - try { // 15 - f.apply(this, arguments); // 16 - } catch (e) { // 17 - if (!(e instanceof SwitchedToQuery)) // 18 - throw e; // 19 - } // 20 - }; // 21 -}; // 22 - // 23 -// OplogObserveDriver is an alternative to PollingObserveDriver which follows // 24 -// the Mongo operation log instead of just re-polling the query. It obeys the // 25 -// same simple interface: constructing it starts sending observeChanges // 26 -// callbacks (and a ready() invocation) to the ObserveMultiplexer, and you stop // 27 -// it by calling the stop() method. // 28 -OplogObserveDriver = function (options) { // 29 - var self = this; // 30 - self._usesOplog = true; // tests look at this // 31 - // 32 - self._cursorDescription = options.cursorDescription; // 33 - self._mongoHandle = options.mongoHandle; // 34 - self._multiplexer = options.multiplexer; // 35 - // 36 - if (options.ordered) { // 37 - throw Error("OplogObserveDriver only supports unordered observeChanges"); // 38 - } // 39 - // 40 - var sorter = options.sorter; // 41 - // We don't support $near and other geo-queries so it's OK to initialize the // 42 - // comparator only once in the constructor. // 43 - var comparator = sorter && sorter.getComparator(); // 44 - // 45 - if (options.cursorDescription.options.limit) { // 46 - // There are several properties ordered driver implements: // 47 - // - _limit is a positive number // 48 - // - _comparator is a function-comparator by which the query is ordered // 49 - // - _unpublishedBuffer is non-null Min/Max Heap, // 50 - // the empty buffer in STEADY phase implies that the // 51 - // everything that matches the queries selector fits // 52 - // into published set. // 53 - // - _published - Min Heap (also implements IdMap methods) // 54 - // 55 - var heapOptions = { IdMap: LocalCollection._IdMap }; // 56 - self._limit = self._cursorDescription.options.limit; // 57 - self._comparator = comparator; // 58 - self._sorter = sorter; // 59 - self._unpublishedBuffer = new MinMaxHeap(comparator, heapOptions); // 60 - // We need something that can find Max value in addition to IdMap interface // 61 - self._published = new MaxHeap(comparator, heapOptions); // 62 - } else { // 63 - self._limit = 0; // 64 - self._comparator = null; // 65 - self._sorter = null; // 66 - self._unpublishedBuffer = null; // 67 - self._published = new LocalCollection._IdMap; // 68 - } // 69 - // 70 - // Indicates if it is safe to insert a new document at the end of the buffer // 71 - // for this query. i.e. it is known that there are no documents matching the // 72 - // selector those are not in published or buffer. // 73 - self._safeAppendToBuffer = false; // 74 - // 75 - self._stopped = false; // 76 - self._stopHandles = []; // 77 - // 78 - Package.facts && Package.facts.Facts.incrementServerFact( // 79 - "mongo-livedata", "observe-drivers-oplog", 1); // 80 - // 81 - self._registerPhaseChange(PHASE.QUERYING); // 82 - // 83 - var selector = self._cursorDescription.selector; // 84 - self._matcher = options.matcher; // 85 - var projection = self._cursorDescription.options.fields || {}; // 86 - self._projectionFn = LocalCollection._compileProjection(projection); // 87 - // Projection function, result of combining important fields for selector and // 88 - // existing fields projection // 89 - self._sharedProjection = self._matcher.combineIntoProjection(projection); // 90 - if (sorter) // 91 - self._sharedProjection = sorter.combineIntoProjection(self._sharedProjection); // 92 - self._sharedProjectionFn = LocalCollection._compileProjection( // 93 - self._sharedProjection); // 94 - // 95 - self._needToFetch = new LocalCollection._IdMap; // 96 - self._currentlyFetching = null; // 97 - self._fetchGeneration = 0; // 98 - // 99 - self._requeryWhenDoneThisQuery = false; // 100 - self._writesToCommitWhenWeReachSteady = []; // 101 - // 102 - // If the oplog handle tells us that it skipped some entries (because it got // 103 - // behind, say), re-poll. // 104 - self._stopHandles.push(self._mongoHandle._oplogHandle.onSkippedEntries( // 105 - finishIfNeedToPollQuery(function () { // 106 - self._needToPollQuery(); // 107 - }) // 108 - )); // 109 - // 110 - forEachTrigger(self._cursorDescription, function (trigger) { // 111 - self._stopHandles.push(self._mongoHandle._oplogHandle.onOplogEntry( // 112 - trigger, function (notification) { // 113 - Meteor._noYieldsAllowed(finishIfNeedToPollQuery(function () { // 114 - var op = notification.op; // 115 - if (notification.dropCollection) { // 116 - // Note: this call is not allowed to block on anything (especially // 117 - // on waiting for oplog entries to catch up) because that will block // 118 - // onOplogEntry! // 119 - self._needToPollQuery(); // 120 - } else { // 121 - // All other operators should be handled depending on phase // 122 - if (self._phase === PHASE.QUERYING) // 123 - self._handleOplogEntryQuerying(op); // 124 - else // 125 - self._handleOplogEntrySteadyOrFetching(op); // 126 - } // 127 - })); // 128 - } // 129 - )); // 130 - }); // 131 - // 132 - // XXX ordering w.r.t. everything else? // 133 - self._stopHandles.push(listenAll( // 134 - self._cursorDescription, function (notification) { // 135 - // If we're not in a write fence, we don't have to do anything. // 136 - var fence = DDPServer._CurrentWriteFence.get(); // 137 - if (!fence) // 138 - return; // 139 - var write = fence.beginWrite(); // 140 - // This write cannot complete until we've caught up to "this point" in the // 141 - // oplog, and then made it back to the steady state. // 142 - Meteor.defer(function () { // 143 - self._mongoHandle._oplogHandle.waitUntilCaughtUp(); // 144 - if (self._stopped) { // 145 - // We're stopped, so just immediately commit. // 146 - write.committed(); // 147 - } else if (self._phase === PHASE.STEADY) { // 148 - // Make sure that all of the callbacks have made it through the // 149 - // multiplexer and been delivered to ObserveHandles before committing // 150 - // writes. // 151 - self._multiplexer.onFlush(function () { // 152 - write.committed(); // 153 - }); // 154 - } else { // 155 - self._writesToCommitWhenWeReachSteady.push(write); // 156 - } // 157 - }); // 158 - } // 159 - )); // 160 - // 161 - // When Mongo fails over, we need to repoll the query, in case we processed an // 162 - // oplog entry that got rolled back. // 163 - self._stopHandles.push(self._mongoHandle._onFailover(finishIfNeedToPollQuery( // 164 - function () { // 165 - self._needToPollQuery(); // 166 - }))); // 167 - // 168 - // Give _observeChanges a chance to add the new ObserveHandle to our // 169 - // multiplexer, so that the added calls get streamed. // 170 - Meteor.defer(finishIfNeedToPollQuery(function () { // 171 - self._runInitialQuery(); // 172 - })); // 173 -}; // 174 - // 175 -_.extend(OplogObserveDriver.prototype, { // 176 - _addPublished: function (id, doc) { // 177 - var self = this; // 178 - Meteor._noYieldsAllowed(function () { // 179 - var fields = _.clone(doc); // 180 - delete fields._id; // 181 - self._published.set(id, self._sharedProjectionFn(doc)); // 182 - self._multiplexer.added(id, self._projectionFn(fields)); // 183 - // 184 - // After adding this document, the published set might be overflowed // 185 - // (exceeding capacity specified by limit). If so, push the maximum // 186 - // element to the buffer, we might want to save it in memory to reduce the // 187 - // amount of Mongo lookups in the future. // 188 - if (self._limit && self._published.size() > self._limit) { // 189 - // XXX in theory the size of published is no more than limit+1 // 190 - if (self._published.size() !== self._limit + 1) { // 191 - throw new Error("After adding to published, " + // 192 - (self._published.size() - self._limit) + // 193 - " documents are overflowing the set"); // 194 - } // 195 - // 196 - var overflowingDocId = self._published.maxElementId(); // 197 - var overflowingDoc = self._published.get(overflowingDocId); // 198 - // 199 - if (EJSON.equals(overflowingDocId, id)) { // 200 - throw new Error("The document just added is overflowing the published set"); // 201 - } // 202 - // 203 - self._published.remove(overflowingDocId); // 204 - self._multiplexer.removed(overflowingDocId); // 205 - self._addBuffered(overflowingDocId, overflowingDoc); // 206 - } // 207 - }); // 208 - }, // 209 - _removePublished: function (id) { // 210 - var self = this; // 211 - Meteor._noYieldsAllowed(function () { // 212 - self._published.remove(id); // 213 - self._multiplexer.removed(id); // 214 - if (! self._limit || self._published.size() === self._limit) // 215 - return; // 216 - // 217 - if (self._published.size() > self._limit) // 218 - throw Error("self._published got too big"); // 219 - // 220 - // OK, we are publishing less than the limit. Maybe we should look in the // 221 - // buffer to find the next element past what we were publishing before. // 222 - // 223 - if (!self._unpublishedBuffer.empty()) { // 224 - // There's something in the buffer; move the first thing in it to // 225 - // _published. // 226 - var newDocId = self._unpublishedBuffer.minElementId(); // 227 - var newDoc = self._unpublishedBuffer.get(newDocId); // 228 - self._removeBuffered(newDocId); // 229 - self._addPublished(newDocId, newDoc); // 230 - return; // 231 - } // 232 - // 233 - // There's nothing in the buffer. This could mean one of a few things. // 234 - // 235 - // (a) We could be in the middle of re-running the query (specifically, we // 236 - // could be in _publishNewResults). In that case, _unpublishedBuffer is // 237 - // empty because we clear it at the beginning of _publishNewResults. In // 238 - // this case, our caller already knows the entire answer to the query and // 239 - // we don't need to do anything fancy here. Just return. // 240 - if (self._phase === PHASE.QUERYING) // 241 - return; // 242 - // 243 - // (b) We're pretty confident that the union of _published and // 244 - // _unpublishedBuffer contain all documents that match selector. Because // 245 - // _unpublishedBuffer is empty, that means we're confident that _published // 246 - // contains all documents that match selector. So we have nothing to do. // 247 - if (self._safeAppendToBuffer) // 248 - return; // 249 - // 250 - // (c) Maybe there are other documents out there that should be in our // 251 - // buffer. But in that case, when we emptied _unpublishedBuffer in // 252 - // _removeBuffered, we should have called _needToPollQuery, which will // 253 - // either put something in _unpublishedBuffer or set _safeAppendToBuffer // 254 - // (or both), and it will put us in QUERYING for that whole time. So in // 255 - // fact, we shouldn't be able to get here. // 256 - // 257 - throw new Error("Buffer inexplicably empty"); // 258 - }); // 259 - }, // 260 - _changePublished: function (id, oldDoc, newDoc) { // 261 - var self = this; // 262 - Meteor._noYieldsAllowed(function () { // 263 - self._published.set(id, self._sharedProjectionFn(newDoc)); // 264 - var projectedNew = self._projectionFn(newDoc); // 265 - var projectedOld = self._projectionFn(oldDoc); // 266 - var changed = LocalCollection._makeChangedFields( // 267 - projectedNew, projectedOld); // 268 - if (!_.isEmpty(changed)) // 269 - self._multiplexer.changed(id, changed); // 270 - }); // 271 - }, // 272 - _addBuffered: function (id, doc) { // 273 - var self = this; // 274 - Meteor._noYieldsAllowed(function () { // 275 - self._unpublishedBuffer.set(id, self._sharedProjectionFn(doc)); // 276 - // 277 - // If something is overflowing the buffer, we just remove it from cache // 278 - if (self._unpublishedBuffer.size() > self._limit) { // 279 - var maxBufferedId = self._unpublishedBuffer.maxElementId(); // 280 - // 281 - self._unpublishedBuffer.remove(maxBufferedId); // 282 - // 283 - // Since something matching is removed from cache (both published set and // 284 - // buffer), set flag to false // 285 - self._safeAppendToBuffer = false; // 286 - } // 287 - }); // 288 - }, // 289 - // Is called either to remove the doc completely from matching set or to move // 290 - // it to the published set later. // 291 - _removeBuffered: function (id) { // 292 - var self = this; // 293 - Meteor._noYieldsAllowed(function () { // 294 - self._unpublishedBuffer.remove(id); // 295 - // To keep the contract "buffer is never empty in STEADY phase unless the // 296 - // everything matching fits into published" true, we poll everything as // 297 - // soon as we see the buffer becoming empty. // 298 - if (! self._unpublishedBuffer.size() && ! self._safeAppendToBuffer) // 299 - self._needToPollQuery(); // 300 - }); // 301 - }, // 302 - // Called when a document has joined the "Matching" results set. // 303 - // Takes responsibility of keeping _unpublishedBuffer in sync with _published // 304 - // and the effect of limit enforced. // 305 - _addMatching: function (doc) { // 306 - var self = this; // 307 - Meteor._noYieldsAllowed(function () { // 308 - var id = doc._id; // 309 - if (self._published.has(id)) // 310 - throw Error("tried to add something already published " + id); // 311 - if (self._limit && self._unpublishedBuffer.has(id)) // 312 - throw Error("tried to add something already existed in buffer " + id); // 313 - // 314 - var limit = self._limit; // 315 - var comparator = self._comparator; // 316 - var maxPublished = (limit && self._published.size() > 0) ? // 317 - self._published.get(self._published.maxElementId()) : null; // 318 - var maxBuffered = (limit && self._unpublishedBuffer.size() > 0) // 319 - ? self._unpublishedBuffer.get(self._unpublishedBuffer.maxElementId()) // 320 - : null; // 321 - // The query is unlimited or didn't publish enough documents yet or the // 322 - // new document would fit into published set pushing the maximum element // 323 - // out, then we need to publish the doc. // 324 - var toPublish = ! limit || self._published.size() < limit || // 325 - comparator(doc, maxPublished) < 0; // 326 - // 327 - // Otherwise we might need to buffer it (only in case of limited query). // 328 - // Buffering is allowed if the buffer is not filled up yet and all // 329 - // matching docs are either in the published set or in the buffer. // 330 - var canAppendToBuffer = !toPublish && self._safeAppendToBuffer && // 331 - self._unpublishedBuffer.size() < limit; // 332 - // 333 - // Or if it is small enough to be safely inserted to the middle or the // 334 - // beginning of the buffer. // 335 - var canInsertIntoBuffer = !toPublish && maxBuffered && // 336 - comparator(doc, maxBuffered) <= 0; // 337 - // 338 - var toBuffer = canAppendToBuffer || canInsertIntoBuffer; // 339 - // 340 - if (toPublish) { // 341 - self._addPublished(id, doc); // 342 - } else if (toBuffer) { // 343 - self._addBuffered(id, doc); // 344 - } else { // 345 - // dropping it and not saving to the cache // 346 - self._safeAppendToBuffer = false; // 347 - } // 348 - }); // 349 - }, // 350 - // Called when a document leaves the "Matching" results set. // 351 - // Takes responsibility of keeping _unpublishedBuffer in sync with _published // 352 - // and the effect of limit enforced. // 353 - _removeMatching: function (id) { // 354 - var self = this; // 355 - Meteor._noYieldsAllowed(function () { // 356 - if (! self._published.has(id) && ! self._limit) // 357 - throw Error("tried to remove something matching but not cached " + id); // 358 - // 359 - if (self._published.has(id)) { // 360 - self._removePublished(id); // 361 - } else if (self._unpublishedBuffer.has(id)) { // 362 - self._removeBuffered(id); // 363 - } // 364 - }); // 365 - }, // 366 - _handleDoc: function (id, newDoc) { // 367 - var self = this; // 368 - Meteor._noYieldsAllowed(function () { // 369 - var matchesNow = newDoc && self._matcher.documentMatches(newDoc).result; // 370 - // 371 - var publishedBefore = self._published.has(id); // 372 - var bufferedBefore = self._limit && self._unpublishedBuffer.has(id); // 373 - var cachedBefore = publishedBefore || bufferedBefore; // 374 - // 375 - if (matchesNow && !cachedBefore) { // 376 - self._addMatching(newDoc); // 377 - } else if (cachedBefore && !matchesNow) { // 378 - self._removeMatching(id); // 379 - } else if (cachedBefore && matchesNow) { // 380 - var oldDoc = self._published.get(id); // 381 - var comparator = self._comparator; // 382 - var minBuffered = self._limit && self._unpublishedBuffer.size() && // 383 - self._unpublishedBuffer.get(self._unpublishedBuffer.minElementId()); // 384 - // 385 - if (publishedBefore) { // 386 - // Unlimited case where the document stays in published once it // 387 - // matches or the case when we don't have enough matching docs to // 388 - // publish or the changed but matching doc will stay in published // 389 - // anyways. // 390 - // // 391 - // XXX: We rely on the emptiness of buffer. Be sure to maintain the // 392 - // fact that buffer can't be empty if there are matching documents not // 393 - // published. Notably, we don't want to schedule repoll and continue // 394 - // relying on this property. // 395 - var staysInPublished = ! self._limit || // 396 - self._unpublishedBuffer.size() === 0 || // 397 - comparator(newDoc, minBuffered) <= 0; // 398 - // 399 - if (staysInPublished) { // 400 - self._changePublished(id, oldDoc, newDoc); // 401 - } else { // 402 - // after the change doc doesn't stay in the published, remove it // 403 - self._removePublished(id); // 404 - // but it can move into buffered now, check it // 405 - var maxBuffered = self._unpublishedBuffer.get( // 406 - self._unpublishedBuffer.maxElementId()); // 407 - // 408 - var toBuffer = self._safeAppendToBuffer || // 409 - (maxBuffered && comparator(newDoc, maxBuffered) <= 0); // 410 - // 411 - if (toBuffer) { // 412 - self._addBuffered(id, newDoc); // 413 - } else { // 414 - // Throw away from both published set and buffer // 415 - self._safeAppendToBuffer = false; // 416 - } // 417 - } // 418 - } else if (bufferedBefore) { // 419 - oldDoc = self._unpublishedBuffer.get(id); // 420 - // remove the old version manually instead of using _removeBuffered so // 421 - // we don't trigger the querying immediately. if we end this block // 422 - // with the buffer empty, we will need to trigger the query poll // 423 - // manually too. // 424 - self._unpublishedBuffer.remove(id); // 425 - // 426 - var maxPublished = self._published.get( // 427 - self._published.maxElementId()); // 428 - var maxBuffered = self._unpublishedBuffer.size() && // 429 - self._unpublishedBuffer.get( // 430 - self._unpublishedBuffer.maxElementId()); // 431 - // 432 - // the buffered doc was updated, it could move to published // 433 - var toPublish = comparator(newDoc, maxPublished) < 0; // 434 - // 435 - // or stays in buffer even after the change // 436 - var staysInBuffer = (! toPublish && self._safeAppendToBuffer) || // 437 - (!toPublish && maxBuffered && // 438 - comparator(newDoc, maxBuffered) <= 0); // 439 - // 440 - if (toPublish) { // 441 - self._addPublished(id, newDoc); // 442 - } else if (staysInBuffer) { // 443 - // stays in buffer but changes // 444 - self._unpublishedBuffer.set(id, newDoc); // 445 - } else { // 446 - // Throw away from both published set and buffer // 447 - self._safeAppendToBuffer = false; // 448 - // Normally this check would have been done in _removeBuffered but // 449 - // we didn't use it, so we need to do it ourself now. // 450 - if (! self._unpublishedBuffer.size()) { // 451 - self._needToPollQuery(); // 452 - } // 453 - } // 454 - } else { // 455 - throw new Error("cachedBefore implies either of publishedBefore or bufferedBefore is true."); // 456 - } // 457 - } // 458 - }); // 459 - }, // 460 - _fetchModifiedDocuments: function () { // 461 - var self = this; // 462 - Meteor._noYieldsAllowed(function () { // 463 - self._registerPhaseChange(PHASE.FETCHING); // 464 - // Defer, because nothing called from the oplog entry handler may yield, // 465 - // but fetch() yields. // 466 - Meteor.defer(finishIfNeedToPollQuery(function () { // 467 - while (!self._stopped && !self._needToFetch.empty()) { // 468 - if (self._phase === PHASE.QUERYING) { // 469 - // While fetching, we decided to go into QUERYING mode, and then we // 470 - // saw another oplog entry, so _needToFetch is not empty. But we // 471 - // shouldn't fetch these documents until AFTER the query is done. // 472 - break; // 473 - } // 474 - // 475 - // Being in steady phase here would be surprising. // 476 - if (self._phase !== PHASE.FETCHING) // 477 - throw new Error("phase in fetchModifiedDocuments: " + self._phase); // 478 - // 479 - self._currentlyFetching = self._needToFetch; // 480 - var thisGeneration = ++self._fetchGeneration; // 481 - self._needToFetch = new LocalCollection._IdMap; // 482 - var waiting = 0; // 483 - var fut = new Future; // 484 - // This loop is safe, because _currentlyFetching will not be updated // 485 - // during this loop (in fact, it is never mutated). // 486 - self._currentlyFetching.forEach(function (cacheKey, id) { // 487 - waiting++; // 488 - self._mongoHandle._docFetcher.fetch( // 489 - self._cursorDescription.collectionName, id, cacheKey, // 490 - finishIfNeedToPollQuery(function (err, doc) { // 491 - try { // 492 - if (err) { // 493 - Meteor._debug("Got exception while fetching documents: " + // 494 - err); // 495 - // If we get an error from the fetcher (eg, trouble // 496 - // connecting to Mongo), let's just abandon the fetch phase // 497 - // altogether and fall back to polling. It's not like we're // 498 - // getting live updates anyway. // 499 - if (self._phase !== PHASE.QUERYING) { // 500 - self._needToPollQuery(); // 501 - } // 502 - } else if (!self._stopped && self._phase === PHASE.FETCHING // 503 - && self._fetchGeneration === thisGeneration) { // 504 - // We re-check the generation in case we've had an explicit // 505 - // _pollQuery call (eg, in another fiber) which should // 506 - // effectively cancel this round of fetches. (_pollQuery // 507 - // increments the generation.) // 508 - self._handleDoc(id, doc); // 509 - } // 510 - } finally { // 511 - waiting--; // 512 - // Because fetch() never calls its callback synchronously, // 513 - // this is safe (ie, we won't call fut.return() before the // 514 - // forEach is done). // 515 - if (waiting === 0) // 516 - fut.return(); // 517 - } // 518 - })); // 519 - }); // 520 - fut.wait(); // 521 - // Exit now if we've had a _pollQuery call (here or in another fiber). // 522 - if (self._phase === PHASE.QUERYING) // 523 - return; // 524 - self._currentlyFetching = null; // 525 - } // 526 - // We're done fetching, so we can be steady, unless we've had a // 527 - // _pollQuery call (here or in another fiber). // 528 - if (self._phase !== PHASE.QUERYING) // 529 - self._beSteady(); // 530 - })); // 531 - }); // 532 - }, // 533 - _beSteady: function () { // 534 - var self = this; // 535 - Meteor._noYieldsAllowed(function () { // 536 - self._registerPhaseChange(PHASE.STEADY); // 537 - var writes = self._writesToCommitWhenWeReachSteady; // 538 - self._writesToCommitWhenWeReachSteady = []; // 539 - self._multiplexer.onFlush(function () { // 540 - _.each(writes, function (w) { // 541 - w.committed(); // 542 - }); // 543 - }); // 544 - }); // 545 - }, // 546 - _handleOplogEntryQuerying: function (op) { // 547 - var self = this; // 548 - Meteor._noYieldsAllowed(function () { // 549 - self._needToFetch.set(idForOp(op), op.ts.toString()); // 550 - }); // 551 - }, // 552 - _handleOplogEntrySteadyOrFetching: function (op) { // 553 - var self = this; // 554 - Meteor._noYieldsAllowed(function () { // 555 - var id = idForOp(op); // 556 - // If we're already fetching this one, or about to, we can't optimize; // 557 - // make sure that we fetch it again if necessary. // 558 - if (self._phase === PHASE.FETCHING && // 559 - ((self._currentlyFetching && self._currentlyFetching.has(id)) || // 560 - self._needToFetch.has(id))) { // 561 - self._needToFetch.set(id, op.ts.toString()); // 562 - return; // 563 - } // 564 - // 565 - if (op.op === 'd') { // 566 - if (self._published.has(id) || // 567 - (self._limit && self._unpublishedBuffer.has(id))) // 568 - self._removeMatching(id); // 569 - } else if (op.op === 'i') { // 570 - if (self._published.has(id)) // 571 - throw new Error("insert found for already-existing ID in published"); // 572 - if (self._unpublishedBuffer && self._unpublishedBuffer.has(id)) // 573 - throw new Error("insert found for already-existing ID in buffer"); // 574 - // 575 - // XXX what if selector yields? for now it can't but later it could // 576 - // have $where // 577 - if (self._matcher.documentMatches(op.o).result) // 578 - self._addMatching(op.o); // 579 - } else if (op.op === 'u') { // 580 - // Is this a modifier ($set/$unset, which may require us to poll the // 581 - // database to figure out if the whole document matches the selector) or // 582 - // a replacement (in which case we can just directly re-evaluate the // 583 - // selector)? // 584 - var isReplace = !_.has(op.o, '$set') && !_.has(op.o, '$unset'); // 585 - // If this modifier modifies something inside an EJSON custom type (ie, // 586 - // anything with EJSON$), then we can't try to use // 587 - // LocalCollection._modify, since that just mutates the EJSON encoding, // 588 - // not the actual object. // 589 - var canDirectlyModifyDoc = // 590 - !isReplace && modifierCanBeDirectlyApplied(op.o); // 591 - // 592 - var publishedBefore = self._published.has(id); // 593 - var bufferedBefore = self._limit && self._unpublishedBuffer.has(id); // 594 - // 595 - if (isReplace) { // 596 - self._handleDoc(id, _.extend({_id: id}, op.o)); // 597 - } else if ((publishedBefore || bufferedBefore) && // 598 - canDirectlyModifyDoc) { // 599 - // Oh great, we actually know what the document is, so we can apply // 600 - // this directly. // 601 - var newDoc = self._published.has(id) // 602 - ? self._published.get(id) : self._unpublishedBuffer.get(id); // 603 - newDoc = EJSON.clone(newDoc); // 604 - // 605 - newDoc._id = id; // 606 - try { // 607 - LocalCollection._modify(newDoc, op.o); // 608 - } catch (e) { // 609 - if (e.name !== "MinimongoError") // 610 - throw e; // 611 - // We didn't understand the modifier. Re-fetch. // 612 - self._needToFetch.set(id, op.ts.toString()); // 613 - if (self._phase === PHASE.STEADY) { // 614 - self._fetchModifiedDocuments(); // 615 - } // 616 - return; // 617 - } // 618 - self._handleDoc(id, self._sharedProjectionFn(newDoc)); // 619 - } else if (!canDirectlyModifyDoc || // 620 - self._matcher.canBecomeTrueByModifier(op.o) || // 621 - (self._sorter && self._sorter.affectedByModifier(op.o))) { // 622 - self._needToFetch.set(id, op.ts.toString()); // 623 - if (self._phase === PHASE.STEADY) // 624 - self._fetchModifiedDocuments(); // 625 - } // 626 - } else { // 627 - throw Error("XXX SURPRISING OPERATION: " + op); // 628 - } // 629 - }); // 630 - }, // 631 - // Yields! // 632 - _runInitialQuery: function () { // 633 - var self = this; // 634 - if (self._stopped) // 635 - throw new Error("oplog stopped surprisingly early"); // 636 - // 637 - self._runQuery({initial: true}); // yields // 638 - // 639 - if (self._stopped) // 640 - return; // can happen on queryError // 641 - // 642 - // Allow observeChanges calls to return. (After this, it's possible for // 643 - // stop() to be called.) // 644 - self._multiplexer.ready(); // 645 - // 646 - self._doneQuerying(); // yields // 647 - }, // 648 - // 649 - // In various circumstances, we may just want to stop processing the oplog and // 650 - // re-run the initial query, just as if we were a PollingObserveDriver. // 651 - // // 652 - // This function may not block, because it is called from an oplog entry // 653 - // handler. // 654 - // // 655 - // XXX We should call this when we detect that we've been in FETCHING for "too // 656 - // long". // 657 - // // 658 - // XXX We should call this when we detect Mongo failover (since that might // 659 - // mean that some of the oplog entries we have processed have been rolled // 660 - // back). The Node Mongo driver is in the middle of a bunch of huge // 661 - // refactorings, including the way that it notifies you when primary // 662 - // changes. Will put off implementing this until driver 1.4 is out. // 663 - _pollQuery: function () { // 664 - var self = this; // 665 - Meteor._noYieldsAllowed(function () { // 666 - if (self._stopped) // 667 - return; // 668 - // 669 - // Yay, we get to forget about all the things we thought we had to fetch. // 670 - self._needToFetch = new LocalCollection._IdMap; // 671 - self._currentlyFetching = null; // 672 - ++self._fetchGeneration; // ignore any in-flight fetches // 673 - self._registerPhaseChange(PHASE.QUERYING); // 674 - // 675 - // Defer so that we don't yield. We don't need finishIfNeedToPollQuery // 676 - // here because SwitchedToQuery is not thrown in QUERYING mode. // 677 - Meteor.defer(function () { // 678 - self._runQuery(); // 679 - self._doneQuerying(); // 680 - }); // 681 - }); // 682 - }, // 683 - // 684 - // Yields! // 685 - _runQuery: function (options) { // 686 - var self = this; // 687 - options = options || {}; // 688 - var newResults, newBuffer; // 689 - // 690 - // This while loop is just to retry failures. // 691 - while (true) { // 692 - // If we've been stopped, we don't have to run anything any more. // 693 - if (self._stopped) // 694 - return; // 695 - // 696 - newResults = new LocalCollection._IdMap; // 697 - newBuffer = new LocalCollection._IdMap; // 698 - // 699 - // Query 2x documents as the half excluded from the original query will go // 700 - // into unpublished buffer to reduce additional Mongo lookups in cases // 701 - // when documents are removed from the published set and need a // 702 - // replacement. // 703 - // XXX needs more thought on non-zero skip // 704 - // XXX 2 is a "magic number" meaning there is an extra chunk of docs for // 705 - // buffer if such is needed. // 706 - var cursor = self._cursorForQuery({ limit: self._limit * 2 }); // 707 - try { // 708 - cursor.forEach(function (doc, i) { // yields // 709 - if (!self._limit || i < self._limit) // 710 - newResults.set(doc._id, doc); // 711 - else // 712 - newBuffer.set(doc._id, doc); // 713 - }); // 714 - break; // 715 - } catch (e) { // 716 - if (options.initial && typeof(e.code) === 'number') { // 717 - // This is an error document sent to us by mongod, not a connection // 718 - // error generated by the client. And we've never seen this query work // 719 - // successfully. Probably it's a bad selector or something, so we // 720 - // should NOT retry. Instead, we should halt the observe (which ends // 721 - // up calling `stop` on us). // 722 - self._multiplexer.queryError(e); // 723 - return; // 724 - } // 725 - // 726 - // During failover (eg) if we get an exception we should log and retry // 727 - // instead of crashing. // 728 - Meteor._debug("Got exception while polling query: " + e); // 729 - Meteor._sleepForMs(100); // 730 - } // 731 - } // 732 - // 733 - if (self._stopped) // 734 - return; // 735 - // 736 - self._publishNewResults(newResults, newBuffer); // 737 - }, // 738 - // 739 - // Transitions to QUERYING and runs another query, or (if already in QUERYING) // 740 - // ensures that we will query again later. // 741 - // // 742 - // This function may not block, because it is called from an oplog entry // 743 - // handler. However, if we were not already in the QUERYING phase, it throws // 744 - // an exception that is caught by the closest surrounding // 745 - // finishIfNeedToPollQuery call; this ensures that we don't continue running // 746 - // close that was designed for another phase inside PHASE.QUERYING. // 747 - // // 748 - // (It's also necessary whenever logic in this file yields to check that other // 749 - // phases haven't put us into QUERYING mode, though; eg, // 750 - // _fetchModifiedDocuments does this.) // 751 - _needToPollQuery: function () { // 752 - var self = this; // 753 - Meteor._noYieldsAllowed(function () { // 754 - if (self._stopped) // 755 - return; // 756 - // 757 - // If we're not already in the middle of a query, we can query now // 758 - // (possibly pausing FETCHING). // 759 - if (self._phase !== PHASE.QUERYING) { // 760 - self._pollQuery(); // 761 - throw new SwitchedToQuery; // 762 - } // 763 - // 764 - // We're currently in QUERYING. Set a flag to ensure that we run another // 765 - // query when we're done. // 766 - self._requeryWhenDoneThisQuery = true; // 767 - }); // 768 - }, // 769 - // 770 - // Yields! // 771 - _doneQuerying: function () { // 772 - var self = this; // 773 - // 774 - if (self._stopped) // 775 - return; // 776 - self._mongoHandle._oplogHandle.waitUntilCaughtUp(); // yields // 777 - if (self._stopped) // 778 - return; // 779 - if (self._phase !== PHASE.QUERYING) // 780 - throw Error("Phase unexpectedly " + self._phase); // 781 - // 782 - Meteor._noYieldsAllowed(function () { // 783 - if (self._requeryWhenDoneThisQuery) { // 784 - self._requeryWhenDoneThisQuery = false; // 785 - self._pollQuery(); // 786 - } else if (self._needToFetch.empty()) { // 787 - self._beSteady(); // 788 - } else { // 789 - self._fetchModifiedDocuments(); // 790 - } // 791 - }); // 792 - }, // 793 - // 794 - _cursorForQuery: function (optionsOverwrite) { // 795 - var self = this; // 796 - return Meteor._noYieldsAllowed(function () { // 797 - // The query we run is almost the same as the cursor we are observing, // 798 - // with a few changes. We need to read all the fields that are relevant to // 799 - // the selector, not just the fields we are going to publish (that's the // 800 - // "shared" projection). And we don't want to apply any transform in the // 801 - // cursor, because observeChanges shouldn't use the transform. // 802 - var options = _.clone(self._cursorDescription.options); // 803 - // 804 - // Allow the caller to modify the options. Useful to specify different // 805 - // skip and limit values. // 806 - _.extend(options, optionsOverwrite); // 807 - // 808 - options.fields = self._sharedProjection; // 809 - delete options.transform; // 810 - // We are NOT deep cloning fields or selector here, which should be OK. // 811 - var description = new CursorDescription( // 812 - self._cursorDescription.collectionName, // 813 - self._cursorDescription.selector, // 814 - options); // 815 - return new Cursor(self._mongoHandle, description); // 816 - }); // 817 - }, // 818 - // 819 - // 820 - // Replace self._published with newResults (both are IdMaps), invoking observe // 821 - // callbacks on the multiplexer. // 822 - // Replace self._unpublishedBuffer with newBuffer. // 823 - // // 824 - // XXX This is very similar to LocalCollection._diffQueryUnorderedChanges. We // 825 - // should really: (a) Unify IdMap and OrderedDict into Unordered/OrderedDict // 826 - // (b) Rewrite diff.js to use these classes instead of arrays and objects. // 827 - _publishNewResults: function (newResults, newBuffer) { // 828 - var self = this; // 829 - Meteor._noYieldsAllowed(function () { // 830 - // 831 - // If the query is limited and there is a buffer, shut down so it doesn't // 832 - // stay in a way. // 833 - if (self._limit) { // 834 - self._unpublishedBuffer.clear(); // 835 - } // 836 - // 837 - // First remove anything that's gone. Be careful not to modify // 838 - // self._published while iterating over it. // 839 - var idsToRemove = []; // 840 - self._published.forEach(function (doc, id) { // 841 - if (!newResults.has(id)) // 842 - idsToRemove.push(id); // 843 - }); // 844 - _.each(idsToRemove, function (id) { // 845 - self._removePublished(id); // 846 - }); // 847 - // 848 - // Now do adds and changes. // 849 - // If self has a buffer and limit, the new fetched result will be // 850 - // limited correctly as the query has sort specifier. // 851 - newResults.forEach(function (doc, id) { // 852 - self._handleDoc(id, doc); // 853 - }); // 854 - // 855 - // Sanity-check that everything we tried to put into _published ended up // 856 - // there. // 857 - // XXX if this is slow, remove it later // 858 - if (self._published.size() !== newResults.size()) { // 859 - throw Error( // 860 - "The Mongo server and the Meteor query disagree on how " + // 861 - "many documents match your query. Maybe it is hitting a Mongo " + // 862 - "edge case? The query is: " + // 863 - EJSON.stringify(self._cursorDescription.selector)); // 864 - } // 865 - self._published.forEach(function (doc, id) { // 866 - if (!newResults.has(id)) // 867 - throw Error("_published has a doc that newResults doesn't; " + id); // 868 - }); // 869 - // 870 - // Finally, replace the buffer // 871 - newBuffer.forEach(function (doc, id) { // 872 - self._addBuffered(id, doc); // 873 - }); // 874 - // 875 - self._safeAppendToBuffer = newBuffer.size() < self._limit; // 876 - }); // 877 - }, // 878 - // 879 - // This stop function is invoked from the onStop of the ObserveMultiplexer, so // 880 - // it shouldn't actually be possible to call it until the multiplexer is // 881 - // ready. // 882 - // // 883 - // It's important to check self._stopped after every call in this file that // 884 - // can yield! // 885 - stop: function () { // 886 - var self = this; // 887 - if (self._stopped) // 888 - return; // 889 - self._stopped = true; // 890 - _.each(self._stopHandles, function (handle) { // 891 - handle.stop(); // 892 - }); // 893 - // 894 - // Note: we *don't* use multiplexer.onFlush here because this stop // 895 - // callback is actually invoked by the multiplexer itself when it has // 896 - // determined that there are no handles left. So nothing is actually going // 897 - // to get flushed (and it's probably not valid to call methods on the // 898 - // dying multiplexer). // 899 - _.each(self._writesToCommitWhenWeReachSteady, function (w) { // 900 - w.committed(); // maybe yields? // 901 - }); // 902 - self._writesToCommitWhenWeReachSteady = null; // 903 - // 904 - // Proactively drop references to potentially big things. // 905 - self._published = null; // 906 - self._unpublishedBuffer = null; // 907 - self._needToFetch = null; // 908 - self._currentlyFetching = null; // 909 - self._oplogEntryHandle = null; // 910 - self._listenersHandle = null; // 911 - // 912 - Package.facts && Package.facts.Facts.incrementServerFact( // 913 - "mongo-livedata", "observe-drivers-oplog", -1); // 914 - }, // 915 - // 916 - _registerPhaseChange: function (phase) { // 917 - var self = this; // 918 - Meteor._noYieldsAllowed(function () { // 919 - var now = new Date; // 920 - // 921 - if (self._phase) { // 922 - var timeDiff = now - self._phaseStartTime; // 923 - Package.facts && Package.facts.Facts.incrementServerFact( // 924 - "mongo-livedata", "time-spent-in-" + self._phase + "-phase", timeDiff); // 925 - } // 926 - // 927 - self._phase = phase; // 928 - self._phaseStartTime = now; // 929 - }); // 930 - } // 931 -}); // 932 - // 933 -// Does our oplog tailing code support this cursor? For now, we are being very // 934 -// conservative and allowing only simple queries with simple options. // 935 -// (This is a "static method".) // 936 -OplogObserveDriver.cursorSupported = function (cursorDescription, matcher) { // 937 - // First, check the options. // 938 - var options = cursorDescription.options; // 939 - // 940 - // Did the user say no explicitly? // 941 - if (options._disableOplog) // 942 - return false; // 943 - // 944 - // skip is not supported: to support it we would need to keep track of all // 945 - // "skipped" documents or at least their ids. // 946 - // limit w/o a sort specifier is not supported: current implementation needs a // 947 - // deterministic way to order documents. // 948 - if (options.skip || (options.limit && !options.sort)) return false; // 949 - // 950 - // If a fields projection option is given check if it is supported by // 951 - // minimongo (some operators are not supported). // 952 - if (options.fields) { // 953 - try { // 954 - LocalCollection._checkSupportedProjection(options.fields); // 955 - } catch (e) { // 956 - if (e.name === "MinimongoError") // 957 - return false; // 958 - else // 959 - throw e; // 960 - } // 961 - } // 962 - // 963 - // We don't allow the following selectors: // 964 - // - $where (not confident that we provide the same JS environment // 965 - // as Mongo, and can yield!) // 966 - // - $near (has "interesting" properties in MongoDB, like the possibility // 967 - // of returning an ID multiple times, though even polling maybe // 968 - // have a bug there) // 969 - // XXX: once we support it, we would need to think more on how we // 970 - // initialize the comparators when we create the driver. // 971 - return !matcher.hasWhere() && !matcher.hasGeoQuery(); // 972 -}; // 973 - // 974 -var modifierCanBeDirectlyApplied = function (modifier) { // 975 - return _.all(modifier, function (fields, operation) { // 976 - return _.all(fields, function (value, field) { // 977 - return !/EJSON\$/.test(field); // 978 - }); // 979 - }); // 980 -}; // 981 - // 982 -MongoInternals.OplogObserveDriver = OplogObserveDriver; // 983 - // 984 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/local_collection_driver.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -LocalCollectionDriver = function () { // 1 - var self = this; // 2 - self.noConnCollections = {}; // 3 -}; // 4 - // 5 -var ensureCollection = function (name, collections) { // 6 - if (!(name in collections)) // 7 - collections[name] = new LocalCollection(name); // 8 - return collections[name]; // 9 -}; // 10 - // 11 -_.extend(LocalCollectionDriver.prototype, { // 12 - open: function (name, conn) { // 13 - var self = this; // 14 - if (!name) // 15 - return new LocalCollection; // 16 - if (! conn) { // 17 - return ensureCollection(name, self.noConnCollections); // 18 - } // 19 - if (! conn._mongo_livedata_collections) // 20 - conn._mongo_livedata_collections = {}; // 21 - // XXX is there a way to keep track of a connection's collections without // 22 - // dangling it off the connection object? // 23 - return ensureCollection(name, conn._mongo_livedata_collections); // 24 - } // 25 -}); // 26 - // 27 -// singleton // 28 -LocalCollectionDriver = new LocalCollectionDriver; // 29 - // 30 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/remote_collection_driver.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -MongoInternals.RemoteCollectionDriver = function ( // 1 - mongo_url, options) { // 2 - var self = this; // 3 - self.mongo = new MongoConnection(mongo_url, options); // 4 -}; // 5 - // 6 -_.extend(MongoInternals.RemoteCollectionDriver.prototype, { // 7 - open: function (name) { // 8 - var self = this; // 9 - var ret = {}; // 10 - _.each( // 11 - ['find', 'findOne', 'insert', 'update', 'upsert', // 12 - 'remove', '_ensureIndex', '_dropIndex', '_createCappedCollection', // 13 - 'dropCollection', 'rawCollection'], // 14 - function (m) { // 15 - ret[m] = _.bind(self.mongo[m], self.mongo, name); // 16 - }); // 17 - return ret; // 18 - } // 19 -}); // 20 - // 21 - // 22 -// Create the singleton RemoteCollectionDriver only on demand, so we // 23 -// only require Mongo configuration if it's actually used (eg, not if // 24 -// you're only trying to receive data from a remote DDP server.) // 25 -MongoInternals.defaultRemoteCollectionDriver = _.once(function () { // 26 - var connectionOptions = {}; // 27 - // 28 - var mongoUrl = process.env.MONGO_URL; // 29 - // 30 - if (process.env.MONGO_OPLOG_URL) { // 31 - connectionOptions.oplogUrl = process.env.MONGO_OPLOG_URL; // 32 - } // 33 - // 34 - if (! mongoUrl) // 35 - throw new Error("MONGO_URL must be set in environment"); // 36 - // 37 - return new MongoInternals.RemoteCollectionDriver(mongoUrl, connectionOptions); // 38 -}); // 39 - // 40 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/mongo/collection.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// options.connection, if given, is a LivedataClient or LivedataServer // 1 -// XXX presently there is no way to destroy/clean up a Collection // 2 - // 3 -/** // 4 - * @summary Namespace for MongoDB-related items // 5 - * @namespace // 6 - */ // 7 -Mongo = {}; // 8 - // 9 -/** // 10 - * @summary Constructor for a Collection // 11 - * @locus Anywhere // 12 - * @instancename collection // 13 - * @class // 14 - * @param {String} name The name of the collection. If null, creates an unmanaged (unsynchronized) local collection. // 15 - * @param {Object} [options] // 16 - * @param {Object} options.connection The server connection that will manage this collection. Uses the default connection if not specified. Pass the return value of calling [`DDP.connect`](#ddp_connect) to specify a different server. Pass `null` to specify no connection. Unmanaged (`name` is null) collections cannot specify a connection. - * @param {String} options.idGeneration The method of generating the `_id` fields of new documents in this collection. Possible values: - // 19 - - **`'STRING'`**: random strings // 20 - - **`'MONGO'`**: random [`Mongo.ObjectID`](#mongo_object_id) values // 21 - // 22 -The default id generation technique is `'STRING'`. // 23 - * @param {Function} options.transform An optional transformation function. Documents will be passed through this function before being returned from `fetch` or `findOne`, and before being passed to callbacks of `observe`, `map`, `forEach`, `allow`, and `deny`. Transforms are *not* applied for the callbacks of `observeChanges` or to cursors returned from publish functions. - */ // 25 -Mongo.Collection = function (name, options) { // 26 - var self = this; // 27 - if (! (self instanceof Mongo.Collection)) // 28 - throw new Error('use "new" to construct a Mongo.Collection'); // 29 - // 30 - if (!name && (name !== null)) { // 31 - Meteor._debug("Warning: creating anonymous collection. It will not be " + // 32 - "saved or synchronized over the network. (Pass null for " + // 33 - "the collection name to turn off this warning.)"); // 34 - name = null; // 35 - } // 36 - // 37 - if (name !== null && typeof name !== "string") { // 38 - throw new Error( // 39 - "First argument to new Mongo.Collection must be a string or null"); // 40 - } // 41 - // 42 - if (options && options.methods) { // 43 - // Backwards compatibility hack with original signature (which passed // 44 - // "connection" directly instead of in options. (Connections must have a "methods" // 45 - // method.) // 46 - // XXX remove before 1.0 // 47 - options = {connection: options}; // 48 - } // 49 - // Backwards compatibility: "connection" used to be called "manager". // 50 - if (options && options.manager && !options.connection) { // 51 - options.connection = options.manager; // 52 - } // 53 - options = _.extend({ // 54 - connection: undefined, // 55 - idGeneration: 'STRING', // 56 - transform: null, // 57 - _driver: undefined, // 58 - _preventAutopublish: false // 59 - }, options); // 60 - // 61 - switch (options.idGeneration) { // 62 - case 'MONGO': // 63 - self._makeNewID = function () { // 64 - var src = name ? DDP.randomStream('/collection/' + name) : Random; // 65 - return new Mongo.ObjectID(src.hexString(24)); // 66 - }; // 67 - break; // 68 - case 'STRING': // 69 - default: // 70 - self._makeNewID = function () { // 71 - var src = name ? DDP.randomStream('/collection/' + name) : Random; // 72 - return src.id(); // 73 - }; // 74 - break; // 75 - } // 76 - // 77 - self._transform = LocalCollection.wrapTransform(options.transform); // 78 - // 79 - if (! name || options.connection === null) // 80 - // note: nameless collections never have a connection // 81 - self._connection = null; // 82 - else if (options.connection) // 83 - self._connection = options.connection; // 84 - else if (Meteor.isClient) // 85 - self._connection = Meteor.connection; // 86 - else // 87 - self._connection = Meteor.server; // 88 - // 89 - if (!options._driver) { // 90 - // XXX This check assumes that webapp is loaded so that Meteor.server !== // 91 - // null. We should fully support the case of "want to use a Mongo-backed // 92 - // collection from Node code without webapp", but we don't yet. // 93 - // #MeteorServerNull // 94 - if (name && self._connection === Meteor.server && // 95 - typeof MongoInternals !== "undefined" && // 96 - MongoInternals.defaultRemoteCollectionDriver) { // 97 - options._driver = MongoInternals.defaultRemoteCollectionDriver(); // 98 - } else { // 99 - options._driver = LocalCollectionDriver; // 100 - } // 101 - } // 102 - // 103 - self._collection = options._driver.open(name, self._connection); // 104 - self._name = name; // 105 - self._driver = options._driver; // 106 - // 107 - if (self._connection && self._connection.registerStore) { // 108 - // OK, we're going to be a slave, replicating some remote // 109 - // database, except possibly with some temporary divergence while // 110 - // we have unacknowledged RPC's. // 111 - var ok = self._connection.registerStore(name, { // 112 - // Called at the beginning of a batch of updates. batchSize is the number // 113 - // of update calls to expect. // 114 - // // 115 - // XXX This interface is pretty janky. reset probably ought to go back to // 116 - // being its own function, and callers shouldn't have to calculate // 117 - // batchSize. The optimization of not calling pause/remove should be // 118 - // delayed until later: the first call to update() should buffer its // 119 - // message, and then we can either directly apply it at endUpdate time if // 120 - // it was the only update, or do pauseObservers/apply/apply at the next // 121 - // update() if there's another one. // 122 - beginUpdate: function (batchSize, reset) { // 123 - // pause observers so users don't see flicker when updating several // 124 - // objects at once (including the post-reconnect reset-and-reapply // 125 - // stage), and so that a re-sorting of a query can take advantage of the // 126 - // full _diffQuery moved calculation instead of applying change one at a // 127 - // time. // 128 - if (batchSize > 1 || reset) // 129 - self._collection.pauseObservers(); // 130 - // 131 - if (reset) // 132 - self._collection.remove({}); // 133 - }, // 134 - // 135 - // Apply an update. // 136 - // XXX better specify this interface (not in terms of a wire message)? // 137 - update: function (msg) { // 138 - var mongoId = LocalCollection._idParse(msg.id); // 139 - var doc = self._collection.findOne(mongoId); // 140 - // 141 - // Is this a "replace the whole doc" message coming from the quiescence // 142 - // of method writes to an object? (Note that 'undefined' is a valid // 143 - // value meaning "remove it".) // 144 - if (msg.msg === 'replace') { // 145 - var replace = msg.replace; // 146 - if (!replace) { // 147 - if (doc) // 148 - self._collection.remove(mongoId); // 149 - } else if (!doc) { // 150 - self._collection.insert(replace); // 151 - } else { // 152 - // XXX check that replace has no $ ops // 153 - self._collection.update(mongoId, replace); // 154 - } // 155 - return; // 156 - } else if (msg.msg === 'added') { // 157 - if (doc) { // 158 - throw new Error("Expected not to find a document already present for an add"); // 159 - } // 160 - self._collection.insert(_.extend({_id: mongoId}, msg.fields)); // 161 - } else if (msg.msg === 'removed') { // 162 - if (!doc) // 163 - throw new Error("Expected to find a document already present for removed"); // 164 - self._collection.remove(mongoId); // 165 - } else if (msg.msg === 'changed') { // 166 - if (!doc) // 167 - throw new Error("Expected to find a document to change"); // 168 - if (!_.isEmpty(msg.fields)) { // 169 - var modifier = {}; // 170 - _.each(msg.fields, function (value, key) { // 171 - if (value === undefined) { // 172 - if (!modifier.$unset) // 173 - modifier.$unset = {}; // 174 - modifier.$unset[key] = 1; // 175 - } else { // 176 - if (!modifier.$set) // 177 - modifier.$set = {}; // 178 - modifier.$set[key] = value; // 179 - } // 180 - }); // 181 - self._collection.update(mongoId, modifier); // 182 - } // 183 - } else { // 184 - throw new Error("I don't know how to deal with this message"); // 185 - } // 186 - // 187 - }, // 188 - // 189 - // Called at the end of a batch of updates. // 190 - endUpdate: function () { // 191 - self._collection.resumeObservers(); // 192 - }, // 193 - // 194 - // Called around method stub invocations to capture the original versions // 195 - // of modified documents. // 196 - saveOriginals: function () { // 197 - self._collection.saveOriginals(); // 198 - }, // 199 - retrieveOriginals: function () { // 200 - return self._collection.retrieveOriginals(); // 201 - } // 202 - }); // 203 - // 204 - if (!ok) // 205 - throw new Error("There is already a collection named '" + name + "'"); // 206 - } // 207 - // 208 - self._defineMutationMethods(); // 209 - // 210 - // autopublish // 211 - if (Package.autopublish && !options._preventAutopublish && self._connection // 212 - && self._connection.publish) { // 213 - self._connection.publish(null, function () { // 214 - return self.find(); // 215 - }, {is_auto: true}); // 216 - } // 217 -}; // 218 - // 219 -/// // 220 -/// Main collection API // 221 -/// // 222 - // 223 - // 224 -_.extend(Mongo.Collection.prototype, { // 225 - // 226 - _getFindSelector: function (args) { // 227 - if (args.length == 0) // 228 - return {}; // 229 - else // 230 - return args[0]; // 231 - }, // 232 - // 233 - _getFindOptions: function (args) { // 234 - var self = this; // 235 - if (args.length < 2) { // 236 - return { transform: self._transform }; // 237 - } else { // 238 - check(args[1], Match.Optional(Match.ObjectIncluding({ // 239 - fields: Match.Optional(Match.OneOf(Object, undefined)), // 240 - sort: Match.Optional(Match.OneOf(Object, Array, undefined)), // 241 - limit: Match.Optional(Match.OneOf(Number, undefined)), // 242 - skip: Match.Optional(Match.OneOf(Number, undefined)) // 243 - }))); // 244 - // 245 - return _.extend({ // 246 - transform: self._transform // 247 - }, args[1]); // 248 - } // 249 - }, // 250 - // 251 - /** // 252 - * @summary Find the documents in a collection that match the selector. // 253 - * @locus Anywhere // 254 - * @method find // 255 - * @memberOf Mongo.Collection // 256 - * @instance // 257 - * @param {MongoSelector} [selector] A query describing the documents to find // 258 - * @param {Object} [options] // 259 - * @param {MongoSortSpecifier} options.sort Sort order (default: natural order) // 260 - * @param {Number} options.skip Number of results to skip at the beginning // 261 - * @param {Number} options.limit Maximum number of results to return // 262 - * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. // 263 - * @param {Boolean} options.reactive (Client only) Default `true`; pass `false` to disable reactivity // 264 - * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections) for this cursor. Pass `null` to disable transformation. - * @returns {Mongo.Cursor} // 266 - */ // 267 - find: function (/* selector, options */) { // 268 - // Collection.find() (return all docs) behaves differently // 269 - // from Collection.find(undefined) (return 0 docs). so be // 270 - // careful about the length of arguments. // 271 - var self = this; // 272 - var argArray = _.toArray(arguments); // 273 - return self._collection.find(self._getFindSelector(argArray), // 274 - self._getFindOptions(argArray)); // 275 - }, // 276 - // 277 - /** // 278 - * @summary Finds the first document that matches the selector, as ordered by sort and skip options. // 279 - * @locus Anywhere // 280 - * @method findOne // 281 - * @memberOf Mongo.Collection // 282 - * @instance // 283 - * @param {MongoSelector} [selector] A query describing the documents to find // 284 - * @param {Object} [options] // 285 - * @param {MongoSortSpecifier} options.sort Sort order (default: natural order) // 286 - * @param {Number} options.skip Number of results to skip at the beginning // 287 - * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude. // 288 - * @param {Boolean} options.reactive (Client only) Default true; pass false to disable reactivity // 289 - * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections) for this cursor. Pass `null` to disable transformation. - * @returns {Object} // 291 - */ // 292 - findOne: function (/* selector, options */) { // 293 - var self = this; // 294 - var argArray = _.toArray(arguments); // 295 - return self._collection.findOne(self._getFindSelector(argArray), // 296 - self._getFindOptions(argArray)); // 297 - } // 298 - // 299 -}); // 300 - // 301 -Mongo.Collection._publishCursor = function (cursor, sub, collection) { // 302 - var observeHandle = cursor.observeChanges({ // 303 - added: function (id, fields) { // 304 - sub.added(collection, id, fields); // 305 - }, // 306 - changed: function (id, fields) { // 307 - sub.changed(collection, id, fields); // 308 - }, // 309 - removed: function (id) { // 310 - sub.removed(collection, id); // 311 - } // 312 - }); // 313 - // 314 - // We don't call sub.ready() here: it gets called in livedata_server, after // 315 - // possibly calling _publishCursor on multiple returned cursors. // 316 - // 317 - // register stop callback (expects lambda w/ no args). // 318 - sub.onStop(function () {observeHandle.stop();}); // 319 -}; // 320 - // 321 -// protect against dangerous selectors. falsey and {_id: falsey} are both // 322 -// likely programmer error, and not what you want, particularly for destructive // 323 -// operations. JS regexps don't serialize over DDP but can be trivially // 324 -// replaced by $regex. // 325 -Mongo.Collection._rewriteSelector = function (selector) { // 326 - // shorthand -- scalars match _id // 327 - if (LocalCollection._selectorIsId(selector)) // 328 - selector = {_id: selector}; // 329 - // 330 - if (!selector || (('_id' in selector) && !selector._id)) // 331 - // can't match anything // 332 - return {_id: Random.id()}; // 333 - // 334 - var ret = {}; // 335 - _.each(selector, function (value, key) { // 336 - // Mongo supports both {field: /foo/} and {field: {$regex: /foo/}} // 337 - if (value instanceof RegExp) { // 338 - ret[key] = convertRegexpToMongoSelector(value); // 339 - } else if (value && value.$regex instanceof RegExp) { // 340 - ret[key] = convertRegexpToMongoSelector(value.$regex); // 341 - // if value is {$regex: /foo/, $options: ...} then $options // 342 - // override the ones set on $regex. // 343 - if (value.$options !== undefined) // 344 - ret[key].$options = value.$options; // 345 - } // 346 - else if (_.contains(['$or','$and','$nor'], key)) { // 347 - // Translate lower levels of $and/$or/$nor // 348 - ret[key] = _.map(value, function (v) { // 349 - return Mongo.Collection._rewriteSelector(v); // 350 - }); // 351 - } else { // 352 - ret[key] = value; // 353 - } // 354 - }); // 355 - return ret; // 356 -}; // 357 - // 358 -// convert a JS RegExp object to a Mongo {$regex: ..., $options: ...} // 359 -// selector // 360 -var convertRegexpToMongoSelector = function (regexp) { // 361 - check(regexp, RegExp); // safety belt // 362 - // 363 - var selector = {$regex: regexp.source}; // 364 - var regexOptions = ''; // 365 - // JS RegExp objects support 'i', 'm', and 'g'. Mongo regex $options // 366 - // support 'i', 'm', 'x', and 's'. So we support 'i' and 'm' here. // 367 - if (regexp.ignoreCase) // 368 - regexOptions += 'i'; // 369 - if (regexp.multiline) // 370 - regexOptions += 'm'; // 371 - if (regexOptions) // 372 - selector.$options = regexOptions; // 373 - // 374 - return selector; // 375 -}; // 376 - // 377 -var throwIfSelectorIsNotId = function (selector, methodName) { // 378 - if (!LocalCollection._selectorIsIdPerhapsAsObject(selector)) { // 379 - throw new Meteor.Error( // 380 - 403, "Not permitted. Untrusted code may only " + methodName + // 381 - " documents by ID."); // 382 - } // 383 -}; // 384 - // 385 -// 'insert' immediately returns the inserted document's new _id. // 386 -// The others return values immediately if you are in a stub, an in-memory // 387 -// unmanaged collection, or a mongo-backed collection and you don't pass a // 388 -// callback. 'update' and 'remove' return the number of affected // 389 -// documents. 'upsert' returns an object with keys 'numberAffected' and, if an // 390 -// insert happened, 'insertedId'. // 391 -// // 392 -// Otherwise, the semantics are exactly like other methods: they take // 393 -// a callback as an optional last argument; if no callback is // 394 -// provided, they block until the operation is complete, and throw an // 395 -// exception if it fails; if a callback is provided, then they don't // 396 -// necessarily block, and they call the callback when they finish with error and // 397 -// result arguments. (The insert method provides the document ID as its result; // 398 -// update and remove provide the number of affected docs as the result; upsert // 399 -// provides an object with numberAffected and maybe insertedId.) // 400 -// // 401 -// On the client, blocking is impossible, so if a callback // 402 -// isn't provided, they just return immediately and any error // 403 -// information is lost. // 404 -// // 405 -// There's one more tweak. On the client, if you don't provide a // 406 -// callback, then if there is an error, a message will be logged with // 407 -// Meteor._debug. // 408 -// // 409 -// The intent (though this is actually determined by the underlying // 410 -// drivers) is that the operations should be done synchronously, not // 411 -// generating their result until the database has acknowledged // 412 -// them. In the future maybe we should provide a flag to turn this // 413 -// off. // 414 - // 415 -/** // 416 - * @summary Insert a document in the collection. Returns its unique _id. // 417 - * @locus Anywhere // 418 - * @method insert // 419 - * @memberOf Mongo.Collection // 420 - * @instance // 421 - * @param {Object} doc The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you. - * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the _id as the second. - */ // 424 - // 425 -/** // 426 - * @summary Modify one or more documents in the collection. Returns the number of affected documents. // 427 - * @locus Anywhere // 428 - * @method update // 429 - * @memberOf Mongo.Collection // 430 - * @instance // 431 - * @param {MongoSelector} selector Specifies which documents to modify // 432 - * @param {MongoModifier} modifier Specifies how to modify the documents // 433 - * @param {Object} [options] // 434 - * @param {Boolean} options.multi True to modify all matching documents; false to only modify one of the matching documents (the default). - * @param {Boolean} options.upsert True to insert a document if no matching documents are found. // 436 - * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second. - */ // 438 - // 439 -/** // 440 - * @summary Remove documents from the collection // 441 - * @locus Anywhere // 442 - * @method remove // 443 - * @memberOf Mongo.Collection // 444 - * @instance // 445 - * @param {MongoSelector} selector Specifies which documents to remove // 446 - * @param {Function} [callback] Optional. If present, called with an error object as its argument. // 447 - */ // 448 - // 449 -_.each(["insert", "update", "remove"], function (name) { // 450 - Mongo.Collection.prototype[name] = function (/* arguments */) { // 451 - var self = this; // 452 - var args = _.toArray(arguments); // 453 - var callback; // 454 - var insertId; // 455 - var ret; // 456 - // 457 - // Pull off any callback (or perhaps a 'callback' variable that was passed // 458 - // in undefined, like how 'upsert' does it). // 459 - if (args.length && // 460 - (args[args.length - 1] === undefined || // 461 - args[args.length - 1] instanceof Function)) { // 462 - callback = args.pop(); // 463 - } // 464 - // 465 - if (name === "insert") { // 466 - if (!args.length) // 467 - throw new Error("insert requires an argument"); // 468 - // shallow-copy the document and generate an ID // 469 - args[0] = _.extend({}, args[0]); // 470 - if ('_id' in args[0]) { // 471 - insertId = args[0]._id; // 472 - if (!insertId || !(typeof insertId === 'string' // 473 - || insertId instanceof Mongo.ObjectID)) // 474 - throw new Error("Meteor requires document _id fields to be non-empty strings or ObjectIDs"); // 475 - } else { // 476 - var generateId = true; // 477 - // Don't generate the id if we're the client and the 'outermost' call // 478 - // This optimization saves us passing both the randomSeed and the id // 479 - // Passing both is redundant. // 480 - if (self._connection && self._connection !== Meteor.server) { // 481 - var enclosing = DDP._CurrentInvocation.get(); // 482 - if (!enclosing) { // 483 - generateId = false; // 484 - } // 485 - } // 486 - if (generateId) { // 487 - insertId = args[0]._id = self._makeNewID(); // 488 - } // 489 - } // 490 - } else { // 491 - args[0] = Mongo.Collection._rewriteSelector(args[0]); // 492 - // 493 - if (name === "update") { // 494 - // Mutate args but copy the original options object. We need to add // 495 - // insertedId to options, but don't want to mutate the caller's options // 496 - // object. We need to mutate `args` because we pass `args` into the // 497 - // driver below. // 498 - var options = args[2] = _.clone(args[2]) || {}; // 499 - if (options && typeof options !== "function" && options.upsert) { // 500 - // set `insertedId` if absent. `insertedId` is a Meteor extension. // 501 - if (options.insertedId) { // 502 - if (!(typeof options.insertedId === 'string' // 503 - || options.insertedId instanceof Mongo.ObjectID)) // 504 - throw new Error("insertedId must be string or ObjectID"); // 505 - } else if (! args[0]._id) { // 506 - options.insertedId = self._makeNewID(); // 507 - } // 508 - } // 509 - } // 510 - } // 511 - // 512 - // On inserts, always return the id that we generated; on all other // 513 - // operations, just return the result from the collection. // 514 - var chooseReturnValueFromCollectionResult = function (result) { // 515 - if (name === "insert") { // 516 - if (!insertId && result) { // 517 - insertId = result; // 518 - } // 519 - return insertId; // 520 - } else { // 521 - return result; // 522 - } // 523 - }; // 524 - // 525 - var wrappedCallback; // 526 - if (callback) { // 527 - wrappedCallback = function (error, result) { // 528 - callback(error, ! error && chooseReturnValueFromCollectionResult(result)); // 529 - }; // 530 - } // 531 - // 532 - // XXX see #MeteorServerNull // 533 - if (self._connection && self._connection !== Meteor.server) { // 534 - // just remote to another endpoint, propagate return value or // 535 - // exception. // 536 - // 537 - var enclosing = DDP._CurrentInvocation.get(); // 538 - var alreadyInSimulation = enclosing && enclosing.isSimulation; // 539 - // 540 - if (Meteor.isClient && !wrappedCallback && ! alreadyInSimulation) { // 541 - // Client can't block, so it can't report errors by exception, // 542 - // only by callback. If they forget the callback, give them a // 543 - // default one that logs the error, so they aren't totally // 544 - // baffled if their writes don't work because their database is // 545 - // down. // 546 - // Don't give a default callback in simulation, because inside stubs we // 547 - // want to return the results from the local collection immediately and // 548 - // not force a callback. // 549 - wrappedCallback = function (err) { // 550 - if (err) // 551 - Meteor._debug(name + " failed: " + (err.reason || err.stack)); // 552 - }; // 553 - } // 554 - // 555 - if (!alreadyInSimulation && name !== "insert") { // 556 - // If we're about to actually send an RPC, we should throw an error if // 557 - // this is a non-ID selector, because the mutation methods only allow // 558 - // single-ID selectors. (If we don't throw here, we'll see flicker.) // 559 - throwIfSelectorIsNotId(args[0], name); // 560 - } // 561 - // 562 - ret = chooseReturnValueFromCollectionResult( // 563 - self._connection.apply(self._prefix + name, args, {returnStubValue: true}, wrappedCallback) // 564 - ); // 565 - // 566 - } else { // 567 - // it's my collection. descend into the collection object // 568 - // and propagate any exception. // 569 - args.push(wrappedCallback); // 570 - try { // 571 - // If the user provided a callback and the collection implements this // 572 - // operation asynchronously, then queryRet will be undefined, and the // 573 - // result will be returned through the callback instead. // 574 - var queryRet = self._collection[name].apply(self._collection, args); // 575 - ret = chooseReturnValueFromCollectionResult(queryRet); // 576 - } catch (e) { // 577 - if (callback) { // 578 - callback(e); // 579 - return null; // 580 - } // 581 - throw e; // 582 - } // 583 - } // 584 - // 585 - // both sync and async, unless we threw an exception, return ret // 586 - // (new document ID for insert, num affected for update/remove, object with // 587 - // numberAffected and maybe insertedId for upsert). // 588 - return ret; // 589 - }; // 590 -}); // 591 - // 592 -/** // 593 - * @summary Modify one or more documents in the collection, or insert one if no matching documents were found. Returns an object with keys `numberAffected` (the number of documents modified) and `insertedId` (the unique _id of the document that was inserted, if any). - * @locus Anywhere // 595 - * @param {MongoSelector} selector Specifies which documents to modify // 596 - * @param {MongoModifier} modifier Specifies how to modify the documents // 597 - * @param {Object} [options] // 598 - * @param {Boolean} options.multi True to modify all matching documents; false to only modify one of the matching documents (the default). - * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second. - */ // 601 -Mongo.Collection.prototype.upsert = function (selector, modifier, // 602 - options, callback) { // 603 - var self = this; // 604 - if (! callback && typeof options === "function") { // 605 - callback = options; // 606 - options = {}; // 607 - } // 608 - return self.update(selector, modifier, // 609 - _.extend({}, options, { _returnObject: true, upsert: true }), // 610 - callback); // 611 -}; // 612 - // 613 -// We'll actually design an index API later. For now, we just pass through to // 614 -// Mongo's, but make it synchronous. // 615 -Mongo.Collection.prototype._ensureIndex = function (index, options) { // 616 - var self = this; // 617 - if (!self._collection._ensureIndex) // 618 - throw new Error("Can only call _ensureIndex on server collections"); // 619 - self._collection._ensureIndex(index, options); // 620 -}; // 621 -Mongo.Collection.prototype._dropIndex = function (index) { // 622 - var self = this; // 623 - if (!self._collection._dropIndex) // 624 - throw new Error("Can only call _dropIndex on server collections"); // 625 - self._collection._dropIndex(index); // 626 -}; // 627 -Mongo.Collection.prototype._dropCollection = function () { // 628 - var self = this; // 629 - if (!self._collection.dropCollection) // 630 - throw new Error("Can only call _dropCollection on server collections"); // 631 - self._collection.dropCollection(); // 632 -}; // 633 -Mongo.Collection.prototype._createCappedCollection = function (byteSize, maxDocuments) { // 634 - var self = this; // 635 - if (!self._collection._createCappedCollection) // 636 - throw new Error("Can only call _createCappedCollection on server collections"); // 637 - self._collection._createCappedCollection(byteSize, maxDocuments); // 638 -}; // 639 - // 640 -Mongo.Collection.prototype.rawCollection = function () { // 641 - var self = this; // 642 - if (! self._collection.rawCollection) { // 643 - throw new Error("Can only call rawCollection on server collections"); // 644 - } // 645 - return self._collection.rawCollection(); // 646 -}; // 647 - // 648 -Mongo.Collection.prototype.rawDatabase = function () { // 649 - var self = this; // 650 - if (! (self._driver.mongo && self._driver.mongo.db)) { // 651 - throw new Error("Can only call rawDatabase on server collections"); // 652 - } // 653 - return self._driver.mongo.db; // 654 -}; // 655 - // 656 - // 657 -/** // 658 - * @summary Create a Mongo-style `ObjectID`. If you don't specify a `hexString`, the `ObjectID` will generated randomly (not using MongoDB's ID construction rules). - * @locus Anywhere // 660 - * @class // 661 - * @param {String} hexString Optional. The 24-character hexadecimal contents of the ObjectID to create // 662 - */ // 663 -Mongo.ObjectID = LocalCollection._ObjectID; // 664 - // 665 -/** // 666 - * @summary To create a cursor, use find. To access the documents in a cursor, use forEach, map, or fetch. // 667 - * @class // 668 - * @instanceName cursor // 669 - */ // 670 -Mongo.Cursor = LocalCollection.Cursor; // 671 - // 672 -/** // 673 - * @deprecated in 0.9.1 // 674 - */ // 675 -Mongo.Collection.Cursor = Mongo.Cursor; // 676 - // 677 -/** // 678 - * @deprecated in 0.9.1 // 679 - */ // 680 -Mongo.Collection.ObjectID = Mongo.ObjectID; // 681 - // 682 -/// // 683 -/// Remote methods and access control. // 684 -/// // 685 - // 686 -// Restrict default mutators on collection. allow() and deny() take the // 687 -// same options: // 688 -// // 689 -// options.insert {Function(userId, doc)} // 690 -// return true to allow/deny adding this document // 691 -// // 692 -// options.update {Function(userId, docs, fields, modifier)} // 693 -// return true to allow/deny updating these documents. // 694 -// `fields` is passed as an array of fields that are to be modified // 695 -// // 696 -// options.remove {Function(userId, docs)} // 697 -// return true to allow/deny removing these documents // 698 -// // 699 -// options.fetch {Array} // 700 -// Fields to fetch for these validators. If any call to allow or deny // 701 -// does not have this option then all fields are loaded. // 702 -// // 703 -// allow and deny can be called multiple times. The validators are // 704 -// evaluated as follows: // 705 -// - If neither deny() nor allow() has been called on the collection, // 706 -// then the request is allowed if and only if the "insecure" smart // 707 -// package is in use. // 708 -// - Otherwise, if any deny() function returns true, the request is denied. // 709 -// - Otherwise, if any allow() function returns true, the request is allowed. // 710 -// - Otherwise, the request is denied. // 711 -// // 712 -// Meteor may call your deny() and allow() functions in any order, and may not // 713 -// call all of them if it is able to make a decision without calling them all // 714 -// (so don't include side effects). // 715 - // 716 -(function () { // 717 - var addValidator = function(allowOrDeny, options) { // 718 - // validate keys // 719 - var VALID_KEYS = ['insert', 'update', 'remove', 'fetch', 'transform']; // 720 - _.each(_.keys(options), function (key) { // 721 - if (!_.contains(VALID_KEYS, key)) // 722 - throw new Error(allowOrDeny + ": Invalid key: " + key); // 723 - }); // 724 - // 725 - var self = this; // 726 - self._restricted = true; // 727 - // 728 - _.each(['insert', 'update', 'remove'], function (name) { // 729 - if (options[name]) { // 730 - if (!(options[name] instanceof Function)) { // 731 - throw new Error(allowOrDeny + ": Value for `" + name + "` must be a function"); // 732 - } // 733 - // 734 - // If the transform is specified at all (including as 'null') in this // 735 - // call, then take that; otherwise, take the transform from the // 736 - // collection. // 737 - if (options.transform === undefined) { // 738 - options[name].transform = self._transform; // already wrapped // 739 - } else { // 740 - options[name].transform = LocalCollection.wrapTransform( // 741 - options.transform); // 742 - } // 743 - // 744 - self._validators[name][allowOrDeny].push(options[name]); // 745 - } // 746 - }); // 747 - // 748 - // Only update the fetch fields if we're passed things that affect // 749 - // fetching. This way allow({}) and allow({insert: f}) don't result in // 750 - // setting fetchAllFields // 751 - if (options.update || options.remove || options.fetch) { // 752 - if (options.fetch && !(options.fetch instanceof Array)) { // 753 - throw new Error(allowOrDeny + ": Value for `fetch` must be an array"); // 754 - } // 755 - self._updateFetch(options.fetch); // 756 - } // 757 - }; // 758 - // 759 - /** // 760 - * @summary Allow users to write directly to this collection from client code, subject to limitations you define. // 761 - * @locus Server // 762 - * @param {Object} options // 763 - * @param {Function} options.insert,update,remove Functions that look at a proposed modification to the database and return true if it should be allowed. - * @param {String[]} options.fetch Optional performance enhancement. Limits the fields that will be fetched from the database for inspection by your `update` and `remove` functions. - * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections). Pass `null` to disable transformation. - */ // 767 - Mongo.Collection.prototype.allow = function(options) { // 768 - addValidator.call(this, 'allow', options); // 769 - }; // 770 - // 771 - /** // 772 - * @summary Override `allow` rules. // 773 - * @locus Server // 774 - * @param {Object} options // 775 - * @param {Function} options.insert,update,remove Functions that look at a proposed modification to the database and return true if it should be denied, even if an [allow](#allow) rule says otherwise. - * @param {String[]} options.fetch Optional performance enhancement. Limits the fields that will be fetched from the database for inspection by your `update` and `remove` functions. - * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections). Pass `null` to disable transformation. - */ // 779 - Mongo.Collection.prototype.deny = function(options) { // 780 - addValidator.call(this, 'deny', options); // 781 - }; // 782 -})(); // 783 - // 784 - // 785 -Mongo.Collection.prototype._defineMutationMethods = function() { // 786 - var self = this; // 787 - // 788 - // set to true once we call any allow or deny methods. If true, use // 789 - // allow/deny semantics. If false, use insecure mode semantics. // 790 - self._restricted = false; // 791 - // 792 - // Insecure mode (default to allowing writes). Defaults to 'undefined' which // 793 - // means insecure iff the insecure package is loaded. This property can be // 794 - // overriden by tests or packages wishing to change insecure mode behavior of // 795 - // their collections. // 796 - self._insecure = undefined; // 797 - // 798 - self._validators = { // 799 - insert: {allow: [], deny: []}, // 800 - update: {allow: [], deny: []}, // 801 - remove: {allow: [], deny: []}, // 802 - upsert: {allow: [], deny: []}, // dummy arrays; can't set these! // 803 - fetch: [], // 804 - fetchAllFields: false // 805 - }; // 806 - // 807 - if (!self._name) // 808 - return; // anonymous collection // 809 - // 810 - // XXX Think about method namespacing. Maybe methods should be // 811 - // "Meteor:Mongo:insert/NAME"? // 812 - self._prefix = '/' + self._name + '/'; // 813 - // 814 - // mutation methods // 815 - if (self._connection) { // 816 - var m = {}; // 817 - // 818 - _.each(['insert', 'update', 'remove'], function (method) { // 819 - m[self._prefix + method] = function (/* ... */) { // 820 - // All the methods do their own validation, instead of using check(). // 821 - check(arguments, [Match.Any]); // 822 - var args = _.toArray(arguments); // 823 - try { // 824 - // For an insert, if the client didn't specify an _id, generate one // 825 - // now; because this uses DDP.randomStream, it will be consistent with // 826 - // what the client generated. We generate it now rather than later so // 827 - // that if (eg) an allow/deny rule does an insert to the same // 828 - // collection (not that it really should), the generated _id will // 829 - // still be the first use of the stream and will be consistent. // 830 - // // 831 - // However, we don't actually stick the _id onto the document yet, // 832 - // because we want allow/deny rules to be able to differentiate // 833 - // between arbitrary client-specified _id fields and merely // 834 - // client-controlled-via-randomSeed fields. // 835 - var generatedId = null; // 836 - if (method === "insert" && !_.has(args[0], '_id')) { // 837 - generatedId = self._makeNewID(); // 838 - } // 839 - // 840 - if (this.isSimulation) { // 841 - // In a client simulation, you can do any mutation (even with a // 842 - // complex selector). // 843 - if (generatedId !== null) // 844 - args[0]._id = generatedId; // 845 - return self._collection[method].apply( // 846 - self._collection, args); // 847 - } // 848 - // 849 - // This is the server receiving a method call from the client. // 850 - // 851 - // We don't allow arbitrary selectors in mutations from the client: only // 852 - // single-ID selectors. // 853 - if (method !== 'insert') // 854 - throwIfSelectorIsNotId(args[0], method); // 855 - // 856 - if (self._restricted) { // 857 - // short circuit if there is no way it will pass. // 858 - if (self._validators[method].allow.length === 0) { // 859 - throw new Meteor.Error( // 860 - 403, "Access denied. No allow validators set on restricted " + // 861 - "collection for method '" + method + "'."); // 862 - } // 863 - // 864 - var validatedMethodName = // 865 - '_validated' + method.charAt(0).toUpperCase() + method.slice(1); // 866 - args.unshift(this.userId); // 867 - method === 'insert' && args.push(generatedId); // 868 - return self[validatedMethodName].apply(self, args); // 869 - } else if (self._isInsecure()) { // 870 - if (generatedId !== null) // 871 - args[0]._id = generatedId; // 872 - // In insecure mode, allow any mutation (with a simple selector). // 873 - // XXX This is kind of bogus. Instead of blindly passing whatever // 874 - // we get from the network to this function, we should actually // 875 - // know the correct arguments for the function and pass just // 876 - // them. For example, if you have an extraneous extra null // 877 - // argument and this is Mongo on the server, the .wrapAsync'd // 878 - // functions like update will get confused and pass the // 879 - // "fut.resolver()" in the wrong slot, where _update will never // 880 - // invoke it. Bam, broken DDP connection. Probably should just // 881 - // take this whole method and write it three times, invoking // 882 - // helpers for the common code. // 883 - return self._collection[method].apply(self._collection, args); // 884 - } else { // 885 - // In secure mode, if we haven't called allow or deny, then nothing // 886 - // is permitted. // 887 - throw new Meteor.Error(403, "Access denied"); // 888 - } // 889 - } catch (e) { // 890 - if (e.name === 'MongoError' || e.name === 'MinimongoError') { // 891 - throw new Meteor.Error(409, e.toString()); // 892 - } else { // 893 - throw e; // 894 - } // 895 - } // 896 - }; // 897 - }); // 898 - // Minimongo on the server gets no stubs; instead, by default // 899 - // it wait()s until its result is ready, yielding. // 900 - // This matches the behavior of macromongo on the server better. // 901 - // XXX see #MeteorServerNull // 902 - if (Meteor.isClient || self._connection === Meteor.server) // 903 - self._connection.methods(m); // 904 - } // 905 -}; // 906 - // 907 - // 908 -Mongo.Collection.prototype._updateFetch = function (fields) { // 909 - var self = this; // 910 - // 911 - if (!self._validators.fetchAllFields) { // 912 - if (fields) { // 913 - self._validators.fetch = _.union(self._validators.fetch, fields); // 914 - } else { // 915 - self._validators.fetchAllFields = true; // 916 - // clear fetch just to make sure we don't accidentally read it // 917 - self._validators.fetch = null; // 918 - } // 919 - } // 920 -}; // 921 - // 922 -Mongo.Collection.prototype._isInsecure = function () { // 923 - var self = this; // 924 - if (self._insecure === undefined) // 925 - return !!Package.insecure; // 926 - return self._insecure; // 927 -}; // 928 - // 929 -var docToValidate = function (validator, doc, generatedId) { // 930 - var ret = doc; // 931 - if (validator.transform) { // 932 - ret = EJSON.clone(doc); // 933 - // If you set a server-side transform on your collection, then you don't get // 934 - // to tell the difference between "client specified the ID" and "server // 935 - // generated the ID", because transforms expect to get _id. If you want to // 936 - // do that check, you can do it with a specific // 937 - // `C.allow({insert: f, transform: null})` validator. // 938 - if (generatedId !== null) { // 939 - ret._id = generatedId; // 940 - } // 941 - ret = validator.transform(ret); // 942 - } // 943 - return ret; // 944 -}; // 945 - // 946 -Mongo.Collection.prototype._validatedInsert = function (userId, doc, // 947 - generatedId) { // 948 - var self = this; // 949 - // 950 - // call user validators. // 951 - // Any deny returns true means denied. // 952 - if (_.any(self._validators.insert.deny, function(validator) { // 953 - return validator(userId, docToValidate(validator, doc, generatedId)); // 954 - })) { // 955 - throw new Meteor.Error(403, "Access denied"); // 956 - } // 957 - // Any allow returns true means proceed. Throw error if they all fail. // 958 - if (_.all(self._validators.insert.allow, function(validator) { // 959 - return !validator(userId, docToValidate(validator, doc, generatedId)); // 960 - })) { // 961 - throw new Meteor.Error(403, "Access denied"); // 962 - } // 963 - // 964 - // If we generated an ID above, insert it now: after the validation, but // 965 - // before actually inserting. // 966 - if (generatedId !== null) // 967 - doc._id = generatedId; // 968 - // 969 - self._collection.insert.call(self._collection, doc); // 970 -}; // 971 - // 972 -var transformDoc = function (validator, doc) { // 973 - if (validator.transform) // 974 - return validator.transform(doc); // 975 - return doc; // 976 -}; // 977 - // 978 -// Simulate a mongo `update` operation while validating that the access // 979 -// control rules set by calls to `allow/deny` are satisfied. If all // 980 -// pass, rewrite the mongo operation to use $in to set the list of // 981 -// document ids to change ##ValidatedChange // 982 -Mongo.Collection.prototype._validatedUpdate = function( // 983 - userId, selector, mutator, options) { // 984 - var self = this; // 985 - // 986 - check(mutator, Object); // 987 - // 988 - options = _.clone(options) || {}; // 989 - // 990 - if (!LocalCollection._selectorIsIdPerhapsAsObject(selector)) // 991 - throw new Error("validated update should be of a single ID"); // 992 - // 993 - // We don't support upserts because they don't fit nicely into allow/deny // 994 - // rules. // 995 - if (options.upsert) // 996 - throw new Meteor.Error(403, "Access denied. Upserts not " + // 997 - "allowed in a restricted collection."); // 998 - // 999 - var noReplaceError = "Access denied. In a restricted collection you can only" + // 1000 - " update documents, not replace them. Use a Mongo update operator, such " + // 1001 - "as '$set'."; // 1002 - // 1003 - // compute modified fields // 1004 - var fields = []; // 1005 - if (_.isEmpty(mutator)) { // 1006 - throw new Meteor.Error(403, noReplaceError); // 1007 - } // 1008 - _.each(mutator, function (params, op) { // 1009 - if (op.charAt(0) !== '$') { // 1010 - throw new Meteor.Error(403, noReplaceError); // 1011 - } else if (!_.has(ALLOWED_UPDATE_OPERATIONS, op)) { // 1012 - throw new Meteor.Error( // 1013 - 403, "Access denied. Operator " + op + " not allowed in a restricted collection."); // 1014 - } else { // 1015 - _.each(_.keys(params), function (field) { // 1016 - // treat dotted fields as if they are replacing their // 1017 - // top-level part // 1018 - if (field.indexOf('.') !== -1) // 1019 - field = field.substring(0, field.indexOf('.')); // 1020 - // 1021 - // record the field we are trying to change // 1022 - if (!_.contains(fields, field)) // 1023 - fields.push(field); // 1024 - }); // 1025 - } // 1026 - }); // 1027 - // 1028 - var findOptions = {transform: null}; // 1029 - if (!self._validators.fetchAllFields) { // 1030 - findOptions.fields = {}; // 1031 - _.each(self._validators.fetch, function(fieldName) { // 1032 - findOptions.fields[fieldName] = 1; // 1033 - }); // 1034 - } // 1035 - // 1036 - var doc = self._collection.findOne(selector, findOptions); // 1037 - if (!doc) // none satisfied! // 1038 - return 0; // 1039 - // 1040 - // call user validators. // 1041 - // Any deny returns true means denied. // 1042 - if (_.any(self._validators.update.deny, function(validator) { // 1043 - var factoriedDoc = transformDoc(validator, doc); // 1044 - return validator(userId, // 1045 - factoriedDoc, // 1046 - fields, // 1047 - mutator); // 1048 - })) { // 1049 - throw new Meteor.Error(403, "Access denied"); // 1050 - } // 1051 - // Any allow returns true means proceed. Throw error if they all fail. // 1052 - if (_.all(self._validators.update.allow, function(validator) { // 1053 - var factoriedDoc = transformDoc(validator, doc); // 1054 - return !validator(userId, // 1055 - factoriedDoc, // 1056 - fields, // 1057 - mutator); // 1058 - })) { // 1059 - throw new Meteor.Error(403, "Access denied"); // 1060 - } // 1061 - // 1062 - options._forbidReplace = true; // 1063 - // 1064 - // Back when we supported arbitrary client-provided selectors, we actually // 1065 - // rewrote the selector to include an _id clause before passing to Mongo to // 1066 - // avoid races, but since selector is guaranteed to already just be an ID, we // 1067 - // don't have to any more. // 1068 - // 1069 - return self._collection.update.call( // 1070 - self._collection, selector, mutator, options); // 1071 -}; // 1072 - // 1073 -// Only allow these operations in validated updates. Specifically // 1074 -// whitelist operations, rather than blacklist, so new complex // 1075 -// operations that are added aren't automatically allowed. A complex // 1076 -// operation is one that does more than just modify its target // 1077 -// field. For now this contains all update operations except '$rename'. // 1078 -// http://docs.mongodb.org/manual/reference/operators/#update // 1079 -var ALLOWED_UPDATE_OPERATIONS = { // 1080 - $inc:1, $set:1, $unset:1, $addToSet:1, $pop:1, $pullAll:1, $pull:1, // 1081 - $pushAll:1, $push:1, $bit:1 // 1082 -}; // 1083 - // 1084 -// Simulate a mongo `remove` operation while validating access control // 1085 -// rules. See #ValidatedChange // 1086 -Mongo.Collection.prototype._validatedRemove = function(userId, selector) { // 1087 - var self = this; // 1088 - // 1089 - var findOptions = {transform: null}; // 1090 - if (!self._validators.fetchAllFields) { // 1091 - findOptions.fields = {}; // 1092 - _.each(self._validators.fetch, function(fieldName) { // 1093 - findOptions.fields[fieldName] = 1; // 1094 - }); // 1095 - } // 1096 - // 1097 - var doc = self._collection.findOne(selector, findOptions); // 1098 - if (!doc) // 1099 - return 0; // 1100 - // 1101 - // call user validators. // 1102 - // Any deny returns true means denied. // 1103 - if (_.any(self._validators.remove.deny, function(validator) { // 1104 - return validator(userId, transformDoc(validator, doc)); // 1105 - })) { // 1106 - throw new Meteor.Error(403, "Access denied"); // 1107 - } // 1108 - // Any allow returns true means proceed. Throw error if they all fail. // 1109 - if (_.all(self._validators.remove.allow, function(validator) { // 1110 - return !validator(userId, transformDoc(validator, doc)); // 1111 - })) { // 1112 - throw new Meteor.Error(403, "Access denied"); // 1113 - } // 1114 - // 1115 - // Back when we supported arbitrary client-provided selectors, we actually // 1116 - // rewrote the selector to {_id: {$in: [ids that we found]}} before passing to // 1117 - // Mongo to avoid races, but since selector is guaranteed to already just be // 1118 - // an ID, we don't have to any more. // 1119 - // 1120 - return self._collection.remove.call(self._collection, selector); // 1121 -}; // 1122 - // 1123 -/** // 1124 - * @deprecated in 0.9.1 // 1125 - */ // 1126 -Meteor.Collection = Mongo.Collection; // 1127 - // 1128 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.mongo = { - MongoInternals: MongoInternals, - MongoTest: MongoTest, - Mongo: Mongo -}; - -})(); - -//# sourceMappingURL=mongo.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/mongo.js.map b/web-app/.meteor/local/build/programs/server/packages/mongo.js.map deleted file mode 100644 index f7a96ef..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mongo.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["mongo/mongo_driver.js","mongo/oplog_tailing.js","mongo/observe_multiplex.js","mongo/doc_fetcher.js","mongo/polling_observe_driver.js","mongo/oplog_observe_driver.js","mongo/local_collection_driver.js","mongo/remote_collection_driver.js","mongo/collection.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,G;AACA,+D;AACA,qE;AACA,qB;AACA,E;AACA,uE;AACA,8C;AACA,G;;AAEA,+B;AACA,qC;AACA,kC;AACA,wD;;AAEA,oB;AACA,e;;AAEA,6B;AACA,Y;AACA,yD;AACA,mB;AACA,G;AACA,E;;AAEA,6C;AACA,0E;AACA,oB;AACA,0B;AACA,mC;;AAEA,8E;AACA,sE;AACA,6C;AACA,kC;AACA,2B;AACA,8D;AACA,K;AACA,iB;AACA,yC;AACA,qD;AACA,O;AACA,e;AACA,G;AACA,e;AACA,E;;AAEA,4E;AACA,6B;AACA,2E;AACA,iD;AACA,oC;AACA,c;AACA,E;;AAEA,gE;AACA,kE;;AAEA,sD;AACA,2C;AACA,sC;AACA,kC;AACA,G;AACA,6C;AACA,sD;AACA,G;AACA,uD;AACA,kC;AACA,yE;AACA,G;AACA,8C;AACA,gF;AACA,4E;AACA,gF;AACA,+C;AACA,oB;AACA,G;AACA,mB;AACA,E;;AAEA,sD;AACA,iC;AACA,qE;AACA,+E;AACA,+B;AACA,oD;AACA,G;AACA,2C;AACA,wD;AACA,G;AACA,8C;AACA,gF;AACA,4E;AACA,gF;AACA,+C;AACA,oB;AACA,G;AACA,sC;AACA,qE;AACA,G;AACA,uE;AACA,4E;AACA,mB;AACA,E;;AAEA,yD;AACA,wD;AACA,oB;;AAEA,uD;AACA,yC;AACA,gC;;AAEA,qB;AACA,wC;AACA,yD;AACA,8B;AACA,kC;AACA,2B;AACA,gC;AACA,6B;AACA,K;AACA,K;AACA,a;AACA,E;;;AAGA,2C;AACA,kB;AACA,0B;AACA,iC;AACA,kC;;AAEA,iE;;AAEA,qE;AACA,uE;AACA,sD;AACA,gD;AACA,8C;AACA,G;;AAEA,sE;AACA,sB;AACA,iE;AACA,oE;AACA,iB;AACA,wE;AACA,2C;AACA,kE;AACA,+C;AACA,0C;AACA,G;;AAEA,6E;AACA,4B;AACA,mC;AACA,6E;AACA,2E;AACA,oD;AACA,qD;AACA,G;;AAEA,iB;AACA,8E;AACA,yE;AACA,uD;AACA,uB;AACA,2B;AACA,0B;;;AAGA,iC;AACA,kB;AACA,Q;AACA,iB;AACA,2B;AACA,0B;AACA,kB;AACA,oB;AACA,S;;AAEA,iE;AACA,0C;AACA,6D;AACA,2B;AACA,iE;AACA,qC;AACA,kD;AACA,4C;AACA,+D;AACA,6B;AACA,8B;AACA,mB;AACA,e;AACA,kD;AACA,6E;AACA,8E;AACA,2E;AACA,6E;AACA,iE;AACA,mC;AACA,a;AACA,c;;AAEA,2C;AACA,oC;AACA,Q;AACA,8C;AACA,K;AACA,I;;AAEA,iE;AACA,iC;;AAEA,uD;AACA,gF;AACA,4C;AACA,G;AACA,E;;AAEA,8C;AACA,kB;;AAEA,gB;AACA,2D;;AAEA,0B;AACA,sC;AACA,2B;AACA,kB;AACA,uB;;AAEA,+D;AACA,8D;AACA,2B;AACA,2D;AACA,E;;AAEA,kD;AACA,qE;AACA,kB;;AAEA,gB;AACA,mE;;AAEA,0B;AACA,wD;AACA,uB;AACA,E;;AAEA,8D;AACA,6C;AACA,kB;;AAEA,gB;AACA,6E;;AAEA,4B;AACA,2B;AACA,mB;AACA,wD;AACA,uB;AACA,gB;AACA,E;;AAEA,gE;AACA,oE;AACA,kE;AACA,kE;AACA,gE;AACA,0D;AACA,kB;AACA,iD;AACA,Y;AACA,8B;AACA,M;AACA,uC;AACA,E;;AAEA,6E;AACA,kC;AACA,6D;AACA,iD;AACA,E;;;AAGA,kC;;AAEA,6E;AACA,8E;AACA,+E;AACA,4E;AACA,wB;AACA,E;AACA,oE;AACA,sE;AACA,mE;AACA,yE;AACA,4D;AACA,E;AACA,8D;AACA,mE;AACA,6D;;AAEA,yD;AACA,iC;AACA,gB;AACA,uD;AACA,gB;AACA,K;AACA,sB;AACA,iB;AACA,4B;AACA,iB;AACA,gB;AACA,I;AACA,E;;AAEA,mD;AACA,yD;AACA,E;;AAEA,wE;AACA,yD;AACA,kB;;AAEA,gC;AACA,iB;AACA,yB;AACA,Y;AACA,I;;AAEA,gE;AACA,sC;AACA,sB;AACA,iB;AACA,W;AACA,G;;AAEA,mD;AACA,0C;AACA,wB;AACA,0D;AACA,W;AACA,G;;AAEA,sC;AACA,6B;AACA,qE;AACA,I;AACA,8E;AACA,O;AACA,yD;AACA,yE;AACA,8C;AACA,e;AACA,sB;AACA,Y;AACA,G;AACA,E;;AAEA,2E;AACA,S;AACA,0E;AACA,kB;AACA,gD;AACA,2E;AACA,+E;AACA,8E;AACA,W;AACA,oE;AACA,oB;AACA,uC;AACA,qD;AACA,O;AACA,U;AACA,+B;AACA,G;AACA,E;;AAEA,wE;AACA,yD;AACA,kB;;AAEA,gE;AACA,sC;AACA,sB;AACA,iB;AACA,yB;AACA,Q;AACA,c;AACA,G;;AAEA,sC;AACA,6B;AACA,6C;AACA,I;AACA,8E;;AAEA,O;AACA,yD;AACA,yE;AACA,8C;AACA,e;AACA,sB;AACA,Y;AACA,G;AACA,E;;AAEA,2E;AACA,kB;;AAEA,sC;AACA,6B;AACA,yD;AACA,2C;AACA,I;AACA,kE;;AAEA,O;AACA,wD;AACA,wB;AACA,e;AACA,sB;AACA,Y;AACA,G;AACA,E;;AAEA,6E;AACA,kE;AACA,kB;;AAEA,kD;AACA,uB;AACA,mB;AACA,G;;AAEA,gE;AACA,sC;AACA,sB;AACA,iB;AACA,yB;AACA,Q;AACA,c;AACA,G;;AAEA,kE;AACA,gE;AACA,+D;AACA,uE;AACA,gB;AACA,sC;AACA,qE;;AAEA,8C;AACA,qC;AACA,oB;AACA,uD;AACA,iC;AACA,W;AACA,G;;AAEA,6B;;AAEA,sC;AACA,6B;AACA,6C;AACA,I;AACA,qD;AACA,O;AACA,yD;AACA,iC;AACA,0D;AACA,gD;AACA,8C;AACA,2E;AACA,6E;AACA,6B;AACA,wD;;AAEA,2E;AACA,iE;;AAEA,+C;AACA,0C;;AAEA,+C;AACA,yE;AACA,qB;AACA,2B;AACA,c;AACA,gB;AACA,O;AACA,K;;AAEA,8D;AACA,4E;AACA,uE;AACA,oE;AACA,+E;AACA,yC;AACA,Q;AACA,2E;AACA,+E;AACA,sE;AACA,Q;AACA,kC;AACA,+E;AACA,mC;AACA,4C;AACA,0B;AACA,uE;AACA,6E;AACA,mC;AACA,gC;AACA,gF;AACA,+E;AACA,4E;AACA,gD;AACA,iD;AACA,c;AACA,kC;AACA,S;AACA,Q;AACA,Y;AACA,wB;AACA,2C;AACA,+D;AACA,sB;AACA,kD;AACA,kD;AACA,8D;AACA,6D;AACA,wC;AACA,8C;AACA,0C;AACA,4C;AACA,a;AACA,W;AACA,gC;AACA,Y;AACA,K;AACA,e;AACA,sB;AACA,Y;AACA,G;AACA,E;;AAEA,wC;AACA,wB;AACA,uB;AACA,sB;AACA,iC;AACA,sB;AACA,Y;AACA,uB;AACA,K;AACA,G;AACA,8B;AACA,oB;AACA,6E;AACA,G;AACA,kB;AACA,E;;AAEA,6B;;AAEA,sB;AACA,yD;AACA,+E;AACA,+C;AACA,yB;AACA,gB;AACA,+D;AACA,gB;;AAEA,+E;AACA,gF;AACA,iE;AACA,+D;AACA,gB;;AAEA,e;AACA,E;;AAEA,uE;AACA,2E;AACA,4E;AACA,0E;AACA,0E;AACA,iE;AACA,wE;AACA,qE;AACA,2E;AACA,6E;AACA,uE;AACA,yE;AACA,qE;AACA,wE;AACA,gB;;AAEA,a;AACA,iE;AACA,8C;AACA,iB;AACA,mE;AACA,gE;AACA,gE;AACA,mD;AACA,uE;AACA,gE;AACA,yB;AACA,U;AACA,iB;AACA,G;;AAEA,oD;AACA,4B;AACA,e;AACA,wB;AACA,I;AACA,4B;AACA,e;AACA,gB;AACA,I;;AAEA,mC;;AAEA,8B;AACA,Y;AACA,kB;AACA,qF;AACA,Y;AACA,0D;AACA,wE;AACA,kC;AACA,0C;AACA,0C;AACA,4C;AACA,oD;AACA,+B;AACA,8B;AACA,kD;AACA,4B;AACA,K;AACA,I;;AAEA,yC;AACA,qC;AACA,kE;AACA,c;AACA,sE;AACA,sE;AACA,kC;AACA,oD;AACA,uE;AACA,wE;AACA,4E;AACA,uC;AACA,kC;AACA,0C;AACA,2B;AACA,gC;AACA,0C;AACA,mD;AACA,kD;AACA,6B;AACA,yB;AACA,0B;AACA,I;;AAEA,a;AACA,E;;AAEA,4E;AACA,kE;AACA,oB;AACA,uE;AACA,I;AACA,G;;AAEA,+E;AACA,6E;AACA,Q;AACA,2E;AACA,iE;AACA,kB;AACA,oD;AACA,uB;AACA,iB;AACA,G;;AAEA,mD;AACA,4C;AACA,oC;AACA,0C;AACA,mC;AACA,E;;AAEA,+E;AACA,kB;;AAEA,6B;AACA,kB;;AAEA,oB;AACA,oE;AACA,E;;AAEA,wE;AACA,wD;AACA,kB;AACA,6B;AACA,kB;;AAEA,0B;AACA,oB;AACA,kE;AACA,E;;AAEA,6E;AACA,oC;AACA,yE;AACA,6D;AACA,kB;AACA,4C;;AAEA,+E;AACA,+C;AACA,sD;AACA,0B;AACA,4E;AACA,gB;AACA,E;AACA,yE;AACA,kB;;AAEA,8E;AACA,mC;AACA,sD;AACA,0B;AACA,iE;AACA,gB;AACA,E;;AAEA,U;;AAEA,qD;AACA,E;AACA,yE;AACA,6E;AACA,6E;AACA,4E;AACA,mD;AACA,E;AACA,yD;AACA,6D;AACA,E;AACA,yE;AACA,8E;AACA,8E;AACA,gC;AACA,E;AACA,+E;AACA,sC;AACA,E;AACA,gF;AACA,yB;AACA,E;AACA,mE;AACA,4E;AACA,iB;AACA,6E;AACA,wB;AACA,+E;AACA,4E;AACA,8E;;AAEA,kE;AACA,kB;AACA,uC;AACA,8D;AACA,+B;AACA,E;;AAEA,8C;AACA,kB;;AAEA,sB;AACA,8C;AACA,iC;AACA,E;;AAEA,gE;AACA,0C;AACA,oB;;AAEA,8C;AACA,iD;AACA,yE;;AAEA,mC;AACA,qE;AACA,kC;AACA,+E;AACA,+C;AACA,iC;AACA,4B;AACA,W;AACA,K;;AAEA,iD;AACA,0C;AACA,I;AACA,G;;AAEA,2E;AACA,2E;AACA,uD;AACA,wB;AACA,uC;AACA,E;;AAEA,6C;AACA,mD;AACA,E;;AAEA,gF;AACA,+E;AACA,a;;AAEA,kD;AACA,kB;AACA,0D;AACA,gE;AACA,E;;AAEA,yE;AACA,wE;AACA,+C;AACA,mD;AACA,kB;AACA,gD;AACA,C;;AAEA,iD;AACA,kB;AACA,qE;AACA,E;;AAEA,wD;AACA,kB;AACA,8E;AACA,qC;AACA,iD;AACA,E;;AAEA,8D;AACA,iC;AACA,kB;AACA,sE;;AAEA,wE;AACA,gD;AACA,sB;AACA,6B;AACA,+B;AACA,4B;AACA,I;;AAEA,2E;AACA,+B;AACA,mC;AACA,iC;AACA,8E;AACA,+D;AACA,kC;AACA,gF;AACA,+B;AACA,sC;AACA,8E;AACA,gF;AACA,8E;AACA,8E;AACA,oC;AACA,gE;AACA,wC;AACA,sC;AACA,K;AACA,G;;AAEA,iC;AACA,yE;AACA,wC;;AAEA,qE;AACA,E;;AAEA,yE;AACA,kB;AACA,sE;;AAEA,4B;AACA,8C;AACA,0E;AACA,uE;AACA,4D;AACA,oE;AACA,oD;AACA,2C;AACA,U;AACA,2B;AACA,G;;AAEA,2E;AACA,wE;AACA,kE;AACA,4C;AACA,2C;AACA,sE;AACA,gD;AACA,E;;AAEA,uC;AACA,4B;AACA,oB;;AAEA,kB;AACA,qD;;AAEA,4B;AACA,0D;;AAEA,2E;AACA,2E;AACA,gF;AACA,+E;AACA,gF;AACA,gF;AACA,uE;AACA,oD;AACA,4C;AACA,O;;AAEA,0B;AACA,mC;;AAEA,iB;AACA,K;AACA,I;;AAEA,yC;AACA,oB;;AAEA,iC;AACA,mB;;AAEA,0E;AACA,8E;AACA,2D;AACA,kB;AACA,kB;AACA,mC;AACA,uB;AACA,mE;AACA,K;AACA,I;;AAEA,kE;AACA,qC;AACA,oB;AACA,iB;AACA,wC;AACA,2E;AACA,O;AACA,e;AACA,I;;AAEA,wB;AACA,oB;;AAEA,8B;AACA,4B;;AAEA,kD;AACA,I;;AAEA,wC;AACA,sB;AACA,oB;;AAEA,2B;AACA,I;;AAEA,sB;AACA,oB;AACA,gC;AACA,I;;AAEA,sB;AACA,oB;AACA,2C;AACA,I;;AAEA,0C;AACA,qC;AACA,oB;AACA,kB;AACA,0B;AACA,Y;AACA,+C;AACA,mC;AACA,kC;AACA,S;AACA,qB;AACA,K;AACA,G;AACA,G;;AAEA,4E;AACA,kB;AACA,0C;AACA,uD;;AAEA,gE;;AAEA,sB;AACA,yB;AACA,0B;AACA,kB;AACA,kB;AACA,e;AACA,W;AACA,uC;AACA,qB;AACA,0E;AACA,2E;AACA,oE;AACA,mB;AACA,O;AACA,6E;AACA,wD;AACA,kB;AACA,e;AACA,gB;AACA,6E;AACA,8E;AACA,+E;AACA,qD;AACA,wB;AACA,yB;AACA,c;AACA,8D;AACA,qB;AACA,yC;AACA,S;AACA,qE;AACA,2C;AACA,sB;AACA,sC;AACA,6E;AACA,yE;AACA,oB;AACA,qC;AACA,c;AACA,O;AACA,K;AACA,I;;AAEA,qB;;AAEA,U;AACA,uB;AACA,qB;AACA,qB;AACA,K;AACA,I;AACA,E;;AAEA,sD;AACA,4C;AACA,kB;;AAEA,2C;AACA,+E;AACA,G;;AAEA,gF;AACA,oC;AACA,yC;AACA,oD;AACA,yD;AACA,wE;AACA,G;;AAEA,kC;AACA,qD;;AAEA,iC;AACA,0B;;AAEA,gF;AACA,6E;AACA,2E;AACA,uC;AACA,uD;AACA,0D;AACA,Y;AACA,yB;AACA,yC;AACA,4C;AACA,yB;AACA,6B;AACA,uD;AACA,+B;AACA,S;AACA,S;AACA,0D;AACA,K;AACA,K;;AAEA,gE;;AAEA,oB;AACA,wB;AACA,6B;AACA,mB;AACA,8E;AACA,4E;AACA,6B;AACA,+C;AACA,2C;AACA,sB;AACA,+E;AACA,wE;AACA,a;AACA,sE;AACA,sB;AACA,qB;AACA,wE;AACA,iE;AACA,uB;AACA,S;AACA,sB;AACA,8D;AACA,8E;AACA,sB;AACA,4E;AACA,yB;AACA,4C;AACA,sB;AACA,a;AACA,uE;AACA,8D;AACA,sB;AACA,qB;AACA,wE;AACA,iE;AACA,uB;AACA,S;AACA,iE;;AAEA,8E;AACA,qC;AACA,2C;AACA,wB;AACA,+B;AACA,uB;AACA,8C;AACA,4C;AACA,4D;AACA,O;;AAEA,+C;AACA,+C;AACA,G;;AAEA,kD;AACA,yD;;AAEA,uB;AACA,E;;AAEA,wE;AACA,8E;AACA,0E;AACA,8E;AACA,kC;;AAEA,0D;AACA,qB;AACA,wD;AACA,0D;AACA,gC;AACA,K;;AAEA,U;AACA,uB;AACA,6C;AACA,wB;AACA,S;AACA,K;AACA,I;AACA,E;;AAEA,gE;AACA,2D;AACA,0D;AACA,gC;AACA,oB;AACA,uC;AACA,+C;AACA,O;AACA,qE;AACA,U;AACA,yB;AACA,G;AACA,E;;AAEA,6D;AACA,E;AACA,wC;AACA,8E;AACA,gF;AACA,U;AACA,8E;AACA,2E;AACA,kE;AACA,2E;AACA,yE;AACA,gF;AACA,4E;AACA,iD;AACA,yE;AACA,6E;AACA,wD;AACA,yC;AACA,gF;AACA,4E;AACA,8E;AACA,+E;AACA,gF;AACA,uE;AACA,2E;AACA,0E;AACA,8E;AACA,4B;AACA,8D;AACA,4C;AACA,kB;;AAEA,4E;AACA,sC;AACA,4C;AACA,uC;AACA,6E;AACA,mD;AACA,yE;AACA,G;;AAEA,sD;AACA,qB;AACA,mB;AACA,mD;AACA,kB;AACA,kB;AACA,2C;AACA,Y;AACA,+B;AACA,K;AACA,K;AACA,E;;AAEA,sE;AACA,6D;AACA,iD;AACA,kD;;AAEA,4C;;;;;;;;;;;;;;;;;;;AC9vCA,0C;;AAEA,8B;;AAEA,qE;;AAEA,+D;AACA,+D;AACA,iD;AACA,gC;AACA,gD;AACA,E;;AAEA,4B;AACA,wE;AACA,E;;AAEA,yB;AACA,oB;AACA,oB;AACA,yB;AACA,oB;AACA,yB;AACA,qB;AACA,yB;AACA,mE;AACA,qC;AACA,M;AACA,sD;AACA,E;;AAEA,2C;AACA,kB;AACA,4B;AACA,wB;;AAEA,wC;AACA,mC;AACA,wB;AACA,0B;AACA,mC;AACA,4C;AACA,6D;AACA,K;AACA,6B;AACA,0D;AACA,U;AACA,qC;AACA,qD;AACA,+C;AACA,I;;AAEA,2E;AACA,4E;AACA,yD;AACA,sE;AACA,I;AACA,2E;AACA,oE;AACA,4D;AACA,I;AACA,2E;AACA,gF;AACA,yE;AACA,6E;AACA,6E;AACA,0E;AACA,8D;AACA,I;AACA,2E;AACA,+B;AACA,+B;;AAEA,yC;AACA,qD;AACA,K;;AAEA,oD;AACA,6B;;AAEA,uB;AACA,E;;AAEA,iC;AACA,qB;AACA,oB;AACA,sB;AACA,a;AACA,yB;AACA,yB;AACA,8B;AACA,uC;AACA,I;AACA,8C;AACA,oB;AACA,sB;AACA,gE;;AAEA,4E;AACA,6B;;AAEA,oC;AACA,+D;AACA,gE;AACA,kD;AACA,uB;AACA,0D;AACA,O;AACA,gE;AACA,Y;AACA,yB;AACA,4B;AACA,O;AACA,M;AACA,I;AACA,0E;AACA,oC;AACA,yC;AACA,oB;AACA,sB;AACA,oE;AACA,yD;AACA,I;AACA,6E;AACA,uE;AACA,uB;AACA,4E;AACA,yB;AACA,kC;AACA,oB;AACA,sB;AACA,qE;;AAEA,gF;AACA,gB;AACA,6B;;AAEA,4B;AACA,2E;AACA,+E;AACA,gE;AACA,W;AACA,+D;AACA,oD;AACA,mD;AACA,c;AACA,mB;AACA,8E;AACA,+B;AACA,sE;AACA,gC;AACA,O;AACA,K;;AAEA,sB;AACA,a;;AAEA,qB;AACA,wE;AACA,a;AACA,K;;AAEA,0B;AACA,Y;AACA,2E;;AAEA,6E;AACA,yC;AACA,a;AACA,K;;;AAGA,+E;AACA,6E;AACA,kD;AACA,qD;AACA,8B;AACA,4E;AACA,oB;AACA,K;AACA,uB;AACA,wE;AACA,a;AACA,I;AACA,8B;AACA,oB;AACA,iE;AACA,gD;AACA,gE;AACA,8E;AACA,yC;AACA,K;;AAEA,uE;AACA,6E;AACA,0E;AACA,6E;AACA,sE;AACA,8E;AACA,gF;AACA,uB;AACA,M;AACA,8E;AACA,2D;AACA,oD;AACA,qC;AACA,0D;AACA,yE;AACA,8D;AACA,yD;AACA,qC;;AAEA,2E;AACA,wC;AACA,uB;AACA,sD;AACA,qC;AACA,+B;AACA,6E;AACA,8C;AACA,8E;AACA,yC;AACA,K;;AAEA,iC;AACA,gE;AACA,qE;;AAEA,yD;AACA,yB;AACA,0D;AACA,kD;AACA,2E;AACA,yE;AACA,8B;AACA,gD;AACA,K;;AAEA,kD;AACA,yD;;AAEA,sD;AACA,yC;AACA,mC;AACA,iC;AACA,O;AACA,M;AACA,+B;AACA,I;;AAEA,kC;AACA,oB;AACA,2B;AACA,a;AACA,8B;AACA,8B;AACA,W;AACA,iE;AACA,6E;AACA,wC;AACA,yD;AACA,mD;AACA,qC;;AAEA,iE;AACA,yB;AACA,0B;AACA,e;;AAEA,6E;AACA,mD;AACA,mD;AACA,qB;AACA,W;;AAEA,6C;;AAEA,oE;AACA,6D;AACA,wC;AACA,6C;AACA,W;;AAEA,4E;AACA,+C;AACA,kC;;AAEA,gF;AACA,yB;AACA,8C;AACA,4C;AACA,0C;AACA,8B;AACA,kB;AACA,wC;AACA,sC;AACA,W;;AAEA,uC;;AAEA,qE;AACA,wB;AACA,sB;AACA,2E;AACA,2C;AACA,S;AACA,iB;AACA,mC;AACA,O;AACA,O;AACA,I;AACA,sC;AACA,oB;AACA,+B;AACA,8C;AACA,4D;AACA,sC;AACA,sD;AACA,gC;AACA,K;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACjUA,0C;;AAEA,yC;AACA,kB;;AAEA,6C;AACA,0C;;AAEA,2D;AACA,iD;;AAEA,kC;AACA,kD;AACA,+C;AACA,qB;AACA,iC;AACA,4D;AACA,+B;AACA,sE;AACA,4E;AACA,c;AACA,mD;;AAEA,wD;AACA,+C;AACA,8D;AACA,M;AACA,K;AACA,E;;AAEA,wC;AACA,kD;AACA,oB;;AAEA,2E;AACA,qE;AACA,qE;AACA,uB;AACA,qC;AACA,sB;AACA,gF;AACA,mD;;AAEA,6D;AACA,8C;;AAEA,qC;AACA,yC;AACA,qE;AACA,+B;AACA,6B;AACA,qD;AACA,O;AACA,wD;AACA,6B;AACA,I;;AAEA,0E;AACA,yE;AACA,I;AACA,8E;AACA,8E;AACA,8D;AACA,+B;AACA,oB;;AAEA,4E;AACA,+E;AACA,0B;AACA,uB;AACA,2E;;AAEA,6B;;AAEA,6D;AACA,+C;;AAEA,mC;AACA,6D;AACA,mB;AACA,K;AACA,I;AACA,6B;AACA,oB;AACA,4B;;AAEA,yE;AACA,iD;AACA,oD;AACA,iD;;AAEA,4E;AACA,kE;AACA,mB;AACA,6D;AACA,oD;;AAEA,8E;AACA,4D;AACA,yB;AACA,I;;AAEA,+E;AACA,8C;AACA,sB;AACA,oB;AACA,uC;AACA,wB;AACA,gE;AACA,iC;AACA,O;AACA,I;;AAEA,2E;AACA,8E;AACA,gF;AACA,yE;AACA,2E;AACA,8C;AACA,8B;AACA,oB;AACA,qC;AACA,wB;AACA,uE;AACA,yC;AACA,mC;AACA,O;AACA,I;;AAEA,8E;AACA,8E;AACA,4E;AACA,0B;AACA,oB;AACA,uC;AACA,yB;AACA,6E;AACA,W;AACA,O;AACA,I;AACA,8B;AACA,oB;AACA,sB;AACA,kE;AACA,Q;AACA,6C;AACA,I;AACA,uB;AACA,0C;AACA,I;AACA,iD;AACA,oB;AACA,uC;AACA,mD;AACA,yB;AACA,e;;AAEA,8C;AACA,8E;AACA,2E;AACA,0E;AACA,gB;AACA,2E;;AAEA,gF;AACA,c;AACA,2B;AACA,yE;AACA,wE;AACA,O;;AAEA,2E;AACA,gF;AACA,gF;AACA,6E;AACA,wE;AACA,yD;AACA,8D;AACA,oB;AACA,iB;AACA,kD;AACA,uE;AACA,4D;AACA,S;AACA,O;AACA,I;;AAEA,gF;AACA,2E;AACA,gF;AACA,qE;AACA,gC;AACA,oB;AACA,oC;AACA,sE;AACA,kE;AACA,a;AACA,a;AACA,oD;AACA,iD;AACA,4C;AACA,uE;AACA,oC;AACA,wB;AACA,wB;AACA,qE;AACA,U;AACA,wB;AACA,O;AACA,G;AACA,G;;;AAGA,4B;AACA,mD;AACA,kB;AACA,wE;AACA,2C;AACA,kC;AACA,uD;AACA,0B;AACA,yC;AACA,2D;AACA,2E;AACA,6E;AACA,0E;AACA,gB;AACA,yD;AACA,oC;AACA,Q;AACA,K;AACA,K;AACA,wB;AACA,mC;AACA,E;AACA,4C;AACA,kB;AACA,oB;AACA,W;AACA,uB;AACA,2C;AACA,E;;;;;;;;;;;;;;;;;;;ACjPA,kC;AACA,0C;;AAEA,yC;AACA,kB;AACA,0C;AACA,qC;AACA,kC;AACA,E;;AAEA,gC;AACA,2E;AACA,W;AACA,I;AACA,6E;AACA,2E;AACA,kD;AACA,I;AACA,4E;AACA,iC;AACA,4D;AACA,oB;;AAEA,kC;AACA,gC;AACA,4B;;AAEA,8E;AACA,gD;AACA,sD;AACA,0D;AACA,a;AACA,K;;AAEA,sE;;AAEA,uB;AACA,W;AACA,gD;AACA,6C;AACA,yE;AACA,uD;AACA,uC;AACA,+E;AACA,yE;AACA,+E;AACA,kC;AACA,2C;AACA,2C;AACA,S;AACA,mB;AACA,uC;AACA,6B;AACA,S;AACA,iB;AACA,0E;AACA,kC;AACA,oD;AACA,O;AACA,a;AACA,G;AACA,G;;AAEA,kC;;;;;;;;;;;;;;;;;;;AC/DA,2C;AACA,kB;;AAEA,sD;AACA,0C;AACA,kC;AACA,0C;AACA,2B;AACA,wB;;AAEA,uE;AACA,6B;;AAEA,kE;AACA,kC;AACA,uB;;AAEA,+E;AACA,gF;AACA,6E;AACA,+E;AACA,0E;AACA,+E;AACA,iD;AACA,wC;AACA,sE;;AAEA,iE;AACA,iC;AACA,2C;AACA,yD;;AAEA,4C;AACA,mD;;AAEA,kC;AACA,sD;AACA,8E;AACA,8E;AACA,mE;AACA,qD;AACA,gB;AACA,qD;AACA,0E;AACA,6E;AACA,sD;AACA,kD;AACA,sC;AACA,K;AACA,I;AACA,oE;;AAEA,yE;AACA,sE;AACA,c;AACA,I;AACA,6E;AACA,+E;AACA,U;AACA,sC;AACA,+D;AACA,U;AACA,4C;AACA,4D;AACA,0C;AACA,2C;AACA,O;AACA,G;;AAEA,qC;AACA,2C;;AAEA,2D;AACA,oD;AACA,E;;AAEA,0C;AACA,uE;AACA,kD;AACA,oB;AACA,8C;AACA,a;AACA,wC;AACA,2C;AACA,wB;AACA,O;AACA,I;;AAEA,iD;AACA,I;AACA,+E;AACA,oE;AACA,2E;AACA,a;AACA,I;AACA,yE;AACA,+B;AACA,oB;AACA,sE;AACA,4D;AACA,wC;AACA,yE;AACA,2C;;AAEA,8E;AACA,uB;AACA,gD;AACA,0D;AACA,yD;AACA,I;AACA,8B;AACA,oB;AACA,uE;AACA,gD;AACA,0D;AACA,yD;AACA,0D;AACA,4D;AACA,yC;AACA,wB;AACA,O;AACA,I;;AAEA,2B;AACA,oB;AACA,wC;;AAEA,sB;AACA,a;;AAEA,sB;AACA,mC;AACA,sB;AACA,mB;AACA,2C;AACA,mE;AACA,K;;AAEA,+D;;AAEA,oE;AACA,6C;AACA,6B;;AAEA,gD;AACA,S;AACA,4E;AACA,iB;AACA,iD;AACA,2E;AACA,8E;AACA,gF;AACA,gF;AACA,yB;AACA,qC;AACA,oB;AACA,8C;AACA,2E;AACA,e;AACA,O;;AAEA,uE;AACA,8E;AACA,4D;AACA,+E;AACA,0E;AACA,2D;AACA,sE;AACA,sD;AACA,8E;AACA,a;AACA,K;;AAEA,iB;AACA,yB;AACA,wC;AACA,kE;AACA,K;;AAEA,gF;AACA,mE;AACA,4B;AACA,c;AACA,gC;;AAEA,gF;AACA,wE;AACA,+C;AACA,+B;;AAEA,8E;AACA,mE;AACA,yE;AACA,qD;AACA,2C;AACA,2C;AACA,sB;AACA,S;AACA,O;AACA,I;;AAEA,qB;AACA,oB;AACA,yB;AACA,uD;AACA,uD;AACA,8C;AACA,oB;AACA,O;AACA,6D;AACA,uD;AACA,G;AACA,G;;;;;;;;;;;;;;;;;;;ACpNA,kC;AACA,0C;;AAEA,a;AACA,uB;AACA,uB;AACA,kB;AACA,E;;AAEA,yE;AACA,6C;AACA,qC;AACA,4C;AACA,sB;AACA,S;AACA,+B;AACA,iB;AACA,0C;AACA,gB;AACA,K;AACA,I;AACA,E;;AAEA,6E;AACA,6E;AACA,uE;AACA,+E;AACA,mC;AACA,yC;AACA,kB;AACA,gD;;AAEA,sD;AACA,0C;AACA,0C;;AAEA,wB;AACA,6E;AACA,G;;AAEA,8B;AACA,8E;AACA,6C;AACA,oD;;AAEA,gD;AACA,8D;AACA,oC;AACA,2E;AACA,qD;AACA,6E;AACA,6E;AACA,+C;AACA,8D;;AAEA,wD;AACA,wD;AACA,kC;AACA,0B;AACA,sE;AACA,+E;AACA,2D;AACA,U;AACA,oB;AACA,4B;AACA,wB;AACA,mC;AACA,iD;AACA,G;;AAEA,8E;AACA,8E;AACA,mD;AACA,mC;;AAEA,wB;AACA,yB;;AAEA,2D;AACA,kD;;AAEA,4C;;AAEA,kD;AACA,kC;AACA,gE;AACA,sE;AACA,+E;AACA,+B;AACA,2E;AACA,a;AACA,kF;AACA,gE;AACA,4B;;AAEA,iD;AACA,iC;AACA,4B;;AAEA,yC;AACA,6C;;AAEA,8E;AACA,2B;AACA,yE;AACA,yC;AACA,8B;AACA,M;AACA,K;;AAEA,8D;AACA,uE;AACA,wC;AACA,qE;AACA,mC;AACA,4C;AACA,8E;AACA,gF;AACA,4B;AACA,oC;AACA,kB;AACA,uE;AACA,+C;AACA,iD;AACA,gB;AACA,yD;AACA,W;AACA,Y;AACA,O;AACA,O;AACA,K;;AAEA,yC;AACA,mC;AACA,sD;AACA,qE;AACA,qD;AACA,iB;AACA,e;AACA,qC;AACA,gF;AACA,0D;AACA,gC;AACA,2D;AACA,4B;AACA,uD;AACA,4B;AACA,kD;AACA,yE;AACA,+E;AACA,oB;AACA,iD;AACA,8B;AACA,a;AACA,gB;AACA,4D;AACA,S;AACA,S;AACA,K;AACA,K;;AAEA,gF;AACA,sC;AACA,+E;AACA,iB;AACA,8B;AACA,S;;AAEA,sE;AACA,uD;AACA,oD;AACA,4B;AACA,M;AACA,E;;AAEA,wC;AACA,qC;AACA,oB;AACA,yC;AACA,gC;AACA,wB;AACA,6D;AACA,8D;;AAEA,0E;AACA,yE;AACA,gF;AACA,+C;AACA,gE;AACA,sE;AACA,yD;AACA,yD;AACA,kE;AACA,gE;AACA,S;;AAEA,8D;AACA,mE;;AAEA,iD;AACA,sF;AACA,S;;AAEA,iD;AACA,oD;AACA,4D;AACA,O;AACA,O;AACA,I;AACA,mC;AACA,oB;AACA,yC;AACA,iC;AACA,oC;AACA,kE;AACA,e;;AAEA,+C;AACA,mD;;AAEA,+E;AACA,6E;;AAEA,6C;AACA,yE;AACA,sB;AACA,8D;AACA,2D;AACA,uC;AACA,6C;AACA,e;AACA,O;;AAEA,6E;;AAEA,gF;AACA,6E;AACA,6E;AACA,+E;AACA,+D;AACA,yC;AACA,e;;AAEA,oE;AACA,8E;AACA,gF;AACA,8E;AACA,mC;AACA,e;;AAEA,4E;AACA,wE;AACA,4E;AACA,8E;AACA,6E;AACA,gD;;AAEA,mD;AACA,O;AACA,I;AACA,mD;AACA,oB;AACA,yC;AACA,gE;AACA,oD;AACA,oD;AACA,uD;AACA,oC;AACA,8B;AACA,+C;AACA,O;AACA,I;AACA,oC;AACA,oB;AACA,yC;AACA,qE;;AAEA,6E;AACA,yD;AACA,mE;;AAEA,sD;;AAEA,iF;AACA,qC;AACA,yC;AACA,O;AACA,O;AACA,I;AACA,+E;AACA,mC;AACA,kC;AACA,oB;AACA,yC;AACA,yC;AACA,+E;AACA,6E;AACA,kD;AACA,yE;AACA,gC;AACA,O;AACA,I;AACA,kE;AACA,+E;AACA,sC;AACA,gC;AACA,oB;AACA,yC;AACA,uB;AACA,kC;AACA,sE;AACA,yD;AACA,8E;;AAEA,8B;AACA,wC;AACA,gE;AACA,mE;AACA,qE;AACA,6E;AACA,e;AACA,6E;AACA,8E;AACA,8C;AACA,kE;AACA,0C;;AAEA,8E;AACA,wE;AACA,wE;AACA,uE;AACA,+C;;AAEA,4E;AACA,iC;AACA,4D;AACA,0C;;AAEA,8D;;AAEA,sB;AACA,oC;AACA,4B;AACA,mC;AACA,c;AACA,kD;AACA,yC;AACA,O;AACA,O;AACA,I;AACA,8D;AACA,+E;AACA,sC;AACA,kC;AACA,oB;AACA,yC;AACA,qD;AACA,+E;;AAEA,oC;AACA,kC;AACA,mD;AACA,iC;AACA,O;AACA,O;AACA,I;AACA,qC;AACA,oB;AACA,yC;AACA,8E;;AAEA,oD;AACA,0E;AACA,2D;;AAEA,wC;AACA,kC;AACA,+C;AACA,iC;AACA,8C;AACA,6C;AACA,0C;AACA,0E;AACA,8E;;AAEA,8B;AACA,yE;AACA,2E;AACA,2E;AACA,qB;AACA,Y;AACA,6E;AACA,gF;AACA,8E;AACA,sC;AACA,iD;AACA,mD;AACA,iD;;AAEA,iC;AACA,sD;AACA,kB;AACA,4E;AACA,sC;AACA,0D;AACA,0D;AACA,sD;;AAEA,sD;AACA,wE;;AAEA,2B;AACA,4C;AACA,oB;AACA,8D;AACA,+C;AACA,a;AACA,W;AACA,oC;AACA,mD;AACA,gF;AACA,6E;AACA,0E;AACA,0B;AACA,6C;;AAEA,iD;AACA,4C;AACA,6D;AACA,4C;AACA,0D;;AAEA,qE;AACA,+D;;AAEA,qD;AACA,0E;AACA,6C;AACA,uD;;AAEA,0B;AACA,2C;AACA,qC;AACA,0C;AACA,oD;AACA,kB;AACA,4D;AACA,6C;AACA,8E;AACA,iE;AACA,mD;AACA,sC;AACA,a;AACA,W;AACA,gB;AACA,uG;AACA,S;AACA,O;AACA,O;AACA,I;AACA,wC;AACA,oB;AACA,yC;AACA,gD;AACA,8E;AACA,4B;AACA,wD;AACA,8D;AACA,+C;AACA,+E;AACA,4E;AACA,6E;AACA,kB;AACA,W;;AAEA,4D;AACA,6C;AACA,+E;;AAEA,sD;AACA,uD;AACA,yD;AACA,0B;AACA,+B;AACA,8E;AACA,6D;AACA,mE;AACA,sB;AACA,gD;AACA,mE;AACA,2D;AACA,qB;AACA,4B;AACA,8E;AACA,uC;AACA,uE;AACA,+E;AACA,+E;AACA,mD;AACA,yD;AACA,8C;AACA,qB;AACA,6E;AACA,2E;AACA,+E;AACA,0E;AACA,6E;AACA,kD;AACA,6C;AACA,mB;AACA,2B;AACA,4B;AACA,4E;AACA,4E;AACA,sC;AACA,oC;AACA,iC;AACA,iB;AACA,kB;AACA,a;AACA,qB;AACA,gF;AACA,6C;AACA,mB;AACA,yC;AACA,S;AACA,uE;AACA,sD;AACA,2C;AACA,2B;AACA,U;AACA,O;AACA,I;AACA,0B;AACA,oB;AACA,yC;AACA,8C;AACA,yD;AACA,iD;AACA,6C;AACA,qC;AACA,wB;AACA,W;AACA,S;AACA,O;AACA,I;AACA,4C;AACA,oB;AACA,yC;AACA,2D;AACA,O;AACA,I;AACA,oD;AACA,oB;AACA,yC;AACA,2B;AACA,4E;AACA,uD;AACA,2C;AACA,0E;AACA,wC;AACA,oD;AACA,e;AACA,O;;AAEA,0B;AACA,sC;AACA,6D;AACA,mC;AACA,iC;AACA,oC;AACA,+E;AACA,uE;AACA,4E;;AAEA,4E;AACA,sB;AACA,uD;AACA,kC;AACA,iC;AACA,4E;AACA,gF;AACA,4E;AACA,qB;AACA,uE;AACA,+E;AACA,0D;AACA,+E;AACA,iC;AACA,kC;AACA,2D;;AAEA,sD;AACA,4E;;AAEA,wB;AACA,yD;AACA,yD;AACA,0C;AACA,6E;AACA,2B;AACA,8C;AACA,wE;AACA,uC;;AAEA,0B;AACA,e;AACA,kD;AACA,uB;AACA,4C;AACA,sB;AACA,4D;AACA,wD;AACA,+C;AACA,6C;AACA,a;AACA,mB;AACA,W;AACA,gE;AACA,2C;AACA,iE;AACA,6E;AACA,sD;AACA,2C;AACA,2C;AACA,S;AACA,c;AACA,uD;AACA,O;AACA,O;AACA,I;AACA,Y;AACA,iC;AACA,oB;AACA,sB;AACA,0D;;AAEA,+C;;AAEA,sB;AACA,0C;;AAEA,2E;AACA,4B;AACA,8B;;AAEA,oC;AACA,I;;AAEA,gF;AACA,yE;AACA,I;AACA,0E;AACA,a;AACA,I;AACA,gF;AACA,W;AACA,I;AACA,4E;AACA,2E;AACA,qE;AACA,sE;AACA,qE;AACA,2B;AACA,oB;AACA,yC;AACA,wB;AACA,e;;AAEA,+E;AACA,qD;AACA,qC;AACA,+D;AACA,gD;;AAEA,6E;AACA,qE;AACA,gC;AACA,yB;AACA,6B;AACA,S;AACA,O;AACA,I;;AAEA,Y;AACA,iC;AACA,oB;AACA,4B;AACA,8B;;AAEA,iD;AACA,kB;AACA,uE;AACA,wB;AACA,e;;AAEA,8C;AACA,6C;;AAEA,gF;AACA,4E;AACA,qE;AACA,qB;AACA,gD;AACA,8E;AACA,kC;AACA,oE;AACA,W;AACA,qD;AACA,8C;AACA,yC;AACA,c;AACA,wC;AACA,W;AACA,c;AACA,mB;AACA,6D;AACA,6E;AACA,gF;AACA,2E;AACA,8E;AACA,sC;AACA,0C;AACA,iB;AACA,S;;AAEA,8E;AACA,+B;AACA,iE;AACA,gC;AACA,O;AACA,K;;AAEA,sB;AACA,a;;AAEA,mD;AACA,I;;AAEA,gF;AACA,4C;AACA,I;AACA,0E;AACA,8E;AACA,2D;AACA,8E;AACA,qE;AACA,I;AACA,gF;AACA,0D;AACA,wC;AACA,iC;AACA,oB;AACA,yC;AACA,wB;AACA,e;;AAEA,wE;AACA,qC;AACA,2C;AACA,0B;AACA,kC;AACA,O;;AAEA,8E;AACA,+B;AACA,4C;AACA,O;AACA,I;;AAEA,Y;AACA,8B;AACA,oB;;AAEA,sB;AACA,a;AACA,kE;AACA,sB;AACA,a;AACA,uC;AACA,uD;;AAEA,yC;AACA,2C;AACA,+C;AACA,0B;AACA,6C;AACA,yB;AACA,c;AACA,uC;AACA,O;AACA,O;AACA,I;;AAEA,gD;AACA,oB;AACA,gD;AACA,4E;AACA,gF;AACA,8E;AACA,8E;AACA,oE;AACA,6D;;AAEA,4E;AACA,+B;AACA,0C;;AAEA,8C;AACA,+B;AACA,6E;AACA,8C;AACA,+C;AACA,yC;AACA,iB;AACA,wD;AACA,O;AACA,I;;;AAGA,gF;AACA,kC;AACA,oD;AACA,I;AACA,+E;AACA,8E;AACA,4E;AACA,wD;AACA,oB;AACA,yC;;AAEA,+E;AACA,uB;AACA,wB;AACA,wC;AACA,O;;AAEA,oE;AACA,iD;AACA,2B;AACA,kD;AACA,gC;AACA,+B;AACA,S;AACA,yC;AACA,kC;AACA,S;;AAEA,iC;AACA,uE;AACA,2D;AACA,6C;AACA,iC;AACA,S;;AAEA,8E;AACA,e;AACA,6C;AACA,yD;AACA,oB;AACA,oE;AACA,6E;AACA,yC;AACA,+D;AACA,O;AACA,kD;AACA,gC;AACA,6E;AACA,S;;AAEA,oC;AACA,4C;AACA,mC;AACA,S;;AAEA,gE;AACA,O;AACA,I;;AAEA,gF;AACA,0E;AACA,W;AACA,I;AACA,6E;AACA,e;AACA,qB;AACA,oB;AACA,sB;AACA,a;AACA,yB;AACA,iD;AACA,oB;AACA,O;;AAEA,sE;AACA,yE;AACA,8E;AACA,yE;AACA,0B;AACA,gE;AACA,sC;AACA,O;AACA,iD;;AAEA,6D;AACA,2B;AACA,mC;AACA,6B;AACA,mC;AACA,kC;AACA,iC;;AAEA,6D;AACA,qD;AACA,I;;AAEA,0C;AACA,oB;AACA,yC;AACA,yB;;AAEA,wB;AACA,kD;AACA,iE;AACA,iF;AACA,O;;AAEA,0B;AACA,iC;AACA,O;AACA,G;AACA,G;;AAEA,8E;AACA,qE;AACA,+B;AACA,4E;AACA,8B;AACA,0C;;AAEA,oC;AACA,4B;AACA,iB;;AAEA,4E;AACA,+C;AACA,gF;AACA,0C;AACA,qE;;AAEA,uE;AACA,kD;AACA,uB;AACA,S;AACA,gE;AACA,iB;AACA,sC;AACA,qB;AACA,U;AACA,gB;AACA,K;AACA,G;;AAEA,4C;AACA,sE;AACA,0C;AACA,6E;AACA,4E;AACA,iC;AACA,6E;AACA,oE;AACA,uD;AACA,E;;AAEA,wD;AACA,uD;AACA,kD;AACA,oC;AACA,O;AACA,K;AACA,E;;AAEA,uD;;;;;;;;;;;;;;;;;;;ACt9BA,qC;AACA,kB;AACA,8B;AACA,E;;AAEA,qD;AACA,6B;AACA,kD;AACA,2B;AACA,E;;AAEA,2C;AACA,+B;AACA,oB;AACA,c;AACA,iC;AACA,iB;AACA,4D;AACA,K;AACA,2C;AACA,4C;AACA,6E;AACA,6C;AACA,oE;AACA,G;AACA,G;;AAEA,Y;AACA,kD;;;;;;;;;;;;;;;;;;;AC5BA,kD;AACA,uB;AACA,kB;AACA,uD;AACA,E;;AAEA,2D;AACA,yB;AACA,oB;AACA,iB;AACA,W;AACA,uD;AACA,yE;AACA,0C;AACA,oB;AACA,yD;AACA,S;AACA,e;AACA,G;AACA,G;;;AAGA,oE;AACA,qE;AACA,gE;AACA,mE;AACA,6B;;AAEA,uC;;AAEA,oC;AACA,6D;AACA,G;;AAEA,iB;AACA,4D;;AAEA,gF;AACA,G;;;;;;;;;;;;;;;;;;;ACtCA,sE;AACA,iE;;AAEA,G;AACA,+C;AACA,a;AACA,G;AACA,W;;AAEA,G;AACA,wC;AACA,kB;AACA,2B;AACA,S;AACA,qH;AACA,4B;AACA,oV;AACA,wI;;AAEA,iC;AACA,qE;;AAEA,kD;AACA,uX;AACA,G;AACA,6C;AACA,kB;AACA,2C;AACA,iE;;AAEA,iC;AACA,6E;AACA,6E;AACA,oE;AACA,gB;AACA,G;;AAEA,kD;AACA,oB;AACA,yE;AACA,G;;AAEA,mC;AACA,yE;AACA,sF;AACA,e;AACA,4B;AACA,oC;AACA,G;AACA,uE;AACA,0D;AACA,yC;AACA,G;AACA,sB;AACA,0B;AACA,2B;AACA,oB;AACA,uB;AACA,8B;AACA,c;;AAEA,iC;AACA,e;AACA,mC;AACA,wE;AACA,mD;AACA,M;AACA,U;AACA,gB;AACA,U;AACA,mC;AACA,wE;AACA,sB;AACA,M;AACA,U;AACA,G;;AAEA,qE;;AAEA,4C;AACA,yD;AACA,4B;AACA,8B;AACA,0C;AACA,2B;AACA,yC;AACA,M;AACA,qC;;AAEA,yB;AACA,6E;AACA,4E;AACA,mE;AACA,wB;AACA,qD;AACA,gD;AACA,uD;AACA,uE;AACA,Y;AACA,8C;AACA,K;AACA,G;;AAEA,kE;AACA,oB;AACA,iC;;AAEA,2D;AACA,6D;AACA,qE;AACA,oC;AACA,mD;AACA,+E;AACA,mC;AACA,Q;AACA,+E;AACA,wE;AACA,0E;AACA,0E;AACA,+E;AACA,6E;AACA,yC;AACA,gD;AACA,2E;AACA,0E;AACA,gF;AACA,gF;AACA,gB;AACA,mC;AACA,4C;;AAEA,kB;AACA,sC;AACA,Q;;AAEA,yB;AACA,4E;AACA,8B;AACA,uD;AACA,oD;;AAEA,+E;AACA,2E;AACA,sC;AACA,oC;AACA,oC;AACA,yB;AACA,oB;AACA,+C;AACA,4B;AACA,6C;AACA,kB;AACA,kD;AACA,sD;AACA,W;AACA,iB;AACA,yC;AACA,oB;AACA,0F;AACA,W;AACA,wE;AACA,2C;AACA,mB;AACA,uF;AACA,2C;AACA,2C;AACA,mB;AACA,qE;AACA,uC;AACA,8B;AACA,sD;AACA,wC;AACA,qC;AACA,uC;AACA,yC;AACA,sB;AACA,mC;AACA,qC;AACA,2C;AACA,e;AACA,e;AACA,uD;AACA,W;AACA,gB;AACA,wE;AACA,S;;AAEA,Q;;AAEA,iD;AACA,8B;AACA,2C;AACA,Q;;AAEA,+E;AACA,+B;AACA,kC;AACA,yC;AACA,Q;AACA,sC;AACA,oD;AACA,O;AACA,O;;AAEA,Y;AACA,4E;AACA,G;;AAEA,gC;;AAEA,gB;AACA,6E;AACA,oC;AACA,gD;AACA,yB;AACA,wB;AACA,G;AACA,E;;AAEA,G;AACA,uB;AACA,G;;;AAGA,sC;;AAEA,qC;AACA,yB;AACA,gB;AACA,Q;AACA,qB;AACA,I;;AAEA,oC;AACA,oB;AACA,0B;AACA,4C;AACA,Y;AACA,2D;AACA,+D;AACA,oE;AACA,8D;AACA,4D;AACA,U;;AAEA,uB;AACA,kC;AACA,kB;AACA,K;AACA,I;;AAEA,K;AACA,yE;AACA,oB;AACA,iB;AACA,+B;AACA,c;AACA,+E;AACA,8B;AACA,iF;AACA,4E;AACA,sE;AACA,2F;AACA,uG;AACA,4J;AACA,4B;AACA,K;AACA,4C;AACA,8D;AACA,8D;AACA,6C;AACA,oB;AACA,wC;AACA,iE;AACA,iE;AACA,I;;AAEA,K;AACA,sG;AACA,oB;AACA,oB;AACA,+B;AACA,c;AACA,+E;AACA,8B;AACA,iF;AACA,4E;AACA,2F;AACA,mG;AACA,2J;AACA,sB;AACA,K;AACA,+C;AACA,oB;AACA,wC;AACA,oE;AACA,oE;AACA,G;;AAEA,G;;AAEA,sE;AACA,6C;AACA,kC;AACA,wC;AACA,M;AACA,oC;AACA,0C;AACA,M;AACA,4B;AACA,kC;AACA,K;AACA,K;;AAEA,6E;AACA,kE;;AAEA,wD;AACA,kD;AACA,E;;AAEA,0E;AACA,+E;AACA,wE;AACA,sB;AACA,yD;AACA,mC;AACA,8C;AACA,+B;;AAEA,0D;AACA,2B;AACA,8B;;AAEA,e;AACA,0C;AACA,sE;AACA,kC;AACA,qD;AACA,yD;AACA,4D;AACA,iE;AACA,yC;AACA,uC;AACA,2C;AACA,K;AACA,sD;AACA,gD;AACA,4C;AACA,oD;AACA,S;AACA,Y;AACA,uB;AACA,K;AACA,K;AACA,a;AACA,E;;AAEA,qE;AACA,W;AACA,sD;AACA,uC;;AAEA,yC;AACA,wB;AACA,sE;AACA,oE;AACA,wB;AACA,wB;AACA,uB;AACA,wB;AACA,mB;AACA,qC;;AAEA,kB;AACA,E;;AAEA,8D;AACA,gE;AACA,2B;AACA,mE;AACA,6B;AACA,G;AACA,E;;AAEA,gE;AACA,0E;AACA,0E;AACA,gE;AACA,8E;AACA,iC;AACA,E;AACA,qE;AACA,6D;AACA,qE;AACA,oE;AACA,gF;AACA,gF;AACA,8E;AACA,gE;AACA,E;AACA,0D;AACA,6D;AACA,uB;AACA,E;AACA,gE;AACA,qE;AACA,iB;AACA,E;AACA,mE;AACA,oE;AACA,8D;AACA,kE;AACA,O;;AAEA,G;AACA,yE;AACA,kB;AACA,kB;AACA,6B;AACA,Y;AACA,iI;AACA,iJ;AACA,G;;AAEA,G;AACA,qG;AACA,kB;AACA,iB;AACA,6B;AACA,Y;AACA,sE;AACA,wE;AACA,4B;AACA,0I;AACA,gG;AACA,0K;AACA,G;;AAEA,G;AACA,gD;AACA,kB;AACA,iB;AACA,6B;AACA,Y;AACA,sE;AACA,mG;AACA,G;;AAEA,wD;AACA,iE;AACA,oB;AACA,oC;AACA,iB;AACA,iB;AACA,Y;;AAEA,8E;AACA,gD;AACA,sB;AACA,+C;AACA,sD;AACA,4B;AACA,K;;AAEA,4B;AACA,uB;AACA,uD;AACA,qD;AACA,sC;AACA,6B;AACA,+B;AACA,uD;AACA,qD;AACA,sG;AACA,c;AACA,8B;AACA,6E;AACA,4E;AACA,qC;AACA,qE;AACA,uD;AACA,2B;AACA,+B;AACA,W;AACA,S;AACA,yB;AACA,qD;AACA,S;AACA,O;AACA,Y;AACA,2D;;AAEA,8B;AACA,2E;AACA,+E;AACA,2E;AACA,wB;AACA,uD;AACA,yE;AACA,6E;AACA,mC;AACA,wD;AACA,mE;AACA,uE;AACA,qC;AACA,mD;AACA,W;AACA,S;AACA,O;AACA,K;;AAEA,uE;AACA,8D;AACA,mE;AACA,8B;AACA,kC;AACA,4B;AACA,S;AACA,wB;AACA,c;AACA,sB;AACA,O;AACA,M;;AAEA,wB;AACA,mB;AACA,kD;AACA,kF;AACA,Q;AACA,K;;AAEA,gC;AACA,iE;AACA,mE;AACA,mB;;AAEA,mD;AACA,oE;;AAEA,yE;AACA,sE;AACA,qE;AACA,kE;AACA,uE;AACA,gB;AACA,+E;AACA,+E;AACA,gC;AACA,0C;AACA,kB;AACA,0E;AACA,U;AACA,O;;AAEA,sD;AACA,8E;AACA,6E;AACA,4E;AACA,8C;AACA,O;;AAEA,kD;AACA,mG;AACA,Q;;AAEA,Y;AACA,gE;AACA,qC;AACA,iC;AACA,W;AACA,6E;AACA,6E;AACA,gE;AACA,4E;AACA,8D;AACA,mB;AACA,uB;AACA,sB;AACA,sB;AACA,S;AACA,gB;AACA,O;AACA,K;;AAEA,oE;AACA,+E;AACA,uD;AACA,e;AACA,I;AACA,G;;AAEA,G;AACA,4Q;AACA,kB;AACA,sE;AACA,wE;AACA,4B;AACA,0I;AACA,0K;AACA,G;AACA,iE;AACA,mE;AACA,kB;AACA,oD;AACA,uB;AACA,iB;AACA,G;AACA,wC;AACA,2E;AACA,wB;AACA,E;;AAEA,6E;AACA,oC;AACA,qE;AACA,kB;AACA,qC;AACA,wE;AACA,gD;AACA,E;AACA,0D;AACA,kB;AACA,mC;AACA,sE;AACA,qC;AACA,E;AACA,0D;AACA,kB;AACA,uC;AACA,2E;AACA,oC;AACA,E;AACA,wF;AACA,kB;AACA,gD;AACA,mF;AACA,mE;AACA,E;;AAEA,wD;AACA,kB;AACA,yC;AACA,yE;AACA,G;AACA,0C;AACA,E;;AAEA,sD;AACA,kB;AACA,wD;AACA,uE;AACA,G;AACA,+B;AACA,E;;;AAGA,G;AACA,qK;AACA,kB;AACA,S;AACA,uG;AACA,G;AACA,2C;;AAEA,G;AACA,0G;AACA,S;AACA,uB;AACA,G;AACA,sC;;AAEA,G;AACA,uB;AACA,G;AACA,uC;;AAEA,G;AACA,uB;AACA,G;AACA,2C;;AAEA,G;AACA,sC;AACA,G;;AAEA,uE;AACA,gB;AACA,E;AACA,yC;AACA,mD;AACA,E;AACA,4D;AACA,wD;AACA,qE;AACA,E;AACA,0C;AACA,uD;AACA,E;AACA,wB;AACA,uE;AACA,0D;AACA,E;AACA,kE;AACA,wB;AACA,qE;AACA,oE;AACA,uB;AACA,2E;AACA,6E;AACA,sC;AACA,E;AACA,8E;AACA,6E;AACA,mC;;AAEA,c;AACA,qD;AACA,oB;AACA,0E;AACA,4C;AACA,uC;AACA,+D;AACA,O;;AAEA,oB;AACA,4B;;AAEA,4D;AACA,0B;AACA,mD;AACA,yF;AACA,S;;AAEA,6E;AACA,uE;AACA,sB;AACA,8C;AACA,wE;AACA,gB;AACA,kE;AACA,+B;AACA,S;;AAEA,gE;AACA,O;AACA,O;;AAEA,sE;AACA,0E;AACA,6B;AACA,4D;AACA,+D;AACA,8E;AACA,O;AACA,uC;AACA,K;AACA,I;;AAEA,K;AACA,mH;AACA,kB;AACA,4B;AACA,2J;AACA,uL;AACA,4I;AACA,K;AACA,wD;AACA,8C;AACA,I;;AAEA,K;AACA,qC;AACA,kB;AACA,4B;AACA,0M;AACA,uL;AACA,4I;AACA,K;AACA,uD;AACA,6C;AACA,I;AACA,K;;;AAGA,gE;AACA,kB;;AAEA,qE;AACA,iE;AACA,2B;;AAEA,8E;AACA,4E;AACA,+E;AACA,uB;AACA,6B;;AAEA,sB;AACA,kC;AACA,kC;AACA,kC;AACA,oE;AACA,c;AACA,yB;AACA,I;;AAEA,kB;AACA,mC;;AAEA,gE;AACA,gC;AACA,wC;;AAEA,qB;AACA,yB;AACA,e;;AAEA,8D;AACA,uD;AACA,6E;AACA,sC;AACA,wC;AACA,a;AACA,6E;AACA,gF;AACA,+E;AACA,uE;AACA,2E;AACA,yE;AACA,Y;AACA,4E;AACA,yE;AACA,qE;AACA,qD;AACA,iC;AACA,8D;AACA,4C;AACA,W;;AAEA,kC;AACA,2E;AACA,iC;AACA,qC;AACA,wC;AACA,kD;AACA,sC;AACA,W;;AAEA,wE;;AAEA,kF;AACA,iC;AACA,kC;AACA,oD;;AAEA,iC;AACA,6D;AACA,8D;AACA,qC;AACA,8E;AACA,6D;AACA,a;;AAEA,qC;AACA,kF;AACA,sC;AACA,0D;AACA,+D;AACA,0C;AACA,qC;AACA,wC;AACA,6E;AACA,8E;AACA,+E;AACA,4E;AACA,2E;AACA,6E;AACA,uE;AACA,+E;AACA,+E;AACA,4E;AACA,+C;AACA,0E;AACA,kB;AACA,+E;AACA,4B;AACA,yD;AACA,W;AACA,qB;AACA,uE;AACA,sD;AACA,kB;AACA,oB;AACA,W;AACA,S;AACA,Q;AACA,O;AACA,iE;AACA,sD;AACA,oE;AACA,gC;AACA,8D;AACA,kC;AACA,G;AACA,E;;;AAGA,6D;AACA,kB;;AAEA,yC;AACA,iB;AACA,uE;AACA,Y;AACA,6C;AACA,oE;AACA,oC;AACA,K;AACA,G;AACA,E;;AAEA,sD;AACA,kB;AACA,mC;AACA,8B;AACA,wB;AACA,E;;AAEA,4D;AACA,gB;AACA,4B;AACA,2B;AACA,gF;AACA,2E;AACA,+E;AACA,mD;AACA,yD;AACA,+B;AACA,4B;AACA,K;AACA,mC;AACA,G;AACA,a;AACA,E;;AAEA,oE;AACA,uE;AACA,kB;;AAEA,0B;AACA,wC;AACA,+D;AACA,yE;AACA,O;AACA,iD;AACA,G;AACA,wE;AACA,gE;AACA,0E;AACA,O;AACA,iD;AACA,G;;AAEA,0E;AACA,+B;AACA,2B;AACA,0B;;AAEA,sD;AACA,E;;AAEA,8C;AACA,0B;AACA,oC;AACA,a;AACA,E;;AAEA,uE;AACA,mE;AACA,kE;AACA,2C;AACA,uD;AACA,yC;AACA,kB;;AAEA,yB;;AAEA,mC;;AAEA,8D;AACA,iE;;AAEA,2E;AACA,W;AACA,qB;AACA,+D;AACA,kE;;AAEA,iF;AACA,mF;AACA,qB;;AAEA,4B;AACA,kB;AACA,2B;AACA,gD;AACA,G;AACA,yC;AACA,+B;AACA,kD;AACA,uD;AACA,6B;AACA,2F;AACA,Y;AACA,+C;AACA,6D;AACA,yB;AACA,sC;AACA,yD;;AAEA,mD;AACA,uC;AACA,6B;AACA,S;AACA,K;AACA,K;;AAEA,sC;AACA,yC;AACA,4B;AACA,wD;AACA,wC;AACA,O;AACA,G;;AAEA,4D;AACA,+B;AACA,a;;AAEA,0B;AACA,wC;AACA,+D;AACA,oD;AACA,4B;AACA,kC;AACA,4B;AACA,8B;AACA,O;AACA,iD;AACA,G;AACA,wE;AACA,gE;AACA,oD;AACA,6B;AACA,mC;AACA,6B;AACA,+B;AACA,O;AACA,iD;AACA,G;;AAEA,gC;;AAEA,4E;AACA,6E;AACA,+E;AACA,4B;;AAEA,sC;AACA,kD;AACA,E;;AAEA,iE;AACA,8D;AACA,oE;AACA,8D;AACA,uE;AACA,6D;AACA,iC;AACA,qE;AACA,6B;AACA,E;;AAEA,sE;AACA,8B;AACA,0E;AACA,kB;;AAEA,sC;AACA,yC;AACA,4B;AACA,wD;AACA,wC;AACA,O;AACA,G;;AAEA,4D;AACA,W;AACA,a;;AAEA,0B;AACA,wC;AACA,+D;AACA,2D;AACA,O;AACA,iD;AACA,G;AACA,wE;AACA,gE;AACA,4D;AACA,O;AACA,iD;AACA,G;;AAEA,4E;AACA,gF;AACA,8E;AACA,sC;;AAEA,kE;AACA,E;;AAEA,G;AACA,uB;AACA,G;AACA,qC","file":"/packages/mongo.js","sourcesContent":["/**\n * Provide a synchronous Collection API using fibers, backed by\n * MongoDB. This is only for use on the server, and mostly identical\n * to the client API.\n *\n * NOTE: the public API methods must be run within a fiber. If you call\n * these outside of a fiber they will explode!\n */\n\nvar path = Npm.require('path');\nvar MongoDB = Npm.require('mongodb');\nvar Fiber = Npm.require('fibers');\nvar Future = Npm.require(path.join('fibers', 'future'));\n\nMongoInternals = {};\nMongoTest = {};\n\nMongoInternals.NpmModules = {\n mongodb: {\n version: Npm.require('mongodb/package.json').version,\n module: MongoDB\n }\n};\n\n// Older version of what is now available via\n// MongoInternals.NpmModules.mongodb.module. It was never documented, but\n// people do use it.\n// XXX COMPAT WITH 1.0.3.2\nMongoInternals.NpmModule = MongoDB;\n\n// This is used to add or remove EJSON from the beginning of everything nested\n// inside an EJSON custom type. It should only be called on pure JSON!\nvar replaceNames = function (filter, thing) {\n if (typeof thing === \"object\") {\n if (_.isArray(thing)) {\n return _.map(thing, _.bind(replaceNames, null, filter));\n }\n var ret = {};\n _.each(thing, function (value, key) {\n ret[filter(key)] = replaceNames(filter, value);\n });\n return ret;\n }\n return thing;\n};\n\n// Ensure that EJSON.clone keeps a Timestamp as a Timestamp (instead of just\n// doing a structural clone).\n// XXX how ok is this? what if there are multiple copies of MongoDB loaded?\nMongoDB.Timestamp.prototype.clone = function () {\n // Timestamps should be immutable.\n return this;\n};\n\nvar makeMongoLegal = function (name) { return \"EJSON\" + name; };\nvar unmakeMongoLegal = function (name) { return name.substr(5); };\n\nvar replaceMongoAtomWithMeteor = function (document) {\n if (document instanceof MongoDB.Binary) {\n var buffer = document.value(true);\n return new Uint8Array(buffer);\n }\n if (document instanceof MongoDB.ObjectID) {\n return new Mongo.ObjectID(document.toHexString());\n }\n if (document[\"EJSON$type\"] && document[\"EJSON$value\"]\n && _.size(document) === 2) {\n return EJSON.fromJSONValue(replaceNames(unmakeMongoLegal, document));\n }\n if (document instanceof MongoDB.Timestamp) {\n // For now, the Meteor representation of a Mongo timestamp type (not a date!\n // this is a weird internal thing used in the oplog!) is the same as the\n // Mongo representation. We need to do this explicitly or else we would do a\n // structural clone and lose the prototype.\n return document;\n }\n return undefined;\n};\n\nvar replaceMeteorAtomWithMongo = function (document) {\n if (EJSON.isBinary(document)) {\n // This does more copies than we'd like, but is necessary because\n // MongoDB.BSON only looks like it takes a Uint8Array (and doesn't actually\n // serialize it correctly).\n return new MongoDB.Binary(new Buffer(document));\n }\n if (document instanceof Mongo.ObjectID) {\n return new MongoDB.ObjectID(document.toHexString());\n }\n if (document instanceof MongoDB.Timestamp) {\n // For now, the Meteor representation of a Mongo timestamp type (not a date!\n // this is a weird internal thing used in the oplog!) is the same as the\n // Mongo representation. We need to do this explicitly or else we would do a\n // structural clone and lose the prototype.\n return document;\n }\n if (EJSON._isCustomType(document)) {\n return replaceNames(makeMongoLegal, EJSON.toJSONValue(document));\n }\n // It is not ordinarily possible to stick dollar-sign keys into mongo\n // so we don't bother checking for things that need escaping at this time.\n return undefined;\n};\n\nvar replaceTypes = function (document, atomTransformer) {\n if (typeof document !== 'object' || document === null)\n return document;\n\n var replacedTopLevelAtom = atomTransformer(document);\n if (replacedTopLevelAtom !== undefined)\n return replacedTopLevelAtom;\n\n var ret = document;\n _.each(document, function (val, key) {\n var valReplaced = replaceTypes(val, atomTransformer);\n if (val !== valReplaced) {\n // Lazy clone. Shallow copy.\n if (ret === document)\n ret = _.clone(document);\n ret[key] = valReplaced;\n }\n });\n return ret;\n};\n\n\nMongoConnection = function (url, options) {\n var self = this;\n options = options || {};\n self._observeMultiplexers = {};\n self._onFailoverHook = new Hook;\n\n var mongoOptions = {db: {safe: true}, server: {}, replSet: {}};\n\n // Set autoReconnect to true, unless passed on the URL. Why someone\n // would want to set autoReconnect to false, I'm not really sure, but\n // keeping this for backwards compatibility for now.\n if (!(/[\\?&]auto_?[rR]econnect=/.test(url))) {\n mongoOptions.server.auto_reconnect = true;\n }\n\n // Disable the native parser by default, unless specifically enabled\n // in the mongo URL.\n // - The native driver can cause errors which normally would be\n // thrown, caught, and handled into segfaults that take down the\n // whole app.\n // - Binary modules don't yet work when you bundle and move the bundle\n // to a different platform (aka deploy)\n // We should revisit this after binary npm module support lands.\n if (!(/[\\?&]native_?[pP]arser=/.test(url))) {\n mongoOptions.db.native_parser = false;\n }\n\n // XXX maybe we should have a better way of allowing users to configure the\n // underlying Mongo driver\n if (_.has(options, 'poolSize')) {\n // If we just set this for \"server\", replSet will override it. If we just\n // set it for replSet, it will be ignored if we're not using a replSet.\n mongoOptions.server.poolSize = options.poolSize;\n mongoOptions.replSet.poolSize = options.poolSize;\n }\n\n self.db = null;\n // We keep track of the ReplSet's primary, so that we can trigger hooks when\n // it changes. The Node driver's joined callback seems to fire way too\n // often, which is why we need to track it ourselves.\n self._primary = null;\n self._oplogHandle = null;\n self._docFetcher = null;\n\n\n var connectFuture = new Future;\n MongoDB.connect(\n url,\n mongoOptions,\n Meteor.bindEnvironment(\n function (err, db) {\n if (err) {\n throw err;\n }\n\n // First, figure out what the current primary is, if any.\n if (db.serverConfig._state.master)\n self._primary = db.serverConfig._state.master.name;\n db.serverConfig.on(\n 'joined', Meteor.bindEnvironment(function (kind, doc) {\n if (kind === 'primary') {\n if (doc.primary !== self._primary) {\n self._primary = doc.primary;\n self._onFailoverHook.each(function (callback) {\n callback();\n return true;\n });\n }\n } else if (doc.me === self._primary) {\n // The thing we thought was primary is now something other than\n // primary. Forget that we thought it was primary. (This means\n // that if a server stops being primary and then starts being\n // primary again without another server becoming primary in the\n // middle, we'll correctly count it as a failover.)\n self._primary = null;\n }\n }));\n\n // Allow the constructor to return.\n connectFuture['return'](db);\n },\n connectFuture.resolver() // onException\n )\n );\n\n // Wait for the connection to be successful; throws on failure.\n self.db = connectFuture.wait();\n\n if (options.oplogUrl && ! Package['disable-oplog']) {\n self._oplogHandle = new OplogHandle(options.oplogUrl, self.db.databaseName);\n self._docFetcher = new DocFetcher(self);\n }\n};\n\nMongoConnection.prototype.close = function() {\n var self = this;\n\n if (! self.db)\n throw Error(\"close called before Connection created?\");\n\n // XXX probably untested\n var oplogHandle = self._oplogHandle;\n self._oplogHandle = null;\n if (oplogHandle)\n oplogHandle.stop();\n\n // Use Future.wrap so that errors get thrown. This happens to\n // work even outside a fiber since the 'close' method is not\n // actually asynchronous.\n Future.wrap(_.bind(self.db.close, self.db))(true).wait();\n};\n\n// Returns the Mongo Collection object; may yield.\nMongoConnection.prototype.rawCollection = function (collectionName) {\n var self = this;\n\n if (! self.db)\n throw Error(\"rawCollection called before Connection created?\");\n\n var future = new Future;\n self.db.collection(collectionName, future.resolver());\n return future.wait();\n};\n\nMongoConnection.prototype._createCappedCollection = function (\n collectionName, byteSize, maxDocuments) {\n var self = this;\n\n if (! self.db)\n throw Error(\"_createCappedCollection called before Connection created?\");\n\n var future = new Future();\n self.db.createCollection(\n collectionName,\n { capped: true, size: byteSize, max: maxDocuments },\n future.resolver());\n future.wait();\n};\n\n// This should be called synchronously with a write, to create a\n// transaction on the current write fence, if any. After we can read\n// the write, and after observers have been notified (or at least,\n// after the observer notifiers have added themselves to the write\n// fence), you should call 'committed()' on the object returned.\nMongoConnection.prototype._maybeBeginWrite = function () {\n var self = this;\n var fence = DDPServer._CurrentWriteFence.get();\n if (fence)\n return fence.beginWrite();\n else\n return {committed: function () {}};\n};\n\n// Internal interface: adds a callback which is called when the Mongo primary\n// changes. Returns a stop handle.\nMongoConnection.prototype._onFailover = function (callback) {\n return this._onFailoverHook.register(callback);\n};\n\n\n//////////// Public API //////////\n\n// The write methods block until the database has confirmed the write (it may\n// not be replicated or stable on disk, but one server has confirmed it) if no\n// callback is provided. If a callback is provided, then they call the callback\n// when the write is confirmed. They return nothing on success, and raise an\n// exception on failure.\n//\n// After making a write (with insert, update, remove), observers are\n// notified asynchronously. If you want to receive a callback once all\n// of the observer notifications have landed for your write, do the\n// writes inside a write fence (set DDPServer._CurrentWriteFence to a new\n// _WriteFence, and then set a callback on the write fence.)\n//\n// Since our execution environment is single-threaded, this is\n// well-defined -- a write \"has been made\" if it's returned, and an\n// observer \"has been notified\" if its callback has returned.\n\nvar writeCallback = function (write, refresh, callback) {\n return function (err, result) {\n if (! err) {\n // XXX We don't have to run this on error, right?\n refresh();\n }\n write.committed();\n if (callback)\n callback(err, result);\n else if (err)\n throw err;\n };\n};\n\nvar bindEnvironmentForWrite = function (callback) {\n return Meteor.bindEnvironment(callback, \"Mongo write\");\n};\n\nMongoConnection.prototype._insert = function (collection_name, document,\n callback) {\n var self = this;\n\n var sendError = function (e) {\n if (callback)\n return callback(e);\n throw e;\n };\n\n if (collection_name === \"___meteor_failure_test_collection\") {\n var e = new Error(\"Failure test\");\n e.expected = true;\n sendError(e);\n return;\n }\n\n if (!(LocalCollection._isPlainObject(document) &&\n !EJSON._isCustomType(document))) {\n sendError(new Error(\n \"Only plain objects may be inserted into MongoDB\"));\n return;\n }\n\n var write = self._maybeBeginWrite();\n var refresh = function () {\n Meteor.refresh({collection: collection_name, id: document._id });\n };\n callback = bindEnvironmentForWrite(writeCallback(write, refresh, callback));\n try {\n var collection = self.rawCollection(collection_name);\n collection.insert(replaceTypes(document, replaceMeteorAtomWithMongo),\n {safe: true}, callback);\n } catch (e) {\n write.committed();\n throw e;\n }\n};\n\n// Cause queries that may be affected by the selector to poll in this write\n// fence.\nMongoConnection.prototype._refresh = function (collectionName, selector) {\n var self = this;\n var refreshKey = {collection: collectionName};\n // If we know which documents we're removing, don't poll queries that are\n // specific to other documents. (Note that multiple notifications here should\n // not cause multiple polls, since all our listener is doing is enqueueing a\n // poll.)\n var specificIds = LocalCollection._idsMatchedBySelector(selector);\n if (specificIds) {\n _.each(specificIds, function (id) {\n Meteor.refresh(_.extend({id: id}, refreshKey));\n });\n } else {\n Meteor.refresh(refreshKey);\n }\n};\n\nMongoConnection.prototype._remove = function (collection_name, selector,\n callback) {\n var self = this;\n\n if (collection_name === \"___meteor_failure_test_collection\") {\n var e = new Error(\"Failure test\");\n e.expected = true;\n if (callback)\n return callback(e);\n else\n throw e;\n }\n\n var write = self._maybeBeginWrite();\n var refresh = function () {\n self._refresh(collection_name, selector);\n };\n callback = bindEnvironmentForWrite(writeCallback(write, refresh, callback));\n\n try {\n var collection = self.rawCollection(collection_name);\n collection.remove(replaceTypes(selector, replaceMeteorAtomWithMongo),\n {safe: true}, callback);\n } catch (e) {\n write.committed();\n throw e;\n }\n};\n\nMongoConnection.prototype._dropCollection = function (collectionName, cb) {\n var self = this;\n\n var write = self._maybeBeginWrite();\n var refresh = function () {\n Meteor.refresh({collection: collectionName, id: null,\n dropCollection: true});\n };\n cb = bindEnvironmentForWrite(writeCallback(write, refresh, cb));\n\n try {\n var collection = self.rawCollection(collectionName);\n collection.drop(cb);\n } catch (e) {\n write.committed();\n throw e;\n }\n};\n\nMongoConnection.prototype._update = function (collection_name, selector, mod,\n options, callback) {\n var self = this;\n\n if (! callback && options instanceof Function) {\n callback = options;\n options = null;\n }\n\n if (collection_name === \"___meteor_failure_test_collection\") {\n var e = new Error(\"Failure test\");\n e.expected = true;\n if (callback)\n return callback(e);\n else\n throw e;\n }\n\n // explicit safety check. null and undefined can crash the mongo\n // driver. Although the node driver and minimongo do 'support'\n // non-object modifier in that they don't crash, they are not\n // meaningful operations and do not do anything. Defensively throw an\n // error here.\n if (!mod || typeof mod !== 'object')\n throw new Error(\"Invalid modifier. Modifier must be an object.\");\n\n if (!(LocalCollection._isPlainObject(mod) &&\n !EJSON._isCustomType(mod))) {\n throw new Error(\n \"Only plain objects may be used as replacement\" +\n \" documents in MongoDB\");\n return;\n }\n\n if (!options) options = {};\n\n var write = self._maybeBeginWrite();\n var refresh = function () {\n self._refresh(collection_name, selector);\n };\n callback = writeCallback(write, refresh, callback);\n try {\n var collection = self.rawCollection(collection_name);\n var mongoOpts = {safe: true};\n // explictly enumerate options that minimongo supports\n if (options.upsert) mongoOpts.upsert = true;\n if (options.multi) mongoOpts.multi = true;\n // Lets you get a more more full result from MongoDB. Use with caution:\n // might not work with C.upsert (as opposed to C.update({upsert:true}) or\n // with simulated upsert.\n if (options.fullResult) mongoOpts.fullResult = true;\n\n var mongoSelector = replaceTypes(selector, replaceMeteorAtomWithMongo);\n var mongoMod = replaceTypes(mod, replaceMeteorAtomWithMongo);\n\n var isModify = isModificationMod(mongoMod);\n var knownId = selector._id || mod._id;\n\n if (options._forbidReplace && ! isModify) {\n var e = new Error(\"Invalid modifier. Replacements are forbidden.\");\n if (callback) {\n return callback(e);\n } else {\n throw e;\n }\n }\n\n if (options.upsert && (! knownId) && options.insertedId) {\n // XXX If we know we're using Mongo 2.6 (and this isn't a replacement)\n // we should be able to just use $setOnInsert instead of this\n // simulated upsert thing. (We can't use $setOnInsert with\n // replacements because there's nowhere to write it, and $setOnInsert\n // can't set _id on Mongo 2.4.)\n //\n // Also, in the future we could do a real upsert for the mongo id\n // generation case, if the the node mongo driver gives us back the id\n // of the upserted doc (which our current version does not).\n //\n // For more context, see\n // https://github.com/meteor/meteor/issues/2278#issuecomment-64252706\n simulateUpsertWithInsertedId(\n collection, mongoSelector, mongoMod,\n isModify, options,\n // This callback does not need to be bindEnvironment'ed because\n // simulateUpsertWithInsertedId() wraps it and then passes it through\n // bindEnvironmentForWrite.\n function (err, result) {\n // If we got here via a upsert() call, then options._returnObject will\n // be set and we should return the whole object. Otherwise, we should\n // just return the number of affected docs to match the mongo API.\n if (result && ! options._returnObject)\n callback(err, result.numberAffected);\n else\n callback(err, result);\n }\n );\n } else {\n collection.update(\n mongoSelector, mongoMod, mongoOpts,\n bindEnvironmentForWrite(function (err, result, extra) {\n if (! err) {\n if (result && options._returnObject) {\n result = { numberAffected: result };\n // If this was an upsert() call, and we ended up\n // inserting a new doc and we know its id, then\n // return that id as well.\n if (options.upsert && knownId &&\n ! extra.updatedExisting)\n result.insertedId = knownId;\n }\n }\n callback(err, result);\n }));\n }\n } catch (e) {\n write.committed();\n throw e;\n }\n};\n\nvar isModificationMod = function (mod) {\n var isReplace = false;\n var isModify = false;\n for (var k in mod) {\n if (k.substr(0, 1) === '$') {\n isModify = true;\n } else {\n isReplace = true;\n }\n }\n if (isModify && isReplace) {\n throw new Error(\n \"Update parameter cannot have both modifier and non-modifier fields.\");\n }\n return isModify;\n};\n\nvar NUM_OPTIMISTIC_TRIES = 3;\n\n// exposed for testing\nMongoConnection._isCannotChangeIdError = function (err) {\n // First check for what this error looked like in Mongo 2.4. Either of these\n // checks should work, but just to be safe...\n if (err.code === 13596)\n return true;\n if (err.err.indexOf(\"cannot change _id of a document\") === 0)\n return true;\n\n // Now look for what it looks like in Mongo 2.6. We don't use the error code\n // here, because the error code we observed it producing (16837) appears to be\n // a far more generic error code based on examining the source.\n if (err.err.indexOf(\"The _id field cannot be changed\") === 0)\n return true;\n\n return false;\n};\n\nvar simulateUpsertWithInsertedId = function (collection, selector, mod,\n isModify, options, callback) {\n // STRATEGY: First try doing a plain update. If it affected 0 documents,\n // then without affecting the database, we know we should probably do an\n // insert. We then do a *conditional* insert that will fail in the case\n // of a race condition. This conditional insert is actually an\n // upsert-replace with an _id, which will never successfully update an\n // existing document. If this upsert fails with an error saying it\n // couldn't change an existing _id, then we know an intervening write has\n // caused the query to match something. We go back to step one and repeat.\n // Like all \"optimistic write\" schemes, we rely on the fact that it's\n // unlikely our writes will continue to be interfered with under normal\n // circumstances (though sufficiently heavy contention with writers\n // disagreeing on the existence of an object will cause writes to fail\n // in theory).\n\n var newDoc;\n // Run this code up front so that it fails fast if someone uses\n // a Mongo update operator we don't support.\n if (isModify) {\n // We've already run replaceTypes/replaceMeteorAtomWithMongo on\n // selector and mod. We assume it doesn't matter, as far as\n // the behavior of modifiers is concerned, whether `_modify`\n // is run on EJSON or on mongo-converted EJSON.\n var selectorDoc = LocalCollection._removeDollarOperators(selector);\n LocalCollection._modify(selectorDoc, mod, {isInsert: true});\n newDoc = selectorDoc;\n } else {\n newDoc = mod;\n }\n\n var insertedId = options.insertedId; // must exist\n var mongoOptsForUpdate = {\n safe: true,\n multi: options.multi\n };\n var mongoOptsForInsert = {\n safe: true,\n upsert: true\n };\n\n var tries = NUM_OPTIMISTIC_TRIES;\n\n var doUpdate = function () {\n tries--;\n if (! tries) {\n callback(new Error(\"Upsert failed after \" + NUM_OPTIMISTIC_TRIES + \" tries.\"));\n } else {\n collection.update(selector, mod, mongoOptsForUpdate,\n bindEnvironmentForWrite(function (err, result) {\n if (err)\n callback(err);\n else if (result)\n callback(null, {\n numberAffected: result\n });\n else\n doConditionalInsert();\n }));\n }\n };\n\n var doConditionalInsert = function () {\n var replacementWithId = _.extend(\n replaceTypes({_id: insertedId}, replaceMeteorAtomWithMongo),\n newDoc);\n collection.update(selector, replacementWithId, mongoOptsForInsert,\n bindEnvironmentForWrite(function (err, result) {\n if (err) {\n // figure out if this is a\n // \"cannot change _id of document\" error, and\n // if so, try doUpdate() again, up to 3 times.\n if (MongoConnection._isCannotChangeIdError(err)) {\n doUpdate();\n } else {\n callback(err);\n }\n } else {\n callback(null, {\n numberAffected: result,\n insertedId: insertedId\n });\n }\n }));\n };\n\n doUpdate();\n};\n\n_.each([\"insert\", \"update\", \"remove\", \"dropCollection\"], function (method) {\n MongoConnection.prototype[method] = function (/* arguments */) {\n var self = this;\n return Meteor.wrapAsync(self[\"_\" + method]).apply(self, arguments);\n };\n});\n\n// XXX MongoConnection.upsert() does not return the id of the inserted document\n// unless you set it explicitly in the selector or modifier (as a replacement\n// doc).\nMongoConnection.prototype.upsert = function (collectionName, selector, mod,\n options, callback) {\n var self = this;\n if (typeof options === \"function\" && ! callback) {\n callback = options;\n options = {};\n }\n\n return self.update(collectionName, selector, mod,\n _.extend({}, options, {\n upsert: true,\n _returnObject: true\n }), callback);\n};\n\nMongoConnection.prototype.find = function (collectionName, selector, options) {\n var self = this;\n\n if (arguments.length === 1)\n selector = {};\n\n return new Cursor(\n self, new CursorDescription(collectionName, selector, options));\n};\n\nMongoConnection.prototype.findOne = function (collection_name, selector,\n options) {\n var self = this;\n if (arguments.length === 1)\n selector = {};\n\n options = options || {};\n options.limit = 1;\n return self.find(collection_name, selector, options).fetch()[0];\n};\n\n// We'll actually design an index API later. For now, we just pass through to\n// Mongo's, but make it synchronous.\nMongoConnection.prototype._ensureIndex = function (collectionName, index,\n options) {\n var self = this;\n options = _.extend({safe: true}, options);\n\n // We expect this function to be called at startup, not from within a method,\n // so we don't interact with the write fence.\n var collection = self.rawCollection(collectionName);\n var future = new Future;\n var indexName = collection.ensureIndex(index, options, future.resolver());\n future.wait();\n};\nMongoConnection.prototype._dropIndex = function (collectionName, index) {\n var self = this;\n\n // This function is only used by test code, not within a method, so we don't\n // interact with the write fence.\n var collection = self.rawCollection(collectionName);\n var future = new Future;\n var indexName = collection.dropIndex(index, future.resolver());\n future.wait();\n};\n\n// CURSORS\n\n// There are several classes which relate to cursors:\n//\n// CursorDescription represents the arguments used to construct a cursor:\n// collectionName, selector, and (find) options. Because it is used as a key\n// for cursor de-dup, everything in it should either be JSON-stringifiable or\n// not affect observeChanges output (eg, options.transform functions are not\n// stringifiable but do not affect observeChanges).\n//\n// SynchronousCursor is a wrapper around a MongoDB cursor\n// which includes fully-synchronous versions of forEach, etc.\n//\n// Cursor is the cursor object returned from find(), which implements the\n// documented Mongo.Collection cursor API. It wraps a CursorDescription and a\n// SynchronousCursor (lazily: it doesn't contact Mongo until you call a method\n// like fetch or forEach on it).\n//\n// ObserveHandle is the \"observe handle\" returned from observeChanges. It has a\n// reference to an ObserveMultiplexer.\n//\n// ObserveMultiplexer allows multiple identical ObserveHandles to be driven by a\n// single observe driver.\n//\n// There are two \"observe drivers\" which drive ObserveMultiplexers:\n// - PollingObserveDriver caches the results of a query and reruns it when\n// necessary.\n// - OplogObserveDriver follows the Mongo operation log to directly observe\n// database changes.\n// Both implementations follow the same simple interface: when you create them,\n// they start sending observeChanges callbacks (and a ready() invocation) to\n// their ObserveMultiplexer, and you stop them by calling their stop() method.\n\nCursorDescription = function (collectionName, selector, options) {\n var self = this;\n self.collectionName = collectionName;\n self.selector = Mongo.Collection._rewriteSelector(selector);\n self.options = options || {};\n};\n\nCursor = function (mongo, cursorDescription) {\n var self = this;\n\n self._mongo = mongo;\n self._cursorDescription = cursorDescription;\n self._synchronousCursor = null;\n};\n\n_.each(['forEach', 'map', 'fetch', 'count'], function (method) {\n Cursor.prototype[method] = function () {\n var self = this;\n\n // You can only observe a tailable cursor.\n if (self._cursorDescription.options.tailable)\n throw new Error(\"Cannot call \" + method + \" on a tailable cursor\");\n\n if (!self._synchronousCursor) {\n self._synchronousCursor = self._mongo._createSynchronousCursor(\n self._cursorDescription, {\n // Make sure that the \"self\" argument to forEach/map callbacks is the\n // Cursor, not the SynchronousCursor.\n selfForIteration: self,\n useTransform: true\n });\n }\n\n return self._synchronousCursor[method].apply(\n self._synchronousCursor, arguments);\n };\n});\n\n// Since we don't actually have a \"nextObject\" interface, there's really no\n// reason to have a \"rewind\" interface. All it did was make multiple calls\n// to fetch/map/forEach return nothing the second time.\n// XXX COMPAT WITH 0.8.1\nCursor.prototype.rewind = function () {\n};\n\nCursor.prototype.getTransform = function () {\n return this._cursorDescription.options.transform;\n};\n\n// When you call Meteor.publish() with a function that returns a Cursor, we need\n// to transmute it into the equivalent subscription. This is the function that\n// does that.\n\nCursor.prototype._publishCursor = function (sub) {\n var self = this;\n var collection = self._cursorDescription.collectionName;\n return Mongo.Collection._publishCursor(self, sub, collection);\n};\n\n// Used to guarantee that publish functions return at most one cursor per\n// collection. Private, because we might later have cursors that include\n// documents from multiple collections somehow.\nCursor.prototype._getCollectionName = function () {\n var self = this;\n return self._cursorDescription.collectionName;\n}\n\nCursor.prototype.observe = function (callbacks) {\n var self = this;\n return LocalCollection._observeFromObserveChanges(self, callbacks);\n};\n\nCursor.prototype.observeChanges = function (callbacks) {\n var self = this;\n var ordered = LocalCollection._observeChangesCallbacksAreOrdered(callbacks);\n return self._mongo._observeChanges(\n self._cursorDescription, ordered, callbacks);\n};\n\nMongoConnection.prototype._createSynchronousCursor = function(\n cursorDescription, options) {\n var self = this;\n options = _.pick(options || {}, 'selfForIteration', 'useTransform');\n\n var collection = self.rawCollection(cursorDescription.collectionName);\n var cursorOptions = cursorDescription.options;\n var mongoOptions = {\n sort: cursorOptions.sort,\n limit: cursorOptions.limit,\n skip: cursorOptions.skip\n };\n\n // Do we want a tailable cursor (which only works on capped collections)?\n if (cursorOptions.tailable) {\n // We want a tailable cursor...\n mongoOptions.tailable = true;\n // ... and for the server to wait a bit if any getMore has no data (rather\n // than making us put the relevant sleeps in the client)...\n mongoOptions.awaitdata = true;\n // ... and to keep querying the server indefinitely rather than just 5 times\n // if there's no more data.\n mongoOptions.numberOfRetries = -1;\n // And if this is on the oplog collection and the cursor specifies a 'ts',\n // then set the undocumented oplog replay flag, which does a special scan to\n // find the first document (instead of creating an index on ts). This is a\n // very hard-coded Mongo flag which only works on the oplog collection and\n // only works with the ts field.\n if (cursorDescription.collectionName === OPLOG_COLLECTION &&\n cursorDescription.selector.ts) {\n mongoOptions.oplogReplay = true;\n }\n }\n\n var dbCursor = collection.find(\n replaceTypes(cursorDescription.selector, replaceMeteorAtomWithMongo),\n cursorOptions.fields, mongoOptions);\n\n return new SynchronousCursor(dbCursor, cursorDescription, options);\n};\n\nvar SynchronousCursor = function (dbCursor, cursorDescription, options) {\n var self = this;\n options = _.pick(options || {}, 'selfForIteration', 'useTransform');\n\n self._dbCursor = dbCursor;\n self._cursorDescription = cursorDescription;\n // The \"self\" argument passed to forEach/map callbacks. If we're wrapped\n // inside a user-visible Cursor, we want to provide the outer cursor!\n self._selfForIteration = options.selfForIteration || self;\n if (options.useTransform && cursorDescription.options.transform) {\n self._transform = LocalCollection.wrapTransform(\n cursorDescription.options.transform);\n } else {\n self._transform = null;\n }\n\n // Need to specify that the callback is the first argument to nextObject,\n // since otherwise when we try to call it with no args the driver will\n // interpret \"undefined\" first arg as an options hash and crash.\n self._synchronousNextObject = Future.wrap(\n dbCursor.nextObject.bind(dbCursor), 0);\n self._synchronousCount = Future.wrap(dbCursor.count.bind(dbCursor));\n self._visitedIds = new LocalCollection._IdMap;\n};\n\n_.extend(SynchronousCursor.prototype, {\n _nextObject: function () {\n var self = this;\n\n while (true) {\n var doc = self._synchronousNextObject().wait();\n\n if (!doc) return null;\n doc = replaceTypes(doc, replaceMongoAtomWithMeteor);\n\n if (!self._cursorDescription.options.tailable && _.has(doc, '_id')) {\n // Did Mongo give us duplicate documents in the same cursor? If so,\n // ignore this one. (Do this before the transform, since transform might\n // return some unrelated value.) We don't do this for tailable cursors,\n // because we want to maintain O(1) memory usage. And if there isn't _id\n // for some reason (maybe it's the oplog), then we don't do this either.\n // (Be careful to do this for falsey but existing _id, though.)\n if (self._visitedIds.has(doc._id)) continue;\n self._visitedIds.set(doc._id, true);\n }\n\n if (self._transform)\n doc = self._transform(doc);\n\n return doc;\n }\n },\n\n forEach: function (callback, thisArg) {\n var self = this;\n\n // Get back to the beginning.\n self._rewind();\n\n // We implement the loop ourself instead of using self._dbCursor.each,\n // because \"each\" will call its callback outside of a fiber which makes it\n // much more complex to make this function synchronous.\n var index = 0;\n while (true) {\n var doc = self._nextObject();\n if (!doc) return;\n callback.call(thisArg, doc, index++, self._selfForIteration);\n }\n },\n\n // XXX Allow overlapping callback executions if callback yields.\n map: function (callback, thisArg) {\n var self = this;\n var res = [];\n self.forEach(function (doc, index) {\n res.push(callback.call(thisArg, doc, index, self._selfForIteration));\n });\n return res;\n },\n\n _rewind: function () {\n var self = this;\n\n // known to be synchronous\n self._dbCursor.rewind();\n\n self._visitedIds = new LocalCollection._IdMap;\n },\n\n // Mostly usable for tailable cursors.\n close: function () {\n var self = this;\n\n self._dbCursor.close();\n },\n\n fetch: function () {\n var self = this;\n return self.map(_.identity);\n },\n\n count: function () {\n var self = this;\n return self._synchronousCount().wait();\n },\n\n // This method is NOT wrapped in Cursor.\n getRawObjects: function (ordered) {\n var self = this;\n if (ordered) {\n return self.fetch();\n } else {\n var results = new LocalCollection._IdMap;\n self.forEach(function (doc) {\n results.set(doc._id, doc);\n });\n return results;\n }\n }\n});\n\nMongoConnection.prototype.tail = function (cursorDescription, docCallback) {\n var self = this;\n if (!cursorDescription.options.tailable)\n throw new Error(\"Can only tail a tailable cursor\");\n\n var cursor = self._createSynchronousCursor(cursorDescription);\n\n var stopped = false;\n var lastTS = undefined;\n var loop = function () {\n while (true) {\n if (stopped)\n return;\n try {\n var doc = cursor._nextObject();\n } catch (err) {\n // There's no good way to figure out if this was actually an error\n // from Mongo. Ah well. But either way, we need to retry the cursor\n // (unless the failure was because the observe got stopped).\n doc = null;\n }\n // Since cursor._nextObject can yield, we need to check again to see if\n // we've been stopped before calling the callback.\n if (stopped)\n return;\n if (doc) {\n // If a tailable cursor contains a \"ts\" field, use it to recreate the\n // cursor on error. (\"ts\" is a standard that Mongo uses internally for\n // the oplog, and there's a special flag that lets you do binary search\n // on it instead of needing to use an index.)\n lastTS = doc.ts;\n docCallback(doc);\n } else {\n var newSelector = _.clone(cursorDescription.selector);\n if (lastTS) {\n newSelector.ts = {$gt: lastTS};\n }\n cursor = self._createSynchronousCursor(new CursorDescription(\n cursorDescription.collectionName,\n newSelector,\n cursorDescription.options));\n // Mongo failover takes many seconds. Retry in a bit. (Without this\n // setTimeout, we peg the CPU at 100% and never notice the actual\n // failover.\n Meteor.setTimeout(loop, 100);\n break;\n }\n }\n };\n\n Meteor.defer(loop);\n\n return {\n stop: function () {\n stopped = true;\n cursor.close();\n }\n };\n};\n\nMongoConnection.prototype._observeChanges = function (\n cursorDescription, ordered, callbacks) {\n var self = this;\n\n if (cursorDescription.options.tailable) {\n return self._observeChangesTailable(cursorDescription, ordered, callbacks);\n }\n\n // You may not filter out _id when observing changes, because the id is a core\n // part of the observeChanges API.\n if (cursorDescription.options.fields &&\n (cursorDescription.options.fields._id === 0 ||\n cursorDescription.options.fields._id === false)) {\n throw Error(\"You may not observe a cursor with {fields: {_id: 0}}\");\n }\n\n var observeKey = JSON.stringify(\n _.extend({ordered: ordered}, cursorDescription));\n\n var multiplexer, observeDriver;\n var firstHandle = false;\n\n // Find a matching ObserveMultiplexer, or create a new one. This next block is\n // guaranteed to not yield (and it doesn't call anything that can observe a\n // new query), so no other calls to this function can interleave with it.\n Meteor._noYieldsAllowed(function () {\n if (_.has(self._observeMultiplexers, observeKey)) {\n multiplexer = self._observeMultiplexers[observeKey];\n } else {\n firstHandle = true;\n // Create a new ObserveMultiplexer.\n multiplexer = new ObserveMultiplexer({\n ordered: ordered,\n onStop: function () {\n delete self._observeMultiplexers[observeKey];\n observeDriver.stop();\n }\n });\n self._observeMultiplexers[observeKey] = multiplexer;\n }\n });\n\n var observeHandle = new ObserveHandle(multiplexer, callbacks);\n\n if (firstHandle) {\n var matcher, sorter;\n var canUseOplog = _.all([\n function () {\n // At a bare minimum, using the oplog requires us to have an oplog, to\n // want unordered callbacks, and to not want a callback on the polls\n // that won't happen.\n return self._oplogHandle && !ordered &&\n !callbacks._testOnlyPollCallback;\n }, function () {\n // We need to be able to compile the selector. Fall back to polling for\n // some newfangled $selector that minimongo doesn't support yet.\n try {\n matcher = new Minimongo.Matcher(cursorDescription.selector);\n return true;\n } catch (e) {\n // XXX make all compilation errors MinimongoError or something\n // so that this doesn't ignore unrelated exceptions\n return false;\n }\n }, function () {\n // ... and the selector itself needs to support oplog.\n return OplogObserveDriver.cursorSupported(cursorDescription, matcher);\n }, function () {\n // And we need to be able to compile the sort, if any. eg, can't be\n // {$natural: 1}.\n if (!cursorDescription.options.sort)\n return true;\n try {\n sorter = new Minimongo.Sorter(cursorDescription.options.sort,\n { matcher: matcher });\n return true;\n } catch (e) {\n // XXX make all compilation errors MinimongoError or something\n // so that this doesn't ignore unrelated exceptions\n return false;\n }\n }], function (f) { return f(); }); // invoke each function\n\n var driverClass = canUseOplog ? OplogObserveDriver : PollingObserveDriver;\n observeDriver = new driverClass({\n cursorDescription: cursorDescription,\n mongoHandle: self,\n multiplexer: multiplexer,\n ordered: ordered,\n matcher: matcher, // ignored by polling\n sorter: sorter, // ignored by polling\n _testOnlyPollCallback: callbacks._testOnlyPollCallback\n });\n\n // This field is only set for use in tests.\n multiplexer._observeDriver = observeDriver;\n }\n\n // Blocks until the initial adds have been sent.\n multiplexer.addHandleAndSendInitialAdds(observeHandle);\n\n return observeHandle;\n};\n\n// Listen for the invalidation messages that will trigger us to poll the\n// database for changes. If this selector specifies specific IDs, specify them\n// here, so that updates to different specific IDs don't cause us to poll.\n// listenCallback is the same kind of (notification, complete) callback passed\n// to InvalidationCrossbar.listen.\n\nlistenAll = function (cursorDescription, listenCallback) {\n var listeners = [];\n forEachTrigger(cursorDescription, function (trigger) {\n listeners.push(DDPServer._InvalidationCrossbar.listen(\n trigger, listenCallback));\n });\n\n return {\n stop: function () {\n _.each(listeners, function (listener) {\n listener.stop();\n });\n }\n };\n};\n\nforEachTrigger = function (cursorDescription, triggerCallback) {\n var key = {collection: cursorDescription.collectionName};\n var specificIds = LocalCollection._idsMatchedBySelector(\n cursorDescription.selector);\n if (specificIds) {\n _.each(specificIds, function (id) {\n triggerCallback(_.extend({id: id}, key));\n });\n triggerCallback(_.extend({dropCollection: true, id: null}, key));\n } else {\n triggerCallback(key);\n }\n};\n\n// observeChanges for tailable cursors on capped collections.\n//\n// Some differences from normal cursors:\n// - Will never produce anything other than 'added' or 'addedBefore'. If you\n// do update a document that has already been produced, this will not notice\n// it.\n// - If you disconnect and reconnect from Mongo, it will essentially restart\n// the query, which will lead to duplicate results. This is pretty bad,\n// but if you include a field called 'ts' which is inserted as\n// new MongoInternals.MongoTimestamp(0, 0) (which is initialized to the\n// current Mongo-style timestamp), we'll be able to find the place to\n// restart properly. (This field is specifically understood by Mongo with an\n// optimization which allows it to find the right place to start without\n// an index on ts. It's how the oplog works.)\n// - No callbacks are triggered synchronously with the call (there's no\n// differentiation between \"initial data\" and \"later changes\"; everything\n// that matches the query gets sent asynchronously).\n// - De-duplication is not implemented.\n// - Does not yet interact with the write fence. Probably, this should work by\n// ignoring removes (which don't work on capped collections) and updates\n// (which don't affect tailable cursors), and just keeping track of the ID\n// of the inserted object, and closing the write fence once you get to that\n// ID (or timestamp?). This doesn't work well if the document doesn't match\n// the query, though. On the other hand, the write fence can close\n// immediately if it does not match the query. So if we trust minimongo\n// enough to accurately evaluate the query against the write fence, we\n// should be able to do this... Of course, minimongo doesn't even support\n// Mongo Timestamps yet.\nMongoConnection.prototype._observeChangesTailable = function (\n cursorDescription, ordered, callbacks) {\n var self = this;\n\n // Tailable cursors only ever call added/addedBefore callbacks, so it's an\n // error if you didn't provide them.\n if ((ordered && !callbacks.addedBefore) ||\n (!ordered && !callbacks.added)) {\n throw new Error(\"Can't observe an \" + (ordered ? \"ordered\" : \"unordered\")\n + \" tailable cursor without a \"\n + (ordered ? \"addedBefore\" : \"added\") + \" callback\");\n }\n\n return self.tail(cursorDescription, function (doc) {\n var id = doc._id;\n delete doc._id;\n // The ts is an implementation detail. Hide it.\n delete doc.ts;\n if (ordered) {\n callbacks.addedBefore(id, doc, null);\n } else {\n callbacks.added(id, doc);\n }\n });\n};\n\n// XXX We probably need to find a better way to expose this. Right now\n// it's only used by tests, but in fact you need it in normal\n// operation to interact with capped collections.\nMongoInternals.MongoTimestamp = MongoDB.Timestamp;\n\nMongoInternals.Connection = MongoConnection;\n","var Future = Npm.require('fibers/future');\n\nOPLOG_COLLECTION = 'oplog.rs';\n\nvar TOO_FAR_BEHIND = process.env.METEOR_OPLOG_TOO_FAR_BEHIND || 2000;\n\n// Like Perl's quotemeta: quotes all regexp metacharacters. See\n// https://github.com/substack/quotemeta/blob/master/index.js\n// XXX this is duplicated with accounts_server.js\nvar quotemeta = function (str) {\n return String(str).replace(/(\\W)/g, '\\\\$1');\n};\n\nvar showTS = function (ts) {\n return \"Timestamp(\" + ts.getHighBits() + \", \" + ts.getLowBits() + \")\";\n};\n\nidForOp = function (op) {\n if (op.op === 'd')\n return op.o._id;\n else if (op.op === 'i')\n return op.o._id;\n else if (op.op === 'u')\n return op.o2._id;\n else if (op.op === 'c')\n throw Error(\"Operator 'c' doesn't supply an object with id: \" +\n EJSON.stringify(op));\n else\n throw Error(\"Unknown op: \" + EJSON.stringify(op));\n};\n\nOplogHandle = function (oplogUrl, dbName) {\n var self = this;\n self._oplogUrl = oplogUrl;\n self._dbName = dbName;\n\n self._oplogLastEntryConnection = null;\n self._oplogTailConnection = null;\n self._stopped = false;\n self._tailHandle = null;\n self._readyFuture = new Future();\n self._crossbar = new DDPServer._Crossbar({\n factPackage: \"mongo-livedata\", factName: \"oplog-watchers\"\n });\n self._baseOplogSelector = {\n ns: new RegExp('^' + quotemeta(self._dbName) + '\\\\.'),\n $or: [\n { op: {$in: ['i', 'u', 'd']} },\n // If it is not db.collection.drop(), ignore it\n { op: 'c', 'o.drop': { $exists: true } }]\n };\n\n // Data structures to support waitUntilCaughtUp(). Each oplog entry has a\n // MongoTimestamp object on it (which is not the same as a Date --- it's a\n // combination of time and an incrementing counter; see\n // http://docs.mongodb.org/manual/reference/bson-types/#timestamps).\n //\n // _catchingUpFutures is an array of {ts: MongoTimestamp, future: Future}\n // objects, sorted by ascending timestamp. _lastProcessedTS is the\n // MongoTimestamp of the last oplog entry we've processed.\n //\n // Each time we call waitUntilCaughtUp, we take a peek at the final oplog\n // entry in the db. If we've already processed it (ie, it is not greater than\n // _lastProcessedTS), waitUntilCaughtUp immediately returns. Otherwise,\n // waitUntilCaughtUp makes a new Future and inserts it along with the final\n // timestamp entry that it read, into _catchingUpFutures. waitUntilCaughtUp\n // then waits on that future, which is resolved once _lastProcessedTS is\n // incremented to be past its timestamp by the worker fiber.\n //\n // XXX use a priority queue or something else that's faster than an array\n self._catchingUpFutures = [];\n self._lastProcessedTS = null;\n\n self._onSkippedEntriesHook = new Hook({\n debugPrintExceptions: \"onSkippedEntries callback\"\n });\n\n self._entryQueue = new Meteor._DoubleEndedQueue();\n self._workerActive = false;\n\n self._startTailing();\n};\n\n_.extend(OplogHandle.prototype, {\n stop: function () {\n var self = this;\n if (self._stopped)\n return;\n self._stopped = true;\n if (self._tailHandle)\n self._tailHandle.stop();\n // XXX should close connections too\n },\n onOplogEntry: function (trigger, callback) {\n var self = this;\n if (self._stopped)\n throw new Error(\"Called onOplogEntry on stopped handle!\");\n\n // Calling onOplogEntry requires us to wait for the tailing to be ready.\n self._readyFuture.wait();\n\n var originalCallback = callback;\n callback = Meteor.bindEnvironment(function (notification) {\n // XXX can we avoid this clone by making oplog.js careful?\n originalCallback(EJSON.clone(notification));\n }, function (err) {\n Meteor._debug(\"Error in oplog callback\", err.stack);\n });\n var listenHandle = self._crossbar.listen(trigger, callback);\n return {\n stop: function () {\n listenHandle.stop();\n }\n };\n },\n // Register a callback to be invoked any time we skip oplog entries (eg,\n // because we are too far behind).\n onSkippedEntries: function (callback) {\n var self = this;\n if (self._stopped)\n throw new Error(\"Called onSkippedEntries on stopped handle!\");\n return self._onSkippedEntriesHook.register(callback);\n },\n // Calls `callback` once the oplog has been processed up to a point that is\n // roughly \"now\": specifically, once we've processed all ops that are\n // currently visible.\n // XXX become convinced that this is actually safe even if oplogConnection\n // is some kind of pool\n waitUntilCaughtUp: function () {\n var self = this;\n if (self._stopped)\n throw new Error(\"Called waitUntilCaughtUp on stopped handle!\");\n\n // Calling waitUntilCaughtUp requries us to wait for the oplog connection to\n // be ready.\n self._readyFuture.wait();\n\n while (!self._stopped) {\n // We need to make the selector at least as restrictive as the actual\n // tailing selector (ie, we need to specify the DB name) or else we might\n // find a TS that won't show up in the actual tail stream.\n try {\n var lastEntry = self._oplogLastEntryConnection.findOne(\n OPLOG_COLLECTION, self._baseOplogSelector,\n {fields: {ts: 1}, sort: {$natural: -1}});\n break;\n } catch (e) {\n // During failover (eg) if we get an exception we should log and retry\n // instead of crashing.\n Meteor._debug(\"Got exception while reading last entry: \" + e);\n Meteor._sleepForMs(100);\n }\n }\n\n if (self._stopped)\n return;\n\n if (!lastEntry) {\n // Really, nothing in the oplog? Well, we've processed everything.\n return;\n }\n\n var ts = lastEntry.ts;\n if (!ts)\n throw Error(\"oplog entry without ts: \" + EJSON.stringify(lastEntry));\n\n if (self._lastProcessedTS && ts.lessThanOrEqual(self._lastProcessedTS)) {\n // We've already caught up to here.\n return;\n }\n\n\n // Insert the future into our list. Almost always, this will be at the end,\n // but it's conceivable that if we fail over from one primary to another,\n // the oplog entries we see will go backwards.\n var insertAfter = self._catchingUpFutures.length;\n while (insertAfter - 1 > 0\n && self._catchingUpFutures[insertAfter - 1].ts.greaterThan(ts)) {\n insertAfter--;\n }\n var f = new Future;\n self._catchingUpFutures.splice(insertAfter, 0, {ts: ts, future: f});\n f.wait();\n },\n _startTailing: function () {\n var self = this;\n // First, make sure that we're talking to the local database.\n var mongodbUri = Npm.require('mongodb-uri');\n if (mongodbUri.parse(self._oplogUrl).database !== 'local') {\n throw Error(\"$MONGO_OPLOG_URL must be set to the 'local' database of \" +\n \"a Mongo replica set\");\n }\n\n // We make two separate connections to Mongo. The Node Mongo driver\n // implements a naive round-robin connection pool: each \"connection\" is a\n // pool of several (5 by default) TCP connections, and each request is\n // rotated through the pools. Tailable cursor queries block on the server\n // until there is some data to return (or until a few seconds have\n // passed). So if the connection pool used for tailing cursors is the same\n // pool used for other queries, the other queries will be delayed by seconds\n // 1/5 of the time.\n //\n // The tail connection will only ever be running a single tail command, so\n // it only needs to make one underlying TCP connection.\n self._oplogTailConnection = new MongoConnection(\n self._oplogUrl, {poolSize: 1});\n // XXX better docs, but: it's to get monotonic results\n // XXX is it safe to say \"if there's an in flight query, just use its\n // results\"? I don't think so but should consider that\n self._oplogLastEntryConnection = new MongoConnection(\n self._oplogUrl, {poolSize: 1});\n\n // Now, make sure that there actually is a repl set here. If not, oplog\n // tailing won't ever find anything!\n var f = new Future;\n self._oplogLastEntryConnection.db.admin().command(\n { ismaster: 1 }, f.resolver());\n var isMasterDoc = f.wait();\n if (!(isMasterDoc && isMasterDoc.documents && isMasterDoc.documents[0] &&\n isMasterDoc.documents[0].setName)) {\n throw Error(\"$MONGO_OPLOG_URL must be set to the 'local' database of \" +\n \"a Mongo replica set\");\n }\n\n // Find the last oplog entry.\n var lastOplogEntry = self._oplogLastEntryConnection.findOne(\n OPLOG_COLLECTION, {}, {sort: {$natural: -1}, fields: {ts: 1}});\n\n var oplogSelector = _.clone(self._baseOplogSelector);\n if (lastOplogEntry) {\n // Start after the last entry that currently exists.\n oplogSelector.ts = {$gt: lastOplogEntry.ts};\n // If there are any calls to callWhenProcessedLatest before any other\n // oplog entries show up, allow callWhenProcessedLatest to call its\n // callback immediately.\n self._lastProcessedTS = lastOplogEntry.ts;\n }\n\n var cursorDescription = new CursorDescription(\n OPLOG_COLLECTION, oplogSelector, {tailable: true});\n\n self._tailHandle = self._oplogTailConnection.tail(\n cursorDescription, function (doc) {\n self._entryQueue.push(doc);\n self._maybeStartWorker();\n }\n );\n self._readyFuture.return();\n },\n\n _maybeStartWorker: function () {\n var self = this;\n if (self._workerActive)\n return;\n self._workerActive = true;\n Meteor.defer(function () {\n try {\n while (! self._stopped && ! self._entryQueue.isEmpty()) {\n // Are we too far behind? Just tell our observers that they need to\n // repoll, and drop our queue.\n if (self._entryQueue.length > TOO_FAR_BEHIND) {\n var lastEntry = self._entryQueue.pop();\n self._entryQueue.clear();\n\n self._onSkippedEntriesHook.each(function (callback) {\n callback();\n return true;\n });\n\n // Free any waitUntilCaughtUp() calls that were waiting for us to\n // pass something that we just skipped.\n self._setLastProcessedTS(lastEntry.ts);\n continue;\n }\n\n var doc = self._entryQueue.shift();\n\n if (!(doc.ns && doc.ns.length > self._dbName.length + 1 &&\n doc.ns.substr(0, self._dbName.length + 1) ===\n (self._dbName + '.'))) {\n throw new Error(\"Unexpected ns\");\n }\n\n var trigger = {collection: doc.ns.substr(self._dbName.length + 1),\n dropCollection: false,\n op: doc};\n\n // Is it a special command and the collection name is hidden somewhere\n // in operator?\n if (trigger.collection === \"$cmd\") {\n trigger.collection = doc.o.drop;\n trigger.dropCollection = true;\n trigger.id = null;\n } else {\n // All other ops have an id.\n trigger.id = idForOp(doc);\n }\n\n self._crossbar.fire(trigger);\n\n // Now that we've processed this operation, process pending\n // sequencers.\n if (!doc.ts)\n throw Error(\"oplog entry without ts: \" + EJSON.stringify(doc));\n self._setLastProcessedTS(doc.ts);\n }\n } finally {\n self._workerActive = false;\n }\n });\n },\n _setLastProcessedTS: function (ts) {\n var self = this;\n self._lastProcessedTS = ts;\n while (!_.isEmpty(self._catchingUpFutures)\n && self._catchingUpFutures[0].ts.lessThanOrEqual(\n self._lastProcessedTS)) {\n var sequencer = self._catchingUpFutures.shift();\n sequencer.future.return();\n }\n }\n});\n","var Future = Npm.require('fibers/future');\n\nObserveMultiplexer = function (options) {\n var self = this;\n\n if (!options || !_.has(options, 'ordered'))\n throw Error(\"must specified ordered\");\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-multiplexers\", 1);\n\n self._ordered = options.ordered;\n self._onStop = options.onStop || function () {};\n self._queue = new Meteor._SynchronousQueue();\n self._handles = {};\n self._readyFuture = new Future;\n self._cache = new LocalCollection._CachingChangeObserver({\n ordered: options.ordered});\n // Number of addHandleAndSendInitialAdds tasks scheduled but not yet\n // running. removeHandle uses this to know if it's time to call the onStop\n // callback.\n self._addHandleTasksScheduledButNotPerformed = 0;\n\n _.each(self.callbackNames(), function (callbackName) {\n self[callbackName] = function (/* ... */) {\n self._applyCallback(callbackName, _.toArray(arguments));\n };\n });\n};\n\n_.extend(ObserveMultiplexer.prototype, {\n addHandleAndSendInitialAdds: function (handle) {\n var self = this;\n\n // Check this before calling runTask (even though runTask does the same\n // check) so that we don't leak an ObserveMultiplexer on error by\n // incrementing _addHandleTasksScheduledButNotPerformed and never\n // decrementing it.\n if (!self._queue.safeToRunTask())\n throw new Error(\n \"Can't call observeChanges from an observe callback on the same query\");\n ++self._addHandleTasksScheduledButNotPerformed;\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-handles\", 1);\n\n self._queue.runTask(function () {\n self._handles[handle._id] = handle;\n // Send out whatever adds we have so far (whether or not we the\n // multiplexer is ready).\n self._sendAdds(handle);\n --self._addHandleTasksScheduledButNotPerformed;\n });\n // *outside* the task, since otherwise we'd deadlock\n self._readyFuture.wait();\n },\n\n // Remove an observe handle. If it was the last observe handle, call the\n // onStop callback; you cannot add any more observe handles after this.\n //\n // This is not synchronized with polls and handle additions: this means that\n // you can safely call it from within an observe callback, but it also means\n // that we have to be careful when we iterate over _handles.\n removeHandle: function (id) {\n var self = this;\n\n // This should not be possible: you can only call removeHandle by having\n // access to the ObserveHandle, which isn't returned to user code until the\n // multiplex is ready.\n if (!self._ready())\n throw new Error(\"Can't remove handles until the multiplex is ready\");\n\n delete self._handles[id];\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-handles\", -1);\n\n if (_.isEmpty(self._handles) &&\n self._addHandleTasksScheduledButNotPerformed === 0) {\n self._stop();\n }\n },\n _stop: function (options) {\n var self = this;\n options = options || {};\n\n // It shouldn't be possible for us to stop when all our handles still\n // haven't been returned from observeChanges!\n if (! self._ready() && ! options.fromQueryError)\n throw Error(\"surprising _stop: not ready\");\n\n // Call stop callback (which kills the underlying process which sends us\n // callbacks and removes us from the connection's dictionary).\n self._onStop();\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-multiplexers\", -1);\n\n // Cause future addHandleAndSendInitialAdds calls to throw (but the onStop\n // callback should make our connection forget about us).\n self._handles = null;\n },\n\n // Allows all addHandleAndSendInitialAdds calls to return, once all preceding\n // adds have been processed. Does not block.\n ready: function () {\n var self = this;\n self._queue.queueTask(function () {\n if (self._ready())\n throw Error(\"can't make ObserveMultiplex ready twice!\");\n self._readyFuture.return();\n });\n },\n\n // If trying to execute the query results in an error, call this. This is\n // intended for permanent errors, not transient network errors that could be\n // fixed. It should only be called before ready(), because if you called ready\n // that meant that you managed to run the query once. It will stop this\n // ObserveMultiplex and cause addHandleAndSendInitialAdds calls (and thus\n // observeChanges calls) to throw the error.\n queryError: function (err) {\n var self = this;\n self._queue.runTask(function () {\n if (self._ready())\n throw Error(\"can't claim query has an error after it worked!\");\n self._stop({fromQueryError: true});\n self._readyFuture.throw(err);\n });\n },\n\n // Calls \"cb\" once the effects of all \"ready\", \"addHandleAndSendInitialAdds\"\n // and observe callbacks which came before this call have been propagated to\n // all handles. \"ready\" must have already been called on this multiplexer.\n onFlush: function (cb) {\n var self = this;\n self._queue.queueTask(function () {\n if (!self._ready())\n throw Error(\"only call onFlush on a multiplexer that will be ready\");\n cb();\n });\n },\n callbackNames: function () {\n var self = this;\n if (self._ordered)\n return [\"addedBefore\", \"changed\", \"movedBefore\", \"removed\"];\n else\n return [\"added\", \"changed\", \"removed\"];\n },\n _ready: function () {\n return this._readyFuture.isResolved();\n },\n _applyCallback: function (callbackName, args) {\n var self = this;\n self._queue.queueTask(function () {\n // If we stopped in the meantime, do nothing.\n if (!self._handles)\n return;\n\n // First, apply the change to the cache.\n // XXX We could make applyChange callbacks promise not to hang on to any\n // state from their arguments (assuming that their supplied callbacks\n // don't) and skip this clone. Currently 'changed' hangs on to state\n // though.\n self._cache.applyChange[callbackName].apply(null, EJSON.clone(args));\n\n // If we haven't finished the initial adds, then we should only be getting\n // adds.\n if (!self._ready() &&\n (callbackName !== 'added' && callbackName !== 'addedBefore')) {\n throw new Error(\"Got \" + callbackName + \" during initial adds\");\n }\n\n // Now multiplex the callbacks out to all observe handles. It's OK if\n // these calls yield; since we're inside a task, no other use of our queue\n // can continue until these are done. (But we do have to be careful to not\n // use a handle that got removed, because removeHandle does not use the\n // queue; thus, we iterate over an array of keys that we control.)\n _.each(_.keys(self._handles), function (handleId) {\n var handle = self._handles && self._handles[handleId];\n if (!handle)\n return;\n var callback = handle['_' + callbackName];\n // clone arguments so that callbacks can mutate their arguments\n callback && callback.apply(null, EJSON.clone(args));\n });\n });\n },\n\n // Sends initial adds to a handle. It should only be called from within a task\n // (the task that is processing the addHandleAndSendInitialAdds call). It\n // synchronously invokes the handle's added or addedBefore; there's no need to\n // flush the queue afterwards to ensure that the callbacks get out.\n _sendAdds: function (handle) {\n var self = this;\n if (self._queue.safeToRunTask())\n throw Error(\"_sendAdds may only be called from within a task!\");\n var add = self._ordered ? handle._addedBefore : handle._added;\n if (!add)\n return;\n // note: docs may be an _IdMap or an OrderedDict\n self._cache.docs.forEach(function (doc, id) {\n if (!_.has(self._handles, handle._id))\n throw Error(\"handle got removed before sending initial adds!\");\n var fields = EJSON.clone(doc);\n delete fields._id;\n if (self._ordered)\n add(id, fields, null); // we're going in order, so add at end\n else\n add(id, fields);\n });\n }\n});\n\n\nvar nextObserveHandleId = 1;\nObserveHandle = function (multiplexer, callbacks) {\n var self = this;\n // The end user is only supposed to call stop(). The other fields are\n // accessible to the multiplexer, though.\n self._multiplexer = multiplexer;\n _.each(multiplexer.callbackNames(), function (name) {\n if (callbacks[name]) {\n self['_' + name] = callbacks[name];\n } else if (name === \"addedBefore\" && callbacks.added) {\n // Special case: if you specify \"added\" and \"movedBefore\", you get an\n // ordered observe where for some reason you don't get ordering data on\n // the adds. I dunno, we wrote tests for it, there must have been a\n // reason.\n self._addedBefore = function (id, fields, before) {\n callbacks.added(id, fields);\n };\n }\n });\n self._stopped = false;\n self._id = nextObserveHandleId++;\n};\nObserveHandle.prototype.stop = function () {\n var self = this;\n if (self._stopped)\n return;\n self._stopped = true;\n self._multiplexer.removeHandle(self._id);\n};\n","var Fiber = Npm.require('fibers');\nvar Future = Npm.require('fibers/future');\n\nDocFetcher = function (mongoConnection) {\n var self = this;\n self._mongoConnection = mongoConnection;\n // Map from cache key -> [callback]\n self._callbacksForCacheKey = {};\n};\n\n_.extend(DocFetcher.prototype, {\n // Fetches document \"id\" from collectionName, returning it or null if not\n // found.\n //\n // If you make multiple calls to fetch() with the same cacheKey (a string),\n // DocFetcher may assume that they all return the same document. (It does\n // not check to see if collectionName/id match.)\n //\n // You may assume that callback is never called synchronously (and in fact\n // OplogObserveDriver does so).\n fetch: function (collectionName, id, cacheKey, callback) {\n var self = this;\n\n check(collectionName, String);\n // id is some sort of scalar\n check(cacheKey, String);\n\n // If there's already an in-progress fetch for this cache key, yield until\n // it's done and return whatever it returns.\n if (_.has(self._callbacksForCacheKey, cacheKey)) {\n self._callbacksForCacheKey[cacheKey].push(callback);\n return;\n }\n\n var callbacks = self._callbacksForCacheKey[cacheKey] = [callback];\n\n Fiber(function () {\n try {\n var doc = self._mongoConnection.findOne(\n collectionName, {_id: id}) || null;\n // Return doc to all relevant callbacks. Note that this array can\n // continue to grow during callback excecution.\n while (!_.isEmpty(callbacks)) {\n // Clone the document so that the various calls to fetch don't return\n // objects that are intertwingled with each other. Clone before\n // popping the future, so that if clone throws, the error gets passed\n // to the next callback.\n var clonedDoc = EJSON.clone(doc);\n callbacks.pop()(null, clonedDoc);\n }\n } catch (e) {\n while (!_.isEmpty(callbacks)) {\n callbacks.pop()(e);\n }\n } finally {\n // XXX consider keeping the doc around for a period of time before\n // removing from the cache\n delete self._callbacksForCacheKey[cacheKey];\n }\n }).run();\n }\n});\n\nMongoTest.DocFetcher = DocFetcher;\n","PollingObserveDriver = function (options) {\n var self = this;\n\n self._cursorDescription = options.cursorDescription;\n self._mongoHandle = options.mongoHandle;\n self._ordered = options.ordered;\n self._multiplexer = options.multiplexer;\n self._stopCallbacks = [];\n self._stopped = false;\n\n self._synchronousCursor = self._mongoHandle._createSynchronousCursor(\n self._cursorDescription);\n\n // previous results snapshot. on each poll cycle, diffs against\n // results drives the callbacks.\n self._results = null;\n\n // The number of _pollMongo calls that have been added to self._taskQueue but\n // have not started running. Used to make sure we never schedule more than one\n // _pollMongo (other than possibly the one that is currently running). It's\n // also used by _suspendPolling to pretend there's a poll scheduled. Usually,\n // it's either 0 (for \"no polls scheduled other than maybe one currently\n // running\") or 1 (for \"a poll scheduled that isn't running yet\"), but it can\n // also be 2 if incremented by _suspendPolling.\n self._pollsScheduledButNotStarted = 0;\n self._pendingWrites = []; // people to notify when polling completes\n\n // Make sure to create a separately throttled function for each\n // PollingObserveDriver object.\n self._ensurePollIsScheduled = _.throttle(\n self._unthrottledEnsurePollIsScheduled, 50 /* ms */);\n\n // XXX figure out if we still need a queue\n self._taskQueue = new Meteor._SynchronousQueue();\n\n var listenersHandle = listenAll(\n self._cursorDescription, function (notification) {\n // When someone does a transaction that might affect us, schedule a poll\n // of the database. If that transaction happens inside of a write fence,\n // block the fence until we've polled and notified observers.\n var fence = DDPServer._CurrentWriteFence.get();\n if (fence)\n self._pendingWrites.push(fence.beginWrite());\n // Ensure a poll is scheduled... but if we already know that one is,\n // don't hit the throttled _ensurePollIsScheduled function (which might\n // lead to us calling it unnecessarily in 50ms).\n if (self._pollsScheduledButNotStarted === 0)\n self._ensurePollIsScheduled();\n }\n );\n self._stopCallbacks.push(function () { listenersHandle.stop(); });\n\n // every once and a while, poll even if we don't think we're dirty, for\n // eventual consistency with database writes from outside the Meteor\n // universe.\n //\n // For testing, there's an undocumented callback argument to observeChanges\n // which disables time-based polling and gets called at the beginning of each\n // poll.\n if (options._testOnlyPollCallback) {\n self._testOnlyPollCallback = options._testOnlyPollCallback;\n } else {\n var intervalHandle = Meteor.setInterval(\n _.bind(self._ensurePollIsScheduled, self), 10 * 1000);\n self._stopCallbacks.push(function () {\n Meteor.clearInterval(intervalHandle);\n });\n }\n\n // Make sure we actually poll soon!\n self._unthrottledEnsurePollIsScheduled();\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-drivers-polling\", 1);\n};\n\n_.extend(PollingObserveDriver.prototype, {\n // This is always called through _.throttle (except once at startup).\n _unthrottledEnsurePollIsScheduled: function () {\n var self = this;\n if (self._pollsScheduledButNotStarted > 0)\n return;\n ++self._pollsScheduledButNotStarted;\n self._taskQueue.queueTask(function () {\n self._pollMongo();\n });\n },\n\n // test-only interface for controlling polling.\n //\n // _suspendPolling blocks until any currently running and scheduled polls are\n // done, and prevents any further polls from being scheduled. (new\n // ObserveHandles can be added and receive their initial added callbacks,\n // though.)\n //\n // _resumePolling immediately polls, and allows further polls to occur.\n _suspendPolling: function() {\n var self = this;\n // Pretend that there's another poll scheduled (which will prevent\n // _ensurePollIsScheduled from queueing any more polls).\n ++self._pollsScheduledButNotStarted;\n // Now block until all currently running or scheduled polls are done.\n self._taskQueue.runTask(function() {});\n\n // Confirm that there is only one \"poll\" (the fake one we're pretending to\n // have) scheduled.\n if (self._pollsScheduledButNotStarted !== 1)\n throw new Error(\"_pollsScheduledButNotStarted is \" +\n self._pollsScheduledButNotStarted);\n },\n _resumePolling: function() {\n var self = this;\n // We should be in the same state as in the end of _suspendPolling.\n if (self._pollsScheduledButNotStarted !== 1)\n throw new Error(\"_pollsScheduledButNotStarted is \" +\n self._pollsScheduledButNotStarted);\n // Run a poll synchronously (which will counteract the\n // ++_pollsScheduledButNotStarted from _suspendPolling).\n self._taskQueue.runTask(function () {\n self._pollMongo();\n });\n },\n\n _pollMongo: function () {\n var self = this;\n --self._pollsScheduledButNotStarted;\n\n if (self._stopped)\n return;\n\n var first = false;\n var oldResults = self._results;\n if (!oldResults) {\n first = true;\n // XXX maybe use OrderedDict instead?\n oldResults = self._ordered ? [] : new LocalCollection._IdMap;\n }\n\n self._testOnlyPollCallback && self._testOnlyPollCallback();\n\n // Save the list of pending writes which this round will commit.\n var writesForCycle = self._pendingWrites;\n self._pendingWrites = [];\n\n // Get the new query results. (This yields.)\n try {\n var newResults = self._synchronousCursor.getRawObjects(self._ordered);\n } catch (e) {\n if (first && typeof(e.code) === 'number') {\n // This is an error document sent to us by mongod, not a connection\n // error generated by the client. And we've never seen this query work\n // successfully. Probably it's a bad selector or something, so we should\n // NOT retry. Instead, we should halt the observe (which ends up calling\n // `stop` on us).\n self._multiplexer.queryError(\n new Error(\n \"Exception while polling query \" +\n JSON.stringify(self._cursorDescription) + \": \" + e.message));\n return;\n }\n\n // getRawObjects can throw if we're having trouble talking to the\n // database. That's fine --- we will repoll later anyway. But we should\n // make sure not to lose track of this cycle's writes.\n // (It also can throw if there's just something invalid about this query;\n // unfortunately the ObserveDriver API doesn't provide a good way to\n // \"cancel\" the observe from the inside in this case.\n Array.prototype.push.apply(self._pendingWrites, writesForCycle);\n Meteor._debug(\"Exception while polling query \" +\n JSON.stringify(self._cursorDescription) + \": \" + e.stack);\n return;\n }\n\n // Run diffs.\n if (!self._stopped) {\n LocalCollection._diffQueryChanges(\n self._ordered, oldResults, newResults, self._multiplexer);\n }\n\n // Signals the multiplexer to allow all observeChanges calls that share this\n // multiplexer to return. (This happens asynchronously, via the\n // multiplexer's queue.)\n if (first)\n self._multiplexer.ready();\n\n // Replace self._results atomically. (This assignment is what makes `first`\n // stay through on the next cycle, so we've waited until after we've\n // committed to ready-ing the multiplexer.)\n self._results = newResults;\n\n // Once the ObserveMultiplexer has processed everything we've done in this\n // round, mark all the writes which existed before this call as\n // commmitted. (If new writes have shown up in the meantime, there'll\n // already be another _pollMongo task scheduled.)\n self._multiplexer.onFlush(function () {\n _.each(writesForCycle, function (w) {\n w.committed();\n });\n });\n },\n\n stop: function () {\n var self = this;\n self._stopped = true;\n _.each(self._stopCallbacks, function (c) { c(); });\n // Release any write fences that are waiting on us.\n _.each(self._pendingWrites, function (w) {\n w.committed();\n });\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-drivers-polling\", -1);\n }\n});\n","var Fiber = Npm.require('fibers');\nvar Future = Npm.require('fibers/future');\n\nvar PHASE = {\n QUERYING: \"QUERYING\",\n FETCHING: \"FETCHING\",\n STEADY: \"STEADY\"\n};\n\n// Exception thrown by _needToPollQuery which unrolls the stack up to the\n// enclosing call to finishIfNeedToPollQuery.\nvar SwitchedToQuery = function () {};\nvar finishIfNeedToPollQuery = function (f) {\n return function () {\n try {\n f.apply(this, arguments);\n } catch (e) {\n if (!(e instanceof SwitchedToQuery))\n throw e;\n }\n };\n};\n\n// OplogObserveDriver is an alternative to PollingObserveDriver which follows\n// the Mongo operation log instead of just re-polling the query. It obeys the\n// same simple interface: constructing it starts sending observeChanges\n// callbacks (and a ready() invocation) to the ObserveMultiplexer, and you stop\n// it by calling the stop() method.\nOplogObserveDriver = function (options) {\n var self = this;\n self._usesOplog = true; // tests look at this\n\n self._cursorDescription = options.cursorDescription;\n self._mongoHandle = options.mongoHandle;\n self._multiplexer = options.multiplexer;\n\n if (options.ordered) {\n throw Error(\"OplogObserveDriver only supports unordered observeChanges\");\n }\n\n var sorter = options.sorter;\n // We don't support $near and other geo-queries so it's OK to initialize the\n // comparator only once in the constructor.\n var comparator = sorter && sorter.getComparator();\n\n if (options.cursorDescription.options.limit) {\n // There are several properties ordered driver implements:\n // - _limit is a positive number\n // - _comparator is a function-comparator by which the query is ordered\n // - _unpublishedBuffer is non-null Min/Max Heap,\n // the empty buffer in STEADY phase implies that the\n // everything that matches the queries selector fits\n // into published set.\n // - _published - Min Heap (also implements IdMap methods)\n\n var heapOptions = { IdMap: LocalCollection._IdMap };\n self._limit = self._cursorDescription.options.limit;\n self._comparator = comparator;\n self._sorter = sorter;\n self._unpublishedBuffer = new MinMaxHeap(comparator, heapOptions);\n // We need something that can find Max value in addition to IdMap interface\n self._published = new MaxHeap(comparator, heapOptions);\n } else {\n self._limit = 0;\n self._comparator = null;\n self._sorter = null;\n self._unpublishedBuffer = null;\n self._published = new LocalCollection._IdMap;\n }\n\n // Indicates if it is safe to insert a new document at the end of the buffer\n // for this query. i.e. it is known that there are no documents matching the\n // selector those are not in published or buffer.\n self._safeAppendToBuffer = false;\n\n self._stopped = false;\n self._stopHandles = [];\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-drivers-oplog\", 1);\n\n self._registerPhaseChange(PHASE.QUERYING);\n\n var selector = self._cursorDescription.selector;\n self._matcher = options.matcher;\n var projection = self._cursorDescription.options.fields || {};\n self._projectionFn = LocalCollection._compileProjection(projection);\n // Projection function, result of combining important fields for selector and\n // existing fields projection\n self._sharedProjection = self._matcher.combineIntoProjection(projection);\n if (sorter)\n self._sharedProjection = sorter.combineIntoProjection(self._sharedProjection);\n self._sharedProjectionFn = LocalCollection._compileProjection(\n self._sharedProjection);\n\n self._needToFetch = new LocalCollection._IdMap;\n self._currentlyFetching = null;\n self._fetchGeneration = 0;\n\n self._requeryWhenDoneThisQuery = false;\n self._writesToCommitWhenWeReachSteady = [];\n\n // If the oplog handle tells us that it skipped some entries (because it got\n // behind, say), re-poll.\n self._stopHandles.push(self._mongoHandle._oplogHandle.onSkippedEntries(\n finishIfNeedToPollQuery(function () {\n self._needToPollQuery();\n })\n ));\n\n forEachTrigger(self._cursorDescription, function (trigger) {\n self._stopHandles.push(self._mongoHandle._oplogHandle.onOplogEntry(\n trigger, function (notification) {\n Meteor._noYieldsAllowed(finishIfNeedToPollQuery(function () {\n var op = notification.op;\n if (notification.dropCollection) {\n // Note: this call is not allowed to block on anything (especially\n // on waiting for oplog entries to catch up) because that will block\n // onOplogEntry!\n self._needToPollQuery();\n } else {\n // All other operators should be handled depending on phase\n if (self._phase === PHASE.QUERYING)\n self._handleOplogEntryQuerying(op);\n else\n self._handleOplogEntrySteadyOrFetching(op);\n }\n }));\n }\n ));\n });\n\n // XXX ordering w.r.t. everything else?\n self._stopHandles.push(listenAll(\n self._cursorDescription, function (notification) {\n // If we're not in a write fence, we don't have to do anything.\n var fence = DDPServer._CurrentWriteFence.get();\n if (!fence)\n return;\n var write = fence.beginWrite();\n // This write cannot complete until we've caught up to \"this point\" in the\n // oplog, and then made it back to the steady state.\n Meteor.defer(function () {\n self._mongoHandle._oplogHandle.waitUntilCaughtUp();\n if (self._stopped) {\n // We're stopped, so just immediately commit.\n write.committed();\n } else if (self._phase === PHASE.STEADY) {\n // Make sure that all of the callbacks have made it through the\n // multiplexer and been delivered to ObserveHandles before committing\n // writes.\n self._multiplexer.onFlush(function () {\n write.committed();\n });\n } else {\n self._writesToCommitWhenWeReachSteady.push(write);\n }\n });\n }\n ));\n\n // When Mongo fails over, we need to repoll the query, in case we processed an\n // oplog entry that got rolled back.\n self._stopHandles.push(self._mongoHandle._onFailover(finishIfNeedToPollQuery(\n function () {\n self._needToPollQuery();\n })));\n\n // Give _observeChanges a chance to add the new ObserveHandle to our\n // multiplexer, so that the added calls get streamed.\n Meteor.defer(finishIfNeedToPollQuery(function () {\n self._runInitialQuery();\n }));\n};\n\n_.extend(OplogObserveDriver.prototype, {\n _addPublished: function (id, doc) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n var fields = _.clone(doc);\n delete fields._id;\n self._published.set(id, self._sharedProjectionFn(doc));\n self._multiplexer.added(id, self._projectionFn(fields));\n\n // After adding this document, the published set might be overflowed\n // (exceeding capacity specified by limit). If so, push the maximum\n // element to the buffer, we might want to save it in memory to reduce the\n // amount of Mongo lookups in the future.\n if (self._limit && self._published.size() > self._limit) {\n // XXX in theory the size of published is no more than limit+1\n if (self._published.size() !== self._limit + 1) {\n throw new Error(\"After adding to published, \" +\n (self._published.size() - self._limit) +\n \" documents are overflowing the set\");\n }\n\n var overflowingDocId = self._published.maxElementId();\n var overflowingDoc = self._published.get(overflowingDocId);\n\n if (EJSON.equals(overflowingDocId, id)) {\n throw new Error(\"The document just added is overflowing the published set\");\n }\n\n self._published.remove(overflowingDocId);\n self._multiplexer.removed(overflowingDocId);\n self._addBuffered(overflowingDocId, overflowingDoc);\n }\n });\n },\n _removePublished: function (id) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._published.remove(id);\n self._multiplexer.removed(id);\n if (! self._limit || self._published.size() === self._limit)\n return;\n\n if (self._published.size() > self._limit)\n throw Error(\"self._published got too big\");\n\n // OK, we are publishing less than the limit. Maybe we should look in the\n // buffer to find the next element past what we were publishing before.\n\n if (!self._unpublishedBuffer.empty()) {\n // There's something in the buffer; move the first thing in it to\n // _published.\n var newDocId = self._unpublishedBuffer.minElementId();\n var newDoc = self._unpublishedBuffer.get(newDocId);\n self._removeBuffered(newDocId);\n self._addPublished(newDocId, newDoc);\n return;\n }\n\n // There's nothing in the buffer. This could mean one of a few things.\n\n // (a) We could be in the middle of re-running the query (specifically, we\n // could be in _publishNewResults). In that case, _unpublishedBuffer is\n // empty because we clear it at the beginning of _publishNewResults. In\n // this case, our caller already knows the entire answer to the query and\n // we don't need to do anything fancy here. Just return.\n if (self._phase === PHASE.QUERYING)\n return;\n\n // (b) We're pretty confident that the union of _published and\n // _unpublishedBuffer contain all documents that match selector. Because\n // _unpublishedBuffer is empty, that means we're confident that _published\n // contains all documents that match selector. So we have nothing to do.\n if (self._safeAppendToBuffer)\n return;\n\n // (c) Maybe there are other documents out there that should be in our\n // buffer. But in that case, when we emptied _unpublishedBuffer in\n // _removeBuffered, we should have called _needToPollQuery, which will\n // either put something in _unpublishedBuffer or set _safeAppendToBuffer\n // (or both), and it will put us in QUERYING for that whole time. So in\n // fact, we shouldn't be able to get here.\n\n throw new Error(\"Buffer inexplicably empty\");\n });\n },\n _changePublished: function (id, oldDoc, newDoc) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._published.set(id, self._sharedProjectionFn(newDoc));\n var projectedNew = self._projectionFn(newDoc);\n var projectedOld = self._projectionFn(oldDoc);\n var changed = LocalCollection._makeChangedFields(\n projectedNew, projectedOld);\n if (!_.isEmpty(changed))\n self._multiplexer.changed(id, changed);\n });\n },\n _addBuffered: function (id, doc) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._unpublishedBuffer.set(id, self._sharedProjectionFn(doc));\n\n // If something is overflowing the buffer, we just remove it from cache\n if (self._unpublishedBuffer.size() > self._limit) {\n var maxBufferedId = self._unpublishedBuffer.maxElementId();\n\n self._unpublishedBuffer.remove(maxBufferedId);\n\n // Since something matching is removed from cache (both published set and\n // buffer), set flag to false\n self._safeAppendToBuffer = false;\n }\n });\n },\n // Is called either to remove the doc completely from matching set or to move\n // it to the published set later.\n _removeBuffered: function (id) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._unpublishedBuffer.remove(id);\n // To keep the contract \"buffer is never empty in STEADY phase unless the\n // everything matching fits into published\" true, we poll everything as\n // soon as we see the buffer becoming empty.\n if (! self._unpublishedBuffer.size() && ! self._safeAppendToBuffer)\n self._needToPollQuery();\n });\n },\n // Called when a document has joined the \"Matching\" results set.\n // Takes responsibility of keeping _unpublishedBuffer in sync with _published\n // and the effect of limit enforced.\n _addMatching: function (doc) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n var id = doc._id;\n if (self._published.has(id))\n throw Error(\"tried to add something already published \" + id);\n if (self._limit && self._unpublishedBuffer.has(id))\n throw Error(\"tried to add something already existed in buffer \" + id);\n\n var limit = self._limit;\n var comparator = self._comparator;\n var maxPublished = (limit && self._published.size() > 0) ?\n self._published.get(self._published.maxElementId()) : null;\n var maxBuffered = (limit && self._unpublishedBuffer.size() > 0)\n ? self._unpublishedBuffer.get(self._unpublishedBuffer.maxElementId())\n : null;\n // The query is unlimited or didn't publish enough documents yet or the\n // new document would fit into published set pushing the maximum element\n // out, then we need to publish the doc.\n var toPublish = ! limit || self._published.size() < limit ||\n comparator(doc, maxPublished) < 0;\n\n // Otherwise we might need to buffer it (only in case of limited query).\n // Buffering is allowed if the buffer is not filled up yet and all\n // matching docs are either in the published set or in the buffer.\n var canAppendToBuffer = !toPublish && self._safeAppendToBuffer &&\n self._unpublishedBuffer.size() < limit;\n\n // Or if it is small enough to be safely inserted to the middle or the\n // beginning of the buffer.\n var canInsertIntoBuffer = !toPublish && maxBuffered &&\n comparator(doc, maxBuffered) <= 0;\n\n var toBuffer = canAppendToBuffer || canInsertIntoBuffer;\n\n if (toPublish) {\n self._addPublished(id, doc);\n } else if (toBuffer) {\n self._addBuffered(id, doc);\n } else {\n // dropping it and not saving to the cache\n self._safeAppendToBuffer = false;\n }\n });\n },\n // Called when a document leaves the \"Matching\" results set.\n // Takes responsibility of keeping _unpublishedBuffer in sync with _published\n // and the effect of limit enforced.\n _removeMatching: function (id) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n if (! self._published.has(id) && ! self._limit)\n throw Error(\"tried to remove something matching but not cached \" + id);\n\n if (self._published.has(id)) {\n self._removePublished(id);\n } else if (self._unpublishedBuffer.has(id)) {\n self._removeBuffered(id);\n }\n });\n },\n _handleDoc: function (id, newDoc) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n var matchesNow = newDoc && self._matcher.documentMatches(newDoc).result;\n\n var publishedBefore = self._published.has(id);\n var bufferedBefore = self._limit && self._unpublishedBuffer.has(id);\n var cachedBefore = publishedBefore || bufferedBefore;\n\n if (matchesNow && !cachedBefore) {\n self._addMatching(newDoc);\n } else if (cachedBefore && !matchesNow) {\n self._removeMatching(id);\n } else if (cachedBefore && matchesNow) {\n var oldDoc = self._published.get(id);\n var comparator = self._comparator;\n var minBuffered = self._limit && self._unpublishedBuffer.size() &&\n self._unpublishedBuffer.get(self._unpublishedBuffer.minElementId());\n\n if (publishedBefore) {\n // Unlimited case where the document stays in published once it\n // matches or the case when we don't have enough matching docs to\n // publish or the changed but matching doc will stay in published\n // anyways.\n //\n // XXX: We rely on the emptiness of buffer. Be sure to maintain the\n // fact that buffer can't be empty if there are matching documents not\n // published. Notably, we don't want to schedule repoll and continue\n // relying on this property.\n var staysInPublished = ! self._limit ||\n self._unpublishedBuffer.size() === 0 ||\n comparator(newDoc, minBuffered) <= 0;\n\n if (staysInPublished) {\n self._changePublished(id, oldDoc, newDoc);\n } else {\n // after the change doc doesn't stay in the published, remove it\n self._removePublished(id);\n // but it can move into buffered now, check it\n var maxBuffered = self._unpublishedBuffer.get(\n self._unpublishedBuffer.maxElementId());\n\n var toBuffer = self._safeAppendToBuffer ||\n (maxBuffered && comparator(newDoc, maxBuffered) <= 0);\n\n if (toBuffer) {\n self._addBuffered(id, newDoc);\n } else {\n // Throw away from both published set and buffer\n self._safeAppendToBuffer = false;\n }\n }\n } else if (bufferedBefore) {\n oldDoc = self._unpublishedBuffer.get(id);\n // remove the old version manually instead of using _removeBuffered so\n // we don't trigger the querying immediately. if we end this block\n // with the buffer empty, we will need to trigger the query poll\n // manually too.\n self._unpublishedBuffer.remove(id);\n\n var maxPublished = self._published.get(\n self._published.maxElementId());\n var maxBuffered = self._unpublishedBuffer.size() &&\n self._unpublishedBuffer.get(\n self._unpublishedBuffer.maxElementId());\n\n // the buffered doc was updated, it could move to published\n var toPublish = comparator(newDoc, maxPublished) < 0;\n\n // or stays in buffer even after the change\n var staysInBuffer = (! toPublish && self._safeAppendToBuffer) ||\n (!toPublish && maxBuffered &&\n comparator(newDoc, maxBuffered) <= 0);\n\n if (toPublish) {\n self._addPublished(id, newDoc);\n } else if (staysInBuffer) {\n // stays in buffer but changes\n self._unpublishedBuffer.set(id, newDoc);\n } else {\n // Throw away from both published set and buffer\n self._safeAppendToBuffer = false;\n // Normally this check would have been done in _removeBuffered but\n // we didn't use it, so we need to do it ourself now.\n if (! self._unpublishedBuffer.size()) {\n self._needToPollQuery();\n }\n }\n } else {\n throw new Error(\"cachedBefore implies either of publishedBefore or bufferedBefore is true.\");\n }\n }\n });\n },\n _fetchModifiedDocuments: function () {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._registerPhaseChange(PHASE.FETCHING);\n // Defer, because nothing called from the oplog entry handler may yield,\n // but fetch() yields.\n Meteor.defer(finishIfNeedToPollQuery(function () {\n while (!self._stopped && !self._needToFetch.empty()) {\n if (self._phase === PHASE.QUERYING) {\n // While fetching, we decided to go into QUERYING mode, and then we\n // saw another oplog entry, so _needToFetch is not empty. But we\n // shouldn't fetch these documents until AFTER the query is done.\n break;\n }\n\n // Being in steady phase here would be surprising.\n if (self._phase !== PHASE.FETCHING)\n throw new Error(\"phase in fetchModifiedDocuments: \" + self._phase);\n\n self._currentlyFetching = self._needToFetch;\n var thisGeneration = ++self._fetchGeneration;\n self._needToFetch = new LocalCollection._IdMap;\n var waiting = 0;\n var fut = new Future;\n // This loop is safe, because _currentlyFetching will not be updated\n // during this loop (in fact, it is never mutated).\n self._currentlyFetching.forEach(function (cacheKey, id) {\n waiting++;\n self._mongoHandle._docFetcher.fetch(\n self._cursorDescription.collectionName, id, cacheKey,\n finishIfNeedToPollQuery(function (err, doc) {\n try {\n if (err) {\n Meteor._debug(\"Got exception while fetching documents: \" +\n err);\n // If we get an error from the fetcher (eg, trouble\n // connecting to Mongo), let's just abandon the fetch phase\n // altogether and fall back to polling. It's not like we're\n // getting live updates anyway.\n if (self._phase !== PHASE.QUERYING) {\n self._needToPollQuery();\n }\n } else if (!self._stopped && self._phase === PHASE.FETCHING\n && self._fetchGeneration === thisGeneration) {\n // We re-check the generation in case we've had an explicit\n // _pollQuery call (eg, in another fiber) which should\n // effectively cancel this round of fetches. (_pollQuery\n // increments the generation.)\n self._handleDoc(id, doc);\n }\n } finally {\n waiting--;\n // Because fetch() never calls its callback synchronously,\n // this is safe (ie, we won't call fut.return() before the\n // forEach is done).\n if (waiting === 0)\n fut.return();\n }\n }));\n });\n fut.wait();\n // Exit now if we've had a _pollQuery call (here or in another fiber).\n if (self._phase === PHASE.QUERYING)\n return;\n self._currentlyFetching = null;\n }\n // We're done fetching, so we can be steady, unless we've had a\n // _pollQuery call (here or in another fiber).\n if (self._phase !== PHASE.QUERYING)\n self._beSteady();\n }));\n });\n },\n _beSteady: function () {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._registerPhaseChange(PHASE.STEADY);\n var writes = self._writesToCommitWhenWeReachSteady;\n self._writesToCommitWhenWeReachSteady = [];\n self._multiplexer.onFlush(function () {\n _.each(writes, function (w) {\n w.committed();\n });\n });\n });\n },\n _handleOplogEntryQuerying: function (op) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n self._needToFetch.set(idForOp(op), op.ts.toString());\n });\n },\n _handleOplogEntrySteadyOrFetching: function (op) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n var id = idForOp(op);\n // If we're already fetching this one, or about to, we can't optimize;\n // make sure that we fetch it again if necessary.\n if (self._phase === PHASE.FETCHING &&\n ((self._currentlyFetching && self._currentlyFetching.has(id)) ||\n self._needToFetch.has(id))) {\n self._needToFetch.set(id, op.ts.toString());\n return;\n }\n\n if (op.op === 'd') {\n if (self._published.has(id) ||\n (self._limit && self._unpublishedBuffer.has(id)))\n self._removeMatching(id);\n } else if (op.op === 'i') {\n if (self._published.has(id))\n throw new Error(\"insert found for already-existing ID in published\");\n if (self._unpublishedBuffer && self._unpublishedBuffer.has(id))\n throw new Error(\"insert found for already-existing ID in buffer\");\n\n // XXX what if selector yields? for now it can't but later it could\n // have $where\n if (self._matcher.documentMatches(op.o).result)\n self._addMatching(op.o);\n } else if (op.op === 'u') {\n // Is this a modifier ($set/$unset, which may require us to poll the\n // database to figure out if the whole document matches the selector) or\n // a replacement (in which case we can just directly re-evaluate the\n // selector)?\n var isReplace = !_.has(op.o, '$set') && !_.has(op.o, '$unset');\n // If this modifier modifies something inside an EJSON custom type (ie,\n // anything with EJSON$), then we can't try to use\n // LocalCollection._modify, since that just mutates the EJSON encoding,\n // not the actual object.\n var canDirectlyModifyDoc =\n !isReplace && modifierCanBeDirectlyApplied(op.o);\n\n var publishedBefore = self._published.has(id);\n var bufferedBefore = self._limit && self._unpublishedBuffer.has(id);\n\n if (isReplace) {\n self._handleDoc(id, _.extend({_id: id}, op.o));\n } else if ((publishedBefore || bufferedBefore) &&\n canDirectlyModifyDoc) {\n // Oh great, we actually know what the document is, so we can apply\n // this directly.\n var newDoc = self._published.has(id)\n ? self._published.get(id) : self._unpublishedBuffer.get(id);\n newDoc = EJSON.clone(newDoc);\n\n newDoc._id = id;\n try {\n LocalCollection._modify(newDoc, op.o);\n } catch (e) {\n if (e.name !== \"MinimongoError\")\n throw e;\n // We didn't understand the modifier. Re-fetch.\n self._needToFetch.set(id, op.ts.toString());\n if (self._phase === PHASE.STEADY) {\n self._fetchModifiedDocuments();\n }\n return;\n }\n self._handleDoc(id, self._sharedProjectionFn(newDoc));\n } else if (!canDirectlyModifyDoc ||\n self._matcher.canBecomeTrueByModifier(op.o) ||\n (self._sorter && self._sorter.affectedByModifier(op.o))) {\n self._needToFetch.set(id, op.ts.toString());\n if (self._phase === PHASE.STEADY)\n self._fetchModifiedDocuments();\n }\n } else {\n throw Error(\"XXX SURPRISING OPERATION: \" + op);\n }\n });\n },\n // Yields!\n _runInitialQuery: function () {\n var self = this;\n if (self._stopped)\n throw new Error(\"oplog stopped surprisingly early\");\n\n self._runQuery({initial: true}); // yields\n\n if (self._stopped)\n return; // can happen on queryError\n\n // Allow observeChanges calls to return. (After this, it's possible for\n // stop() to be called.)\n self._multiplexer.ready();\n\n self._doneQuerying(); // yields\n },\n\n // In various circumstances, we may just want to stop processing the oplog and\n // re-run the initial query, just as if we were a PollingObserveDriver.\n //\n // This function may not block, because it is called from an oplog entry\n // handler.\n //\n // XXX We should call this when we detect that we've been in FETCHING for \"too\n // long\".\n //\n // XXX We should call this when we detect Mongo failover (since that might\n // mean that some of the oplog entries we have processed have been rolled\n // back). The Node Mongo driver is in the middle of a bunch of huge\n // refactorings, including the way that it notifies you when primary\n // changes. Will put off implementing this until driver 1.4 is out.\n _pollQuery: function () {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n if (self._stopped)\n return;\n\n // Yay, we get to forget about all the things we thought we had to fetch.\n self._needToFetch = new LocalCollection._IdMap;\n self._currentlyFetching = null;\n ++self._fetchGeneration; // ignore any in-flight fetches\n self._registerPhaseChange(PHASE.QUERYING);\n\n // Defer so that we don't yield. We don't need finishIfNeedToPollQuery\n // here because SwitchedToQuery is not thrown in QUERYING mode.\n Meteor.defer(function () {\n self._runQuery();\n self._doneQuerying();\n });\n });\n },\n\n // Yields!\n _runQuery: function (options) {\n var self = this;\n options = options || {};\n var newResults, newBuffer;\n\n // This while loop is just to retry failures.\n while (true) {\n // If we've been stopped, we don't have to run anything any more.\n if (self._stopped)\n return;\n\n newResults = new LocalCollection._IdMap;\n newBuffer = new LocalCollection._IdMap;\n\n // Query 2x documents as the half excluded from the original query will go\n // into unpublished buffer to reduce additional Mongo lookups in cases\n // when documents are removed from the published set and need a\n // replacement.\n // XXX needs more thought on non-zero skip\n // XXX 2 is a \"magic number\" meaning there is an extra chunk of docs for\n // buffer if such is needed.\n var cursor = self._cursorForQuery({ limit: self._limit * 2 });\n try {\n cursor.forEach(function (doc, i) { // yields\n if (!self._limit || i < self._limit)\n newResults.set(doc._id, doc);\n else\n newBuffer.set(doc._id, doc);\n });\n break;\n } catch (e) {\n if (options.initial && typeof(e.code) === 'number') {\n // This is an error document sent to us by mongod, not a connection\n // error generated by the client. And we've never seen this query work\n // successfully. Probably it's a bad selector or something, so we\n // should NOT retry. Instead, we should halt the observe (which ends\n // up calling `stop` on us).\n self._multiplexer.queryError(e);\n return;\n }\n\n // During failover (eg) if we get an exception we should log and retry\n // instead of crashing.\n Meteor._debug(\"Got exception while polling query: \" + e);\n Meteor._sleepForMs(100);\n }\n }\n\n if (self._stopped)\n return;\n\n self._publishNewResults(newResults, newBuffer);\n },\n\n // Transitions to QUERYING and runs another query, or (if already in QUERYING)\n // ensures that we will query again later.\n //\n // This function may not block, because it is called from an oplog entry\n // handler. However, if we were not already in the QUERYING phase, it throws\n // an exception that is caught by the closest surrounding\n // finishIfNeedToPollQuery call; this ensures that we don't continue running\n // close that was designed for another phase inside PHASE.QUERYING.\n //\n // (It's also necessary whenever logic in this file yields to check that other\n // phases haven't put us into QUERYING mode, though; eg,\n // _fetchModifiedDocuments does this.)\n _needToPollQuery: function () {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n if (self._stopped)\n return;\n\n // If we're not already in the middle of a query, we can query now\n // (possibly pausing FETCHING).\n if (self._phase !== PHASE.QUERYING) {\n self._pollQuery();\n throw new SwitchedToQuery;\n }\n\n // We're currently in QUERYING. Set a flag to ensure that we run another\n // query when we're done.\n self._requeryWhenDoneThisQuery = true;\n });\n },\n\n // Yields!\n _doneQuerying: function () {\n var self = this;\n\n if (self._stopped)\n return;\n self._mongoHandle._oplogHandle.waitUntilCaughtUp(); // yields\n if (self._stopped)\n return;\n if (self._phase !== PHASE.QUERYING)\n throw Error(\"Phase unexpectedly \" + self._phase);\n\n Meteor._noYieldsAllowed(function () {\n if (self._requeryWhenDoneThisQuery) {\n self._requeryWhenDoneThisQuery = false;\n self._pollQuery();\n } else if (self._needToFetch.empty()) {\n self._beSteady();\n } else {\n self._fetchModifiedDocuments();\n }\n });\n },\n\n _cursorForQuery: function (optionsOverwrite) {\n var self = this;\n return Meteor._noYieldsAllowed(function () {\n // The query we run is almost the same as the cursor we are observing,\n // with a few changes. We need to read all the fields that are relevant to\n // the selector, not just the fields we are going to publish (that's the\n // \"shared\" projection). And we don't want to apply any transform in the\n // cursor, because observeChanges shouldn't use the transform.\n var options = _.clone(self._cursorDescription.options);\n\n // Allow the caller to modify the options. Useful to specify different\n // skip and limit values.\n _.extend(options, optionsOverwrite);\n\n options.fields = self._sharedProjection;\n delete options.transform;\n // We are NOT deep cloning fields or selector here, which should be OK.\n var description = new CursorDescription(\n self._cursorDescription.collectionName,\n self._cursorDescription.selector,\n options);\n return new Cursor(self._mongoHandle, description);\n });\n },\n\n\n // Replace self._published with newResults (both are IdMaps), invoking observe\n // callbacks on the multiplexer.\n // Replace self._unpublishedBuffer with newBuffer.\n //\n // XXX This is very similar to LocalCollection._diffQueryUnorderedChanges. We\n // should really: (a) Unify IdMap and OrderedDict into Unordered/OrderedDict\n // (b) Rewrite diff.js to use these classes instead of arrays and objects.\n _publishNewResults: function (newResults, newBuffer) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n\n // If the query is limited and there is a buffer, shut down so it doesn't\n // stay in a way.\n if (self._limit) {\n self._unpublishedBuffer.clear();\n }\n\n // First remove anything that's gone. Be careful not to modify\n // self._published while iterating over it.\n var idsToRemove = [];\n self._published.forEach(function (doc, id) {\n if (!newResults.has(id))\n idsToRemove.push(id);\n });\n _.each(idsToRemove, function (id) {\n self._removePublished(id);\n });\n\n // Now do adds and changes.\n // If self has a buffer and limit, the new fetched result will be\n // limited correctly as the query has sort specifier.\n newResults.forEach(function (doc, id) {\n self._handleDoc(id, doc);\n });\n\n // Sanity-check that everything we tried to put into _published ended up\n // there.\n // XXX if this is slow, remove it later\n if (self._published.size() !== newResults.size()) {\n throw Error(\n \"The Mongo server and the Meteor query disagree on how \" +\n \"many documents match your query. Maybe it is hitting a Mongo \" +\n \"edge case? The query is: \" +\n EJSON.stringify(self._cursorDescription.selector));\n }\n self._published.forEach(function (doc, id) {\n if (!newResults.has(id))\n throw Error(\"_published has a doc that newResults doesn't; \" + id);\n });\n\n // Finally, replace the buffer\n newBuffer.forEach(function (doc, id) {\n self._addBuffered(id, doc);\n });\n\n self._safeAppendToBuffer = newBuffer.size() < self._limit;\n });\n },\n\n // This stop function is invoked from the onStop of the ObserveMultiplexer, so\n // it shouldn't actually be possible to call it until the multiplexer is\n // ready.\n //\n // It's important to check self._stopped after every call in this file that\n // can yield!\n stop: function () {\n var self = this;\n if (self._stopped)\n return;\n self._stopped = true;\n _.each(self._stopHandles, function (handle) {\n handle.stop();\n });\n\n // Note: we *don't* use multiplexer.onFlush here because this stop\n // callback is actually invoked by the multiplexer itself when it has\n // determined that there are no handles left. So nothing is actually going\n // to get flushed (and it's probably not valid to call methods on the\n // dying multiplexer).\n _.each(self._writesToCommitWhenWeReachSteady, function (w) {\n w.committed(); // maybe yields?\n });\n self._writesToCommitWhenWeReachSteady = null;\n\n // Proactively drop references to potentially big things.\n self._published = null;\n self._unpublishedBuffer = null;\n self._needToFetch = null;\n self._currentlyFetching = null;\n self._oplogEntryHandle = null;\n self._listenersHandle = null;\n\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"observe-drivers-oplog\", -1);\n },\n\n _registerPhaseChange: function (phase) {\n var self = this;\n Meteor._noYieldsAllowed(function () {\n var now = new Date;\n\n if (self._phase) {\n var timeDiff = now - self._phaseStartTime;\n Package.facts && Package.facts.Facts.incrementServerFact(\n \"mongo-livedata\", \"time-spent-in-\" + self._phase + \"-phase\", timeDiff);\n }\n\n self._phase = phase;\n self._phaseStartTime = now;\n });\n }\n});\n\n// Does our oplog tailing code support this cursor? For now, we are being very\n// conservative and allowing only simple queries with simple options.\n// (This is a \"static method\".)\nOplogObserveDriver.cursorSupported = function (cursorDescription, matcher) {\n // First, check the options.\n var options = cursorDescription.options;\n\n // Did the user say no explicitly?\n if (options._disableOplog)\n return false;\n\n // skip is not supported: to support it we would need to keep track of all\n // \"skipped\" documents or at least their ids.\n // limit w/o a sort specifier is not supported: current implementation needs a\n // deterministic way to order documents.\n if (options.skip || (options.limit && !options.sort)) return false;\n\n // If a fields projection option is given check if it is supported by\n // minimongo (some operators are not supported).\n if (options.fields) {\n try {\n LocalCollection._checkSupportedProjection(options.fields);\n } catch (e) {\n if (e.name === \"MinimongoError\")\n return false;\n else\n throw e;\n }\n }\n\n // We don't allow the following selectors:\n // - $where (not confident that we provide the same JS environment\n // as Mongo, and can yield!)\n // - $near (has \"interesting\" properties in MongoDB, like the possibility\n // of returning an ID multiple times, though even polling maybe\n // have a bug there)\n // XXX: once we support it, we would need to think more on how we\n // initialize the comparators when we create the driver.\n return !matcher.hasWhere() && !matcher.hasGeoQuery();\n};\n\nvar modifierCanBeDirectlyApplied = function (modifier) {\n return _.all(modifier, function (fields, operation) {\n return _.all(fields, function (value, field) {\n return !/EJSON\\$/.test(field);\n });\n });\n};\n\nMongoInternals.OplogObserveDriver = OplogObserveDriver;\n","LocalCollectionDriver = function () {\n var self = this;\n self.noConnCollections = {};\n};\n\nvar ensureCollection = function (name, collections) {\n if (!(name in collections))\n collections[name] = new LocalCollection(name);\n return collections[name];\n};\n\n_.extend(LocalCollectionDriver.prototype, {\n open: function (name, conn) {\n var self = this;\n if (!name)\n return new LocalCollection;\n if (! conn) {\n return ensureCollection(name, self.noConnCollections);\n }\n if (! conn._mongo_livedata_collections)\n conn._mongo_livedata_collections = {};\n // XXX is there a way to keep track of a connection's collections without\n // dangling it off the connection object?\n return ensureCollection(name, conn._mongo_livedata_collections);\n }\n});\n\n// singleton\nLocalCollectionDriver = new LocalCollectionDriver;\n","MongoInternals.RemoteCollectionDriver = function (\n mongo_url, options) {\n var self = this;\n self.mongo = new MongoConnection(mongo_url, options);\n};\n\n_.extend(MongoInternals.RemoteCollectionDriver.prototype, {\n open: function (name) {\n var self = this;\n var ret = {};\n _.each(\n ['find', 'findOne', 'insert', 'update', 'upsert',\n 'remove', '_ensureIndex', '_dropIndex', '_createCappedCollection',\n 'dropCollection', 'rawCollection'],\n function (m) {\n ret[m] = _.bind(self.mongo[m], self.mongo, name);\n });\n return ret;\n }\n});\n\n\n// Create the singleton RemoteCollectionDriver only on demand, so we\n// only require Mongo configuration if it's actually used (eg, not if\n// you're only trying to receive data from a remote DDP server.)\nMongoInternals.defaultRemoteCollectionDriver = _.once(function () {\n var connectionOptions = {};\n\n var mongoUrl = process.env.MONGO_URL;\n\n if (process.env.MONGO_OPLOG_URL) {\n connectionOptions.oplogUrl = process.env.MONGO_OPLOG_URL;\n }\n\n if (! mongoUrl)\n throw new Error(\"MONGO_URL must be set in environment\");\n\n return new MongoInternals.RemoteCollectionDriver(mongoUrl, connectionOptions);\n});\n","// options.connection, if given, is a LivedataClient or LivedataServer\n// XXX presently there is no way to destroy/clean up a Collection\n\n/**\n * @summary Namespace for MongoDB-related items\n * @namespace\n */\nMongo = {};\n\n/**\n * @summary Constructor for a Collection\n * @locus Anywhere\n * @instancename collection\n * @class\n * @param {String} name The name of the collection. If null, creates an unmanaged (unsynchronized) local collection.\n * @param {Object} [options]\n * @param {Object} options.connection The server connection that will manage this collection. Uses the default connection if not specified. Pass the return value of calling [`DDP.connect`](#ddp_connect) to specify a different server. Pass `null` to specify no connection. Unmanaged (`name` is null) collections cannot specify a connection.\n * @param {String} options.idGeneration The method of generating the `_id` fields of new documents in this collection. Possible values:\n\n - **`'STRING'`**: random strings\n - **`'MONGO'`**: random [`Mongo.ObjectID`](#mongo_object_id) values\n\nThe default id generation technique is `'STRING'`.\n * @param {Function} options.transform An optional transformation function. Documents will be passed through this function before being returned from `fetch` or `findOne`, and before being passed to callbacks of `observe`, `map`, `forEach`, `allow`, and `deny`. Transforms are *not* applied for the callbacks of `observeChanges` or to cursors returned from publish functions.\n */\nMongo.Collection = function (name, options) {\n var self = this;\n if (! (self instanceof Mongo.Collection))\n throw new Error('use \"new\" to construct a Mongo.Collection');\n\n if (!name && (name !== null)) {\n Meteor._debug(\"Warning: creating anonymous collection. It will not be \" +\n \"saved or synchronized over the network. (Pass null for \" +\n \"the collection name to turn off this warning.)\");\n name = null;\n }\n\n if (name !== null && typeof name !== \"string\") {\n throw new Error(\n \"First argument to new Mongo.Collection must be a string or null\");\n }\n\n if (options && options.methods) {\n // Backwards compatibility hack with original signature (which passed\n // \"connection\" directly instead of in options. (Connections must have a \"methods\"\n // method.)\n // XXX remove before 1.0\n options = {connection: options};\n }\n // Backwards compatibility: \"connection\" used to be called \"manager\".\n if (options && options.manager && !options.connection) {\n options.connection = options.manager;\n }\n options = _.extend({\n connection: undefined,\n idGeneration: 'STRING',\n transform: null,\n _driver: undefined,\n _preventAutopublish: false\n }, options);\n\n switch (options.idGeneration) {\n case 'MONGO':\n self._makeNewID = function () {\n var src = name ? DDP.randomStream('/collection/' + name) : Random;\n return new Mongo.ObjectID(src.hexString(24));\n };\n break;\n case 'STRING':\n default:\n self._makeNewID = function () {\n var src = name ? DDP.randomStream('/collection/' + name) : Random;\n return src.id();\n };\n break;\n }\n\n self._transform = LocalCollection.wrapTransform(options.transform);\n\n if (! name || options.connection === null)\n // note: nameless collections never have a connection\n self._connection = null;\n else if (options.connection)\n self._connection = options.connection;\n else if (Meteor.isClient)\n self._connection = Meteor.connection;\n else\n self._connection = Meteor.server;\n\n if (!options._driver) {\n // XXX This check assumes that webapp is loaded so that Meteor.server !==\n // null. We should fully support the case of \"want to use a Mongo-backed\n // collection from Node code without webapp\", but we don't yet.\n // #MeteorServerNull\n if (name && self._connection === Meteor.server &&\n typeof MongoInternals !== \"undefined\" &&\n MongoInternals.defaultRemoteCollectionDriver) {\n options._driver = MongoInternals.defaultRemoteCollectionDriver();\n } else {\n options._driver = LocalCollectionDriver;\n }\n }\n\n self._collection = options._driver.open(name, self._connection);\n self._name = name;\n self._driver = options._driver;\n\n if (self._connection && self._connection.registerStore) {\n // OK, we're going to be a slave, replicating some remote\n // database, except possibly with some temporary divergence while\n // we have unacknowledged RPC's.\n var ok = self._connection.registerStore(name, {\n // Called at the beginning of a batch of updates. batchSize is the number\n // of update calls to expect.\n //\n // XXX This interface is pretty janky. reset probably ought to go back to\n // being its own function, and callers shouldn't have to calculate\n // batchSize. The optimization of not calling pause/remove should be\n // delayed until later: the first call to update() should buffer its\n // message, and then we can either directly apply it at endUpdate time if\n // it was the only update, or do pauseObservers/apply/apply at the next\n // update() if there's another one.\n beginUpdate: function (batchSize, reset) {\n // pause observers so users don't see flicker when updating several\n // objects at once (including the post-reconnect reset-and-reapply\n // stage), and so that a re-sorting of a query can take advantage of the\n // full _diffQuery moved calculation instead of applying change one at a\n // time.\n if (batchSize > 1 || reset)\n self._collection.pauseObservers();\n\n if (reset)\n self._collection.remove({});\n },\n\n // Apply an update.\n // XXX better specify this interface (not in terms of a wire message)?\n update: function (msg) {\n var mongoId = LocalCollection._idParse(msg.id);\n var doc = self._collection.findOne(mongoId);\n\n // Is this a \"replace the whole doc\" message coming from the quiescence\n // of method writes to an object? (Note that 'undefined' is a valid\n // value meaning \"remove it\".)\n if (msg.msg === 'replace') {\n var replace = msg.replace;\n if (!replace) {\n if (doc)\n self._collection.remove(mongoId);\n } else if (!doc) {\n self._collection.insert(replace);\n } else {\n // XXX check that replace has no $ ops\n self._collection.update(mongoId, replace);\n }\n return;\n } else if (msg.msg === 'added') {\n if (doc) {\n throw new Error(\"Expected not to find a document already present for an add\");\n }\n self._collection.insert(_.extend({_id: mongoId}, msg.fields));\n } else if (msg.msg === 'removed') {\n if (!doc)\n throw new Error(\"Expected to find a document already present for removed\");\n self._collection.remove(mongoId);\n } else if (msg.msg === 'changed') {\n if (!doc)\n throw new Error(\"Expected to find a document to change\");\n if (!_.isEmpty(msg.fields)) {\n var modifier = {};\n _.each(msg.fields, function (value, key) {\n if (value === undefined) {\n if (!modifier.$unset)\n modifier.$unset = {};\n modifier.$unset[key] = 1;\n } else {\n if (!modifier.$set)\n modifier.$set = {};\n modifier.$set[key] = value;\n }\n });\n self._collection.update(mongoId, modifier);\n }\n } else {\n throw new Error(\"I don't know how to deal with this message\");\n }\n\n },\n\n // Called at the end of a batch of updates.\n endUpdate: function () {\n self._collection.resumeObservers();\n },\n\n // Called around method stub invocations to capture the original versions\n // of modified documents.\n saveOriginals: function () {\n self._collection.saveOriginals();\n },\n retrieveOriginals: function () {\n return self._collection.retrieveOriginals();\n }\n });\n\n if (!ok)\n throw new Error(\"There is already a collection named '\" + name + \"'\");\n }\n\n self._defineMutationMethods();\n\n // autopublish\n if (Package.autopublish && !options._preventAutopublish && self._connection\n && self._connection.publish) {\n self._connection.publish(null, function () {\n return self.find();\n }, {is_auto: true});\n }\n};\n\n///\n/// Main collection API\n///\n\n\n_.extend(Mongo.Collection.prototype, {\n\n _getFindSelector: function (args) {\n if (args.length == 0)\n return {};\n else\n return args[0];\n },\n\n _getFindOptions: function (args) {\n var self = this;\n if (args.length < 2) {\n return { transform: self._transform };\n } else {\n check(args[1], Match.Optional(Match.ObjectIncluding({\n fields: Match.Optional(Match.OneOf(Object, undefined)),\n sort: Match.Optional(Match.OneOf(Object, Array, undefined)),\n limit: Match.Optional(Match.OneOf(Number, undefined)),\n skip: Match.Optional(Match.OneOf(Number, undefined))\n })));\n\n return _.extend({\n transform: self._transform\n }, args[1]);\n }\n },\n\n /**\n * @summary Find the documents in a collection that match the selector.\n * @locus Anywhere\n * @method find\n * @memberOf Mongo.Collection\n * @instance\n * @param {MongoSelector} [selector] A query describing the documents to find\n * @param {Object} [options]\n * @param {MongoSortSpecifier} options.sort Sort order (default: natural order)\n * @param {Number} options.skip Number of results to skip at the beginning\n * @param {Number} options.limit Maximum number of results to return\n * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude.\n * @param {Boolean} options.reactive (Client only) Default `true`; pass `false` to disable reactivity\n * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections) for this cursor. Pass `null` to disable transformation.\n * @returns {Mongo.Cursor}\n */\n find: function (/* selector, options */) {\n // Collection.find() (return all docs) behaves differently\n // from Collection.find(undefined) (return 0 docs). so be\n // careful about the length of arguments.\n var self = this;\n var argArray = _.toArray(arguments);\n return self._collection.find(self._getFindSelector(argArray),\n self._getFindOptions(argArray));\n },\n\n /**\n * @summary Finds the first document that matches the selector, as ordered by sort and skip options.\n * @locus Anywhere\n * @method findOne\n * @memberOf Mongo.Collection\n * @instance\n * @param {MongoSelector} [selector] A query describing the documents to find\n * @param {Object} [options]\n * @param {MongoSortSpecifier} options.sort Sort order (default: natural order)\n * @param {Number} options.skip Number of results to skip at the beginning\n * @param {MongoFieldSpecifier} options.fields Dictionary of fields to return or exclude.\n * @param {Boolean} options.reactive (Client only) Default true; pass false to disable reactivity\n * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections) for this cursor. Pass `null` to disable transformation.\n * @returns {Object}\n */\n findOne: function (/* selector, options */) {\n var self = this;\n var argArray = _.toArray(arguments);\n return self._collection.findOne(self._getFindSelector(argArray),\n self._getFindOptions(argArray));\n }\n\n});\n\nMongo.Collection._publishCursor = function (cursor, sub, collection) {\n var observeHandle = cursor.observeChanges({\n added: function (id, fields) {\n sub.added(collection, id, fields);\n },\n changed: function (id, fields) {\n sub.changed(collection, id, fields);\n },\n removed: function (id) {\n sub.removed(collection, id);\n }\n });\n\n // We don't call sub.ready() here: it gets called in livedata_server, after\n // possibly calling _publishCursor on multiple returned cursors.\n\n // register stop callback (expects lambda w/ no args).\n sub.onStop(function () {observeHandle.stop();});\n};\n\n// protect against dangerous selectors. falsey and {_id: falsey} are both\n// likely programmer error, and not what you want, particularly for destructive\n// operations. JS regexps don't serialize over DDP but can be trivially\n// replaced by $regex.\nMongo.Collection._rewriteSelector = function (selector) {\n // shorthand -- scalars match _id\n if (LocalCollection._selectorIsId(selector))\n selector = {_id: selector};\n\n if (!selector || (('_id' in selector) && !selector._id))\n // can't match anything\n return {_id: Random.id()};\n\n var ret = {};\n _.each(selector, function (value, key) {\n // Mongo supports both {field: /foo/} and {field: {$regex: /foo/}}\n if (value instanceof RegExp) {\n ret[key] = convertRegexpToMongoSelector(value);\n } else if (value && value.$regex instanceof RegExp) {\n ret[key] = convertRegexpToMongoSelector(value.$regex);\n // if value is {$regex: /foo/, $options: ...} then $options\n // override the ones set on $regex.\n if (value.$options !== undefined)\n ret[key].$options = value.$options;\n }\n else if (_.contains(['$or','$and','$nor'], key)) {\n // Translate lower levels of $and/$or/$nor\n ret[key] = _.map(value, function (v) {\n return Mongo.Collection._rewriteSelector(v);\n });\n } else {\n ret[key] = value;\n }\n });\n return ret;\n};\n\n// convert a JS RegExp object to a Mongo {$regex: ..., $options: ...}\n// selector\nvar convertRegexpToMongoSelector = function (regexp) {\n check(regexp, RegExp); // safety belt\n\n var selector = {$regex: regexp.source};\n var regexOptions = '';\n // JS RegExp objects support 'i', 'm', and 'g'. Mongo regex $options\n // support 'i', 'm', 'x', and 's'. So we support 'i' and 'm' here.\n if (regexp.ignoreCase)\n regexOptions += 'i';\n if (regexp.multiline)\n regexOptions += 'm';\n if (regexOptions)\n selector.$options = regexOptions;\n\n return selector;\n};\n\nvar throwIfSelectorIsNotId = function (selector, methodName) {\n if (!LocalCollection._selectorIsIdPerhapsAsObject(selector)) {\n throw new Meteor.Error(\n 403, \"Not permitted. Untrusted code may only \" + methodName +\n \" documents by ID.\");\n }\n};\n\n// 'insert' immediately returns the inserted document's new _id.\n// The others return values immediately if you are in a stub, an in-memory\n// unmanaged collection, or a mongo-backed collection and you don't pass a\n// callback. 'update' and 'remove' return the number of affected\n// documents. 'upsert' returns an object with keys 'numberAffected' and, if an\n// insert happened, 'insertedId'.\n//\n// Otherwise, the semantics are exactly like other methods: they take\n// a callback as an optional last argument; if no callback is\n// provided, they block until the operation is complete, and throw an\n// exception if it fails; if a callback is provided, then they don't\n// necessarily block, and they call the callback when they finish with error and\n// result arguments. (The insert method provides the document ID as its result;\n// update and remove provide the number of affected docs as the result; upsert\n// provides an object with numberAffected and maybe insertedId.)\n//\n// On the client, blocking is impossible, so if a callback\n// isn't provided, they just return immediately and any error\n// information is lost.\n//\n// There's one more tweak. On the client, if you don't provide a\n// callback, then if there is an error, a message will be logged with\n// Meteor._debug.\n//\n// The intent (though this is actually determined by the underlying\n// drivers) is that the operations should be done synchronously, not\n// generating their result until the database has acknowledged\n// them. In the future maybe we should provide a flag to turn this\n// off.\n\n/**\n * @summary Insert a document in the collection. Returns its unique _id.\n * @locus Anywhere\n * @method insert\n * @memberOf Mongo.Collection\n * @instance\n * @param {Object} doc The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you.\n * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the _id as the second.\n */\n\n/**\n * @summary Modify one or more documents in the collection. Returns the number of affected documents.\n * @locus Anywhere\n * @method update\n * @memberOf Mongo.Collection\n * @instance\n * @param {MongoSelector} selector Specifies which documents to modify\n * @param {MongoModifier} modifier Specifies how to modify the documents\n * @param {Object} [options]\n * @param {Boolean} options.multi True to modify all matching documents; false to only modify one of the matching documents (the default).\n * @param {Boolean} options.upsert True to insert a document if no matching documents are found.\n * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second.\n */\n\n/**\n * @summary Remove documents from the collection\n * @locus Anywhere\n * @method remove\n * @memberOf Mongo.Collection\n * @instance\n * @param {MongoSelector} selector Specifies which documents to remove\n * @param {Function} [callback] Optional. If present, called with an error object as its argument.\n */\n\n_.each([\"insert\", \"update\", \"remove\"], function (name) {\n Mongo.Collection.prototype[name] = function (/* arguments */) {\n var self = this;\n var args = _.toArray(arguments);\n var callback;\n var insertId;\n var ret;\n\n // Pull off any callback (or perhaps a 'callback' variable that was passed\n // in undefined, like how 'upsert' does it).\n if (args.length &&\n (args[args.length - 1] === undefined ||\n args[args.length - 1] instanceof Function)) {\n callback = args.pop();\n }\n\n if (name === \"insert\") {\n if (!args.length)\n throw new Error(\"insert requires an argument\");\n // shallow-copy the document and generate an ID\n args[0] = _.extend({}, args[0]);\n if ('_id' in args[0]) {\n insertId = args[0]._id;\n if (!insertId || !(typeof insertId === 'string'\n || insertId instanceof Mongo.ObjectID))\n throw new Error(\"Meteor requires document _id fields to be non-empty strings or ObjectIDs\");\n } else {\n var generateId = true;\n // Don't generate the id if we're the client and the 'outermost' call\n // This optimization saves us passing both the randomSeed and the id\n // Passing both is redundant.\n if (self._connection && self._connection !== Meteor.server) {\n var enclosing = DDP._CurrentInvocation.get();\n if (!enclosing) {\n generateId = false;\n }\n }\n if (generateId) {\n insertId = args[0]._id = self._makeNewID();\n }\n }\n } else {\n args[0] = Mongo.Collection._rewriteSelector(args[0]);\n\n if (name === \"update\") {\n // Mutate args but copy the original options object. We need to add\n // insertedId to options, but don't want to mutate the caller's options\n // object. We need to mutate `args` because we pass `args` into the\n // driver below.\n var options = args[2] = _.clone(args[2]) || {};\n if (options && typeof options !== \"function\" && options.upsert) {\n // set `insertedId` if absent. `insertedId` is a Meteor extension.\n if (options.insertedId) {\n if (!(typeof options.insertedId === 'string'\n || options.insertedId instanceof Mongo.ObjectID))\n throw new Error(\"insertedId must be string or ObjectID\");\n } else if (! args[0]._id) {\n options.insertedId = self._makeNewID();\n }\n }\n }\n }\n\n // On inserts, always return the id that we generated; on all other\n // operations, just return the result from the collection.\n var chooseReturnValueFromCollectionResult = function (result) {\n if (name === \"insert\") {\n if (!insertId && result) {\n insertId = result;\n }\n return insertId;\n } else {\n return result;\n }\n };\n\n var wrappedCallback;\n if (callback) {\n wrappedCallback = function (error, result) {\n callback(error, ! error && chooseReturnValueFromCollectionResult(result));\n };\n }\n\n // XXX see #MeteorServerNull\n if (self._connection && self._connection !== Meteor.server) {\n // just remote to another endpoint, propagate return value or\n // exception.\n\n var enclosing = DDP._CurrentInvocation.get();\n var alreadyInSimulation = enclosing && enclosing.isSimulation;\n\n if (Meteor.isClient && !wrappedCallback && ! alreadyInSimulation) {\n // Client can't block, so it can't report errors by exception,\n // only by callback. If they forget the callback, give them a\n // default one that logs the error, so they aren't totally\n // baffled if their writes don't work because their database is\n // down.\n // Don't give a default callback in simulation, because inside stubs we\n // want to return the results from the local collection immediately and\n // not force a callback.\n wrappedCallback = function (err) {\n if (err)\n Meteor._debug(name + \" failed: \" + (err.reason || err.stack));\n };\n }\n\n if (!alreadyInSimulation && name !== \"insert\") {\n // If we're about to actually send an RPC, we should throw an error if\n // this is a non-ID selector, because the mutation methods only allow\n // single-ID selectors. (If we don't throw here, we'll see flicker.)\n throwIfSelectorIsNotId(args[0], name);\n }\n\n ret = chooseReturnValueFromCollectionResult(\n self._connection.apply(self._prefix + name, args, {returnStubValue: true}, wrappedCallback)\n );\n\n } else {\n // it's my collection. descend into the collection object\n // and propagate any exception.\n args.push(wrappedCallback);\n try {\n // If the user provided a callback and the collection implements this\n // operation asynchronously, then queryRet will be undefined, and the\n // result will be returned through the callback instead.\n var queryRet = self._collection[name].apply(self._collection, args);\n ret = chooseReturnValueFromCollectionResult(queryRet);\n } catch (e) {\n if (callback) {\n callback(e);\n return null;\n }\n throw e;\n }\n }\n\n // both sync and async, unless we threw an exception, return ret\n // (new document ID for insert, num affected for update/remove, object with\n // numberAffected and maybe insertedId for upsert).\n return ret;\n };\n});\n\n/**\n * @summary Modify one or more documents in the collection, or insert one if no matching documents were found. Returns an object with keys `numberAffected` (the number of documents modified) and `insertedId` (the unique _id of the document that was inserted, if any).\n * @locus Anywhere\n * @param {MongoSelector} selector Specifies which documents to modify\n * @param {MongoModifier} modifier Specifies how to modify the documents\n * @param {Object} [options]\n * @param {Boolean} options.multi True to modify all matching documents; false to only modify one of the matching documents (the default).\n * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second.\n */\nMongo.Collection.prototype.upsert = function (selector, modifier,\n options, callback) {\n var self = this;\n if (! callback && typeof options === \"function\") {\n callback = options;\n options = {};\n }\n return self.update(selector, modifier,\n _.extend({}, options, { _returnObject: true, upsert: true }),\n callback);\n};\n\n// We'll actually design an index API later. For now, we just pass through to\n// Mongo's, but make it synchronous.\nMongo.Collection.prototype._ensureIndex = function (index, options) {\n var self = this;\n if (!self._collection._ensureIndex)\n throw new Error(\"Can only call _ensureIndex on server collections\");\n self._collection._ensureIndex(index, options);\n};\nMongo.Collection.prototype._dropIndex = function (index) {\n var self = this;\n if (!self._collection._dropIndex)\n throw new Error(\"Can only call _dropIndex on server collections\");\n self._collection._dropIndex(index);\n};\nMongo.Collection.prototype._dropCollection = function () {\n var self = this;\n if (!self._collection.dropCollection)\n throw new Error(\"Can only call _dropCollection on server collections\");\n self._collection.dropCollection();\n};\nMongo.Collection.prototype._createCappedCollection = function (byteSize, maxDocuments) {\n var self = this;\n if (!self._collection._createCappedCollection)\n throw new Error(\"Can only call _createCappedCollection on server collections\");\n self._collection._createCappedCollection(byteSize, maxDocuments);\n};\n\nMongo.Collection.prototype.rawCollection = function () {\n var self = this;\n if (! self._collection.rawCollection) {\n throw new Error(\"Can only call rawCollection on server collections\");\n }\n return self._collection.rawCollection();\n};\n\nMongo.Collection.prototype.rawDatabase = function () {\n var self = this;\n if (! (self._driver.mongo && self._driver.mongo.db)) {\n throw new Error(\"Can only call rawDatabase on server collections\");\n }\n return self._driver.mongo.db;\n};\n\n\n/**\n * @summary Create a Mongo-style `ObjectID`. If you don't specify a `hexString`, the `ObjectID` will generated randomly (not using MongoDB's ID construction rules).\n * @locus Anywhere\n * @class\n * @param {String} hexString Optional. The 24-character hexadecimal contents of the ObjectID to create\n */\nMongo.ObjectID = LocalCollection._ObjectID;\n\n/**\n * @summary To create a cursor, use find. To access the documents in a cursor, use forEach, map, or fetch.\n * @class\n * @instanceName cursor\n */\nMongo.Cursor = LocalCollection.Cursor;\n\n/**\n * @deprecated in 0.9.1\n */\nMongo.Collection.Cursor = Mongo.Cursor;\n\n/**\n * @deprecated in 0.9.1\n */\nMongo.Collection.ObjectID = Mongo.ObjectID;\n\n///\n/// Remote methods and access control.\n///\n\n// Restrict default mutators on collection. allow() and deny() take the\n// same options:\n//\n// options.insert {Function(userId, doc)}\n// return true to allow/deny adding this document\n//\n// options.update {Function(userId, docs, fields, modifier)}\n// return true to allow/deny updating these documents.\n// `fields` is passed as an array of fields that are to be modified\n//\n// options.remove {Function(userId, docs)}\n// return true to allow/deny removing these documents\n//\n// options.fetch {Array}\n// Fields to fetch for these validators. If any call to allow or deny\n// does not have this option then all fields are loaded.\n//\n// allow and deny can be called multiple times. The validators are\n// evaluated as follows:\n// - If neither deny() nor allow() has been called on the collection,\n// then the request is allowed if and only if the \"insecure\" smart\n// package is in use.\n// - Otherwise, if any deny() function returns true, the request is denied.\n// - Otherwise, if any allow() function returns true, the request is allowed.\n// - Otherwise, the request is denied.\n//\n// Meteor may call your deny() and allow() functions in any order, and may not\n// call all of them if it is able to make a decision without calling them all\n// (so don't include side effects).\n\n(function () {\n var addValidator = function(allowOrDeny, options) {\n // validate keys\n var VALID_KEYS = ['insert', 'update', 'remove', 'fetch', 'transform'];\n _.each(_.keys(options), function (key) {\n if (!_.contains(VALID_KEYS, key))\n throw new Error(allowOrDeny + \": Invalid key: \" + key);\n });\n\n var self = this;\n self._restricted = true;\n\n _.each(['insert', 'update', 'remove'], function (name) {\n if (options[name]) {\n if (!(options[name] instanceof Function)) {\n throw new Error(allowOrDeny + \": Value for `\" + name + \"` must be a function\");\n }\n\n // If the transform is specified at all (including as 'null') in this\n // call, then take that; otherwise, take the transform from the\n // collection.\n if (options.transform === undefined) {\n options[name].transform = self._transform; // already wrapped\n } else {\n options[name].transform = LocalCollection.wrapTransform(\n options.transform);\n }\n\n self._validators[name][allowOrDeny].push(options[name]);\n }\n });\n\n // Only update the fetch fields if we're passed things that affect\n // fetching. This way allow({}) and allow({insert: f}) don't result in\n // setting fetchAllFields\n if (options.update || options.remove || options.fetch) {\n if (options.fetch && !(options.fetch instanceof Array)) {\n throw new Error(allowOrDeny + \": Value for `fetch` must be an array\");\n }\n self._updateFetch(options.fetch);\n }\n };\n\n /**\n * @summary Allow users to write directly to this collection from client code, subject to limitations you define.\n * @locus Server\n * @param {Object} options\n * @param {Function} options.insert,update,remove Functions that look at a proposed modification to the database and return true if it should be allowed.\n * @param {String[]} options.fetch Optional performance enhancement. Limits the fields that will be fetched from the database for inspection by your `update` and `remove` functions.\n * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections). Pass `null` to disable transformation.\n */\n Mongo.Collection.prototype.allow = function(options) {\n addValidator.call(this, 'allow', options);\n };\n\n /**\n * @summary Override `allow` rules.\n * @locus Server\n * @param {Object} options\n * @param {Function} options.insert,update,remove Functions that look at a proposed modification to the database and return true if it should be denied, even if an [allow](#allow) rule says otherwise.\n * @param {String[]} options.fetch Optional performance enhancement. Limits the fields that will be fetched from the database for inspection by your `update` and `remove` functions.\n * @param {Function} options.transform Overrides `transform` on the [`Collection`](#collections). Pass `null` to disable transformation.\n */\n Mongo.Collection.prototype.deny = function(options) {\n addValidator.call(this, 'deny', options);\n };\n})();\n\n\nMongo.Collection.prototype._defineMutationMethods = function() {\n var self = this;\n\n // set to true once we call any allow or deny methods. If true, use\n // allow/deny semantics. If false, use insecure mode semantics.\n self._restricted = false;\n\n // Insecure mode (default to allowing writes). Defaults to 'undefined' which\n // means insecure iff the insecure package is loaded. This property can be\n // overriden by tests or packages wishing to change insecure mode behavior of\n // their collections.\n self._insecure = undefined;\n\n self._validators = {\n insert: {allow: [], deny: []},\n update: {allow: [], deny: []},\n remove: {allow: [], deny: []},\n upsert: {allow: [], deny: []}, // dummy arrays; can't set these!\n fetch: [],\n fetchAllFields: false\n };\n\n if (!self._name)\n return; // anonymous collection\n\n // XXX Think about method namespacing. Maybe methods should be\n // \"Meteor:Mongo:insert/NAME\"?\n self._prefix = '/' + self._name + '/';\n\n // mutation methods\n if (self._connection) {\n var m = {};\n\n _.each(['insert', 'update', 'remove'], function (method) {\n m[self._prefix + method] = function (/* ... */) {\n // All the methods do their own validation, instead of using check().\n check(arguments, [Match.Any]);\n var args = _.toArray(arguments);\n try {\n // For an insert, if the client didn't specify an _id, generate one\n // now; because this uses DDP.randomStream, it will be consistent with\n // what the client generated. We generate it now rather than later so\n // that if (eg) an allow/deny rule does an insert to the same\n // collection (not that it really should), the generated _id will\n // still be the first use of the stream and will be consistent.\n //\n // However, we don't actually stick the _id onto the document yet,\n // because we want allow/deny rules to be able to differentiate\n // between arbitrary client-specified _id fields and merely\n // client-controlled-via-randomSeed fields.\n var generatedId = null;\n if (method === \"insert\" && !_.has(args[0], '_id')) {\n generatedId = self._makeNewID();\n }\n\n if (this.isSimulation) {\n // In a client simulation, you can do any mutation (even with a\n // complex selector).\n if (generatedId !== null)\n args[0]._id = generatedId;\n return self._collection[method].apply(\n self._collection, args);\n }\n\n // This is the server receiving a method call from the client.\n\n // We don't allow arbitrary selectors in mutations from the client: only\n // single-ID selectors.\n if (method !== 'insert')\n throwIfSelectorIsNotId(args[0], method);\n\n if (self._restricted) {\n // short circuit if there is no way it will pass.\n if (self._validators[method].allow.length === 0) {\n throw new Meteor.Error(\n 403, \"Access denied. No allow validators set on restricted \" +\n \"collection for method '\" + method + \"'.\");\n }\n\n var validatedMethodName =\n '_validated' + method.charAt(0).toUpperCase() + method.slice(1);\n args.unshift(this.userId);\n method === 'insert' && args.push(generatedId);\n return self[validatedMethodName].apply(self, args);\n } else if (self._isInsecure()) {\n if (generatedId !== null)\n args[0]._id = generatedId;\n // In insecure mode, allow any mutation (with a simple selector).\n // XXX This is kind of bogus. Instead of blindly passing whatever\n // we get from the network to this function, we should actually\n // know the correct arguments for the function and pass just\n // them. For example, if you have an extraneous extra null\n // argument and this is Mongo on the server, the .wrapAsync'd\n // functions like update will get confused and pass the\n // \"fut.resolver()\" in the wrong slot, where _update will never\n // invoke it. Bam, broken DDP connection. Probably should just\n // take this whole method and write it three times, invoking\n // helpers for the common code.\n return self._collection[method].apply(self._collection, args);\n } else {\n // In secure mode, if we haven't called allow or deny, then nothing\n // is permitted.\n throw new Meteor.Error(403, \"Access denied\");\n }\n } catch (e) {\n if (e.name === 'MongoError' || e.name === 'MinimongoError') {\n throw new Meteor.Error(409, e.toString());\n } else {\n throw e;\n }\n }\n };\n });\n // Minimongo on the server gets no stubs; instead, by default\n // it wait()s until its result is ready, yielding.\n // This matches the behavior of macromongo on the server better.\n // XXX see #MeteorServerNull\n if (Meteor.isClient || self._connection === Meteor.server)\n self._connection.methods(m);\n }\n};\n\n\nMongo.Collection.prototype._updateFetch = function (fields) {\n var self = this;\n\n if (!self._validators.fetchAllFields) {\n if (fields) {\n self._validators.fetch = _.union(self._validators.fetch, fields);\n } else {\n self._validators.fetchAllFields = true;\n // clear fetch just to make sure we don't accidentally read it\n self._validators.fetch = null;\n }\n }\n};\n\nMongo.Collection.prototype._isInsecure = function () {\n var self = this;\n if (self._insecure === undefined)\n return !!Package.insecure;\n return self._insecure;\n};\n\nvar docToValidate = function (validator, doc, generatedId) {\n var ret = doc;\n if (validator.transform) {\n ret = EJSON.clone(doc);\n // If you set a server-side transform on your collection, then you don't get\n // to tell the difference between \"client specified the ID\" and \"server\n // generated the ID\", because transforms expect to get _id. If you want to\n // do that check, you can do it with a specific\n // `C.allow({insert: f, transform: null})` validator.\n if (generatedId !== null) {\n ret._id = generatedId;\n }\n ret = validator.transform(ret);\n }\n return ret;\n};\n\nMongo.Collection.prototype._validatedInsert = function (userId, doc,\n generatedId) {\n var self = this;\n\n // call user validators.\n // Any deny returns true means denied.\n if (_.any(self._validators.insert.deny, function(validator) {\n return validator(userId, docToValidate(validator, doc, generatedId));\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n // Any allow returns true means proceed. Throw error if they all fail.\n if (_.all(self._validators.insert.allow, function(validator) {\n return !validator(userId, docToValidate(validator, doc, generatedId));\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n\n // If we generated an ID above, insert it now: after the validation, but\n // before actually inserting.\n if (generatedId !== null)\n doc._id = generatedId;\n\n self._collection.insert.call(self._collection, doc);\n};\n\nvar transformDoc = function (validator, doc) {\n if (validator.transform)\n return validator.transform(doc);\n return doc;\n};\n\n// Simulate a mongo `update` operation while validating that the access\n// control rules set by calls to `allow/deny` are satisfied. If all\n// pass, rewrite the mongo operation to use $in to set the list of\n// document ids to change ##ValidatedChange\nMongo.Collection.prototype._validatedUpdate = function(\n userId, selector, mutator, options) {\n var self = this;\n\n check(mutator, Object);\n\n options = _.clone(options) || {};\n\n if (!LocalCollection._selectorIsIdPerhapsAsObject(selector))\n throw new Error(\"validated update should be of a single ID\");\n\n // We don't support upserts because they don't fit nicely into allow/deny\n // rules.\n if (options.upsert)\n throw new Meteor.Error(403, \"Access denied. Upserts not \" +\n \"allowed in a restricted collection.\");\n\n var noReplaceError = \"Access denied. In a restricted collection you can only\" +\n \" update documents, not replace them. Use a Mongo update operator, such \" +\n \"as '$set'.\";\n\n // compute modified fields\n var fields = [];\n if (_.isEmpty(mutator)) {\n throw new Meteor.Error(403, noReplaceError);\n }\n _.each(mutator, function (params, op) {\n if (op.charAt(0) !== '$') {\n throw new Meteor.Error(403, noReplaceError);\n } else if (!_.has(ALLOWED_UPDATE_OPERATIONS, op)) {\n throw new Meteor.Error(\n 403, \"Access denied. Operator \" + op + \" not allowed in a restricted collection.\");\n } else {\n _.each(_.keys(params), function (field) {\n // treat dotted fields as if they are replacing their\n // top-level part\n if (field.indexOf('.') !== -1)\n field = field.substring(0, field.indexOf('.'));\n\n // record the field we are trying to change\n if (!_.contains(fields, field))\n fields.push(field);\n });\n }\n });\n\n var findOptions = {transform: null};\n if (!self._validators.fetchAllFields) {\n findOptions.fields = {};\n _.each(self._validators.fetch, function(fieldName) {\n findOptions.fields[fieldName] = 1;\n });\n }\n\n var doc = self._collection.findOne(selector, findOptions);\n if (!doc) // none satisfied!\n return 0;\n\n // call user validators.\n // Any deny returns true means denied.\n if (_.any(self._validators.update.deny, function(validator) {\n var factoriedDoc = transformDoc(validator, doc);\n return validator(userId,\n factoriedDoc,\n fields,\n mutator);\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n // Any allow returns true means proceed. Throw error if they all fail.\n if (_.all(self._validators.update.allow, function(validator) {\n var factoriedDoc = transformDoc(validator, doc);\n return !validator(userId,\n factoriedDoc,\n fields,\n mutator);\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n\n options._forbidReplace = true;\n\n // Back when we supported arbitrary client-provided selectors, we actually\n // rewrote the selector to include an _id clause before passing to Mongo to\n // avoid races, but since selector is guaranteed to already just be an ID, we\n // don't have to any more.\n\n return self._collection.update.call(\n self._collection, selector, mutator, options);\n};\n\n// Only allow these operations in validated updates. Specifically\n// whitelist operations, rather than blacklist, so new complex\n// operations that are added aren't automatically allowed. A complex\n// operation is one that does more than just modify its target\n// field. For now this contains all update operations except '$rename'.\n// http://docs.mongodb.org/manual/reference/operators/#update\nvar ALLOWED_UPDATE_OPERATIONS = {\n $inc:1, $set:1, $unset:1, $addToSet:1, $pop:1, $pullAll:1, $pull:1,\n $pushAll:1, $push:1, $bit:1\n};\n\n// Simulate a mongo `remove` operation while validating access control\n// rules. See #ValidatedChange\nMongo.Collection.prototype._validatedRemove = function(userId, selector) {\n var self = this;\n\n var findOptions = {transform: null};\n if (!self._validators.fetchAllFields) {\n findOptions.fields = {};\n _.each(self._validators.fetch, function(fieldName) {\n findOptions.fields[fieldName] = 1;\n });\n }\n\n var doc = self._collection.findOne(selector, findOptions);\n if (!doc)\n return 0;\n\n // call user validators.\n // Any deny returns true means denied.\n if (_.any(self._validators.remove.deny, function(validator) {\n return validator(userId, transformDoc(validator, doc));\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n // Any allow returns true means proceed. Throw error if they all fail.\n if (_.all(self._validators.remove.allow, function(validator) {\n return !validator(userId, transformDoc(validator, doc));\n })) {\n throw new Meteor.Error(403, \"Access denied\");\n }\n\n // Back when we supported arbitrary client-provided selectors, we actually\n // rewrote the selector to {_id: {$in: [ids that we found]}} before passing to\n // Mongo to avoid races, but since selector is guaranteed to already just be\n // an ID, we don't have to any more.\n\n return self._collection.remove.call(self._collection, selector);\n};\n\n/**\n * @deprecated in 0.9.1\n */\nMeteor.Collection = Mongo.Collection;\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js b/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js deleted file mode 100644 index 06fec4f..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['mquandalle:jade'] = {}; - -})(); - -//# sourceMappingURL=mquandalle_jade.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js.map b/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js.map deleted file mode 100644 index 951bf40..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/mquandalle_jade.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js b/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js deleted file mode 100644 index a3d0b98..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js +++ /dev/null @@ -1,32 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - -/* Package-scope variables */ -var topojson; - -(function () { - -/////////////////////////////////////////////////////////////////////// -// // -// packages/mrt:topojson/meteor-topojson.js // -// // -/////////////////////////////////////////////////////////////////////// - // -topojson = Npm.require('topojson'); // 1 - // 2 -/////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['mrt:topojson'] = { - topojson: topojson -}; - -})(); - -//# sourceMappingURL=mrt_topojson.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js.map b/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js.map deleted file mode 100644 index 65fb22e..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"/packages/mrt:topojson.js","sources":["mrt:topojson/meteor-topojson.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mC","sourcesContent":["topojson = Npm.require('topojson');\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js b/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js deleted file mode 100644 index b3beb93..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js +++ /dev/null @@ -1,979 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - -/* Package-scope variables */ -var numeral; - -(function () { - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/numeral:numeral/numeral.js // -// // -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/*! // 1 - * numeral.js // 2 - * version : 1.5.3 // 3 - * author : Adam Draper // 4 - * license : MIT // 5 - * http://adamwdraper.github.com/Numeral-js/ // 6 - */ // 7 - // 8 -(function() { // 9 - // 10 - /************************************ // 11 - Constants // 12 - ************************************/ // 13 - // 14 - var numeral, // 15 - VERSION = '1.5.3', // 16 - // internal storage for language config files // 17 - languages = {}, // 18 - currentLanguage = 'en', // 19 - zeroFormat = null, // 20 - defaultFormat = '0,0', // 21 - // check for nodeJS // 22 - hasModule = (typeof module !== 'undefined' && module.exports); // 23 - // 24 - // 25 - /************************************ // 26 - Constructors // 27 - ************************************/ // 28 - // 29 - // 30 - // Numeral prototype object // 31 - function Numeral(number) { // 32 - this._value = number; // 33 - } // 34 - // 35 - /** // 36 - * Implementation of toFixed() that treats floats more like decimals // 37 - * // 38 - * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present // 39 - * problems for accounting- and finance-related software. // 40 - */ // 41 - function toFixed(value, precision, roundingFunction, optionals) { // 42 - var power = Math.pow(10, precision), // 43 - optionalsRegExp, // 44 - output; // 45 - // 46 - //roundingFunction = (roundingFunction !== undefined ? roundingFunction : Math.round); // 47 - // Multiply up by precision, round accurately, then divide and use native toFixed(): // 48 - output = (roundingFunction(value * power) / power).toFixed(precision); // 49 - // 50 - if (optionals) { // 51 - optionalsRegExp = new RegExp('0{1,' + optionals + '}$'); // 52 - output = output.replace(optionalsRegExp, ''); // 53 - } // 54 - // 55 - return output; // 56 - } // 57 - // 58 - /************************************ // 59 - Formatting // 60 - ************************************/ // 61 - // 62 - // determine what type of formatting we need to do // 63 - function formatNumeral(n, format, roundingFunction) { // 64 - var output; // 65 - // 66 - // figure out what kind of format we are dealing with // 67 - if (format.indexOf('$') > -1) { // currency!!!!! // 68 - output = formatCurrency(n, format, roundingFunction); // 69 - } else if (format.indexOf('%') > -1) { // percentage // 70 - output = formatPercentage(n, format, roundingFunction); // 71 - } else if (format.indexOf(':') > -1) { // time // 72 - output = formatTime(n, format); // 73 - } else { // plain ol' numbers or bytes // 74 - output = formatNumber(n._value, format, roundingFunction); // 75 - } // 76 - // 77 - // return string // 78 - return output; // 79 - } // 80 - // 81 - // revert to number // 82 - function unformatNumeral(n, string) { // 83 - var stringOriginal = string, // 84 - thousandRegExp, // 85 - millionRegExp, // 86 - billionRegExp, // 87 - trillionRegExp, // 88 - suffixes = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], // 89 - bytesMultiplier = false, // 90 - power; // 91 - // 92 - if (string.indexOf(':') > -1) { // 93 - n._value = unformatTime(string); // 94 - } else { // 95 - if (string === zeroFormat) { // 96 - n._value = 0; // 97 - } else { // 98 - if (languages[currentLanguage].delimiters.decimal !== '.') { // 99 - string = string.replace(/\./g, '').replace(languages[currentLanguage].delimiters.decimal, '.'); // 100 - } // 101 - // 102 - // see if abbreviations are there so that we can multiply to the correct number // 103 - thousandRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.thousand + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'); - millionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.million + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'); - billionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.billion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'); - trillionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.trillion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$'); - // 108 - // see if bytes are there so that we can multiply to the correct number // 109 - for (power = 0; power <= suffixes.length; power++) { // 110 - bytesMultiplier = (string.indexOf(suffixes[power]) > -1) ? Math.pow(1024, power + 1) : false; // 111 - // 112 - if (bytesMultiplier) { // 113 - break; // 114 - } // 115 - } // 116 - // 117 - // do some math to create our number // 118 - n._value = ((bytesMultiplier) ? bytesMultiplier : 1) * ((stringOriginal.match(thousandRegExp)) ? Math.pow(10, 3) : 1) * ((stringOriginal.match(millionRegExp)) ? Math.pow(10, 6) : 1) * ((stringOriginal.match(billionRegExp)) ? Math.pow(10, 9) : 1) * ((stringOriginal.match(trillionRegExp)) ? Math.pow(10, 12) : 1) * ((string.indexOf('%') > -1) ? 0.01 : 1) * (((string.split('-').length + Math.min(string.split('(').length - 1, string.split(')').length - 1)) % 2) ? 1 : -1) * Number(string.replace(/[^0-9\.]+/g, '')); - // 120 - // round if we are talking about bytes // 121 - n._value = (bytesMultiplier) ? Math.ceil(n._value) : n._value; // 122 - } // 123 - } // 124 - return n._value; // 125 - } // 126 - // 127 - function formatCurrency(n, format, roundingFunction) { // 128 - var symbolIndex = format.indexOf('$'), // 129 - openParenIndex = format.indexOf('('), // 130 - minusSignIndex = format.indexOf('-'), // 131 - space = '', // 132 - spliceIndex, // 133 - output; // 134 - // 135 - // check for space before or after currency // 136 - if (format.indexOf(' $') > -1) { // 137 - space = ' '; // 138 - format = format.replace(' $', ''); // 139 - } else if (format.indexOf('$ ') > -1) { // 140 - space = ' '; // 141 - format = format.replace('$ ', ''); // 142 - } else { // 143 - format = format.replace('$', ''); // 144 - } // 145 - // 146 - // format the number // 147 - output = formatNumber(n._value, format, roundingFunction); // 148 - // 149 - // position the symbol // 150 - if (symbolIndex <= 1) { // 151 - if (output.indexOf('(') > -1 || output.indexOf('-') > -1) { // 152 - output = output.split(''); // 153 - spliceIndex = 1; // 154 - if (symbolIndex < openParenIndex || symbolIndex < minusSignIndex) { // 155 - // the symbol appears before the "(" or "-" // 156 - spliceIndex = 0; // 157 - } // 158 - output.splice(spliceIndex, 0, languages[currentLanguage].currency.symbol + space); // 159 - output = output.join(''); // 160 - } else { // 161 - output = languages[currentLanguage].currency.symbol + space + output; // 162 - } // 163 - } else { // 164 - if (output.indexOf(')') > -1) { // 165 - output = output.split(''); // 166 - output.splice(-1, 0, space + languages[currentLanguage].currency.symbol); // 167 - output = output.join(''); // 168 - } else { // 169 - output = output + space + languages[currentLanguage].currency.symbol; // 170 - } // 171 - } // 172 - // 173 - return output; // 174 - } // 175 - // 176 - function formatPercentage(n, format, roundingFunction) { // 177 - var space = '', // 178 - output, // 179 - value = n._value * 100; // 180 - // 181 - // check for space before % // 182 - if (format.indexOf(' %') > -1) { // 183 - space = ' '; // 184 - format = format.replace(' %', ''); // 185 - } else { // 186 - format = format.replace('%', ''); // 187 - } // 188 - // 189 - output = formatNumber(value, format, roundingFunction); // 190 - // 191 - if (output.indexOf(')') > -1) { // 192 - output = output.split(''); // 193 - output.splice(-1, 0, space + '%'); // 194 - output = output.join(''); // 195 - } else { // 196 - output = output + space + '%'; // 197 - } // 198 - // 199 - return output; // 200 - } // 201 - // 202 - function formatTime(n) { // 203 - var hours = Math.floor(n._value / 60 / 60), // 204 - minutes = Math.floor((n._value - (hours * 60 * 60)) / 60), // 205 - seconds = Math.round(n._value - (hours * 60 * 60) - (minutes * 60)); // 206 - return hours + ':' + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds); - } // 208 - // 209 - function unformatTime(string) { // 210 - var timeArray = string.split(':'), // 211 - seconds = 0; // 212 - // turn hours and minutes into seconds and add them all up // 213 - if (timeArray.length === 3) { // 214 - // hours // 215 - seconds = seconds + (Number(timeArray[0]) * 60 * 60); // 216 - // minutes // 217 - seconds = seconds + (Number(timeArray[1]) * 60); // 218 - // seconds // 219 - seconds = seconds + Number(timeArray[2]); // 220 - } else if (timeArray.length === 2) { // 221 - // minutes // 222 - seconds = seconds + (Number(timeArray[0]) * 60); // 223 - // seconds // 224 - seconds = seconds + Number(timeArray[1]); // 225 - } // 226 - return Number(seconds); // 227 - } // 228 - // 229 - function formatNumber(value, format, roundingFunction) { // 230 - var negP = false, // 231 - signed = false, // 232 - optDec = false, // 233 - abbr = '', // 234 - abbrK = false, // force abbreviation to thousands // 235 - abbrM = false, // force abbreviation to millions // 236 - abbrB = false, // force abbreviation to billions // 237 - abbrT = false, // force abbreviation to trillions // 238 - abbrForce = false, // force abbreviation // 239 - bytes = '', // 240 - ord = '', // 241 - abs = Math.abs(value), // 242 - suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], // 243 - min, // 244 - max, // 245 - power, // 246 - w, // 247 - precision, // 248 - thousands, // 249 - d = '', // 250 - neg = false; // 251 - // 252 - // check if number is zero and a custom zero format has been set // 253 - if (value === 0 && zeroFormat !== null) { // 254 - return zeroFormat; // 255 - } else { // 256 - // see if we should use parentheses for negative number or if we should prefix with a sign // 257 - // if both are present we default to parentheses // 258 - if (format.indexOf('(') > -1) { // 259 - negP = true; // 260 - format = format.slice(1, -1); // 261 - } else if (format.indexOf('+') > -1) { // 262 - signed = true; // 263 - format = format.replace(/\+/g, ''); // 264 - } // 265 - // 266 - // see if abbreviation is wanted // 267 - if (format.indexOf('a') > -1) { // 268 - // check if abbreviation is specified // 269 - abbrK = format.indexOf('aK') >= 0; // 270 - abbrM = format.indexOf('aM') >= 0; // 271 - abbrB = format.indexOf('aB') >= 0; // 272 - abbrT = format.indexOf('aT') >= 0; // 273 - abbrForce = abbrK || abbrM || abbrB || abbrT; // 274 - // 275 - // check for space before abbreviation // 276 - if (format.indexOf(' a') > -1) { // 277 - abbr = ' '; // 278 - format = format.replace(' a', ''); // 279 - } else { // 280 - format = format.replace('a', ''); // 281 - } // 282 - // 283 - if (abs >= Math.pow(10, 12) && !abbrForce || abbrT) { // 284 - // trillion // 285 - abbr = abbr + languages[currentLanguage].abbreviations.trillion; // 286 - value = value / Math.pow(10, 12); // 287 - } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9) && !abbrForce || abbrB) { // 288 - // billion // 289 - abbr = abbr + languages[currentLanguage].abbreviations.billion; // 290 - value = value / Math.pow(10, 9); // 291 - } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6) && !abbrForce || abbrM) { // 292 - // million // 293 - abbr = abbr + languages[currentLanguage].abbreviations.million; // 294 - value = value / Math.pow(10, 6); // 295 - } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3) && !abbrForce || abbrK) { // 296 - // thousand // 297 - abbr = abbr + languages[currentLanguage].abbreviations.thousand; // 298 - value = value / Math.pow(10, 3); // 299 - } // 300 - } // 301 - // 302 - // see if we are formatting bytes // 303 - if (format.indexOf('b') > -1) { // 304 - // check for space before // 305 - if (format.indexOf(' b') > -1) { // 306 - bytes = ' '; // 307 - format = format.replace(' b', ''); // 308 - } else { // 309 - format = format.replace('b', ''); // 310 - } // 311 - // 312 - for (power = 0; power <= suffixes.length; power++) { // 313 - min = Math.pow(1024, power); // 314 - max = Math.pow(1024, power + 1); // 315 - // 316 - if (value >= min && value < max) { // 317 - bytes = bytes + suffixes[power]; // 318 - if (min > 0) { // 319 - value = value / min; // 320 - } // 321 - break; // 322 - } // 323 - } // 324 - } // 325 - // 326 - // see if ordinal is wanted // 327 - if (format.indexOf('o') > -1) { // 328 - // check for space before // 329 - if (format.indexOf(' o') > -1) { // 330 - ord = ' '; // 331 - format = format.replace(' o', ''); // 332 - } else { // 333 - format = format.replace('o', ''); // 334 - } // 335 - // 336 - ord = ord + languages[currentLanguage].ordinal(value); // 337 - } // 338 - // 339 - if (format.indexOf('[.]') > -1) { // 340 - optDec = true; // 341 - format = format.replace('[.]', '.'); // 342 - } // 343 - // 344 - w = value.toString().split('.')[0]; // 345 - precision = format.split('.')[1]; // 346 - thousands = format.indexOf(','); // 347 - // 348 - if (precision) { // 349 - if (precision.indexOf('[') > -1) { // 350 - precision = precision.replace(']', ''); // 351 - precision = precision.split('['); // 352 - d = toFixed(value, (precision[0].length + precision[1].length), roundingFunction, precision[1].length); - } else { // 354 - d = toFixed(value, precision.length, roundingFunction); // 355 - } // 356 - // 357 - w = d.split('.')[0]; // 358 - // 359 - if (d.split('.')[1].length) { // 360 - d = languages[currentLanguage].delimiters.decimal + d.split('.')[1]; // 361 - } else { // 362 - d = ''; // 363 - } // 364 - // 365 - if (optDec && Number(d.slice(1)) === 0) { // 366 - d = ''; // 367 - } // 368 - } else { // 369 - w = toFixed(value, null, roundingFunction); // 370 - } // 371 - // 372 - // format number // 373 - if (w.indexOf('-') > -1) { // 374 - w = w.slice(1); // 375 - neg = true; // 376 - } // 377 - // 378 - if (thousands > -1) { // 379 - w = w.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + languages[currentLanguage].delimiters.thousands); - } // 381 - // 382 - if (format.indexOf('.') === 0) { // 383 - w = ''; // 384 - } // 385 - // 386 - return ((negP && neg) ? '(' : '') + ((!negP && neg) ? '-' : '') + ((!neg && signed) ? '+' : '') + w + d + ((ord) ? ord : '') + ((abbr) ? abbr : '') + ((bytes) ? bytes : '') + ((negP && neg) ? ')' : ''); - } // 388 - } // 389 - // 390 - /************************************ // 391 - Top Level Functions // 392 - ************************************/ // 393 - // 394 - numeral = function(input) { // 395 - if (numeral.isNumeral(input)) { // 396 - input = input.value(); // 397 - } else if (input === 0 || typeof input === 'undefined') { // 398 - input = 0; // 399 - } else if (!Number(input)) { // 400 - input = numeral.fn.unformat(input); // 401 - } // 402 - // 403 - return new Numeral(Number(input)); // 404 - }; // 405 - // 406 - // version number // 407 - numeral.version = VERSION; // 408 - // 409 - // compare numeral object // 410 - numeral.isNumeral = function(obj) { // 411 - return obj instanceof Numeral; // 412 - }; // 413 - // 414 - // This function will load languages and then set the global language. If // 415 - // no arguments are passed in, it will simply return the current global // 416 - // language key. // 417 - numeral.language = function(key, values) { // 418 - if (!key) { // 419 - return currentLanguage; // 420 - } // 421 - // 422 - key = key.toLowerCase(); // 423 - // 424 - if (key && !values) { // 425 - if (!languages[key]) { // 426 - throw new Error('Unknown language : ' + key); // 427 - } // 428 - currentLanguage = key; // 429 - } // 430 - // 431 - if (values || !languages[key]) { // 432 - loadLanguage(key, values); // 433 - } // 434 - // 435 - return numeral; // 436 - }; // 437 - // 438 - // This function provides access to the loaded language data. If // 439 - // no arguments are passed in, it will simply return the current // 440 - // global language object. // 441 - numeral.languageData = function(key) { // 442 - if (!key) { // 443 - return languages[currentLanguage]; // 444 - } // 445 - // 446 - if (!languages[key]) { // 447 - throw new Error('Unknown language : ' + key); // 448 - } // 449 - // 450 - return languages[key]; // 451 - }; // 452 - // 453 - numeral.language('en', { // 454 - delimiters: { // 455 - thousands: ',', // 456 - decimal: '.' // 457 - }, // 458 - abbreviations: { // 459 - thousand: 'k', // 460 - million: 'm', // 461 - billion: 'b', // 462 - trillion: 't' // 463 - }, // 464 - ordinal: function(number) { // 465 - var b = number % 10; // 466 - return (~~(number % 100 / 10) === 1) ? 'th' : // 467 - (b === 1) ? 'st' : // 468 - (b === 2) ? 'nd' : // 469 - (b === 3) ? 'rd' : 'th'; // 470 - }, // 471 - currency: { // 472 - symbol: '$' // 473 - } // 474 - }); // 475 - // 476 - numeral.zeroFormat = function(format) { // 477 - zeroFormat = typeof(format) === 'string' ? format : null; // 478 - }; // 479 - // 480 - numeral.defaultFormat = function(format) { // 481 - defaultFormat = typeof(format) === 'string' ? format : '0.0'; // 482 - }; // 483 - // 484 - numeral.validate = function(val, culture) { // 485 - // 486 - var _decimalSep, // 487 - _thousandSep, // 488 - _currSymbol, // 489 - _valArray, // 490 - _abbrObj, // 491 - _thousandRegEx, // 492 - languageData, // 493 - temp; // 494 - // 495 - //coerce val to string // 496 - if (typeof val !== 'string') { // 497 - val += ''; // 498 - if (console.warn) { // 499 - console.warn('Numeral.js: Value is not string. It has been co-erced to: ', val); // 500 - } // 501 - } // 502 - // 503 - //trim whitespaces from either sides // 504 - val = val.trim(); // 505 - // 506 - //if val is just digits return true // 507 - if ( !! val.match(/^\d+$/)) { // 508 - return true; // 509 - } // 510 - // 511 - //if val is empty return false // 512 - if (val === '') { // 513 - return false; // 514 - } // 515 - // 516 - //get the decimal and thousands separator from numeral.languageData // 517 - try { // 518 - //check if the culture is understood by numeral. if not, default it to current language // 519 - languageData = numeral.languageData(culture); // 520 - } catch (e) { // 521 - languageData = numeral.languageData(numeral.language()); // 522 - } // 523 - // 524 - //setup the delimiters and currency symbol based on culture/language // 525 - _currSymbol = languageData.currency.symbol; // 526 - _abbrObj = languageData.abbreviations; // 527 - _decimalSep = languageData.delimiters.decimal; // 528 - if (languageData.delimiters.thousands === '.') { // 529 - _thousandSep = '\\.'; // 530 - } else { // 531 - _thousandSep = languageData.delimiters.thousands; // 532 - } // 533 - // 534 - // validating currency symbol // 535 - temp = val.match(/^[^\d]+/); // 536 - if (temp !== null) { // 537 - val = val.substr(1); // 538 - if (temp[0] !== _currSymbol) { // 539 - return false; // 540 - } // 541 - } // 542 - // 543 - //validating abbreviation symbol // 544 - temp = val.match(/[^\d]+$/); // 545 - if (temp !== null) { // 546 - val = val.slice(0, -1); // 547 - if (temp[0] !== _abbrObj.thousand && temp[0] !== _abbrObj.million && temp[0] !== _abbrObj.billion && temp[0] !== _abbrObj.trillion) { - return false; // 549 - } // 550 - } // 551 - // 552 - _thousandRegEx = new RegExp(_thousandSep + '{2}'); // 553 - // 554 - if (!val.match(/[^\d.,]/g)) { // 555 - _valArray = val.split(_decimalSep); // 556 - if (_valArray.length > 2) { // 557 - return false; // 558 - } else { // 559 - if (_valArray.length < 2) { // 560 - return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx)); // 561 - } else { // 562 - if (_valArray[0].length === 1) { // 563 - return ( !! _valArray[0].match(/^\d+$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/)); - } else { // 565 - return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/)); - } // 567 - } // 568 - } // 569 - } // 570 - // 571 - return false; // 572 - }; // 573 - // 574 - /************************************ // 575 - Helpers // 576 - ************************************/ // 577 - // 578 - function loadLanguage(key, values) { // 579 - languages[key] = values; // 580 - } // 581 - // 582 - /************************************ // 583 - Floating-point helpers // 584 - ************************************/ // 585 - // 586 - // The floating-point helper functions and implementation // 587 - // borrows heavily from sinful.js: http://guipn.github.io/sinful.js/ // 588 - // 589 - /** // 590 - * Array.prototype.reduce for browsers that don't support it // 591 - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility // 592 - */ // 593 - if ('function' !== typeof Array.prototype.reduce) { // 594 - Array.prototype.reduce = function(callback, opt_initialValue) { // 595 - 'use strict'; // 596 - // 597 - if (null === this || 'undefined' === typeof this) { // 598 - // At the moment all modern browsers, that support strict mode, have // 599 - // native implementation of Array.prototype.reduce. For instance, IE8 // 600 - // does not support strict mode, so this check is actually useless. // 601 - throw new TypeError('Array.prototype.reduce called on null or undefined'); // 602 - } // 603 - // 604 - if ('function' !== typeof callback) { // 605 - throw new TypeError(callback + ' is not a function'); // 606 - } // 607 - // 608 - var index, // 609 - value, // 610 - length = this.length >>> 0, // 611 - isValueSet = false; // 612 - // 613 - if (1 < arguments.length) { // 614 - value = opt_initialValue; // 615 - isValueSet = true; // 616 - } // 617 - // 618 - for (index = 0; length > index; ++index) { // 619 - if (this.hasOwnProperty(index)) { // 620 - if (isValueSet) { // 621 - value = callback(value, this[index], index, this); // 622 - } else { // 623 - value = this[index]; // 624 - isValueSet = true; // 625 - } // 626 - } // 627 - } // 628 - // 629 - if (!isValueSet) { // 630 - throw new TypeError('Reduce of empty array with no initial value'); // 631 - } // 632 - // 633 - return value; // 634 - }; // 635 - } // 636 - // 637 - // 638 - /** // 639 - * Computes the multiplier necessary to make x >= 1, // 640 - * effectively eliminating miscalculations caused by // 641 - * finite precision. // 642 - */ // 643 - function multiplier(x) { // 644 - var parts = x.toString().split('.'); // 645 - if (parts.length < 2) { // 646 - return 1; // 647 - } // 648 - return Math.pow(10, parts[1].length); // 649 - } // 650 - // 651 - /** // 652 - * Given a variable number of arguments, returns the maximum // 653 - * multiplier that must be used to normalize an operation involving // 654 - * all of them. // 655 - */ // 656 - function correctionFactor() { // 657 - var args = Array.prototype.slice.call(arguments); // 658 - return args.reduce(function(prev, next) { // 659 - var mp = multiplier(prev), // 660 - mn = multiplier(next); // 661 - return mp > mn ? mp : mn; // 662 - }, -Infinity); // 663 - } // 664 - // 665 - // 666 - /************************************ // 667 - Numeral Prototype // 668 - ************************************/ // 669 - // 670 - // 671 - numeral.fn = Numeral.prototype = { // 672 - // 673 - clone: function() { // 674 - return numeral(this); // 675 - }, // 676 - // 677 - format: function(inputString, roundingFunction) { // 678 - return formatNumeral(this, // 679 - inputString ? inputString : defaultFormat, (roundingFunction !== undefined) ? roundingFunction : Math.round - ); // 681 - }, // 682 - // 683 - unformat: function(inputString) { // 684 - if (Object.prototype.toString.call(inputString) === '[object Number]') { // 685 - return inputString; // 686 - } // 687 - return unformatNumeral(this, inputString ? inputString : defaultFormat); // 688 - }, // 689 - // 690 - value: function() { // 691 - return this._value; // 692 - }, // 693 - // 694 - valueOf: function() { // 695 - return this._value; // 696 - }, // 697 - // 698 - set: function(value) { // 699 - this._value = Number(value); // 700 - return this; // 701 - }, // 702 - // 703 - add: function(value) { // 704 - var corrFactor = correctionFactor.call(null, this._value, value); // 705 - // 706 - function cback(accum, curr, currI, O) { // 707 - return accum + corrFactor * curr; // 708 - } // 709 - this._value = [this._value, value].reduce(cback, 0) / corrFactor; // 710 - return this; // 711 - }, // 712 - // 713 - subtract: function(value) { // 714 - var corrFactor = correctionFactor.call(null, this._value, value); // 715 - // 716 - function cback(accum, curr, currI, O) { // 717 - return accum - corrFactor * curr; // 718 - } // 719 - this._value = [value].reduce(cback, this._value * corrFactor) / corrFactor; // 720 - return this; // 721 - }, // 722 - // 723 - multiply: function(value) { // 724 - function cback(accum, curr, currI, O) { // 725 - var corrFactor = correctionFactor(accum, curr); // 726 - return (accum * corrFactor) * (curr * corrFactor) / // 727 - (corrFactor * corrFactor); // 728 - } // 729 - this._value = [this._value, value].reduce(cback, 1); // 730 - return this; // 731 - }, // 732 - // 733 - divide: function(value) { // 734 - function cback(accum, curr, currI, O) { // 735 - var corrFactor = correctionFactor(accum, curr); // 736 - return (accum * corrFactor) / (curr * corrFactor); // 737 - } // 738 - this._value = [this._value, value].reduce(cback); // 739 - return this; // 740 - }, // 741 - // 742 - difference: function(value) { // 743 - return Math.abs(numeral(this._value).subtract(value).value()); // 744 - } // 745 - // 746 - }; // 747 - // 748 - /************************************ // 749 - Exposing Numeral // 750 - ************************************/ // 751 - // 752 - // CommonJS module is defined // 753 - if (hasModule) { // 754 - module.exports = numeral; // 755 - } // 756 - // 757 - /*global ender:false */ // 758 - if (typeof ender === 'undefined') { // 759 - // here, `this` means `window` in the browser, or `global` on the server // 760 - // add `numeral` as a global object via a string identifier, // 761 - // for Closure Compiler 'advanced' mode // 762 - this['numeral'] = numeral; // 763 - } // 764 - // 765 - /*global define:false */ // 766 - if (typeof define === 'function' && define.amd) { // 767 - define([], function() { // 768 - return numeral; // 769 - }); // 770 - } // 771 -}).call(this); // 772 - // 773 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/numeral:numeral/min/languages.min.js // -// // -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/*! // 1 - * numeral.js language configuration // 2 - * language : belgium-dutch (be-nl) // 3 - * author : Dieter Luypaert : https://github.com/moeriki // 4 - */ // 5 -!function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:" mln",billion:" mld",trillion:" bln"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?"ste":"de"},currency:{symbol:"€ "}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("be-nl",a)}(),/*! - * numeral.js language configuration // 7 - * language : simplified chinese // 8 - * author : badplum : https://github.com/badplum // 9 - */ // 10 -function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"千",million:"百万",billion:"十亿",trillion:"兆"},ordinal:function(){return"."},currency:{symbol:"¥"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("chs",a)}(),/*! - * numeral.js language configuration // 12 - * language : czech (cs) // 13 - * author : Anatoli Papirovski : https://github.com/apapirovski // 14 - */ // 15 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"tis.",million:"mil.",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"Kč"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("cs",a)}(),/*! - * numeral.js language configuration // 17 - * language : danish denmark (dk) // 18 - * author : Michael Storgaard : https://github.com/mstorgaard // 19 - */ // 20 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"k",million:"mio",billion:"mia",trillion:"b"},ordinal:function(){return"."},currency:{symbol:"DKK"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("da-dk",a)}(),/*! - * numeral.js language configuration // 22 - * language : German in Switzerland (de-ch) // 23 - * author : Michael Piefel : https://github.com/piefel (based on work from Marco Krage : https://github.com/sinky) // 24 - */ // 25 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"CHF"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("de-ch",a)}(),/*! - * numeral.js language configuration // 27 - * language : German (de) – generally useful in Germany, Austria, Luxembourg, Belgium // 28 - * author : Marco Krage : https://github.com/sinky // 29 - */ // 30 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("de",a)}(),/*! - * numeral.js language configuration // 32 - * language : english united kingdom (uk) // 33 - * author : Dan Ristic : https://github.com/dristic // 34 - */ // 35 -function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"},currency:{symbol:"£"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("en-gb",a)}(),/*! - * numeral.js language configuration // 37 - * language : spanish Spain // 38 - * author : Hernan Garcia : https://github.com/hgarcia // 39 - */ // 40 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"k",million:"mm",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===b||3===b?"er":2===b?"do":7===b||0===b?"mo":8===b?"vo":9===b?"no":"to"},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("es",a)}(),/*! - * numeral.js language configuration // 42 - * language : spanish // 43 - * author : Hernan Garcia : https://github.com/hgarcia // 44 - */ // 45 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"k",million:"mm",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===b||3===b?"er":2===b?"do":7===b||0===b?"mo":8===b?"vo":9===b?"no":"to"},currency:{symbol:"$"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("es",a)}(),/*! - * numeral.js language configuration // 47 - * language : Estonian // 48 - * author : Illimar Tambek : https://github.com/ragulka // 49 - * // 50 - * Note: in Estonian, abbreviations are always separated // 51 - * from numbers with a space // 52 - */ // 53 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:" tuh",million:" mln",billion:" mld",trillion:" trl"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("et",a)}(),/*! - * numeral.js language configuration // 55 - * language : Finnish // 56 - * author : Sami Saada : https://github.com/samitheberber // 57 - */ // 58 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"M",billion:"G",trillion:"T"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("fi",a)}(),/*! - * numeral.js language configuration // 60 - * language : french (Canada) (fr-CA) // 61 - * author : Léo Renaud-Allaire : https://github.com/renaudleo // 62 - */ // 63 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"M",billion:"G",trillion:"T"},ordinal:function(a){return 1===a?"er":"e"},currency:{symbol:"$"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("fr-CA",a)}(),/*! - * numeral.js language configuration // 65 - * language : french (fr-ch) // 66 - * author : Adam Draper : https://github.com/adamwdraper // 67 - */ // 68 -function(){var a={delimiters:{thousands:"'",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){return 1===a?"er":"e"},currency:{symbol:"CHF"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("fr-ch",a)}(),/*! - * numeral.js language configuration // 70 - * language : french (fr) // 71 - * author : Adam Draper : https://github.com/adamwdraper // 72 - */ // 73 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){return 1===a?"er":"e"},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("fr",a)}(),/*! - * numeral.js language configuration // 75 - * language : Hungarian (hu) // 76 - * author : Peter Bakondy : https://github.com/pbakondy // 77 - */ // 78 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"E",million:"M",billion:"Mrd",trillion:"T"},ordinal:function(){return"."},currency:{symbol:" Ft"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("hu",a)}(),/*! - * numeral.js language configuration // 80 - * language : italian Italy (it) // 81 - * author : Giacomo Trombi : http://cinquepunti.it // 82 - */ // 83 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"mila",million:"mil",billion:"b",trillion:"t"},ordinal:function(){return"º"},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("it",a)}(),/*! - * numeral.js language configuration // 85 - * language : japanese // 86 - * author : teppeis : https://github.com/teppeis // 87 - */ // 88 -function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"千",million:"百万",billion:"十億",trillion:"兆"},ordinal:function(){return"."},currency:{symbol:"¥"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("ja",a)}(),/*! - * numeral.js language configuration // 90 - * language : Latvian (lv) // 91 - * author : Lauris Bukšis-Haberkorns : https://github.com/Lafriks // 92 - */ // 93 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:" tūkst.",million:" milj.",billion:" mljrd.",trillion:" trilj."},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("lv",a)}(),/*! - * numeral.js language configuration // 95 - * language : netherlands-dutch (nl-nl) // 96 - * author : Dave Clayton : https://github.com/davedx // 97 - */ // 98 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"k",million:"mln",billion:"mrd",trillion:"bln"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?"ste":"de"},currency:{symbol:"€ "}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("nl-nl",a)}(),/*! - * numeral.js language configuration // 100 - * language : polish (pl) // 101 - * author : Dominik Bulaj : https://github.com/dominikbulaj // 102 - */ // 103 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"tys.",million:"mln",billion:"mld",trillion:"bln"},ordinal:function(){return"."},currency:{symbol:"PLN"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("pl",a)}(),/*! - * numeral.js language configuration // 105 - * language : portuguese brazil (pt-br) // 106 - * author : Ramiro Varandas Jr : https://github.com/ramirovjr // 107 - */ // 108 -function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"mil",million:"milhões",billion:"b",trillion:"t"},ordinal:function(){return"º"},currency:{symbol:"R$"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("pt-br",a)}(),/*! - * numeral.js language configuration // 110 - * language : portuguese (pt-pt) // 111 - * author : Diogo Resende : https://github.com/dresende // 112 - */ // 113 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(){return"º"},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("pt-pt",a)}(),function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"тыс.",million:"млн",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"₴"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("ru-UA",a)}(),/*! - * numeral.js language configuration // 115 - * language : russian (ru) // 116 - * author : Anatoli Papirovski : https://github.com/apapirovski // 117 - */ // 118 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"тыс.",million:"млн",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"руб."}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("ru",a)}(),/*! - * numeral.js language configuration // 120 - * language : slovak (sk) // 121 - * author : Ahmed Al Hafoudh : http://www.freevision.sk // 122 - */ // 123 -function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"tis.",million:"mil.",billion:"b",trillion:"t"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("sk",a)}(),/*! - * numeral.js language configuration // 125 - * language : thai (th) // 126 - * author : Sathit Jittanupat : https://github.com/jojosati // 127 - */ // 128 -function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"พัน",million:"ล้าน",billion:"พันล้าน",trillion:"ล้านล้าน"},ordinal:function(){return"."},currency:{symbol:"฿"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("th",a)}(),/*! - * numeral.js language configuration // 130 - * language : turkish (tr) // 131 - * author : Ecmel Ercan : https://github.com/ecmel, Erhan Gundogan : https://github.com/erhangundogan, Burak Yiğit Kaya: https://github.com/BYK - */ // 133 -function(){var a={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"},b={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"bin",million:"milyon",billion:"milyar",trillion:"trilyon"},ordinal:function(b){if(0===b)return"'ıncı";var c=b%10,d=b%100-c,e=b>=100?100:null;return a[c]||a[d]||a[e]},currency:{symbol:"₺"}};"undefined"!=typeof module&&module.exports&&(module.exports=b),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("tr",b)}(),function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"тис.",million:"млн",billion:"млрд",trillion:"блн"},ordinal:function(){return""},currency:{symbol:"₴"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("uk-UA",a)}(); -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/numeral:numeral/meteor/export.js // -// // -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -if ( Meteor.isClient ) { // 1 - numeral = window.numeral; // 2 - delete window.numeral; // 3 -} // 4 - // 5 -if ( Meteor.isServer ) { // 6 - numeral = Npm.require('numeral'); // 7 -} // 8 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['numeral:numeral'] = { - numeral: numeral -}; - -})(); - -//# sourceMappingURL=numeral_numeral.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js.map b/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js.map deleted file mode 100644 index dbb8453..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["numeral:numeral/numeral.js","numeral:numeral/min/languages.min.js","numeral:numeral/meteor/export.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,G;AACA,a;AACA,kB;AACA,uB;AACA,gB;AACA,4C;AACA,G;;AAEA,a;;AAEA,yC;AACA,iB;AACA,yC;;AAEA,gB;AACA,0B;AACA,qD;AACA,uB;AACA,+B;AACA,0B;AACA,8B;AACA,2B;AACA,sE;;;AAGA,yC;AACA,oB;AACA,yC;;;AAGA,+B;AACA,8B;AACA,6B;AACA,K;;AAEA,O;AACA,wE;AACA,M;AACA,oF;AACA,6D;AACA,O;AACA,qE;AACA,4C;AACA,4B;AACA,mB;;AAEA,8F;AACA,4F;AACA,8E;;AAEA,wB;AACA,oE;AACA,yD;AACA,S;;AAEA,sB;AACA,K;;AAEA,yC;AACA,kB;AACA,yC;;AAEA,sD;AACA,yD;AACA,mB;;AAEA,6D;AACA,wD;AACA,iE;AACA,4D;AACA,mE;AACA,sD;AACA,2C;AACA,8C;AACA,sE;AACA,S;;AAEA,wB;AACA,sB;AACA,K;;AAEA,uB;AACA,yC;AACA,oC;AACA,2B;AACA,0B;AACA,0B;AACA,2B;AACA,wE;AACA,oC;AACA,kB;;AAEA,uC;AACA,4C;AACA,gB;AACA,wC;AACA,6B;AACA,oB;AACA,4E;AACA,mH;AACA,iB;;AAEA,+F;AACA,2L;AACA,yL;AACA,yL;AACA,2L;;AAEA,uF;AACA,oE;AACA,iH;;AAEA,0C;AACA,8B;AACA,qB;AACA,iB;;AAEA,oD;AACA,khB;;AAEA,sD;AACA,8E;AACA,a;AACA,S;AACA,wB;AACA,K;;AAEA,0D;AACA,8C;AACA,iD;AACA,iD;AACA,uB;AACA,wB;AACA,mB;;AAEA,mD;AACA,wC;AACA,wB;AACA,8C;AACA,+C;AACA,wB;AACA,8C;AACA,gB;AACA,6C;AACA,S;;AAEA,4B;AACA,kE;;AAEA,8B;AACA,+B;AACA,uE;AACA,0C;AACA,gC;AACA,mF;AACA,+D;AACA,oC;AACA,iB;AACA,kG;AACA,yC;AACA,oB;AACA,qF;AACA,a;AACA,gB;AACA,2C;AACA,0C;AACA,yF;AACA,yC;AACA,oB;AACA,qF;AACA,a;AACA,S;;AAEA,sB;AACA,K;;AAEA,4D;AACA,uB;AACA,mB;AACA,mC;;AAEA,mC;AACA,wC;AACA,wB;AACA,8C;AACA,gB;AACA,6C;AACA,S;;AAEA,+D;;AAEA,uC;AACA,sC;AACA,8C;AACA,qC;AACA,gB;AACA,0C;AACA,S;;AAEA,sB;AACA,K;;AAEA,4B;AACA,mD;AACA,sE;AACA,gF;AACA,2H;AACA,K;;AAEA,mC;AACA,0C;AACA,wB;AACA,kE;AACA,qC;AACA,oB;AACA,iE;AACA,sB;AACA,4D;AACA,sB;AACA,qD;AACA,4C;AACA,sB;AACA,4D;AACA,sB;AACA,qD;AACA,S;AACA,+B;AACA,K;;AAEA,4D;AACA,yB;AACA,2B;AACA,2B;AACA,sB;AACA,6D;AACA,4D;AACA,4D;AACA,6D;AACA,oD;AACA,uB;AACA,qB;AACA,kC;AACA,6E;AACA,gB;AACA,gB;AACA,kB;AACA,c;AACA,sB;AACA,sB;AACA,mB;AACA,wB;;AAEA,wE;AACA,iD;AACA,8B;AACA,gB;AACA,sG;AACA,4D;AACA,2C;AACA,4B;AACA,6C;AACA,kD;AACA,8B;AACA,mD;AACA,a;;AAEA,4C;AACA,2C;AACA,qD;AACA,kD;AACA,kD;AACA,kD;AACA,kD;AACA,6D;;AAEA,sD;AACA,gD;AACA,+B;AACA,sD;AACA,wB;AACA,qD;AACA,iB;;AAEA,qE;AACA,+B;AACA,oF;AACA,qD;AACA,qG;AACA,8B;AACA,mF;AACA,oD;AACA,oG;AACA,8B;AACA,mF;AACA,oD;AACA,oG;AACA,+B;AACA,oF;AACA,oD;AACA,iB;AACA,a;;AAEA,6C;AACA,2C;AACA,yC;AACA,gD;AACA,gC;AACA,sD;AACA,wB;AACA,qD;AACA,iB;;AAEA,oE;AACA,gD;AACA,oD;;AAEA,sD;AACA,wD;AACA,sC;AACA,gD;AACA,yB;AACA,8B;AACA,qB;AACA,iB;AACA,a;;AAEA,uC;AACA,2C;AACA,yC;AACA,gD;AACA,8B;AACA,sD;AACA,wB;AACA,qD;AACA,iB;;AAEA,sE;AACA,a;;AAEA,6C;AACA,8B;AACA,oD;AACA,a;;AAEA,+C;AACA,6C;AACA,4C;;AAEA,4B;AACA,kD;AACA,2D;AACA,qD;AACA,2H;AACA,wB;AACA,2E;AACA,iB;;AAEA,oC;;AAEA,6C;AACA,wF;AACA,wB;AACA,2B;AACA,iB;;AAEA,yD;AACA,2B;AACA,iB;AACA,oB;AACA,2D;AACA,a;;AAEA,4B;AACA,sC;AACA,+B;AACA,2B;AACA,a;;AAEA,iC;AACA,4H;AACA,a;;AAEA,4C;AACA,uB;AACA,a;;AAEA,sN;AACA,S;AACA,K;;AAEA,yC;AACA,2B;AACA,yC;;AAEA,+B;AACA,uC;AACA,kC;AACA,iE;AACA,sB;AACA,oC;AACA,+C;AACA,S;;AAEA,0C;AACA,M;;AAEA,qB;AACA,8B;;AAEA,6B;AACA,uC;AACA,sC;AACA,M;;AAEA,8E;AACA,2E;AACA,oB;AACA,8C;AACA,mB;AACA,mC;AACA,S;AACA,Q;AACA,gC;;AAEA,6B;AACA,kC;AACA,6D;AACA,a;AACA,kC;AACA,S;;AAEA,wC;AACA,sC;AACA,S;;AAEA,uB;AACA,M;;AAEA,qE;AACA,oE;AACA,8B;AACA,0C;AACA,mB;AACA,8C;AACA,S;;AAEA,8B;AACA,yD;AACA,S;;AAEA,8B;AACA,M;;AAEA,4B;AACA,qB;AACA,2B;AACA,wB;AACA,U;AACA,wB;AACA,0B;AACA,yB;AACA,yB;AACA,yB;AACA,U;AACA,mC;AACA,gC;AACA,yD;AACA,kC;AACA,kC;AACA,wC;AACA,U;AACA,mB;AACA,uB;AACA,S;AACA,O;;AAEA,2C;AACA,iE;AACA,M;;AAEA,8C;AACA,qE;AACA,M;;AAEA,+C;;AAEA,wB;AACA,yB;AACA,wB;AACA,sB;AACA,qB;AACA,2B;AACA,yB;AACA,iB;;AAEA,8B;AACA,sC;AACA,sB;AACA,+B;AACA,gG;AACA,a;AACA,S;;AAEA,4C;AACA,yB;;AAEA,2C;AACA,qC;AACA,wB;AACA,S;;AAEA,sC;AACA,yB;AACA,yB;AACA,S;;AAEA,2E;AACA,a;AACA,mG;AACA,yD;AACA,qB;AACA,oE;AACA,S;;AAEA,4E;AACA,mD;AACA,8C;AACA,sD;AACA,wD;AACA,iC;AACA,gB;AACA,6D;AACA,S;;AAEA,qC;AACA,oC;AACA,4B;AACA,gC;AACA,0C;AACA,6B;AACA,a;AACA,S;;AAEA,wC;AACA,oC;AACA,4B;AACA,mC;AACA,iJ;AACA,6B;AACA,a;AACA,S;;AAEA,0D;;AAEA,qC;AACA,+C;AACA,uC;AACA,6B;AACA,oB;AACA,2C;AACA,wG;AACA,wB;AACA,oD;AACA,0I;AACA,4B;AACA,8I;AACA,qB;AACA,iB;AACA,a;AACA,S;;AAEA,qB;AACA,M;;AAEA,yC;AACA,e;AACA,yC;;AAEA,wC;AACA,gC;AACA,K;;AAEA,yC;AACA,8B;AACA,yC;;AAEA,6D;AACA,wE;;AAEA,O;AACA,gE;AACA,kH;AACA,O;AACA,uD;AACA,uE;AACA,yB;;AAEA,+D;AACA,oF;AACA,qF;AACA,mF;AACA,0F;AACA,a;;AAEA,iD;AACA,qE;AACA,a;;AAEA,sB;AACA,sB;AACA,2C;AACA,mC;;AAEA,uC;AACA,yC;AACA,kC;AACA,a;;AAEA,sD;AACA,iD;AACA,qC;AACA,0E;AACA,4B;AACA,4C;AACA,0C;AACA,qB;AACA,iB;AACA,a;;AAEA,8B;AACA,mF;AACA,a;;AAEA,yB;AACA,U;AACA,K;;;AAGA,O;AACA,wD;AACA,wD;AACA,wB;AACA,O;AACA,4B;AACA,4C;AACA,+B;AACA,qB;AACA,S;AACA,6C;AACA,K;;AAEA,O;AACA,gE;AACA,uE;AACA,mB;AACA,O;AACA,iC;AACA,yD;AACA,iD;AACA,sC;AACA,sC;AACA,qC;AACA,sB;AACA,K;;;AAGA,yC;AACA,yB;AACA,yC;;;AAGA,sC;;AAEA,2B;AACA,iC;AACA,U;;AAEA,yD;AACA,sC;AACA,2H;AACA,c;AACA,U;;AAEA,yC;AACA,oF;AACA,mC;AACA,a;AACA,oF;AACA,U;;AAEA,2B;AACA,+B;AACA,U;;AAEA,6B;AACA,+B;AACA,U;;AAEA,8B;AACA,wC;AACA,wB;AACA,U;;AAEA,8B;AACA,6E;;AAEA,mD;AACA,iD;AACA,a;AACA,6E;AACA,wB;AACA,U;;AAEA,mC;AACA,6E;;AAEA,mD;AACA,iD;AACA,a;AACA,uF;AACA,wB;AACA,U;;AAEA,mC;AACA,mD;AACA,+D;AACA,mE;AACA,8C;AACA,a;AACA,gE;AACA,wB;AACA,U;;AAEA,iC;AACA,mD;AACA,+D;AACA,kE;AACA,a;AACA,6D;AACA,wB;AACA,U;;AAEA,qC;AACA,0E;AACA,S;;AAEA,M;;AAEA,yC;AACA,wB;AACA,yC;;AAEA,iC;AACA,oB;AACA,iC;AACA,K;;AAEA,2B;AACA,uC;AACA,gF;AACA,oE;AACA,+C;AACA,kC;AACA,K;;AAEA,4B;AACA,qD;AACA,+B;AACA,2B;AACA,W;AACA,K;AACA,c;;;;;;;;;;;;;;;;;;;ACnwBA,I;AACA,oC;AACA,mC;AACA,wD;AACA,G;AACA,kZ;AACA,oC;AACA,gC;AACA,gD;AACA,G;AACA,uV;AACA,oC;AACA,wB;AACA,+D;AACA,G;AACA,4V;AACA,oC;AACA,iC;AACA,6D;AACA,G;AACA,8V;AACA,oC;AACA,2C;AACA,kH;AACA,G;AACA,0V;AACA,oC;AACA,qF;AACA,kD;AACA,G;AACA,qV;AACA,oC;AACA,yC;AACA,mD;AACA,G;AACA,6Z;AACA,oC;AACA,2B;AACA,sD;AACA,G;AACA,ya;AACA,oC;AACA,qB;AACA,sD;AACA,G;AACA,ya;AACA,oC;AACA,sB;AACA,uD;AACA,E;AACA,wD;AACA,4B;AACA,G;AACA,iW;AACA,oC;AACA,qB;AACA,yD;AACA,G;AACA,oV;AACA,oC;AACA,qC;AACA,6D;AACA,G;AACA,qW;AACA,oC;AACA,4B;AACA,wD;AACA,G;AACA,uW;AACA,oC;AACA,yB;AACA,wD;AACA,G;AACA,iW;AACA,oC;AACA,4B;AACA,uD;AACA,G;AACA,yV;AACA,oC;AACA,gC;AACA,kD;AACA,G;AACA,0V;AACA,oC;AACA,sB;AACA,gD;AACA,G;AACA,sV;AACA,oC;AACA,0B;AACA,iE;AACA,G;AACA,4W;AACA,oC;AACA,uC;AACA,oD;AACA,G;AACA,8Y;AACA,oC;AACA,yB;AACA,2D;AACA,G;AACA,gW;AACA,oC;AACA,uC;AACA,6D;AACA,G;AACA,iW;AACA,oC;AACA,gC;AACA,uD;AACA,G;AACA,irB;AACA,oC;AACA,0B;AACA,+D;AACA,G;AACA,4V;AACA,oC;AACA,yB;AACA,uD;AACA,G;AACA,2V;AACA,oC;AACA,uB;AACA,2D;AACA,G;AACA,uW;AACA,oC;AACA,0B;AACA,+I;AACA,G;AACA,08B;;;;;;;;;;;;;;;;;;ACrIA,wB;AACA,2B;AACA,wB;AACA,C;;AAEA,wB;AACA,mC;AACA,C","file":"/packages/numeral:numeral.js","sourcesContent":["/*!\n * numeral.js\n * version : 1.5.3\n * author : Adam Draper\n * license : MIT\n * http://adamwdraper.github.com/Numeral-js/\n */\n\n(function() {\n\n /************************************\n Constants\n ************************************/\n\n var numeral,\n VERSION = '1.5.3',\n // internal storage for language config files\n languages = {},\n currentLanguage = 'en',\n zeroFormat = null,\n defaultFormat = '0,0',\n // check for nodeJS\n hasModule = (typeof module !== 'undefined' && module.exports);\n\n\n /************************************\n Constructors\n ************************************/\n\n\n // Numeral prototype object\n function Numeral(number) {\n this._value = number;\n }\n\n /**\n * Implementation of toFixed() that treats floats more like decimals\n *\n * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present\n * problems for accounting- and finance-related software.\n */\n function toFixed(value, precision, roundingFunction, optionals) {\n var power = Math.pow(10, precision),\n optionalsRegExp,\n output;\n\n //roundingFunction = (roundingFunction !== undefined ? roundingFunction : Math.round);\n // Multiply up by precision, round accurately, then divide and use native toFixed():\n output = (roundingFunction(value * power) / power).toFixed(precision);\n\n if (optionals) {\n optionalsRegExp = new RegExp('0{1,' + optionals + '}$');\n output = output.replace(optionalsRegExp, '');\n }\n\n return output;\n }\n\n /************************************\n Formatting\n ************************************/\n\n // determine what type of formatting we need to do\n function formatNumeral(n, format, roundingFunction) {\n var output;\n\n // figure out what kind of format we are dealing with\n if (format.indexOf('$') > -1) { // currency!!!!!\n output = formatCurrency(n, format, roundingFunction);\n } else if (format.indexOf('%') > -1) { // percentage\n output = formatPercentage(n, format, roundingFunction);\n } else if (format.indexOf(':') > -1) { // time\n output = formatTime(n, format);\n } else { // plain ol' numbers or bytes\n output = formatNumber(n._value, format, roundingFunction);\n }\n\n // return string\n return output;\n }\n\n // revert to number\n function unformatNumeral(n, string) {\n var stringOriginal = string,\n thousandRegExp,\n millionRegExp,\n billionRegExp,\n trillionRegExp,\n suffixes = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],\n bytesMultiplier = false,\n power;\n\n if (string.indexOf(':') > -1) {\n n._value = unformatTime(string);\n } else {\n if (string === zeroFormat) {\n n._value = 0;\n } else {\n if (languages[currentLanguage].delimiters.decimal !== '.') {\n string = string.replace(/\\./g, '').replace(languages[currentLanguage].delimiters.decimal, '.');\n }\n\n // see if abbreviations are there so that we can multiply to the correct number\n thousandRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.thousand + '(?:\\\\)|(\\\\' + languages[currentLanguage].currency.symbol + ')?(?:\\\\))?)?$');\n millionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.million + '(?:\\\\)|(\\\\' + languages[currentLanguage].currency.symbol + ')?(?:\\\\))?)?$');\n billionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.billion + '(?:\\\\)|(\\\\' + languages[currentLanguage].currency.symbol + ')?(?:\\\\))?)?$');\n trillionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.trillion + '(?:\\\\)|(\\\\' + languages[currentLanguage].currency.symbol + ')?(?:\\\\))?)?$');\n\n // see if bytes are there so that we can multiply to the correct number\n for (power = 0; power <= suffixes.length; power++) {\n bytesMultiplier = (string.indexOf(suffixes[power]) > -1) ? Math.pow(1024, power + 1) : false;\n\n if (bytesMultiplier) {\n break;\n }\n }\n\n // do some math to create our number\n n._value = ((bytesMultiplier) ? bytesMultiplier : 1) * ((stringOriginal.match(thousandRegExp)) ? Math.pow(10, 3) : 1) * ((stringOriginal.match(millionRegExp)) ? Math.pow(10, 6) : 1) * ((stringOriginal.match(billionRegExp)) ? Math.pow(10, 9) : 1) * ((stringOriginal.match(trillionRegExp)) ? Math.pow(10, 12) : 1) * ((string.indexOf('%') > -1) ? 0.01 : 1) * (((string.split('-').length + Math.min(string.split('(').length - 1, string.split(')').length - 1)) % 2) ? 1 : -1) * Number(string.replace(/[^0-9\\.]+/g, ''));\n\n // round if we are talking about bytes\n n._value = (bytesMultiplier) ? Math.ceil(n._value) : n._value;\n }\n }\n return n._value;\n }\n\n function formatCurrency(n, format, roundingFunction) {\n var symbolIndex = format.indexOf('$'),\n openParenIndex = format.indexOf('('),\n minusSignIndex = format.indexOf('-'),\n space = '',\n spliceIndex,\n output;\n\n // check for space before or after currency\n if (format.indexOf(' $') > -1) {\n space = ' ';\n format = format.replace(' $', '');\n } else if (format.indexOf('$ ') > -1) {\n space = ' ';\n format = format.replace('$ ', '');\n } else {\n format = format.replace('$', '');\n }\n\n // format the number\n output = formatNumber(n._value, format, roundingFunction);\n\n // position the symbol\n if (symbolIndex <= 1) {\n if (output.indexOf('(') > -1 || output.indexOf('-') > -1) {\n output = output.split('');\n spliceIndex = 1;\n if (symbolIndex < openParenIndex || symbolIndex < minusSignIndex) {\n // the symbol appears before the \"(\" or \"-\"\n spliceIndex = 0;\n }\n output.splice(spliceIndex, 0, languages[currentLanguage].currency.symbol + space);\n output = output.join('');\n } else {\n output = languages[currentLanguage].currency.symbol + space + output;\n }\n } else {\n if (output.indexOf(')') > -1) {\n output = output.split('');\n output.splice(-1, 0, space + languages[currentLanguage].currency.symbol);\n output = output.join('');\n } else {\n output = output + space + languages[currentLanguage].currency.symbol;\n }\n }\n\n return output;\n }\n\n function formatPercentage(n, format, roundingFunction) {\n var space = '',\n output,\n value = n._value * 100;\n\n // check for space before %\n if (format.indexOf(' %') > -1) {\n space = ' ';\n format = format.replace(' %', '');\n } else {\n format = format.replace('%', '');\n }\n\n output = formatNumber(value, format, roundingFunction);\n\n if (output.indexOf(')') > -1) {\n output = output.split('');\n output.splice(-1, 0, space + '%');\n output = output.join('');\n } else {\n output = output + space + '%';\n }\n\n return output;\n }\n\n function formatTime(n) {\n var hours = Math.floor(n._value / 60 / 60),\n minutes = Math.floor((n._value - (hours * 60 * 60)) / 60),\n seconds = Math.round(n._value - (hours * 60 * 60) - (minutes * 60));\n return hours + ':' + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);\n }\n\n function unformatTime(string) {\n var timeArray = string.split(':'),\n seconds = 0;\n // turn hours and minutes into seconds and add them all up\n if (timeArray.length === 3) {\n // hours\n seconds = seconds + (Number(timeArray[0]) * 60 * 60);\n // minutes\n seconds = seconds + (Number(timeArray[1]) * 60);\n // seconds\n seconds = seconds + Number(timeArray[2]);\n } else if (timeArray.length === 2) {\n // minutes\n seconds = seconds + (Number(timeArray[0]) * 60);\n // seconds\n seconds = seconds + Number(timeArray[1]);\n }\n return Number(seconds);\n }\n\n function formatNumber(value, format, roundingFunction) {\n var negP = false,\n signed = false,\n optDec = false,\n abbr = '',\n abbrK = false, // force abbreviation to thousands\n abbrM = false, // force abbreviation to millions\n abbrB = false, // force abbreviation to billions\n abbrT = false, // force abbreviation to trillions\n abbrForce = false, // force abbreviation\n bytes = '',\n ord = '',\n abs = Math.abs(value),\n suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],\n min,\n max,\n power,\n w,\n precision,\n thousands,\n d = '',\n neg = false;\n\n // check if number is zero and a custom zero format has been set\n if (value === 0 && zeroFormat !== null) {\n return zeroFormat;\n } else {\n // see if we should use parentheses for negative number or if we should prefix with a sign\n // if both are present we default to parentheses\n if (format.indexOf('(') > -1) {\n negP = true;\n format = format.slice(1, -1);\n } else if (format.indexOf('+') > -1) {\n signed = true;\n format = format.replace(/\\+/g, '');\n }\n\n // see if abbreviation is wanted\n if (format.indexOf('a') > -1) {\n // check if abbreviation is specified\n abbrK = format.indexOf('aK') >= 0;\n abbrM = format.indexOf('aM') >= 0;\n abbrB = format.indexOf('aB') >= 0;\n abbrT = format.indexOf('aT') >= 0;\n abbrForce = abbrK || abbrM || abbrB || abbrT;\n\n // check for space before abbreviation\n if (format.indexOf(' a') > -1) {\n abbr = ' ';\n format = format.replace(' a', '');\n } else {\n format = format.replace('a', '');\n }\n\n if (abs >= Math.pow(10, 12) && !abbrForce || abbrT) {\n // trillion\n abbr = abbr + languages[currentLanguage].abbreviations.trillion;\n value = value / Math.pow(10, 12);\n } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9) && !abbrForce || abbrB) {\n // billion\n abbr = abbr + languages[currentLanguage].abbreviations.billion;\n value = value / Math.pow(10, 9);\n } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6) && !abbrForce || abbrM) {\n // million\n abbr = abbr + languages[currentLanguage].abbreviations.million;\n value = value / Math.pow(10, 6);\n } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3) && !abbrForce || abbrK) {\n // thousand\n abbr = abbr + languages[currentLanguage].abbreviations.thousand;\n value = value / Math.pow(10, 3);\n }\n }\n\n // see if we are formatting bytes\n if (format.indexOf('b') > -1) {\n // check for space before\n if (format.indexOf(' b') > -1) {\n bytes = ' ';\n format = format.replace(' b', '');\n } else {\n format = format.replace('b', '');\n }\n\n for (power = 0; power <= suffixes.length; power++) {\n min = Math.pow(1024, power);\n max = Math.pow(1024, power + 1);\n\n if (value >= min && value < max) {\n bytes = bytes + suffixes[power];\n if (min > 0) {\n value = value / min;\n }\n break;\n }\n }\n }\n\n // see if ordinal is wanted\n if (format.indexOf('o') > -1) {\n // check for space before\n if (format.indexOf(' o') > -1) {\n ord = ' ';\n format = format.replace(' o', '');\n } else {\n format = format.replace('o', '');\n }\n\n ord = ord + languages[currentLanguage].ordinal(value);\n }\n\n if (format.indexOf('[.]') > -1) {\n optDec = true;\n format = format.replace('[.]', '.');\n }\n\n w = value.toString().split('.')[0];\n precision = format.split('.')[1];\n thousands = format.indexOf(',');\n\n if (precision) {\n if (precision.indexOf('[') > -1) {\n precision = precision.replace(']', '');\n precision = precision.split('[');\n d = toFixed(value, (precision[0].length + precision[1].length), roundingFunction, precision[1].length);\n } else {\n d = toFixed(value, precision.length, roundingFunction);\n }\n\n w = d.split('.')[0];\n\n if (d.split('.')[1].length) {\n d = languages[currentLanguage].delimiters.decimal + d.split('.')[1];\n } else {\n d = '';\n }\n\n if (optDec && Number(d.slice(1)) === 0) {\n d = '';\n }\n } else {\n w = toFixed(value, null, roundingFunction);\n }\n\n // format number\n if (w.indexOf('-') > -1) {\n w = w.slice(1);\n neg = true;\n }\n\n if (thousands > -1) {\n w = w.toString().replace(/(\\d)(?=(\\d{3})+(?!\\d))/g, '$1' + languages[currentLanguage].delimiters.thousands);\n }\n\n if (format.indexOf('.') === 0) {\n w = '';\n }\n\n return ((negP && neg) ? '(' : '') + ((!negP && neg) ? '-' : '') + ((!neg && signed) ? '+' : '') + w + d + ((ord) ? ord : '') + ((abbr) ? abbr : '') + ((bytes) ? bytes : '') + ((negP && neg) ? ')' : '');\n }\n }\n\n /************************************\n Top Level Functions\n ************************************/\n\n numeral = function(input) {\n if (numeral.isNumeral(input)) {\n input = input.value();\n } else if (input === 0 || typeof input === 'undefined') {\n input = 0;\n } else if (!Number(input)) {\n input = numeral.fn.unformat(input);\n }\n\n return new Numeral(Number(input));\n };\n\n // version number\n numeral.version = VERSION;\n\n // compare numeral object\n numeral.isNumeral = function(obj) {\n return obj instanceof Numeral;\n };\n\n // This function will load languages and then set the global language. If\n // no arguments are passed in, it will simply return the current global\n // language key.\n numeral.language = function(key, values) {\n if (!key) {\n return currentLanguage;\n }\n \n key = key.toLowerCase();\n\n if (key && !values) {\n if (!languages[key]) {\n throw new Error('Unknown language : ' + key);\n }\n currentLanguage = key;\n }\n\n if (values || !languages[key]) {\n loadLanguage(key, values);\n }\n\n return numeral;\n };\n\n // This function provides access to the loaded language data. If\n // no arguments are passed in, it will simply return the current\n // global language object.\n numeral.languageData = function(key) {\n if (!key) {\n return languages[currentLanguage];\n }\n\n if (!languages[key]) {\n throw new Error('Unknown language : ' + key);\n }\n\n return languages[key];\n };\n\n numeral.language('en', {\n delimiters: {\n thousands: ',',\n decimal: '.'\n },\n abbreviations: {\n thousand: 'k',\n million: 'm',\n billion: 'b',\n trillion: 't'\n },\n ordinal: function(number) {\n var b = number % 10;\n return (~~(number % 100 / 10) === 1) ? 'th' :\n (b === 1) ? 'st' :\n (b === 2) ? 'nd' :\n (b === 3) ? 'rd' : 'th';\n },\n currency: {\n symbol: '$'\n }\n });\n\n numeral.zeroFormat = function(format) {\n zeroFormat = typeof(format) === 'string' ? format : null;\n };\n\n numeral.defaultFormat = function(format) {\n defaultFormat = typeof(format) === 'string' ? format : '0.0';\n };\n\n numeral.validate = function(val, culture) {\n\n var _decimalSep,\n _thousandSep,\n _currSymbol,\n _valArray,\n _abbrObj,\n _thousandRegEx,\n languageData,\n temp;\n\n //coerce val to string\n if (typeof val !== 'string') {\n val += '';\n if (console.warn) {\n console.warn('Numeral.js: Value is not string. It has been co-erced to: ', val);\n }\n }\n\n //trim whitespaces from either sides\n val = val.trim();\n\n //if val is just digits return true\n if ( !! val.match(/^\\d+$/)) {\n return true;\n }\n\n //if val is empty return false\n if (val === '') {\n return false;\n }\n\n //get the decimal and thousands separator from numeral.languageData\n try {\n //check if the culture is understood by numeral. if not, default it to current language\n languageData = numeral.languageData(culture);\n } catch (e) {\n languageData = numeral.languageData(numeral.language());\n }\n\n //setup the delimiters and currency symbol based on culture/language\n _currSymbol = languageData.currency.symbol;\n _abbrObj = languageData.abbreviations;\n _decimalSep = languageData.delimiters.decimal;\n if (languageData.delimiters.thousands === '.') {\n _thousandSep = '\\\\.';\n } else {\n _thousandSep = languageData.delimiters.thousands;\n }\n\n // validating currency symbol\n temp = val.match(/^[^\\d]+/);\n if (temp !== null) {\n val = val.substr(1);\n if (temp[0] !== _currSymbol) {\n return false;\n }\n }\n\n //validating abbreviation symbol\n temp = val.match(/[^\\d]+$/);\n if (temp !== null) {\n val = val.slice(0, -1);\n if (temp[0] !== _abbrObj.thousand && temp[0] !== _abbrObj.million && temp[0] !== _abbrObj.billion && temp[0] !== _abbrObj.trillion) {\n return false;\n }\n }\n\n _thousandRegEx = new RegExp(_thousandSep + '{2}');\n\n if (!val.match(/[^\\d.,]/g)) {\n _valArray = val.split(_decimalSep);\n if (_valArray.length > 2) {\n return false;\n } else {\n if (_valArray.length < 2) {\n return ( !! _valArray[0].match(/^\\d+.*\\d$/) && !_valArray[0].match(_thousandRegEx));\n } else {\n if (_valArray[0].length === 1) {\n return ( !! _valArray[0].match(/^\\d+$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\\d+$/));\n } else {\n return ( !! _valArray[0].match(/^\\d+.*\\d$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\\d+$/));\n }\n }\n }\n }\n\n return false;\n };\n\n /************************************\n Helpers\n ************************************/\n\n function loadLanguage(key, values) {\n languages[key] = values;\n }\n\n /************************************\n Floating-point helpers\n ************************************/\n\n // The floating-point helper functions and implementation\n // borrows heavily from sinful.js: http://guipn.github.io/sinful.js/\n\n /**\n * Array.prototype.reduce for browsers that don't support it\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility\n */\n if ('function' !== typeof Array.prototype.reduce) {\n Array.prototype.reduce = function(callback, opt_initialValue) {\n 'use strict';\n\n if (null === this || 'undefined' === typeof this) {\n // At the moment all modern browsers, that support strict mode, have\n // native implementation of Array.prototype.reduce. For instance, IE8\n // does not support strict mode, so this check is actually useless.\n throw new TypeError('Array.prototype.reduce called on null or undefined');\n }\n\n if ('function' !== typeof callback) {\n throw new TypeError(callback + ' is not a function');\n }\n\n var index,\n value,\n length = this.length >>> 0,\n isValueSet = false;\n\n if (1 < arguments.length) {\n value = opt_initialValue;\n isValueSet = true;\n }\n\n for (index = 0; length > index; ++index) {\n if (this.hasOwnProperty(index)) {\n if (isValueSet) {\n value = callback(value, this[index], index, this);\n } else {\n value = this[index];\n isValueSet = true;\n }\n }\n }\n\n if (!isValueSet) {\n throw new TypeError('Reduce of empty array with no initial value');\n }\n\n return value;\n };\n }\n\n\n /**\n * Computes the multiplier necessary to make x >= 1,\n * effectively eliminating miscalculations caused by\n * finite precision.\n */\n function multiplier(x) {\n var parts = x.toString().split('.');\n if (parts.length < 2) {\n return 1;\n }\n return Math.pow(10, parts[1].length);\n }\n\n /**\n * Given a variable number of arguments, returns the maximum\n * multiplier that must be used to normalize an operation involving\n * all of them.\n */\n function correctionFactor() {\n var args = Array.prototype.slice.call(arguments);\n return args.reduce(function(prev, next) {\n var mp = multiplier(prev),\n mn = multiplier(next);\n return mp > mn ? mp : mn;\n }, -Infinity);\n }\n\n\n /************************************\n Numeral Prototype\n ************************************/\n\n\n numeral.fn = Numeral.prototype = {\n\n clone: function() {\n return numeral(this);\n },\n\n format: function(inputString, roundingFunction) {\n return formatNumeral(this,\n inputString ? inputString : defaultFormat, (roundingFunction !== undefined) ? roundingFunction : Math.round\n );\n },\n\n unformat: function(inputString) {\n if (Object.prototype.toString.call(inputString) === '[object Number]') {\n return inputString;\n }\n return unformatNumeral(this, inputString ? inputString : defaultFormat);\n },\n\n value: function() {\n return this._value;\n },\n\n valueOf: function() {\n return this._value;\n },\n\n set: function(value) {\n this._value = Number(value);\n return this;\n },\n\n add: function(value) {\n var corrFactor = correctionFactor.call(null, this._value, value);\n\n function cback(accum, curr, currI, O) {\n return accum + corrFactor * curr;\n }\n this._value = [this._value, value].reduce(cback, 0) / corrFactor;\n return this;\n },\n\n subtract: function(value) {\n var corrFactor = correctionFactor.call(null, this._value, value);\n\n function cback(accum, curr, currI, O) {\n return accum - corrFactor * curr;\n }\n this._value = [value].reduce(cback, this._value * corrFactor) / corrFactor;\n return this;\n },\n\n multiply: function(value) {\n function cback(accum, curr, currI, O) {\n var corrFactor = correctionFactor(accum, curr);\n return (accum * corrFactor) * (curr * corrFactor) /\n (corrFactor * corrFactor);\n }\n this._value = [this._value, value].reduce(cback, 1);\n return this;\n },\n\n divide: function(value) {\n function cback(accum, curr, currI, O) {\n var corrFactor = correctionFactor(accum, curr);\n return (accum * corrFactor) / (curr * corrFactor);\n }\n this._value = [this._value, value].reduce(cback);\n return this;\n },\n\n difference: function(value) {\n return Math.abs(numeral(this._value).subtract(value).value());\n }\n\n };\n\n /************************************\n Exposing Numeral\n ************************************/\n\n // CommonJS module is defined\n if (hasModule) {\n module.exports = numeral;\n }\n\n /*global ender:false */\n if (typeof ender === 'undefined') {\n // here, `this` means `window` in the browser, or `global` on the server\n // add `numeral` as a global object via a string identifier,\n // for Closure Compiler 'advanced' mode\n this['numeral'] = numeral;\n }\n\n /*global define:false */\n if (typeof define === 'function' && define.amd) {\n define([], function() {\n return numeral;\n });\n }\n}).call(this);\n","/*! \n * numeral.js language configuration\n * language : belgium-dutch (be-nl)\n * author : Dieter Luypaert : https://github.com/moeriki\n */\n!function(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\" mln\",billion:\" mld\",trillion:\" bln\"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?\"ste\":\"de\"},currency:{symbol:\"€ \"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"be-nl\",a)}(),/*! \n * numeral.js language configuration\n * language : simplified chinese\n * author : badplum : https://github.com/badplum\n */\nfunction(){var a={delimiters:{thousands:\",\",decimal:\".\"},abbreviations:{thousand:\"千\",million:\"百万\",billion:\"十亿\",trillion:\"兆\"},ordinal:function(){return\".\"},currency:{symbol:\"¥\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"chs\",a)}(),/*!\n * numeral.js language configuration\n * language : czech (cs)\n * author : Anatoli Papirovski : https://github.com/apapirovski\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"tis.\",million:\"mil.\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"Kč\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"cs\",a)}(),/*! \n * numeral.js language configuration\n * language : danish denmark (dk)\n * author : Michael Storgaard : https://github.com/mstorgaard\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"mio\",billion:\"mia\",trillion:\"b\"},ordinal:function(){return\".\"},currency:{symbol:\"DKK\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"da-dk\",a)}(),/*! \n * numeral.js language configuration\n * language : German in Switzerland (de-ch)\n * author : Michael Piefel : https://github.com/piefel (based on work from Marco Krage : https://github.com/sinky)\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"CHF\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"de-ch\",a)}(),/*! \n * numeral.js language configuration\n * language : German (de) – generally useful in Germany, Austria, Luxembourg, Belgium\n * author : Marco Krage : https://github.com/sinky\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"de\",a)}(),/*! \n * numeral.js language configuration\n * language : english united kingdom (uk)\n * author : Dan Ristic : https://github.com/dristic\n */\nfunction(){var a={delimiters:{thousands:\",\",decimal:\".\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?\"th\":1===b?\"st\":2===b?\"nd\":3===b?\"rd\":\"th\"},currency:{symbol:\"£\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"en-gb\",a)}(),/*! \n * numeral.js language configuration\n * language : spanish Spain\n * author : Hernan Garcia : https://github.com/hgarcia\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"mm\",billion:\"b\",trillion:\"t\"},ordinal:function(a){var b=a%10;return 1===b||3===b?\"er\":2===b?\"do\":7===b||0===b?\"mo\":8===b?\"vo\":9===b?\"no\":\"to\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"es\",a)}(),/*! \n * numeral.js language configuration\n * language : spanish\n * author : Hernan Garcia : https://github.com/hgarcia\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"mm\",billion:\"b\",trillion:\"t\"},ordinal:function(a){var b=a%10;return 1===b||3===b?\"er\":2===b?\"do\":7===b||0===b?\"mo\":8===b?\"vo\":9===b?\"no\":\"to\"},currency:{symbol:\"$\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"es\",a)}(),/*! \n * numeral.js language configuration\n * language : Estonian\n * author : Illimar Tambek : https://github.com/ragulka\n *\n * Note: in Estonian, abbreviations are always separated\n * from numbers with a space\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\" tuh\",million:\" mln\",billion:\" mld\",trillion:\" trl\"},ordinal:function(){return\".\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"et\",a)}(),/*! \n * numeral.js language configuration\n * language : Finnish\n * author : Sami Saada : https://github.com/samitheberber\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"M\",billion:\"G\",trillion:\"T\"},ordinal:function(){return\".\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"fi\",a)}(),/*!\n * numeral.js language configuration\n * language : french (Canada) (fr-CA)\n * author : Léo Renaud-Allaire : https://github.com/renaudleo\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"M\",billion:\"G\",trillion:\"T\"},ordinal:function(a){return 1===a?\"er\":\"e\"},currency:{symbol:\"$\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"fr-CA\",a)}(),/*! \n * numeral.js language configuration\n * language : french (fr-ch)\n * author : Adam Draper : https://github.com/adamwdraper\n */\nfunction(){var a={delimiters:{thousands:\"'\",decimal:\".\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(a){return 1===a?\"er\":\"e\"},currency:{symbol:\"CHF\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"fr-ch\",a)}(),/*! \n * numeral.js language configuration\n * language : french (fr)\n * author : Adam Draper : https://github.com/adamwdraper\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(a){return 1===a?\"er\":\"e\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"fr\",a)}(),/*!\n * numeral.js language configuration\n * language : Hungarian (hu)\n * author : Peter Bakondy : https://github.com/pbakondy\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"E\",million:\"M\",billion:\"Mrd\",trillion:\"T\"},ordinal:function(){return\".\"},currency:{symbol:\" Ft\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"hu\",a)}(),/*! \n * numeral.js language configuration\n * language : italian Italy (it)\n * author : Giacomo Trombi : http://cinquepunti.it\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"mila\",million:\"mil\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\"º\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"it\",a)}(),/*! \n * numeral.js language configuration\n * language : japanese\n * author : teppeis : https://github.com/teppeis\n */\nfunction(){var a={delimiters:{thousands:\",\",decimal:\".\"},abbreviations:{thousand:\"千\",million:\"百万\",billion:\"十億\",trillion:\"兆\"},ordinal:function(){return\".\"},currency:{symbol:\"¥\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"ja\",a)}(),/*!\n * numeral.js language configuration\n * language : Latvian (lv)\n * author : Lauris Bukšis-Haberkorns : https://github.com/Lafriks\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\" tūkst.\",million:\" milj.\",billion:\" mljrd.\",trillion:\" trilj.\"},ordinal:function(){return\".\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"lv\",a)}(),/*! \n * numeral.js language configuration\n * language : netherlands-dutch (nl-nl)\n * author : Dave Clayton : https://github.com/davedx\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"mln\",billion:\"mrd\",trillion:\"bln\"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?\"ste\":\"de\"},currency:{symbol:\"€ \"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"nl-nl\",a)}(),/*! \n * numeral.js language configuration\n * language : polish (pl)\n * author : Dominik Bulaj : https://github.com/dominikbulaj\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"tys.\",million:\"mln\",billion:\"mld\",trillion:\"bln\"},ordinal:function(){return\".\"},currency:{symbol:\"PLN\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"pl\",a)}(),/*! \n * numeral.js language configuration\n * language : portuguese brazil (pt-br)\n * author : Ramiro Varandas Jr : https://github.com/ramirovjr\n */\nfunction(){var a={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"mil\",million:\"milhões\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\"º\"},currency:{symbol:\"R$\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"pt-br\",a)}(),/*! \n * numeral.js language configuration\n * language : portuguese (pt-pt)\n * author : Diogo Resende : https://github.com/dresende\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"k\",million:\"m\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\"º\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"pt-pt\",a)}(),function(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"тыс.\",million:\"млн\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"₴\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"ru-UA\",a)}(),/*! \n * numeral.js language configuration\n * language : russian (ru)\n * author : Anatoli Papirovski : https://github.com/apapirovski\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"тыс.\",million:\"млн\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"руб.\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"ru\",a)}(),/*!\n * numeral.js language configuration\n * language : slovak (sk)\n * author : Ahmed Al Hafoudh : http://www.freevision.sk\n */\nfunction(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"tis.\",million:\"mil.\",billion:\"b\",trillion:\"t\"},ordinal:function(){return\".\"},currency:{symbol:\"€\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"sk\",a)}(),/*! \n * numeral.js language configuration\n * language : thai (th)\n * author : Sathit Jittanupat : https://github.com/jojosati\n */\nfunction(){var a={delimiters:{thousands:\",\",decimal:\".\"},abbreviations:{thousand:\"พัน\",million:\"ล้าน\",billion:\"พันล้าน\",trillion:\"ล้านล้าน\"},ordinal:function(){return\".\"},currency:{symbol:\"฿\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"th\",a)}(),/*! \n * numeral.js language configuration\n * language : turkish (tr)\n * author : Ecmel Ercan : https://github.com/ecmel, Erhan Gundogan : https://github.com/erhangundogan, Burak Yiğit Kaya: https://github.com/BYK\n */\nfunction(){var a={1:\"'inci\",5:\"'inci\",8:\"'inci\",70:\"'inci\",80:\"'inci\",2:\"'nci\",7:\"'nci\",20:\"'nci\",50:\"'nci\",3:\"'üncü\",4:\"'üncü\",100:\"'üncü\",6:\"'ncı\",9:\"'uncu\",10:\"'uncu\",30:\"'uncu\",60:\"'ıncı\",90:\"'ıncı\"},b={delimiters:{thousands:\".\",decimal:\",\"},abbreviations:{thousand:\"bin\",million:\"milyon\",billion:\"milyar\",trillion:\"trilyon\"},ordinal:function(b){if(0===b)return\"'ıncı\";var c=b%10,d=b%100-c,e=b>=100?100:null;return a[c]||a[d]||a[e]},currency:{symbol:\"₺\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=b),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"tr\",b)}(),function(){var a={delimiters:{thousands:\" \",decimal:\",\"},abbreviations:{thousand:\"тис.\",million:\"млн\",billion:\"млрд\",trillion:\"блн\"},ordinal:function(){return\"\"},currency:{symbol:\"₴\"}};\"undefined\"!=typeof module&&module.exports&&(module.exports=a),\"undefined\"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language(\"uk-UA\",a)}();","if ( Meteor.isClient ) {\n numeral = window.numeral;\n delete window.numeral;\n}\n\nif ( Meteor.isServer ) {\n numeral = Npm.require('numeral');\n}"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js b/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js deleted file mode 100644 index 68d9226..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js +++ /dev/null @@ -1,384 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; -var LocalCollection = Package.minimongo.LocalCollection; -var Minimongo = Package.minimongo.Minimongo; -var _ = Package.underscore._; -var Random = Package.random.Random; - -/* Package-scope variables */ -var ObserveSequence, seqChangedToEmpty, seqChangedToArray, seqChangedToCursor; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////// -// // -// packages/observe-sequence/observe_sequence.js // -// // -/////////////////////////////////////////////////////////////////////////////////// - // -var warn = function () { // 1 - if (ObserveSequence._suppressWarnings) { // 2 - ObserveSequence._suppressWarnings--; // 3 - } else { // 4 - if (typeof console !== 'undefined' && console.warn) // 5 - console.warn.apply(console, arguments); // 6 - // 7 - ObserveSequence._loggedWarnings++; // 8 - } // 9 -}; // 10 - // 11 -var idStringify = LocalCollection._idStringify; // 12 -var idParse = LocalCollection._idParse; // 13 - // 14 -ObserveSequence = { // 15 - _suppressWarnings: 0, // 16 - _loggedWarnings: 0, // 17 - // 18 - // A mechanism similar to cursor.observe which receives a reactive // 19 - // function returning a sequence type and firing appropriate callbacks // 20 - // when the value changes. // 21 - // // 22 - // @param sequenceFunc {Function} a reactive function returning a // 23 - // sequence type. The currently supported sequence types are: // 24 - // 'null', arrays and cursors. // 25 - // // 26 - // @param callbacks {Object} similar to a specific subset of // 27 - // callbacks passed to `cursor.observe` // 28 - // (http://docs.meteor.com/#observe), with minor variations to // 29 - // support the fact that not all sequences contain objects with // 30 - // _id fields. Specifically: // 31 - // // 32 - // * addedAt(id, item, atIndex, beforeId) // 33 - // * changedAt(id, newItem, oldItem, atIndex) // 34 - // * removedAt(id, oldItem, atIndex) // 35 - // * movedTo(id, item, fromIndex, toIndex, beforeId) // 36 - // // 37 - // @returns {Object(stop: Function)} call 'stop' on the return value // 38 - // to stop observing this sequence function. // 39 - // // 40 - // We don't make any assumptions about our ability to compare sequence // 41 - // elements (ie, we don't assume EJSON.equals works; maybe there is extra // 42 - // state/random methods on the objects) so unlike cursor.observe, we may // 43 - // sometimes call changedAt() when nothing actually changed. // 44 - // XXX consider if we *can* make the stronger assumption and avoid // 45 - // no-op changedAt calls (in some cases?) // 46 - // // 47 - // XXX currently only supports the callbacks used by our // 48 - // implementation of {{#each}}, but this can be expanded. // 49 - // // 50 - // XXX #each doesn't use the indices (though we'll eventually need // 51 - // a way to get them when we support `@index`), but calling // 52 - // `cursor.observe` causes the index to be calculated on every // 53 - // callback using a linear scan (unless you turn it off by passing // 54 - // `_no_indices`). Any way to avoid calculating indices on a pure // 55 - // cursor observe like we used to? // 56 - observe: function (sequenceFunc, callbacks) { // 57 - var lastSeq = null; // 58 - var activeObserveHandle = null; // 59 - // 60 - // 'lastSeqArray' contains the previous value of the sequence // 61 - // we're observing. It is an array of objects with '_id' and // 62 - // 'item' fields. 'item' is the element in the array, or the // 63 - // document in the cursor. // 64 - // // 65 - // '_id' is whichever of the following is relevant, unless it has // 66 - // already appeared -- in which case it's randomly generated. // 67 - // // 68 - // * if 'item' is an object: // 69 - // * an '_id' field, if present // 70 - // * otherwise, the index in the array // 71 - // // 72 - // * if 'item' is a number or string, use that value // 73 - // // 74 - // XXX this can be generalized by allowing {{#each}} to accept a // 75 - // general 'key' argument which could be a function, a dotted // 76 - // field name, or the special @index value. // 77 - var lastSeqArray = []; // elements are objects of form {_id, item} // 78 - var computation = Tracker.autorun(function () { // 79 - var seq = sequenceFunc(); // 80 - // 81 - Tracker.nonreactive(function () { // 82 - var seqArray; // same structure as `lastSeqArray` above. // 83 - // 84 - if (activeObserveHandle) { // 85 - // If we were previously observing a cursor, replace lastSeqArray with // 86 - // more up-to-date information. Then stop the old observe. // 87 - lastSeqArray = _.map(lastSeq.fetch(), function (doc) { // 88 - return {_id: doc._id, item: doc}; // 89 - }); // 90 - activeObserveHandle.stop(); // 91 - activeObserveHandle = null; // 92 - } // 93 - // 94 - if (!seq) { // 95 - seqArray = seqChangedToEmpty(lastSeqArray, callbacks); // 96 - } else if (seq instanceof Array) { // 97 - seqArray = seqChangedToArray(lastSeqArray, seq, callbacks); // 98 - } else if (isStoreCursor(seq)) { // 99 - var result /* [seqArray, activeObserveHandle] */ = // 100 - seqChangedToCursor(lastSeqArray, seq, callbacks); // 101 - seqArray = result[0]; // 102 - activeObserveHandle = result[1]; // 103 - } else { // 104 - throw badSequenceError(); // 105 - } // 106 - // 107 - diffArray(lastSeqArray, seqArray, callbacks); // 108 - lastSeq = seq; // 109 - lastSeqArray = seqArray; // 110 - }); // 111 - }); // 112 - // 113 - return { // 114 - stop: function () { // 115 - computation.stop(); // 116 - if (activeObserveHandle) // 117 - activeObserveHandle.stop(); // 118 - } // 119 - }; // 120 - }, // 121 - // 122 - // Fetch the items of `seq` into an array, where `seq` is of one of the // 123 - // sequence types accepted by `observe`. If `seq` is a cursor, a // 124 - // dependency is established. // 125 - fetch: function (seq) { // 126 - if (!seq) { // 127 - return []; // 128 - } else if (seq instanceof Array) { // 129 - return seq; // 130 - } else if (isStoreCursor(seq)) { // 131 - return seq.fetch(); // 132 - } else { // 133 - throw badSequenceError(); // 134 - } // 135 - } // 136 -}; // 137 - // 138 -var badSequenceError = function () { // 139 - return new Error("{{#each}} currently only accepts " + // 140 - "arrays, cursors or falsey values."); // 141 -}; // 142 - // 143 -var isStoreCursor = function (cursor) { // 144 - return cursor && _.isObject(cursor) && // 145 - _.isFunction(cursor.observe) && _.isFunction(cursor.fetch); // 146 -}; // 147 - // 148 -// Calculates the differences between `lastSeqArray` and // 149 -// `seqArray` and calls appropriate functions from `callbacks`. // 150 -// Reuses Minimongo's diff algorithm implementation. // 151 -var diffArray = function (lastSeqArray, seqArray, callbacks) { // 152 - var diffFn = Package.minimongo.LocalCollection._diffQueryOrderedChanges; // 153 - var oldIdObjects = []; // 154 - var newIdObjects = []; // 155 - var posOld = {}; // maps from idStringify'd ids // 156 - var posNew = {}; // ditto // 157 - var posCur = {}; // 158 - var lengthCur = lastSeqArray.length; // 159 - // 160 - _.each(seqArray, function (doc, i) { // 161 - newIdObjects.push({_id: doc._id}); // 162 - posNew[idStringify(doc._id)] = i; // 163 - }); // 164 - _.each(lastSeqArray, function (doc, i) { // 165 - oldIdObjects.push({_id: doc._id}); // 166 - posOld[idStringify(doc._id)] = i; // 167 - posCur[idStringify(doc._id)] = i; // 168 - }); // 169 - // 170 - // Arrays can contain arbitrary objects. We don't diff the // 171 - // objects. Instead we always fire 'changedAt' callback on every // 172 - // object. The consumer of `observe-sequence` should deal with // 173 - // it appropriately. // 174 - diffFn(oldIdObjects, newIdObjects, { // 175 - addedBefore: function (id, doc, before) { // 176 - var position = before ? posCur[idStringify(before)] : lengthCur; // 177 - // 178 - if (before) { // 179 - // If not adding at the end, we need to update indexes. // 180 - // XXX this can still be improved greatly! // 181 - _.each(posCur, function (pos, id) { // 182 - if (pos >= position) // 183 - posCur[id]++; // 184 - }); // 185 - } // 186 - // 187 - lengthCur++; // 188 - posCur[idStringify(id)] = position; // 189 - // 190 - callbacks.addedAt( // 191 - id, // 192 - seqArray[posNew[idStringify(id)]].item, // 193 - position, // 194 - before); // 195 - }, // 196 - movedBefore: function (id, before) { // 197 - if (id === before) // 198 - return; // 199 - // 200 - var oldPosition = posCur[idStringify(id)]; // 201 - var newPosition = before ? posCur[idStringify(before)] : lengthCur; // 202 - // 203 - // Moving the item forward. The new element is losing one position as it // 204 - // was removed from the old position before being inserted at the new // 205 - // position. // 206 - // Ex.: 0 *1* 2 3 4 // 207 - // 0 2 3 *1* 4 // 208 - // The original issued callback is "1" before "4". // 209 - // The position of "1" is 1, the position of "4" is 4. // 210 - // The generated move is (1) -> (3) // 211 - if (newPosition > oldPosition) { // 212 - newPosition--; // 213 - } // 214 - // 215 - // Fix up the positions of elements between the old and the new positions // 216 - // of the moved element. // 217 - // // 218 - // There are two cases: // 219 - // 1. The element is moved forward. Then all the positions in between // 220 - // are moved back. // 221 - // 2. The element is moved back. Then the positions in between *and* the // 222 - // element that is currently standing on the moved element's future // 223 - // position are moved forward. // 224 - _.each(posCur, function (elCurPosition, id) { // 225 - if (oldPosition < elCurPosition && elCurPosition < newPosition) // 226 - posCur[id]--; // 227 - else if (newPosition <= elCurPosition && elCurPosition < oldPosition) // 228 - posCur[id]++; // 229 - }); // 230 - // 231 - // Finally, update the position of the moved element. // 232 - posCur[idStringify(id)] = newPosition; // 233 - // 234 - callbacks.movedTo( // 235 - id, // 236 - seqArray[posNew[idStringify(id)]].item, // 237 - oldPosition, // 238 - newPosition, // 239 - before); // 240 - }, // 241 - removed: function (id) { // 242 - var prevPosition = posCur[idStringify(id)]; // 243 - // 244 - _.each(posCur, function (pos, id) { // 245 - if (pos >= prevPosition) // 246 - posCur[id]--; // 247 - }); // 248 - // 249 - delete posCur[idStringify(id)]; // 250 - lengthCur--; // 251 - // 252 - callbacks.removedAt( // 253 - id, // 254 - lastSeqArray[posOld[idStringify(id)]].item, // 255 - prevPosition); // 256 - } // 257 - }); // 258 - // 259 - _.each(posNew, function (pos, idString) { // 260 - var id = idParse(idString); // 261 - if (_.has(posOld, idString)) { // 262 - // specifically for primitive types, compare equality before // 263 - // firing the 'changedAt' callback. otherwise, always fire it // 264 - // because doing a deep EJSON comparison is not guaranteed to // 265 - // work (an array can contain arbitrary objects, and 'transform' // 266 - // can be used on cursors). also, deep diffing is not // 267 - // necessarily the most efficient (if only a specific subfield // 268 - // of the object is later accessed). // 269 - var newItem = seqArray[pos].item; // 270 - var oldItem = lastSeqArray[posOld[idString]].item; // 271 - // 272 - if (typeof newItem === 'object' || newItem !== oldItem) // 273 - callbacks.changedAt(id, newItem, oldItem, pos); // 274 - } // 275 - }); // 276 -}; // 277 - // 278 -seqChangedToEmpty = function (lastSeqArray, callbacks) { // 279 - return []; // 280 -}; // 281 - // 282 -seqChangedToArray = function (lastSeqArray, array, callbacks) { // 283 - var idsUsed = {}; // 284 - var seqArray = _.map(array, function (item, index) { // 285 - var id; // 286 - if (typeof item === 'string') { // 287 - // ensure not empty, since other layers (eg DomRange) assume this as well // 288 - id = "-" + item; // 289 - } else if (typeof item === 'number' || // 290 - typeof item === 'boolean' || // 291 - item === undefined) { // 292 - id = item; // 293 - } else if (typeof item === 'object') { // 294 - id = (item && item._id) || index; // 295 - } else { // 296 - throw new Error("{{#each}} doesn't support arrays with " + // 297 - "elements of type " + typeof item); // 298 - } // 299 - // 300 - var idString = idStringify(id); // 301 - if (idsUsed[idString]) { // 302 - if (typeof item === 'object' && '_id' in item) // 303 - warn("duplicate id " + id + " in", array); // 304 - id = Random.id(); // 305 - } else { // 306 - idsUsed[idString] = true; // 307 - } // 308 - // 309 - return { _id: id, item: item }; // 310 - }); // 311 - // 312 - return seqArray; // 313 -}; // 314 - // 315 -seqChangedToCursor = function (lastSeqArray, cursor, callbacks) { // 316 - var initial = true; // are we observing initial data from cursor? // 317 - var seqArray = []; // 318 - // 319 - var observeHandle = cursor.observe({ // 320 - addedAt: function (document, atIndex, before) { // 321 - if (initial) { // 322 - // keep track of initial data so that we can diff once // 323 - // we exit `observe`. // 324 - if (before !== null) // 325 - throw new Error("Expected initial data from observe in order"); // 326 - seqArray.push({ _id: document._id, item: document }); // 327 - } else { // 328 - callbacks.addedAt(document._id, document, atIndex, before); // 329 - } // 330 - }, // 331 - changedAt: function (newDocument, oldDocument, atIndex) { // 332 - callbacks.changedAt(newDocument._id, newDocument, oldDocument, // 333 - atIndex); // 334 - }, // 335 - removedAt: function (oldDocument, atIndex) { // 336 - callbacks.removedAt(oldDocument._id, oldDocument, atIndex); // 337 - }, // 338 - movedTo: function (document, fromIndex, toIndex, before) { // 339 - callbacks.movedTo( // 340 - document._id, document, fromIndex, toIndex, before); // 341 - } // 342 - }); // 343 - initial = false; // 344 - // 345 - return [seqArray, observeHandle]; // 346 -}; // 347 - // 348 -/////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['observe-sequence'] = { - ObserveSequence: ObserveSequence -}; - -})(); - -//# sourceMappingURL=observe-sequence.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js.map b/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js.map deleted file mode 100644 index 49a87b3..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/observe-sequence.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["observe-sequence/observe_sequence.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,wB;AACA,0C;AACA,wC;AACA,U;AACA,uD;AACA,6C;;AAEA,sC;AACA,G;AACA,E;;AAEA,+C;AACA,uC;;AAEA,mB;AACA,uB;AACA,qB;;AAEA,oE;AACA,wE;AACA,4B;AACA,I;AACA,mE;AACA,mE;AACA,oC;AACA,I;AACA,8D;AACA,6C;AACA,oE;AACA,qE;AACA,mC;AACA,I;AACA,+C;AACA,mD;AACA,0C;AACA,0D;AACA,I;AACA,sE;AACA,kD;AACA,I;AACA,wE;AACA,2E;AACA,0E;AACA,8D;AACA,oE;AACA,+C;AACA,I;AACA,0D;AACA,2D;AACA,I;AACA,oE;AACA,6D;AACA,gE;AACA,oE;AACA,oE;AACA,oC;AACA,+C;AACA,uB;AACA,mC;;AAEA,iE;AACA,gE;AACA,iE;AACA,8B;AACA,M;AACA,qE;AACA,iE;AACA,M;AACA,gC;AACA,qC;AACA,4C;AACA,M;AACA,wD;AACA,M;AACA,oE;AACA,iE;AACA,+C;AACA,sE;AACA,mD;AACA,+B;;AAEA,uC;AACA,gE;;AAEA,kC;AACA,gF;AACA,qE;AACA,gE;AACA,6C;AACA,a;AACA,qC;AACA,qC;AACA,S;;AAEA,mB;AACA,gE;AACA,0C;AACA,qE;AACA,wC;AACA,4D;AACA,iE;AACA,+B;AACA,0C;AACA,gB;AACA,mC;AACA,S;;AAEA,qD;AACA,sB;AACA,gC;AACA,S;AACA,O;;AAEA,Y;AACA,yB;AACA,2B;AACA,gC;AACA,qC;AACA,O;AACA,M;AACA,I;;AAEA,yE;AACA,mE;AACA,+B;AACA,yB;AACA,e;AACA,gB;AACA,sC;AACA,iB;AACA,oC;AACA,yB;AACA,Y;AACA,+B;AACA,K;AACA,G;AACA,E;;AAEA,oC;AACA,wD;AACA,wD;AACA,E;;AAEA,uC;AACA,wC;AACA,+D;AACA,E;;AAEA,wD;AACA,+D;AACA,oD;AACA,8D;AACA,0E;AACA,wB;AACA,wB;AACA,iD;AACA,2B;AACA,kB;AACA,sC;;AAEA,sC;AACA,sC;AACA,qC;AACA,K;AACA,0C;AACA,sC;AACA,qC;AACA,qC;AACA,K;;AAEA,4D;AACA,kE;AACA,gE;AACA,sB;AACA,sC;AACA,6C;AACA,sE;;AAEA,mB;AACA,+D;AACA,kD;AACA,2C;AACA,8B;AACA,yB;AACA,W;AACA,O;;AAEA,kB;AACA,yC;;AAEA,wB;AACA,W;AACA,+C;AACA,iB;AACA,gB;AACA,M;AACA,wC;AACA,wB;AACA,e;;AAEA,gD;AACA,yE;;AAEA,8E;AACA,2E;AACA,kB;AACA,iC;AACA,iC;AACA,wD;AACA,4D;AACA,yC;AACA,sC;AACA,sB;AACA,O;;AAEA,+E;AACA,8B;AACA,Q;AACA,6B;AACA,6E;AACA,0B;AACA,gF;AACA,2E;AACA,sC;AACA,mD;AACA,uE;AACA,uB;AACA,6E;AACA,uB;AACA,S;;AAEA,2D;AACA,4C;;AAEA,wB;AACA,W;AACA,+C;AACA,oB;AACA,oB;AACA,gB;AACA,M;AACA,4B;AACA,iD;;AAEA,yC;AACA,gC;AACA,uB;AACA,S;;AAEA,qC;AACA,kB;;AAEA,0B;AACA,W;AACA,mD;AACA,sB;AACA,K;AACA,K;;AAEA,2C;AACA,+B;AACA,kC;AACA,kE;AACA,mE;AACA,mE;AACA,sE;AACA,2D;AACA,oE;AACA,0C;AACA,uC;AACA,wD;;AAEA,6D;AACA,yD;AACA,O;AACA,K;AACA,E;;AAEA,wD;AACA,Y;AACA,E;;AAEA,+D;AACA,mB;AACA,sD;AACA,W;AACA,mC;AACA,+E;AACA,sB;AACA,0C;AACA,2C;AACA,oC;AACA,gB;AACA,0C;AACA,uC;AACA,Y;AACA,gE;AACA,yD;AACA,K;;AAEA,mC;AACA,4B;AACA,oD;AACA,kD;AACA,uB;AACA,Y;AACA,+B;AACA,K;;AAEA,mC;AACA,K;;AAEA,kB;AACA,E;;AAEA,iE;AACA,mE;AACA,oB;;AAEA,sC;AACA,mD;AACA,oB;AACA,8D;AACA,6B;AACA,4B;AACA,yE;AACA,6D;AACA,c;AACA,mE;AACA,O;AACA,M;AACA,6D;AACA,oE;AACA,mC;AACA,M;AACA,gD;AACA,iE;AACA,M;AACA,8D;AACA,wB;AACA,4D;AACA,K;AACA,K;AACA,kB;;AAEA,mC;AACA,E","file":"/packages/observe-sequence.js","sourcesContent":["var warn = function () {\n if (ObserveSequence._suppressWarnings) {\n ObserveSequence._suppressWarnings--;\n } else {\n if (typeof console !== 'undefined' && console.warn)\n console.warn.apply(console, arguments);\n\n ObserveSequence._loggedWarnings++;\n }\n};\n\nvar idStringify = LocalCollection._idStringify;\nvar idParse = LocalCollection._idParse;\n\nObserveSequence = {\n _suppressWarnings: 0,\n _loggedWarnings: 0,\n\n // A mechanism similar to cursor.observe which receives a reactive\n // function returning a sequence type and firing appropriate callbacks\n // when the value changes.\n //\n // @param sequenceFunc {Function} a reactive function returning a\n // sequence type. The currently supported sequence types are:\n // 'null', arrays and cursors.\n //\n // @param callbacks {Object} similar to a specific subset of\n // callbacks passed to `cursor.observe`\n // (http://docs.meteor.com/#observe), with minor variations to\n // support the fact that not all sequences contain objects with\n // _id fields. Specifically:\n //\n // * addedAt(id, item, atIndex, beforeId)\n // * changedAt(id, newItem, oldItem, atIndex)\n // * removedAt(id, oldItem, atIndex)\n // * movedTo(id, item, fromIndex, toIndex, beforeId)\n //\n // @returns {Object(stop: Function)} call 'stop' on the return value\n // to stop observing this sequence function.\n //\n // We don't make any assumptions about our ability to compare sequence\n // elements (ie, we don't assume EJSON.equals works; maybe there is extra\n // state/random methods on the objects) so unlike cursor.observe, we may\n // sometimes call changedAt() when nothing actually changed.\n // XXX consider if we *can* make the stronger assumption and avoid\n // no-op changedAt calls (in some cases?)\n //\n // XXX currently only supports the callbacks used by our\n // implementation of {{#each}}, but this can be expanded.\n //\n // XXX #each doesn't use the indices (though we'll eventually need\n // a way to get them when we support `@index`), but calling\n // `cursor.observe` causes the index to be calculated on every\n // callback using a linear scan (unless you turn it off by passing\n // `_no_indices`). Any way to avoid calculating indices on a pure\n // cursor observe like we used to?\n observe: function (sequenceFunc, callbacks) {\n var lastSeq = null;\n var activeObserveHandle = null;\n\n // 'lastSeqArray' contains the previous value of the sequence\n // we're observing. It is an array of objects with '_id' and\n // 'item' fields. 'item' is the element in the array, or the\n // document in the cursor.\n //\n // '_id' is whichever of the following is relevant, unless it has\n // already appeared -- in which case it's randomly generated.\n //\n // * if 'item' is an object:\n // * an '_id' field, if present\n // * otherwise, the index in the array\n //\n // * if 'item' is a number or string, use that value\n //\n // XXX this can be generalized by allowing {{#each}} to accept a\n // general 'key' argument which could be a function, a dotted\n // field name, or the special @index value.\n var lastSeqArray = []; // elements are objects of form {_id, item}\n var computation = Tracker.autorun(function () {\n var seq = sequenceFunc();\n\n Tracker.nonreactive(function () {\n var seqArray; // same structure as `lastSeqArray` above.\n\n if (activeObserveHandle) {\n // If we were previously observing a cursor, replace lastSeqArray with\n // more up-to-date information. Then stop the old observe.\n lastSeqArray = _.map(lastSeq.fetch(), function (doc) {\n return {_id: doc._id, item: doc};\n });\n activeObserveHandle.stop();\n activeObserveHandle = null;\n }\n\n if (!seq) {\n seqArray = seqChangedToEmpty(lastSeqArray, callbacks);\n } else if (seq instanceof Array) {\n seqArray = seqChangedToArray(lastSeqArray, seq, callbacks);\n } else if (isStoreCursor(seq)) {\n var result /* [seqArray, activeObserveHandle] */ =\n seqChangedToCursor(lastSeqArray, seq, callbacks);\n seqArray = result[0];\n activeObserveHandle = result[1];\n } else {\n throw badSequenceError();\n }\n\n diffArray(lastSeqArray, seqArray, callbacks);\n lastSeq = seq;\n lastSeqArray = seqArray;\n });\n });\n\n return {\n stop: function () {\n computation.stop();\n if (activeObserveHandle)\n activeObserveHandle.stop();\n }\n };\n },\n\n // Fetch the items of `seq` into an array, where `seq` is of one of the\n // sequence types accepted by `observe`. If `seq` is a cursor, a\n // dependency is established.\n fetch: function (seq) {\n if (!seq) {\n return [];\n } else if (seq instanceof Array) {\n return seq;\n } else if (isStoreCursor(seq)) {\n return seq.fetch();\n } else {\n throw badSequenceError();\n }\n }\n};\n\nvar badSequenceError = function () {\n return new Error(\"{{#each}} currently only accepts \" +\n \"arrays, cursors or falsey values.\");\n};\n\nvar isStoreCursor = function (cursor) {\n return cursor && _.isObject(cursor) &&\n _.isFunction(cursor.observe) && _.isFunction(cursor.fetch);\n};\n\n// Calculates the differences between `lastSeqArray` and\n// `seqArray` and calls appropriate functions from `callbacks`.\n// Reuses Minimongo's diff algorithm implementation.\nvar diffArray = function (lastSeqArray, seqArray, callbacks) {\n var diffFn = Package.minimongo.LocalCollection._diffQueryOrderedChanges;\n var oldIdObjects = [];\n var newIdObjects = [];\n var posOld = {}; // maps from idStringify'd ids\n var posNew = {}; // ditto\n var posCur = {};\n var lengthCur = lastSeqArray.length;\n\n _.each(seqArray, function (doc, i) {\n newIdObjects.push({_id: doc._id});\n posNew[idStringify(doc._id)] = i;\n });\n _.each(lastSeqArray, function (doc, i) {\n oldIdObjects.push({_id: doc._id});\n posOld[idStringify(doc._id)] = i;\n posCur[idStringify(doc._id)] = i;\n });\n\n // Arrays can contain arbitrary objects. We don't diff the\n // objects. Instead we always fire 'changedAt' callback on every\n // object. The consumer of `observe-sequence` should deal with\n // it appropriately.\n diffFn(oldIdObjects, newIdObjects, {\n addedBefore: function (id, doc, before) {\n var position = before ? posCur[idStringify(before)] : lengthCur;\n\n if (before) {\n // If not adding at the end, we need to update indexes.\n // XXX this can still be improved greatly!\n _.each(posCur, function (pos, id) {\n if (pos >= position)\n posCur[id]++;\n });\n }\n\n lengthCur++;\n posCur[idStringify(id)] = position;\n\n callbacks.addedAt(\n id,\n seqArray[posNew[idStringify(id)]].item,\n position,\n before);\n },\n movedBefore: function (id, before) {\n if (id === before)\n return;\n\n var oldPosition = posCur[idStringify(id)];\n var newPosition = before ? posCur[idStringify(before)] : lengthCur;\n\n // Moving the item forward. The new element is losing one position as it\n // was removed from the old position before being inserted at the new\n // position.\n // Ex.: 0 *1* 2 3 4\n // 0 2 3 *1* 4\n // The original issued callback is \"1\" before \"4\".\n // The position of \"1\" is 1, the position of \"4\" is 4.\n // The generated move is (1) -> (3)\n if (newPosition > oldPosition) {\n newPosition--;\n }\n\n // Fix up the positions of elements between the old and the new positions\n // of the moved element.\n //\n // There are two cases:\n // 1. The element is moved forward. Then all the positions in between\n // are moved back.\n // 2. The element is moved back. Then the positions in between *and* the\n // element that is currently standing on the moved element's future\n // position are moved forward.\n _.each(posCur, function (elCurPosition, id) {\n if (oldPosition < elCurPosition && elCurPosition < newPosition)\n posCur[id]--;\n else if (newPosition <= elCurPosition && elCurPosition < oldPosition)\n posCur[id]++;\n });\n\n // Finally, update the position of the moved element.\n posCur[idStringify(id)] = newPosition;\n\n callbacks.movedTo(\n id,\n seqArray[posNew[idStringify(id)]].item,\n oldPosition,\n newPosition,\n before);\n },\n removed: function (id) {\n var prevPosition = posCur[idStringify(id)];\n\n _.each(posCur, function (pos, id) {\n if (pos >= prevPosition)\n posCur[id]--;\n });\n\n delete posCur[idStringify(id)];\n lengthCur--;\n\n callbacks.removedAt(\n id,\n lastSeqArray[posOld[idStringify(id)]].item,\n prevPosition);\n }\n });\n\n _.each(posNew, function (pos, idString) {\n var id = idParse(idString);\n if (_.has(posOld, idString)) {\n // specifically for primitive types, compare equality before\n // firing the 'changedAt' callback. otherwise, always fire it\n // because doing a deep EJSON comparison is not guaranteed to\n // work (an array can contain arbitrary objects, and 'transform'\n // can be used on cursors). also, deep diffing is not\n // necessarily the most efficient (if only a specific subfield\n // of the object is later accessed).\n var newItem = seqArray[pos].item;\n var oldItem = lastSeqArray[posOld[idString]].item;\n\n if (typeof newItem === 'object' || newItem !== oldItem)\n callbacks.changedAt(id, newItem, oldItem, pos);\n }\n });\n};\n\nseqChangedToEmpty = function (lastSeqArray, callbacks) {\n return [];\n};\n\nseqChangedToArray = function (lastSeqArray, array, callbacks) {\n var idsUsed = {};\n var seqArray = _.map(array, function (item, index) {\n var id;\n if (typeof item === 'string') {\n // ensure not empty, since other layers (eg DomRange) assume this as well\n id = \"-\" + item;\n } else if (typeof item === 'number' ||\n typeof item === 'boolean' ||\n item === undefined) {\n id = item;\n } else if (typeof item === 'object') {\n id = (item && item._id) || index;\n } else {\n throw new Error(\"{{#each}} doesn't support arrays with \" +\n \"elements of type \" + typeof item);\n }\n\n var idString = idStringify(id);\n if (idsUsed[idString]) {\n if (typeof item === 'object' && '_id' in item)\n warn(\"duplicate id \" + id + \" in\", array);\n id = Random.id();\n } else {\n idsUsed[idString] = true;\n }\n\n return { _id: id, item: item };\n });\n\n return seqArray;\n};\n\nseqChangedToCursor = function (lastSeqArray, cursor, callbacks) {\n var initial = true; // are we observing initial data from cursor?\n var seqArray = [];\n\n var observeHandle = cursor.observe({\n addedAt: function (document, atIndex, before) {\n if (initial) {\n // keep track of initial data so that we can diff once\n // we exit `observe`.\n if (before !== null)\n throw new Error(\"Expected initial data from observe in order\");\n seqArray.push({ _id: document._id, item: document });\n } else {\n callbacks.addedAt(document._id, document, atIndex, before);\n }\n },\n changedAt: function (newDocument, oldDocument, atIndex) {\n callbacks.changedAt(newDocument._id, newDocument, oldDocument,\n atIndex);\n },\n removedAt: function (oldDocument, atIndex) {\n callbacks.removedAt(oldDocument._id, oldDocument, atIndex);\n },\n movedTo: function (document, fromIndex, toIndex, before) {\n callbacks.movedTo(\n document._id, document, fromIndex, toIndex, before);\n }\n });\n initial = false;\n\n return [seqArray, observeHandle];\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js b/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js deleted file mode 100644 index 11b67e9..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js +++ /dev/null @@ -1,241 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; - -/* Package-scope variables */ -var OrderedDict; - -(function () { - -/////////////////////////////////////////////////////////////////////////////////// -// // -// packages/ordered-dict/ordered_dict.js // -// // -/////////////////////////////////////////////////////////////////////////////////// - // -// This file defines an ordered dictionary abstraction that is useful for // 1 -// maintaining a dataset backed by observeChanges. It supports ordering items // 2 -// by specifying the item they now come before. // 3 - // 4 -// The implementation is a dictionary that contains nodes of a doubly-linked // 5 -// list as its values. // 6 - // 7 -// constructs a new element struct // 8 -// next and prev are whole elements, not keys. // 9 -var element = function (key, value, next, prev) { // 10 - return { // 11 - key: key, // 12 - value: value, // 13 - next: next, // 14 - prev: prev // 15 - }; // 16 -}; // 17 -OrderedDict = function (/* ... */) { // 18 - var self = this; // 19 - self._dict = {}; // 20 - self._first = null; // 21 - self._last = null; // 22 - self._size = 0; // 23 - var args = _.toArray(arguments); // 24 - self._stringify = function (x) { return x; }; // 25 - if (typeof args[0] === 'function') // 26 - self._stringify = args.shift(); // 27 - _.each(args, function (kv) { // 28 - self.putBefore(kv[0], kv[1], null); // 29 - }); // 30 -}; // 31 - // 32 -_.extend(OrderedDict.prototype, { // 33 - // the "prefix keys with a space" thing comes from here // 34 - // https://github.com/documentcloud/underscore/issues/376#issuecomment-2815649 // 35 - _k: function (key) { return " " + this._stringify(key); }, // 36 - // 37 - empty: function () { // 38 - var self = this; // 39 - return !self._first; // 40 - }, // 41 - size: function () { // 42 - var self = this; // 43 - return self._size; // 44 - }, // 45 - _linkEltIn: function (elt) { // 46 - var self = this; // 47 - if (!elt.next) { // 48 - elt.prev = self._last; // 49 - if (self._last) // 50 - self._last.next = elt; // 51 - self._last = elt; // 52 - } else { // 53 - elt.prev = elt.next.prev; // 54 - elt.next.prev = elt; // 55 - if (elt.prev) // 56 - elt.prev.next = elt; // 57 - } // 58 - if (self._first === null || self._first === elt.next) // 59 - self._first = elt; // 60 - }, // 61 - _linkEltOut: function (elt) { // 62 - var self = this; // 63 - if (elt.next) // 64 - elt.next.prev = elt.prev; // 65 - if (elt.prev) // 66 - elt.prev.next = elt.next; // 67 - if (elt === self._last) // 68 - self._last = elt.prev; // 69 - if (elt === self._first) // 70 - self._first = elt.next; // 71 - }, // 72 - putBefore: function (key, item, before) { // 73 - var self = this; // 74 - if (self._dict[self._k(key)]) // 75 - throw new Error("Item " + key + " already present in OrderedDict"); // 76 - var elt = before ? // 77 - element(key, item, self._dict[self._k(before)]) : // 78 - element(key, item, null); // 79 - if (elt.next === undefined) // 80 - throw new Error("could not find item to put this one before"); // 81 - self._linkEltIn(elt); // 82 - self._dict[self._k(key)] = elt; // 83 - self._size++; // 84 - }, // 85 - append: function (key, item) { // 86 - var self = this; // 87 - self.putBefore(key, item, null); // 88 - }, // 89 - remove: function (key) { // 90 - var self = this; // 91 - var elt = self._dict[self._k(key)]; // 92 - if (elt === undefined) // 93 - throw new Error("Item " + key + " not present in OrderedDict"); // 94 - self._linkEltOut(elt); // 95 - self._size--; // 96 - delete self._dict[self._k(key)]; // 97 - return elt.value; // 98 - }, // 99 - get: function (key) { // 100 - var self = this; // 101 - if (self.has(key)) // 102 - return self._dict[self._k(key)].value; // 103 - return undefined; // 104 - }, // 105 - has: function (key) { // 106 - var self = this; // 107 - return _.has(self._dict, self._k(key)); // 108 - }, // 109 - // Iterate through the items in this dictionary in order, calling // 110 - // iter(value, key, index) on each one. // 111 - // 112 - // Stops whenever iter returns OrderedDict.BREAK, or after the last element. // 113 - forEach: function (iter) { // 114 - var self = this; // 115 - var i = 0; // 116 - var elt = self._first; // 117 - while (elt !== null) { // 118 - var b = iter(elt.value, elt.key, i); // 119 - if (b === OrderedDict.BREAK) // 120 - return; // 121 - elt = elt.next; // 122 - i++; // 123 - } // 124 - }, // 125 - first: function () { // 126 - var self = this; // 127 - if (self.empty()) // 128 - return undefined; // 129 - return self._first.key; // 130 - }, // 131 - firstValue: function () { // 132 - var self = this; // 133 - if (self.empty()) // 134 - return undefined; // 135 - return self._first.value; // 136 - }, // 137 - last: function () { // 138 - var self = this; // 139 - if (self.empty()) // 140 - return undefined; // 141 - return self._last.key; // 142 - }, // 143 - lastValue: function () { // 144 - var self = this; // 145 - if (self.empty()) // 146 - return undefined; // 147 - return self._last.value; // 148 - }, // 149 - prev: function (key) { // 150 - var self = this; // 151 - if (self.has(key)) { // 152 - var elt = self._dict[self._k(key)]; // 153 - if (elt.prev) // 154 - return elt.prev.key; // 155 - } // 156 - return null; // 157 - }, // 158 - next: function (key) { // 159 - var self = this; // 160 - if (self.has(key)) { // 161 - var elt = self._dict[self._k(key)]; // 162 - if (elt.next) // 163 - return elt.next.key; // 164 - } // 165 - return null; // 166 - }, // 167 - moveBefore: function (key, before) { // 168 - var self = this; // 169 - var elt = self._dict[self._k(key)]; // 170 - var eltBefore = before ? self._dict[self._k(before)] : null; // 171 - if (elt === undefined) // 172 - throw new Error("Item to move is not present"); // 173 - if (eltBefore === undefined) { // 174 - throw new Error("Could not find element to move this one before"); // 175 - } // 176 - if (eltBefore === elt.next) // no moving necessary // 177 - return; // 178 - // remove from its old place // 179 - self._linkEltOut(elt); // 180 - // patch into its new place // 181 - elt.next = eltBefore; // 182 - self._linkEltIn(elt); // 183 - }, // 184 - // Linear, sadly. // 185 - indexOf: function (key) { // 186 - var self = this; // 187 - var ret = null; // 188 - self.forEach(function (v, k, i) { // 189 - if (self._k(k) === self._k(key)) { // 190 - ret = i; // 191 - return OrderedDict.BREAK; // 192 - } // 193 - return undefined; // 194 - }); // 195 - return ret; // 196 - }, // 197 - _checkRep: function () { // 198 - var self = this; // 199 - _.each(self._dict, function (k, v) { // 200 - if (v.next === v) // 201 - throw new Error("Next is a loop"); // 202 - if (v.prev === v) // 203 - throw new Error("Prev is a loop"); // 204 - }); // 205 - } // 206 - // 207 -}); // 208 -OrderedDict.BREAK = {"break": true}; // 209 - // 210 -/////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['ordered-dict'] = { - OrderedDict: OrderedDict -}; - -})(); - -//# sourceMappingURL=ordered-dict.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js.map b/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js.map deleted file mode 100644 index 4fe2638..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/ordered-dict.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["ordered-dict/ordered_dict.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yE;AACA,8E;AACA,+C;;AAEA,4E;AACA,sB;;AAEA,kC;AACA,8C;AACA,iD;AACA,U;AACA,a;AACA,iB;AACA,e;AACA,c;AACA,I;AACA,E;AACA,oC;AACA,kB;AACA,kB;AACA,qB;AACA,oB;AACA,iB;AACA,kC;AACA,+C;AACA,oC;AACA,mC;AACA,8B;AACA,uC;AACA,K;AACA,E;;AAEA,iC;AACA,yD;AACA,gF;AACA,4D;;AAEA,sB;AACA,oB;AACA,wB;AACA,I;AACA,qB;AACA,oB;AACA,sB;AACA,I;AACA,8B;AACA,oB;AACA,oB;AACA,4B;AACA,qB;AACA,8B;AACA,uB;AACA,Y;AACA,+B;AACA,0B;AACA,mB;AACA,4B;AACA,K;AACA,yD;AACA,wB;AACA,I;AACA,+B;AACA,oB;AACA,iB;AACA,+B;AACA,iB;AACA,+B;AACA,2B;AACA,4B;AACA,4B;AACA,6B;AACA,I;AACA,2C;AACA,oB;AACA,iC;AACA,yE;AACA,sB;AACA,2D;AACA,mC;AACA,+B;AACA,oE;AACA,yB;AACA,mC;AACA,iB;AACA,I;AACA,gC;AACA,oB;AACA,oC;AACA,I;AACA,0B;AACA,oB;AACA,uC;AACA,0B;AACA,qE;AACA,0B;AACA,iB;AACA,oC;AACA,qB;AACA,I;AACA,uB;AACA,oB;AACA,sB;AACA,8C;AACA,qB;AACA,I;AACA,uB;AACA,oB;AACA,2C;AACA,I;AACA,mE;AACA,yC;;AAEA,8E;AACA,4B;AACA,oB;AACA,c;AACA,0B;AACA,0B;AACA,0C;AACA,kC;AACA,e;AACA,qB;AACA,U;AACA,K;AACA,I;AACA,sB;AACA,oB;AACA,qB;AACA,uB;AACA,2B;AACA,I;AACA,2B;AACA,oB;AACA,qB;AACA,uB;AACA,6B;AACA,I;AACA,qB;AACA,oB;AACA,qB;AACA,uB;AACA,0B;AACA,I;AACA,0B;AACA,oB;AACA,qB;AACA,uB;AACA,4B;AACA,I;AACA,wB;AACA,oB;AACA,wB;AACA,yC;AACA,mB;AACA,4B;AACA,K;AACA,gB;AACA,I;AACA,wB;AACA,oB;AACA,wB;AACA,yC;AACA,mB;AACA,4B;AACA,K;AACA,gB;AACA,I;AACA,sC;AACA,oB;AACA,uC;AACA,gE;AACA,0B;AACA,qD;AACA,kC;AACA,wE;AACA,K;AACA,sD;AACA,a;AACA,gC;AACA,0B;AACA,+B;AACA,yB;AACA,yB;AACA,I;AACA,mB;AACA,2B;AACA,oB;AACA,mB;AACA,qC;AACA,wC;AACA,gB;AACA,iC;AACA,O;AACA,uB;AACA,O;AACA,e;AACA,I;AACA,0B;AACA,oB;AACA,wC;AACA,uB;AACA,0C;AACA,uB;AACA,0C;AACA,O;AACA,G;;AAEA,G;AACA,oC","file":"/packages/ordered-dict.js","sourcesContent":["// This file defines an ordered dictionary abstraction that is useful for\n// maintaining a dataset backed by observeChanges. It supports ordering items\n// by specifying the item they now come before.\n\n// The implementation is a dictionary that contains nodes of a doubly-linked\n// list as its values.\n\n// constructs a new element struct\n// next and prev are whole elements, not keys.\nvar element = function (key, value, next, prev) {\n return {\n key: key,\n value: value,\n next: next,\n prev: prev\n };\n};\nOrderedDict = function (/* ... */) {\n var self = this;\n self._dict = {};\n self._first = null;\n self._last = null;\n self._size = 0;\n var args = _.toArray(arguments);\n self._stringify = function (x) { return x; };\n if (typeof args[0] === 'function')\n self._stringify = args.shift();\n _.each(args, function (kv) {\n self.putBefore(kv[0], kv[1], null);\n });\n};\n\n_.extend(OrderedDict.prototype, {\n // the \"prefix keys with a space\" thing comes from here\n // https://github.com/documentcloud/underscore/issues/376#issuecomment-2815649\n _k: function (key) { return \" \" + this._stringify(key); },\n\n empty: function () {\n var self = this;\n return !self._first;\n },\n size: function () {\n var self = this;\n return self._size;\n },\n _linkEltIn: function (elt) {\n var self = this;\n if (!elt.next) {\n elt.prev = self._last;\n if (self._last)\n self._last.next = elt;\n self._last = elt;\n } else {\n elt.prev = elt.next.prev;\n elt.next.prev = elt;\n if (elt.prev)\n elt.prev.next = elt;\n }\n if (self._first === null || self._first === elt.next)\n self._first = elt;\n },\n _linkEltOut: function (elt) {\n var self = this;\n if (elt.next)\n elt.next.prev = elt.prev;\n if (elt.prev)\n elt.prev.next = elt.next;\n if (elt === self._last)\n self._last = elt.prev;\n if (elt === self._first)\n self._first = elt.next;\n },\n putBefore: function (key, item, before) {\n var self = this;\n if (self._dict[self._k(key)])\n throw new Error(\"Item \" + key + \" already present in OrderedDict\");\n var elt = before ?\n element(key, item, self._dict[self._k(before)]) :\n element(key, item, null);\n if (elt.next === undefined)\n throw new Error(\"could not find item to put this one before\");\n self._linkEltIn(elt);\n self._dict[self._k(key)] = elt;\n self._size++;\n },\n append: function (key, item) {\n var self = this;\n self.putBefore(key, item, null);\n },\n remove: function (key) {\n var self = this;\n var elt = self._dict[self._k(key)];\n if (elt === undefined)\n throw new Error(\"Item \" + key + \" not present in OrderedDict\");\n self._linkEltOut(elt);\n self._size--;\n delete self._dict[self._k(key)];\n return elt.value;\n },\n get: function (key) {\n var self = this;\n if (self.has(key))\n return self._dict[self._k(key)].value;\n return undefined;\n },\n has: function (key) {\n var self = this;\n return _.has(self._dict, self._k(key));\n },\n // Iterate through the items in this dictionary in order, calling\n // iter(value, key, index) on each one.\n\n // Stops whenever iter returns OrderedDict.BREAK, or after the last element.\n forEach: function (iter) {\n var self = this;\n var i = 0;\n var elt = self._first;\n while (elt !== null) {\n var b = iter(elt.value, elt.key, i);\n if (b === OrderedDict.BREAK)\n return;\n elt = elt.next;\n i++;\n }\n },\n first: function () {\n var self = this;\n if (self.empty())\n return undefined;\n return self._first.key;\n },\n firstValue: function () {\n var self = this;\n if (self.empty())\n return undefined;\n return self._first.value;\n },\n last: function () {\n var self = this;\n if (self.empty())\n return undefined;\n return self._last.key;\n },\n lastValue: function () {\n var self = this;\n if (self.empty())\n return undefined;\n return self._last.value;\n },\n prev: function (key) {\n var self = this;\n if (self.has(key)) {\n var elt = self._dict[self._k(key)];\n if (elt.prev)\n return elt.prev.key;\n }\n return null;\n },\n next: function (key) {\n var self = this;\n if (self.has(key)) {\n var elt = self._dict[self._k(key)];\n if (elt.next)\n return elt.next.key;\n }\n return null;\n },\n moveBefore: function (key, before) {\n var self = this;\n var elt = self._dict[self._k(key)];\n var eltBefore = before ? self._dict[self._k(before)] : null;\n if (elt === undefined)\n throw new Error(\"Item to move is not present\");\n if (eltBefore === undefined) {\n throw new Error(\"Could not find element to move this one before\");\n }\n if (eltBefore === elt.next) // no moving necessary\n return;\n // remove from its old place\n self._linkEltOut(elt);\n // patch into its new place\n elt.next = eltBefore;\n self._linkEltIn(elt);\n },\n // Linear, sadly.\n indexOf: function (key) {\n var self = this;\n var ret = null;\n self.forEach(function (v, k, i) {\n if (self._k(k) === self._k(key)) {\n ret = i;\n return OrderedDict.BREAK;\n }\n return undefined;\n });\n return ret;\n },\n _checkRep: function () {\n var self = this;\n _.each(self._dict, function (k, v) {\n if (v.next === v)\n throw new Error(\"Next is a loop\");\n if (v.prev === v)\n throw new Error(\"Prev is a loop\");\n });\n }\n\n});\nOrderedDict.BREAK = {\"break\": true};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/random.js b/web-app/.meteor/local/build/programs/server/packages/random.js deleted file mode 100644 index d7be090..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/random.js +++ /dev/null @@ -1,285 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; - -/* Package-scope variables */ -var Random; - -(function () { - -////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/random/random.js // -// // -////////////////////////////////////////////////////////////////////////////////////// - // -// We use cryptographically strong PRNGs (crypto.getRandomBytes() on the server, // 1 -// window.crypto.getRandomValues() in the browser) when available. If these // 2 -// PRNGs fail, we fall back to the Alea PRNG, which is not cryptographically // 3 -// strong, and we seed it with various sources such as the date, Math.random, // 4 -// and window size on the client. When using crypto.getRandomValues(), our // 5 -// primitive is hexString(), from which we construct fraction(). When using // 6 -// window.crypto.getRandomValues() or alea, the primitive is fraction and we use // 7 -// that to construct hex string. // 8 - // 9 -if (Meteor.isServer) // 10 - var nodeCrypto = Npm.require('crypto'); // 11 - // 12 -// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript // 13 -// for a full discussion and Alea implementation. // 14 -var Alea = function () { // 15 - function Mash() { // 16 - var n = 0xefc8249d; // 17 - // 18 - var mash = function(data) { // 19 - data = data.toString(); // 20 - for (var i = 0; i < data.length; i++) { // 21 - n += data.charCodeAt(i); // 22 - var h = 0.02519603282416938 * n; // 23 - n = h >>> 0; // 24 - h -= n; // 25 - h *= n; // 26 - n = h >>> 0; // 27 - h -= n; // 28 - n += h * 0x100000000; // 2^32 // 29 - } // 30 - return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 // 31 - }; // 32 - // 33 - mash.version = 'Mash 0.9'; // 34 - return mash; // 35 - } // 36 - // 37 - return (function (args) { // 38 - var s0 = 0; // 39 - var s1 = 0; // 40 - var s2 = 0; // 41 - var c = 1; // 42 - // 43 - if (args.length == 0) { // 44 - args = [+new Date]; // 45 - } // 46 - var mash = Mash(); // 47 - s0 = mash(' '); // 48 - s1 = mash(' '); // 49 - s2 = mash(' '); // 50 - // 51 - for (var i = 0; i < args.length; i++) { // 52 - s0 -= mash(args[i]); // 53 - if (s0 < 0) { // 54 - s0 += 1; // 55 - } // 56 - s1 -= mash(args[i]); // 57 - if (s1 < 0) { // 58 - s1 += 1; // 59 - } // 60 - s2 -= mash(args[i]); // 61 - if (s2 < 0) { // 62 - s2 += 1; // 63 - } // 64 - } // 65 - mash = null; // 66 - // 67 - var random = function() { // 68 - var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 // 69 - s0 = s1; // 70 - s1 = s2; // 71 - return s2 = t - (c = t | 0); // 72 - }; // 73 - random.uint32 = function() { // 74 - return random() * 0x100000000; // 2^32 // 75 - }; // 76 - random.fract53 = function() { // 77 - return random() + // 78 - (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 // 79 - }; // 80 - random.version = 'Alea 0.9'; // 81 - random.args = args; // 82 - return random; // 83 - // 84 - } (Array.prototype.slice.call(arguments))); // 85 -}; // 86 - // 87 -var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz"; // 88 -var BASE64_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + // 89 - "0123456789-_"; // 90 - // 91 -// If seeds are provided, then the alea PRNG will be used, since cryptographic // 92 -// PRNGs (Node crypto and window.crypto.getRandomValues) don't allow us to // 93 -// specify seeds. The caller is responsible for making sure to provide a seed // 94 -// for alea if a csprng is not available. // 95 -var RandomGenerator = function (seedArray) { // 96 - var self = this; // 97 - if (seedArray !== undefined) // 98 - self.alea = Alea.apply(null, seedArray); // 99 -}; // 100 - // 101 -RandomGenerator.prototype.fraction = function () { // 102 - var self = this; // 103 - if (self.alea) { // 104 - return self.alea(); // 105 - } else if (nodeCrypto) { // 106 - var numerator = parseInt(self.hexString(8), 16); // 107 - return numerator * 2.3283064365386963e-10; // 2^-32 // 108 - } else if (typeof window !== "undefined" && window.crypto && // 109 - window.crypto.getRandomValues) { // 110 - var array = new Uint32Array(1); // 111 - window.crypto.getRandomValues(array); // 112 - return array[0] * 2.3283064365386963e-10; // 2^-32 // 113 - } else { // 114 - throw new Error('No random generator available'); // 115 - } // 116 -}; // 117 - // 118 -RandomGenerator.prototype.hexString = function (digits) { // 119 - var self = this; // 120 - if (nodeCrypto && ! self.alea) { // 121 - var numBytes = Math.ceil(digits / 2); // 122 - var bytes; // 123 - // Try to get cryptographically strong randomness. Fall back to // 124 - // non-cryptographically strong if not available. // 125 - try { // 126 - bytes = nodeCrypto.randomBytes(numBytes); // 127 - } catch (e) { // 128 - // XXX should re-throw any error except insufficient entropy // 129 - bytes = nodeCrypto.pseudoRandomBytes(numBytes); // 130 - } // 131 - var result = bytes.toString("hex"); // 132 - // If the number of digits is odd, we'll have generated an extra 4 bits // 133 - // of randomness, so we need to trim the last digit. // 134 - return result.substring(0, digits); // 135 - } else { // 136 - var hexDigits = []; // 137 - for (var i = 0; i < digits; ++i) { // 138 - hexDigits.push(self.choice("0123456789abcdef")); // 139 - } // 140 - return hexDigits.join(''); // 141 - } // 142 -}; // 143 - // 144 -RandomGenerator.prototype._randomString = function (charsCount, // 145 - alphabet) { // 146 - var self = this; // 147 - var digits = []; // 148 - for (var i = 0; i < charsCount; i++) { // 149 - digits[i] = self.choice(alphabet); // 150 - } // 151 - return digits.join(""); // 152 -}; // 153 - // 154 -RandomGenerator.prototype.id = function (charsCount) { // 155 - var self = this; // 156 - // 17 characters is around 96 bits of entropy, which is the amount of // 157 - // state in the Alea PRNG. // 158 - if (charsCount === undefined) // 159 - charsCount = 17; // 160 - // 161 - return self._randomString(charsCount, UNMISTAKABLE_CHARS); // 162 -}; // 163 - // 164 -RandomGenerator.prototype.secret = function (charsCount) { // 165 - var self = this; // 166 - // Default to 256 bits of entropy, or 43 characters at 6 bits per // 167 - // character. // 168 - if (charsCount === undefined) // 169 - charsCount = 43; // 170 - return self._randomString(charsCount, BASE64_CHARS); // 171 -}; // 172 - // 173 -RandomGenerator.prototype.choice = function (arrayOrString) { // 174 - var index = Math.floor(this.fraction() * arrayOrString.length); // 175 - if (typeof arrayOrString === "string") // 176 - return arrayOrString.substr(index, 1); // 177 - else // 178 - return arrayOrString[index]; // 179 -}; // 180 - // 181 -// instantiate RNG. Heuristically collect entropy from various sources when a // 182 -// cryptographic PRNG isn't available. // 183 - // 184 -// client sources // 185 -var height = (typeof window !== 'undefined' && window.innerHeight) || // 186 - (typeof document !== 'undefined' // 187 - && document.documentElement // 188 - && document.documentElement.clientHeight) || // 189 - (typeof document !== 'undefined' // 190 - && document.body // 191 - && document.body.clientHeight) || // 192 - 1; // 193 - // 194 -var width = (typeof window !== 'undefined' && window.innerWidth) || // 195 - (typeof document !== 'undefined' // 196 - && document.documentElement // 197 - && document.documentElement.clientWidth) || // 198 - (typeof document !== 'undefined' // 199 - && document.body // 200 - && document.body.clientWidth) || // 201 - 1; // 202 - // 203 -var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || ""; // 204 - // 205 -if (nodeCrypto || // 206 - (typeof window !== "undefined" && // 207 - window.crypto && window.crypto.getRandomValues)) // 208 - Random = new RandomGenerator(); // 209 -else // 210 - Random = new RandomGenerator([new Date(), height, width, agent, Math.random()]); // 211 - // 212 -Random.createWithSeeds = function () { // 213 - if (arguments.length === 0) { // 214 - throw new Error('No seeds were provided'); // 215 - } // 216 - return new RandomGenerator(arguments); // 217 -}; // 218 - // 219 -////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/random/deprecated.js // -// // -////////////////////////////////////////////////////////////////////////////////////// - // -// Before this package existed, we used to use this Meteor.uuid() // 1 -// implementing the RFC 4122 v4 UUID. It is no longer documented // 2 -// and will go away. // 3 -// XXX COMPAT WITH 0.5.6 // 4 -Meteor.uuid = function () { // 5 - var HEX_DIGITS = "0123456789abcdef"; // 6 - var s = []; // 7 - for (var i = 0; i < 36; i++) { // 8 - s[i] = Random.choice(HEX_DIGITS); // 9 - } // 10 - s[14] = "4"; // 11 - s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1); // 12 - s[8] = s[13] = s[18] = s[23] = "-"; // 13 - // 14 - var uuid = s.join(""); // 15 - return uuid; // 16 -}; // 17 - // 18 -////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.random = { - Random: Random -}; - -})(); - -//# sourceMappingURL=random.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/random.js.map b/web-app/.meteor/local/build/programs/server/packages/random.js.map deleted file mode 100644 index 1b2a187..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/random.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["random/random.js","random/deprecated.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,gF;AACA,2E;AACA,4E;AACA,6E;AACA,2E;AACA,2E;AACA,gF;AACA,gC;;AAEA,oB;AACA,yC;;AAEA,qE;AACA,iD;AACA,wB;AACA,mB;AACA,uB;;AAEA,+B;AACA,6B;AACA,6C;AACA,gC;AACA,wC;AACA,oB;AACA,e;AACA,e;AACA,oB;AACA,e;AACA,qC;AACA,O;AACA,yD;AACA,M;;AAEA,8B;AACA,gB;AACA,G;;AAEA,2B;AACA,e;AACA,e;AACA,e;AACA,c;;AAEA,2B;AACA,yB;AACA,K;AACA,sB;AACA,mB;AACA,mB;AACA,mB;;AAEA,2C;AACA,0B;AACA,mB;AACA,gB;AACA,O;AACA,0B;AACA,mB;AACA,gB;AACA,O;AACA,0B;AACA,mB;AACA,gB;AACA,O;AACA,K;AACA,gB;;AAEA,6B;AACA,iE;AACA,c;AACA,c;AACA,kC;AACA,M;AACA,gC;AACA,4C;AACA,M;AACA,iC;AACA,uB;AACA,oE;AACA,M;AACA,gC;AACA,uB;AACA,kB;;AAEA,6C;AACA,E;;AAEA,mF;AACA,2E;AACA,iB;;AAEA,8E;AACA,0E;AACA,6E;AACA,yC;AACA,4C;AACA,kB;AACA,8B;AACA,4C;AACA,E;;AAEA,kD;AACA,kB;AACA,kB;AACA,uB;AACA,0B;AACA,oD;AACA,uD;AACA,8D;AACA,6C;AACA,mC;AACA,yC;AACA,sD;AACA,U;AACA,qD;AACA,G;AACA,E;;AAEA,yD;AACA,kB;AACA,kC;AACA,yC;AACA,c;AACA,mE;AACA,qD;AACA,S;AACA,+C;AACA,iB;AACA,kE;AACA,qD;AACA,K;AACA,uC;AACA,2E;AACA,wD;AACA,uC;AACA,U;AACA,uB;AACA,sC;AACA,sD;AACA,K;AACA,8B;AACA,G;AACA,E;;AAEA,+D;AACA,+D;AACA,kB;AACA,kB;AACA,wC;AACA,sC;AACA,G;AACA,yB;AACA,E;;AAEA,sD;AACA,kB;AACA,uE;AACA,4B;AACA,+B;AACA,oB;;AAEA,4D;AACA,E;;AAEA,0D;AACA,kB;AACA,mE;AACA,e;AACA,+B;AACA,oB;AACA,sD;AACA,E;;AAEA,6D;AACA,iE;AACA,wC;AACA,0C;AACA,M;AACA,gC;AACA,E;;AAEA,8E;AACA,sC;;AAEA,iB;AACA,qE;AACA,sC;AACA,kC;AACA,mD;AACA,sC;AACA,uB;AACA,wC;AACA,Q;;AAEA,mE;AACA,sC;AACA,kC;AACA,kD;AACA,sC;AACA,uB;AACA,uC;AACA,Q;;AAEA,4E;;AAEA,iB;AACA,qC;AACA,qD;AACA,iC;AACA,I;AACA,kF;;AAEA,sC;AACA,+B;AACA,8C;AACA,G;AACA,wC;AACA,E;;;;;;;;;;;;;;;;;;;ACzNA,iE;AACA,gE;AACA,oB;AACA,wB;AACA,2B;AACA,sC;AACA,a;AACA,gC;AACA,qC;AACA,G;AACA,c;AACA,iE;AACA,qC;;AAEA,wB;AACA,c;AACA,E","file":"/packages/random.js","sourcesContent":["// We use cryptographically strong PRNGs (crypto.getRandomBytes() on the server,\n// window.crypto.getRandomValues() in the browser) when available. If these\n// PRNGs fail, we fall back to the Alea PRNG, which is not cryptographically\n// strong, and we seed it with various sources such as the date, Math.random,\n// and window size on the client. When using crypto.getRandomValues(), our\n// primitive is hexString(), from which we construct fraction(). When using\n// window.crypto.getRandomValues() or alea, the primitive is fraction and we use\n// that to construct hex string.\n\nif (Meteor.isServer)\n var nodeCrypto = Npm.require('crypto');\n\n// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript\n// for a full discussion and Alea implementation.\nvar Alea = function () {\n function Mash() {\n var n = 0xefc8249d;\n\n var mash = function(data) {\n data = data.toString();\n for (var i = 0; i < data.length; i++) {\n n += data.charCodeAt(i);\n var h = 0.02519603282416938 * n;\n n = h >>> 0;\n h -= n;\n h *= n;\n n = h >>> 0;\n h -= n;\n n += h * 0x100000000; // 2^32\n }\n return (n >>> 0) * 2.3283064365386963e-10; // 2^-32\n };\n\n mash.version = 'Mash 0.9';\n return mash;\n }\n\n return (function (args) {\n var s0 = 0;\n var s1 = 0;\n var s2 = 0;\n var c = 1;\n\n if (args.length == 0) {\n args = [+new Date];\n }\n var mash = Mash();\n s0 = mash(' ');\n s1 = mash(' ');\n s2 = mash(' ');\n\n for (var i = 0; i < args.length; i++) {\n s0 -= mash(args[i]);\n if (s0 < 0) {\n s0 += 1;\n }\n s1 -= mash(args[i]);\n if (s1 < 0) {\n s1 += 1;\n }\n s2 -= mash(args[i]);\n if (s2 < 0) {\n s2 += 1;\n }\n }\n mash = null;\n\n var random = function() {\n var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32\n s0 = s1;\n s1 = s2;\n return s2 = t - (c = t | 0);\n };\n random.uint32 = function() {\n return random() * 0x100000000; // 2^32\n };\n random.fract53 = function() {\n return random() +\n (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53\n };\n random.version = 'Alea 0.9';\n random.args = args;\n return random;\n\n } (Array.prototype.slice.call(arguments)));\n};\n\nvar UNMISTAKABLE_CHARS = \"23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz\";\nvar BASE64_CHARS = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" +\n \"0123456789-_\";\n\n// If seeds are provided, then the alea PRNG will be used, since cryptographic\n// PRNGs (Node crypto and window.crypto.getRandomValues) don't allow us to\n// specify seeds. The caller is responsible for making sure to provide a seed\n// for alea if a csprng is not available.\nvar RandomGenerator = function (seedArray) {\n var self = this;\n if (seedArray !== undefined)\n self.alea = Alea.apply(null, seedArray);\n};\n\nRandomGenerator.prototype.fraction = function () {\n var self = this;\n if (self.alea) {\n return self.alea();\n } else if (nodeCrypto) {\n var numerator = parseInt(self.hexString(8), 16);\n return numerator * 2.3283064365386963e-10; // 2^-32\n } else if (typeof window !== \"undefined\" && window.crypto &&\n window.crypto.getRandomValues) {\n var array = new Uint32Array(1);\n window.crypto.getRandomValues(array);\n return array[0] * 2.3283064365386963e-10; // 2^-32\n } else {\n throw new Error('No random generator available');\n }\n};\n\nRandomGenerator.prototype.hexString = function (digits) {\n var self = this;\n if (nodeCrypto && ! self.alea) {\n var numBytes = Math.ceil(digits / 2);\n var bytes;\n // Try to get cryptographically strong randomness. Fall back to\n // non-cryptographically strong if not available.\n try {\n bytes = nodeCrypto.randomBytes(numBytes);\n } catch (e) {\n // XXX should re-throw any error except insufficient entropy\n bytes = nodeCrypto.pseudoRandomBytes(numBytes);\n }\n var result = bytes.toString(\"hex\");\n // If the number of digits is odd, we'll have generated an extra 4 bits\n // of randomness, so we need to trim the last digit.\n return result.substring(0, digits);\n } else {\n var hexDigits = [];\n for (var i = 0; i < digits; ++i) {\n hexDigits.push(self.choice(\"0123456789abcdef\"));\n }\n return hexDigits.join('');\n }\n};\n\nRandomGenerator.prototype._randomString = function (charsCount,\n alphabet) {\n var self = this;\n var digits = [];\n for (var i = 0; i < charsCount; i++) {\n digits[i] = self.choice(alphabet);\n }\n return digits.join(\"\");\n};\n\nRandomGenerator.prototype.id = function (charsCount) {\n var self = this;\n // 17 characters is around 96 bits of entropy, which is the amount of\n // state in the Alea PRNG.\n if (charsCount === undefined)\n charsCount = 17;\n\n return self._randomString(charsCount, UNMISTAKABLE_CHARS);\n};\n\nRandomGenerator.prototype.secret = function (charsCount) {\n var self = this;\n // Default to 256 bits of entropy, or 43 characters at 6 bits per\n // character.\n if (charsCount === undefined)\n charsCount = 43;\n return self._randomString(charsCount, BASE64_CHARS);\n};\n\nRandomGenerator.prototype.choice = function (arrayOrString) {\n var index = Math.floor(this.fraction() * arrayOrString.length);\n if (typeof arrayOrString === \"string\")\n return arrayOrString.substr(index, 1);\n else\n return arrayOrString[index];\n};\n\n// instantiate RNG. Heuristically collect entropy from various sources when a\n// cryptographic PRNG isn't available.\n\n// client sources\nvar height = (typeof window !== 'undefined' && window.innerHeight) ||\n (typeof document !== 'undefined'\n && document.documentElement\n && document.documentElement.clientHeight) ||\n (typeof document !== 'undefined'\n && document.body\n && document.body.clientHeight) ||\n 1;\n\nvar width = (typeof window !== 'undefined' && window.innerWidth) ||\n (typeof document !== 'undefined'\n && document.documentElement\n && document.documentElement.clientWidth) ||\n (typeof document !== 'undefined'\n && document.body\n && document.body.clientWidth) ||\n 1;\n\nvar agent = (typeof navigator !== 'undefined' && navigator.userAgent) || \"\";\n\nif (nodeCrypto ||\n (typeof window !== \"undefined\" &&\n window.crypto && window.crypto.getRandomValues))\n Random = new RandomGenerator();\nelse\n Random = new RandomGenerator([new Date(), height, width, agent, Math.random()]);\n\nRandom.createWithSeeds = function () {\n if (arguments.length === 0) {\n throw new Error('No seeds were provided');\n }\n return new RandomGenerator(arguments);\n};\n","// Before this package existed, we used to use this Meteor.uuid()\n// implementing the RFC 4122 v4 UUID. It is no longer documented\n// and will go away.\n// XXX COMPAT WITH 0.5.6\nMeteor.uuid = function () {\n var HEX_DIGITS = \"0123456789abcdef\";\n var s = [];\n for (var i = 0; i < 36; i++) {\n s[i] = Random.choice(HEX_DIGITS);\n }\n s[14] = \"4\";\n s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1);\n s[8] = s[13] = s[18] = s[23] = \"-\";\n\n var uuid = s.join(\"\");\n return uuid;\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/reactive-var.js b/web-app/.meteor/local/build/programs/server/packages/reactive-var.js deleted file mode 100644 index 36aef1d..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/reactive-var.js +++ /dev/null @@ -1,129 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var Tracker = Package.tracker.Tracker; -var Deps = Package.tracker.Deps; - -/* Package-scope variables */ -var ReactiveVar; - -(function () { - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/reactive-var/reactive-var.js // -// // -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -/* // 1 - * ## [new] ReactiveVar(initialValue, [equalsFunc]) // 2 - * // 3 - * A ReactiveVar holds a single value that can be get and set, // 4 - * such that calling `set` will invalidate any Computations that // 5 - * called `get`, according to the usual contract for reactive // 6 - * data sources. // 7 - * // 8 - * A ReactiveVar is much like a Session variable -- compare `foo.get()` // 9 - * to `Session.get("foo")` -- but it doesn't have a global name and isn't // 10 - * automatically migrated across hot code pushes. Also, while Session // 11 - * variables can only hold JSON or EJSON, ReactiveVars can hold any value. // 12 - * // 13 - * An important property of ReactiveVars, which is sometimes the reason // 14 - * to use one, is that setting the value to the same value as before has // 15 - * no effect, meaning ReactiveVars can be used to absorb extra // 16 - * invalidations that wouldn't serve a purpose. However, by default, // 17 - * ReactiveVars are extremely conservative about what changes they // 18 - * absorb. Calling `set` with an object argument will *always* trigger // 19 - * invalidations, because even if the new value is `===` the old value, // 20 - * the object may have been mutated. You can change the default behavior // 21 - * by passing a function of two arguments, `oldValue` and `newValue`, // 22 - * to the constructor as `equalsFunc`. // 23 - * // 24 - * This class is extremely basic right now, but the idea is to evolve // 25 - * it into the ReactiveVar of Geoff's Lickable Forms proposal. // 26 - */ // 27 - // 28 -/** // 29 - * @class // 30 - * @instanceName reactiveVar // 31 - * @summary Constructor for a ReactiveVar, which represents a single reactive variable. // 32 - * @locus Client // 33 - * @param {Any} initialValue The initial value to set. `equalsFunc` is ignored when setting the initial value. // 34 - * @param {Function} [equalsFunc] Optional. A function of two arguments, called on the old value and the new value whenever the ReactiveVar is set. If it returns true, no set is performed. If omitted, the default `equalsFunc` returns true if its arguments are `===` and are of type number, boolean, string, undefined, or null. - */ // 36 -ReactiveVar = function (initialValue, equalsFunc) { // 37 - if (! (this instanceof ReactiveVar)) // 38 - // called without `new` // 39 - return new ReactiveVar(initialValue, equalsFunc); // 40 - // 41 - this.curValue = initialValue; // 42 - this.equalsFunc = equalsFunc; // 43 - this.dep = new Tracker.Dependency; // 44 -}; // 45 - // 46 -ReactiveVar._isEqual = function (oldValue, newValue) { // 47 - var a = oldValue, b = newValue; // 48 - // Two values are "equal" here if they are `===` and are // 49 - // number, boolean, string, undefined, or null. // 50 - if (a !== b) // 51 - return false; // 52 - else // 53 - return ((!a) || (typeof a === 'number') || (typeof a === 'boolean') || // 54 - (typeof a === 'string')); // 55 -}; // 56 - // 57 -/** // 58 - * @summary Returns the current value of the ReactiveVar, establishing a reactive dependency. // 59 - * @locus Client // 60 - */ // 61 -ReactiveVar.prototype.get = function () { // 62 - if (Tracker.active) // 63 - this.dep.depend(); // 64 - // 65 - return this.curValue; // 66 -}; // 67 - // 68 -/** // 69 - * @summary Sets the current value of the ReactiveVar, invalidating the Computations that called `get` if `newValue` is different from the old value. - * @locus Client // 71 - * @param {Any} newValue // 72 - */ // 73 -ReactiveVar.prototype.set = function (newValue) { // 74 - var oldValue = this.curValue; // 75 - // 76 - if ((this.equalsFunc || ReactiveVar._isEqual)(oldValue, newValue)) // 77 - // value is same as last time // 78 - return; // 79 - // 80 - this.curValue = newValue; // 81 - this.dep.changed(); // 82 -}; // 83 - // 84 -ReactiveVar.prototype.toString = function () { // 85 - return 'ReactiveVar{' + this.get() + '}'; // 86 -}; // 87 - // 88 -ReactiveVar.prototype._numListeners = function() { // 89 - // Tests want to know. // 90 - // Accesses a private field of Tracker.Dependency. // 91 - var count = 0; // 92 - for (var id in this.dep._dependentsById) // 93 - count++; // 94 - return count; // 95 -}; // 96 - // 97 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package['reactive-var'] = { - ReactiveVar: ReactiveVar -}; - -})(); - -//# sourceMappingURL=reactive-var.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/reactive-var.js.map b/web-app/.meteor/local/build/programs/server/packages/reactive-var.js.map deleted file mode 100644 index c1aad1a..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/reactive-var.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["reactive-var/reactive-var.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,E;AACA,mD;AACA,E;AACA,8D;AACA,gE;AACA,6D;AACA,gB;AACA,E;AACA,uE;AACA,yE;AACA,sE;AACA,0E;AACA,E;AACA,uE;AACA,wE;AACA,8D;AACA,qE;AACA,kE;AACA,uE;AACA,uE;AACA,yE;AACA,qE;AACA,sC;AACA,E;AACA,qE;AACA,8D;AACA,G;;AAEA,G;AACA,U;AACA,4B;AACA,uF;AACA,gB;AACA,+G;AACA,yU;AACA,G;AACA,mD;AACA,sC;AACA,2B;AACA,qD;;AAEA,+B;AACA,+B;AACA,oC;AACA,E;;AAEA,sD;AACA,iC;AACA,0D;AACA,iD;AACA,c;AACA,iB;AACA,M;AACA,0E;AACA,qC;AACA,E;;AAEA,G;AACA,6F;AACA,gB;AACA,G;AACA,yC;AACA,qB;AACA,sB;;AAEA,uB;AACA,E;;AAEA,G;AACA,qJ;AACA,gB;AACA,wB;AACA,G;AACA,iD;AACA,+B;;AAEA,oE;AACA,iC;AACA,W;;AAEA,2B;AACA,qB;AACA,E;;AAEA,8C;AACA,2C;AACA,E;;AAEA,kD;AACA,wB;AACA,oD;AACA,gB;AACA,0C;AACA,Y;AACA,e;AACA,E","file":"/packages/reactive-var.js","sourcesContent":["/*\n * ## [new] ReactiveVar(initialValue, [equalsFunc])\n *\n * A ReactiveVar holds a single value that can be get and set,\n * such that calling `set` will invalidate any Computations that\n * called `get`, according to the usual contract for reactive\n * data sources.\n *\n * A ReactiveVar is much like a Session variable -- compare `foo.get()`\n * to `Session.get(\"foo\")` -- but it doesn't have a global name and isn't\n * automatically migrated across hot code pushes. Also, while Session\n * variables can only hold JSON or EJSON, ReactiveVars can hold any value.\n *\n * An important property of ReactiveVars, which is sometimes the reason\n * to use one, is that setting the value to the same value as before has\n * no effect, meaning ReactiveVars can be used to absorb extra\n * invalidations that wouldn't serve a purpose. However, by default,\n * ReactiveVars are extremely conservative about what changes they\n * absorb. Calling `set` with an object argument will *always* trigger\n * invalidations, because even if the new value is `===` the old value,\n * the object may have been mutated. You can change the default behavior\n * by passing a function of two arguments, `oldValue` and `newValue`,\n * to the constructor as `equalsFunc`.\n *\n * This class is extremely basic right now, but the idea is to evolve\n * it into the ReactiveVar of Geoff's Lickable Forms proposal.\n */\n\n/**\n * @class \n * @instanceName reactiveVar\n * @summary Constructor for a ReactiveVar, which represents a single reactive variable.\n * @locus Client\n * @param {Any} initialValue The initial value to set. `equalsFunc` is ignored when setting the initial value.\n * @param {Function} [equalsFunc] Optional. A function of two arguments, called on the old value and the new value whenever the ReactiveVar is set. If it returns true, no set is performed. If omitted, the default `equalsFunc` returns true if its arguments are `===` and are of type number, boolean, string, undefined, or null.\n */\nReactiveVar = function (initialValue, equalsFunc) {\n if (! (this instanceof ReactiveVar))\n // called without `new`\n return new ReactiveVar(initialValue, equalsFunc);\n\n this.curValue = initialValue;\n this.equalsFunc = equalsFunc;\n this.dep = new Tracker.Dependency;\n};\n\nReactiveVar._isEqual = function (oldValue, newValue) {\n var a = oldValue, b = newValue;\n // Two values are \"equal\" here if they are `===` and are\n // number, boolean, string, undefined, or null.\n if (a !== b)\n return false;\n else\n return ((!a) || (typeof a === 'number') || (typeof a === 'boolean') ||\n (typeof a === 'string'));\n};\n\n/**\n * @summary Returns the current value of the ReactiveVar, establishing a reactive dependency.\n * @locus Client\n */\nReactiveVar.prototype.get = function () {\n if (Tracker.active)\n this.dep.depend();\n\n return this.curValue;\n};\n\n/**\n * @summary Sets the current value of the ReactiveVar, invalidating the Computations that called `get` if `newValue` is different from the old value.\n * @locus Client\n * @param {Any} newValue\n */\nReactiveVar.prototype.set = function (newValue) {\n var oldValue = this.curValue;\n\n if ((this.equalsFunc || ReactiveVar._isEqual)(oldValue, newValue))\n // value is same as last time\n return;\n\n this.curValue = newValue;\n this.dep.changed();\n};\n\nReactiveVar.prototype.toString = function () {\n return 'ReactiveVar{' + this.get() + '}';\n};\n\nReactiveVar.prototype._numListeners = function() {\n // Tests want to know.\n // Accesses a private field of Tracker.Dependency.\n var count = 0;\n for (var id in this.dep._dependentsById)\n count++;\n return count;\n};\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/reload.js b/web-app/.meteor/local/build/programs/server/packages/reload.js deleted file mode 100644 index 929e30a..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/reload.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.reload = {}; - -})(); - -//# sourceMappingURL=reload.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/reload.js.map b/web-app/.meteor/local/build/programs/server/packages/reload.js.map deleted file mode 100644 index e58cd9a..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/reload.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/reload.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/retry.js b/web-app/.meteor/local/build/programs/server/packages/retry.js deleted file mode 100644 index 6c7eb86..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/retry.js +++ /dev/null @@ -1,97 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; -var Random = Package.random.Random; - -/* Package-scope variables */ -var Retry; - -(function () { - -///////////////////////////////////////////////////////////////////////////// -// // -// packages/retry/retry.js // -// // -///////////////////////////////////////////////////////////////////////////// - // -// Retry logic with an exponential backoff. // 1 -// // 2 -// options: // 3 -// baseTimeout: time for initial reconnect attempt (ms). // 4 -// exponent: exponential factor to increase timeout each attempt. // 5 -// maxTimeout: maximum time between retries (ms). // 6 -// minCount: how many times to reconnect "instantly". // 7 -// minTimeout: time to wait for the first `minCount` retries (ms). // 8 -// fuzz: factor to randomize retry times by (to avoid retry storms). // 9 - // 10 -Retry = function (options) { // 11 - var self = this; // 12 - _.extend(self, _.defaults(_.clone(options || {}), { // 13 - baseTimeout: 1000, // 1 second // 14 - exponent: 2.2, // 15 - // The default is high-ish to ensure a server can recover from a // 16 - // failure caused by load. // 17 - maxTimeout: 5 * 60000, // 5 minutes // 18 - minTimeout: 10, // 19 - minCount: 2, // 20 - fuzz: 0.5 // +- 25% // 21 - })); // 22 - self.retryTimer = null; // 23 -}; // 24 - // 25 -_.extend(Retry.prototype, { // 26 - // 27 - // Reset a pending retry, if any. // 28 - clear: function () { // 29 - var self = this; // 30 - if (self.retryTimer) // 31 - clearTimeout(self.retryTimer); // 32 - self.retryTimer = null; // 33 - }, // 34 - // 35 - // Calculate how long to wait in milliseconds to retry, based on the // 36 - // `count` of which retry this is. // 37 - _timeout: function (count) { // 38 - var self = this; // 39 - // 40 - if (count < self.minCount) // 41 - return self.minTimeout; // 42 - // 43 - var timeout = Math.min( // 44 - self.maxTimeout, // 45 - self.baseTimeout * Math.pow(self.exponent, count)); // 46 - // fuzz the timeout randomly, to avoid reconnect storms when a // 47 - // server goes down. // 48 - timeout = timeout * ((Random.fraction() * self.fuzz) + // 49 - (1 - self.fuzz/2)); // 50 - return timeout; // 51 - }, // 52 - // 53 - // Call `fn` after a delay, based on the `count` of which retry this is. // 54 - retryLater: function (count, fn) { // 55 - var self = this; // 56 - var timeout = self._timeout(count); // 57 - if (self.retryTimer) // 58 - clearTimeout(self.retryTimer); // 59 - self.retryTimer = Meteor.setTimeout(fn, timeout); // 60 - return timeout; // 61 - } // 62 - // 63 -}); // 64 - // 65 -///////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.retry = { - Retry: Retry -}; - -})(); - -//# sourceMappingURL=retry.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/retry.js.map b/web-app/.meteor/local/build/programs/server/packages/retry.js.map deleted file mode 100644 index c7ca600..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/retry.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["retry/retry.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,2C;AACA,E;AACA,W;AACA,yD;AACA,kE;AACA,kD;AACA,sD;AACA,mE;AACA,qE;;AAEA,4B;AACA,kB;AACA,qD;AACA,kC;AACA,kB;AACA,oE;AACA,8B;AACA,uC;AACA,mB;AACA,gB;AACA,uB;AACA,M;AACA,yB;AACA,E;;AAEA,2B;;AAEA,mC;AACA,sB;AACA,oB;AACA,wB;AACA,oC;AACA,2B;AACA,I;;AAEA,sE;AACA,oC;AACA,8B;AACA,oB;;AAEA,8B;AACA,6B;;AAEA,2B;AACA,sB;AACA,yD;AACA,kE;AACA,wB;AACA,0D;AACA,4C;AACA,mB;AACA,I;;AAEA,0E;AACA,oC;AACA,oB;AACA,uC;AACA,wB;AACA,oC;AACA,qD;AACA,mB;AACA,G;;AAEA,G","file":"/packages/retry.js","sourcesContent":["// Retry logic with an exponential backoff.\n//\n// options:\n// baseTimeout: time for initial reconnect attempt (ms).\n// exponent: exponential factor to increase timeout each attempt.\n// maxTimeout: maximum time between retries (ms).\n// minCount: how many times to reconnect \"instantly\".\n// minTimeout: time to wait for the first `minCount` retries (ms).\n// fuzz: factor to randomize retry times by (to avoid retry storms).\n\nRetry = function (options) {\n var self = this;\n _.extend(self, _.defaults(_.clone(options || {}), {\n baseTimeout: 1000, // 1 second\n exponent: 2.2,\n // The default is high-ish to ensure a server can recover from a\n // failure caused by load.\n maxTimeout: 5 * 60000, // 5 minutes\n minTimeout: 10,\n minCount: 2,\n fuzz: 0.5 // +- 25%\n }));\n self.retryTimer = null;\n};\n\n_.extend(Retry.prototype, {\n\n // Reset a pending retry, if any.\n clear: function () {\n var self = this;\n if (self.retryTimer)\n clearTimeout(self.retryTimer);\n self.retryTimer = null;\n },\n\n // Calculate how long to wait in milliseconds to retry, based on the\n // `count` of which retry this is.\n _timeout: function (count) {\n var self = this;\n\n if (count < self.minCount)\n return self.minTimeout;\n\n var timeout = Math.min(\n self.maxTimeout,\n self.baseTimeout * Math.pow(self.exponent, count));\n // fuzz the timeout randomly, to avoid reconnect storms when a\n // server goes down.\n timeout = timeout * ((Random.fraction() * self.fuzz) +\n (1 - self.fuzz/2));\n return timeout;\n },\n\n // Call `fn` after a delay, based on the `count` of which retry this is.\n retryLater: function (count, fn) {\n var self = this;\n var timeout = self._timeout(count);\n if (self.retryTimer)\n clearTimeout(self.retryTimer);\n self.retryTimer = Meteor.setTimeout(fn, timeout);\n return timeout;\n }\n\n});\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/routepolicy.js b/web-app/.meteor/local/build/programs/server/packages/routepolicy.js deleted file mode 100644 index 41f2d26..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/routepolicy.js +++ /dev/null @@ -1,161 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var _ = Package.underscore._; - -/* Package-scope variables */ -var RoutePolicy, RoutePolicyTest; - -(function () { - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/routepolicy/routepolicy.js // -// // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // -// In addition to listing specific files to be cached, the browser // 1 -// application cache manifest allows URLs to be designated as NETWORK // 2 -// (always fetched from the Internet) and FALLBACK (which we use to // 3 -// serve app HTML on arbitrary URLs). // 4 -// // 5 -// The limitation of the manifest file format is that the designations // 6 -// are by prefix only: if "/foo" is declared NETWORK then "/foobar" // 7 -// will also be treated as a network route. // 8 -// // 9 -// RoutePolicy is a low-level API for declaring the route type of URL prefixes: // 10 -// // 11 -// "network": for network routes that should not conflict with static // 12 -// resources. (For example, if "/sockjs/" is a network route, we // 13 -// shouldn't have "/sockjs/red-sock.jpg" as a static resource). // 14 -// // 15 -// "static-online": for static resources which should not be cached in // 16 -// the app cache. This is implemented by also adding them to the // 17 -// NETWORK section (as otherwise the browser would receive app HTML // 18 -// for them because of the FALLBACK section), but static-online routes // 19 -// don't need to be checked for conflict with static resources. // 20 - // 21 -// The route policy is a singleton in a running application, but we // 22 -// can't unit test the real singleton because messing with the real // 23 -// routes would break tinytest... so allow policy instances to be // 24 -// constructed for testing. // 25 - // 26 -RoutePolicyTest = {}; // 27 - // 28 -var RoutePolicyConstructor = RoutePolicyTest.Constructor = function () { // 29 - var self = this; // 30 - self.urlPrefixTypes = {}; // 31 -}; // 32 - // 33 -_.extend(RoutePolicyConstructor.prototype, { // 34 - // 35 - urlPrefixMatches: function (urlPrefix, url) { // 36 - return url.substr(0, urlPrefix.length) === urlPrefix; // 37 - }, // 38 - // 39 - checkType: function (type) { // 40 - if (! _.contains(['network', 'static-online'], type)) // 41 - return 'the route type must be "network" or "static-online"'; // 42 - return null; // 43 - }, // 44 - // 45 - checkUrlPrefix: function (urlPrefix, type) { // 46 - var self = this; // 47 - // 48 - if (urlPrefix.charAt(0) !== '/') // 49 - return 'a route URL prefix must begin with a slash'; // 50 - // 51 - if (urlPrefix === '/') // 52 - return 'a route URL prefix cannot be /'; // 53 - // 54 - var existingType = self.urlPrefixTypes[urlPrefix]; // 55 - if (existingType && existingType !== type) // 56 - return 'the route URL prefix ' + urlPrefix + ' has already been declared to be of type ' + existingType; // 57 - // 58 - return null; // 59 - }, // 60 - // 61 - checkForConflictWithStatic: function (urlPrefix, type, _testManifest) { // 62 - var self = this; // 63 - if (type === 'static-online') // 64 - return null; // 65 - if (!Package.webapp || !Package.webapp.WebApp // 66 - || !Package.webapp.WebApp.clientPrograms // 67 - || !Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest) { // 68 - // Hack: If we don't have a manifest, deal with it // 69 - // gracefully. This lets us load livedata into a nodejs // 70 - // environment that doesn't have a HTTP server (eg, a // 71 - // command-line tool). // 72 - return null; // 73 - } // 74 - var manifest = _testManifest || // 75 - Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest; // 76 - var conflict = _.find(manifest, function (resource) { // 77 - return (resource.type === 'static' && // 78 - resource.where === 'client' && // 79 - self.urlPrefixMatches(urlPrefix, resource.url)); // 80 - }); // 81 - if (conflict) // 82 - return ('static resource ' + conflict.url + ' conflicts with ' + // 83 - type + ' route ' + urlPrefix); // 84 - else // 85 - return null; // 86 - }, // 87 - // 88 - declare: function (urlPrefix, type) { // 89 - var self = this; // 90 - var problem = self.checkType(type) || // 91 - self.checkUrlPrefix(urlPrefix, type) || // 92 - self.checkForConflictWithStatic(urlPrefix, type); // 93 - if (problem) // 94 - throw new Error(problem); // 95 - // TODO overlapping prefixes, e.g. /foo/ and /foo/bar/ // 96 - self.urlPrefixTypes[urlPrefix] = type; // 97 - }, // 98 - // 99 - isValidUrl: function (url) { // 100 - return url.charAt(0) === '/'; // 101 - }, // 102 - // 103 - classify: function (url) { // 104 - var self = this; // 105 - if (url.charAt(0) !== '/') // 106 - throw new Error('url must be a relative URL: ' + url); // 107 - var prefix = _.find(_.keys(self.urlPrefixTypes), function (_prefix) { // 108 - return self.urlPrefixMatches(_prefix, url); // 109 - }); // 110 - if (prefix) // 111 - return self.urlPrefixTypes[prefix]; // 112 - else // 113 - return null; // 114 - }, // 115 - // 116 - urlPrefixesFor: function (type) { // 117 - var self = this; // 118 - var prefixes = []; // 119 - _.each(self.urlPrefixTypes, function (_type, _prefix) { // 120 - if (_type === type) // 121 - prefixes.push(_prefix); // 122 - }); // 123 - return prefixes.sort(); // 124 - } // 125 -}); // 126 - // 127 -RoutePolicy = new RoutePolicyConstructor(); // 128 - // 129 -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.routepolicy = { - RoutePolicy: RoutePolicy, - RoutePolicyTest: RoutePolicyTest -}; - -})(); - -//# sourceMappingURL=routepolicy.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/routepolicy.js.map b/web-app/.meteor/local/build/programs/server/packages/routepolicy.js.map deleted file mode 100644 index a205592..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/routepolicy.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["routepolicy/routepolicy.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,kE;AACA,qE;AACA,mE;AACA,qC;AACA,E;AACA,sE;AACA,mE;AACA,2C;AACA,E;AACA,+E;AACA,E;AACA,qE;AACA,iE;AACA,+D;AACA,E;AACA,sE;AACA,iE;AACA,mE;AACA,sE;AACA,+D;;AAEA,mE;AACA,mE;AACA,iE;AACA,2B;;AAEA,qB;;AAEA,wE;AACA,kB;AACA,2B;AACA,E;;AAEA,4C;;AAEA,+C;AACA,yD;AACA,I;;AAEA,8B;AACA,yD;AACA,mE;AACA,gB;AACA,I;;AAEA,8C;AACA,oB;;AAEA,oC;AACA,0D;;AAEA,0B;AACA,8C;;AAEA,sD;AACA,8C;AACA,8G;;AAEA,gB;AACA,I;;AAEA,yE;AACA,oB;AACA,iC;AACA,kB;AACA,iD;AACA,gD;AACA,+F;AACA,wD;AACA,6D;AACA,2D;AACA,4B;AACA,kB;AACA,K;AACA,mC;AACA,uF;AACA,yD;AACA,2C;AACA,4C;AACA,8D;AACA,O;AACA,iB;AACA,sE;AACA,4C;AACA,Q;AACA,kB;AACA,I;;AAEA,uC;AACA,oB;AACA,yC;AACA,yD;AACA,mE;AACA,gB;AACA,+B;AACA,0D;AACA,0C;AACA,I;;AAEA,8B;AACA,iC;AACA,I;;AAEA,4B;AACA,oB;AACA,8B;AACA,4D;AACA,yE;AACA,iD;AACA,O;AACA,e;AACA,yC;AACA,Q;AACA,kB;AACA,I;;AAEA,mC;AACA,oB;AACA,sB;AACA,2D;AACA,yB;AACA,+B;AACA,O;AACA,2B;AACA,G;AACA,G;;AAEA,2C","file":"/packages/routepolicy.js","sourcesContent":["// In addition to listing specific files to be cached, the browser\n// application cache manifest allows URLs to be designated as NETWORK\n// (always fetched from the Internet) and FALLBACK (which we use to\n// serve app HTML on arbitrary URLs).\n//\n// The limitation of the manifest file format is that the designations\n// are by prefix only: if \"/foo\" is declared NETWORK then \"/foobar\"\n// will also be treated as a network route.\n//\n// RoutePolicy is a low-level API for declaring the route type of URL prefixes:\n//\n// \"network\": for network routes that should not conflict with static\n// resources. (For example, if \"/sockjs/\" is a network route, we\n// shouldn't have \"/sockjs/red-sock.jpg\" as a static resource).\n//\n// \"static-online\": for static resources which should not be cached in\n// the app cache. This is implemented by also adding them to the\n// NETWORK section (as otherwise the browser would receive app HTML\n// for them because of the FALLBACK section), but static-online routes\n// don't need to be checked for conflict with static resources.\n\n// The route policy is a singleton in a running application, but we\n// can't unit test the real singleton because messing with the real\n// routes would break tinytest... so allow policy instances to be\n// constructed for testing.\n\nRoutePolicyTest = {};\n\nvar RoutePolicyConstructor = RoutePolicyTest.Constructor = function () {\n var self = this;\n self.urlPrefixTypes = {};\n};\n\n_.extend(RoutePolicyConstructor.prototype, {\n\n urlPrefixMatches: function (urlPrefix, url) {\n return url.substr(0, urlPrefix.length) === urlPrefix;\n },\n\n checkType: function (type) {\n if (! _.contains(['network', 'static-online'], type))\n return 'the route type must be \"network\" or \"static-online\"';\n return null;\n },\n\n checkUrlPrefix: function (urlPrefix, type) {\n var self = this;\n\n if (urlPrefix.charAt(0) !== '/')\n return 'a route URL prefix must begin with a slash';\n\n if (urlPrefix === '/')\n return 'a route URL prefix cannot be /';\n\n var existingType = self.urlPrefixTypes[urlPrefix];\n if (existingType && existingType !== type)\n return 'the route URL prefix ' + urlPrefix + ' has already been declared to be of type ' + existingType;\n\n return null;\n },\n\n checkForConflictWithStatic: function (urlPrefix, type, _testManifest) {\n var self = this;\n if (type === 'static-online')\n return null;\n if (!Package.webapp || !Package.webapp.WebApp\n || !Package.webapp.WebApp.clientPrograms\n || !Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest) {\n // Hack: If we don't have a manifest, deal with it\n // gracefully. This lets us load livedata into a nodejs\n // environment that doesn't have a HTTP server (eg, a\n // command-line tool).\n return null;\n }\n var manifest = _testManifest ||\n Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest;\n var conflict = _.find(manifest, function (resource) {\n return (resource.type === 'static' &&\n resource.where === 'client' &&\n self.urlPrefixMatches(urlPrefix, resource.url));\n });\n if (conflict)\n return ('static resource ' + conflict.url + ' conflicts with ' +\n type + ' route ' + urlPrefix);\n else\n return null;\n },\n\n declare: function (urlPrefix, type) {\n var self = this;\n var problem = self.checkType(type) ||\n self.checkUrlPrefix(urlPrefix, type) ||\n self.checkForConflictWithStatic(urlPrefix, type);\n if (problem)\n throw new Error(problem);\n // TODO overlapping prefixes, e.g. /foo/ and /foo/bar/\n self.urlPrefixTypes[urlPrefix] = type;\n },\n\n isValidUrl: function (url) {\n return url.charAt(0) === '/';\n },\n\n classify: function (url) {\n var self = this;\n if (url.charAt(0) !== '/')\n throw new Error('url must be a relative URL: ' + url);\n var prefix = _.find(_.keys(self.urlPrefixTypes), function (_prefix) {\n return self.urlPrefixMatches(_prefix, url);\n });\n if (prefix)\n return self.urlPrefixTypes[prefix];\n else\n return null;\n },\n\n urlPrefixesFor: function (type) {\n var self = this;\n var prefixes = [];\n _.each(self.urlPrefixTypes, function (_type, _prefix) {\n if (_type === type)\n prefixes.push(_prefix);\n });\n return prefixes.sort();\n }\n});\n\nRoutePolicy = new RoutePolicyConstructor();\n"]} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/session.js b/web-app/.meteor/local/build/programs/server/packages/session.js deleted file mode 100644 index 1aa94b7..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/session.js +++ /dev/null @@ -1,14 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; - - - -/* Exports */ -if (typeof Package === 'undefined') Package = {}; -Package.session = {}; - -})(); - -//# sourceMappingURL=session.js.map diff --git a/web-app/.meteor/local/build/programs/server/packages/session.js.map b/web-app/.meteor/local/build/programs/server/packages/session.js.map deleted file mode 100644 index 993d84c..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/session.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":[],"names":[],"mappings":";;;;;","file":"/packages/session.js"} \ No newline at end of file diff --git a/web-app/.meteor/local/build/programs/server/packages/spacebars-compiler.js b/web-app/.meteor/local/build/programs/server/packages/spacebars-compiler.js deleted file mode 100644 index 0162b1b..0000000 --- a/web-app/.meteor/local/build/programs/server/packages/spacebars-compiler.js +++ /dev/null @@ -1,1190 +0,0 @@ -(function () { - -/* Imports */ -var Meteor = Package.meteor.Meteor; -var HTML = Package.htmljs.HTML; -var HTMLTools = Package['html-tools'].HTMLTools; -var BlazeTools = Package['blaze-tools'].BlazeTools; -var _ = Package.underscore._; - -/* Package-scope variables */ -var SpacebarsCompiler, TemplateTag; - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/spacebars-compiler/templatetag.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////// - // -SpacebarsCompiler = {}; // 1 - // 2 -// A TemplateTag is the result of parsing a single `{{...}}` tag. // 3 -// // 4 -// The `.type` of a TemplateTag is one of: // 5 -// // 6 -// - `"DOUBLE"` - `{{foo}}` // 7 -// - `"TRIPLE"` - `{{{foo}}}` // 8 -// - `"COMMENT"` - `{{! foo}}` // 9 -// - `"BLOCKCOMMENT" - `{{!-- foo--}}` // 10 -// - `"INCLUSION"` - `{{> foo}}` // 11 -// - `"BLOCKOPEN"` - `{{#foo}}` // 12 -// - `"BLOCKCLOSE"` - `{{/foo}}` // 13 -// - `"ELSE"` - `{{else}}` // 14 -// - `"ESCAPE"` - `{{|`, `{{{|`, `{{{{|` and so on // 15 -// // 16 -// Besides `type`, the mandatory properties of a TemplateTag are: // 17 -// // 18 -// - `path` - An array of one or more strings. The path of `{{foo.bar}}` // 19 -// is `["foo", "bar"]`. Applies to DOUBLE, TRIPLE, INCLUSION, BLOCKOPEN, // 20 -// and BLOCKCLOSE. // 21 -// // 22 -// - `args` - An array of zero or more argument specs. An argument spec // 23 -// is a two or three element array, consisting of a type, value, and // 24 -// optional keyword name. For example, the `args` of `{{foo "bar" x=3}}` // 25 -// are `[["STRING", "bar"], ["NUMBER", 3, "x"]]`. Applies to DOUBLE, // 26 -// TRIPLE, INCLUSION, and BLOCKOPEN. // 27 -// // 28 -// - `value` - A string of the comment's text. Applies to COMMENT and // 29 -// BLOCKCOMMENT. // 30 -// // 31 -// These additional are typically set during parsing: // 32 -// // 33 -// - `position` - The HTMLTools.TEMPLATE_TAG_POSITION specifying at what sort // 34 -// of site the TemplateTag was encountered (e.g. at element level or as // 35 -// part of an attribute value). Its absence implies // 36 -// TEMPLATE_TAG_POSITION.ELEMENT. // 37 -// // 38 -// - `content` and `elseContent` - When a BLOCKOPEN tag's contents are // 39 -// parsed, they are put here. `elseContent` will only be present if // 40 -// an `{{else}}` was found. // 41 - // 42 -var TEMPLATE_TAG_POSITION = HTMLTools.TEMPLATE_TAG_POSITION; // 43 - // 44 -TemplateTag = SpacebarsCompiler.TemplateTag = function () { // 45 - HTMLTools.TemplateTag.apply(this, arguments); // 46 -}; // 47 -TemplateTag.prototype = new HTMLTools.TemplateTag; // 48 -TemplateTag.prototype.constructorName = 'SpacebarsCompiler.TemplateTag'; // 49 - // 50 -var makeStacheTagStartRegex = function (r) { // 51 - return new RegExp(r.source + /(?![{>!#/])/.source, // 52 - r.ignoreCase ? 'i' : ''); // 53 -}; // 54 - // 55 -// "starts" regexes are used to see what type of template // 56 -// tag the parser is looking at. They must match a non-empty // 57 -// result, but not the interesting part of the tag. // 58 -var starts = { // 59 - ESCAPE: /^\{\{(?=\{*\|)/, // 60 - ELSE: makeStacheTagStartRegex(/^\{\{\s*else(?=[\s}])/i), // 61 - DOUBLE: makeStacheTagStartRegex(/^\{\{\s*(?!\s)/), // 62 - TRIPLE: makeStacheTagStartRegex(/^\{\{\{\s*(?!\s)/), // 63 - BLOCKCOMMENT: makeStacheTagStartRegex(/^\{\{\s*!--/), // 64 - COMMENT: makeStacheTagStartRegex(/^\{\{\s*!/), // 65 - INCLUSION: makeStacheTagStartRegex(/^\{\{\s*>\s*(?!\s)/), // 66 - BLOCKOPEN: makeStacheTagStartRegex(/^\{\{\s*#\s*(?!\s)/), // 67 - BLOCKCLOSE: makeStacheTagStartRegex(/^\{\{\s*\/\s*(?!\s)/) // 68 -}; // 69 - // 70 -var ends = { // 71 - DOUBLE: /^\s*\}\}/, // 72 - TRIPLE: /^\s*\}\}\}/ // 73 -}; // 74 - // 75 -// Parse a tag from the provided scanner or string. If the input // 76 -// doesn't start with `{{`, returns null. Otherwise, either succeeds // 77 -// and returns a SpacebarsCompiler.TemplateTag, or throws an error (using // 78 -// `scanner.fatal` if a scanner is provided). // 79 -TemplateTag.parse = function (scannerOrString) { // 80 - var scanner = scannerOrString; // 81 - if (typeof scanner === 'string') // 82 - scanner = new HTMLTools.Scanner(scannerOrString); // 83 - // 84 - if (! (scanner.peek() === '{' && // 85 - (scanner.rest()).slice(0, 2) === '{{')) // 86 - return null; // 87 - // 88 - var run = function (regex) { // 89 - // regex is assumed to start with `^` // 90 - var result = regex.exec(scanner.rest()); // 91 - if (! result) // 92 - return null; // 93 - var ret = result[0]; // 94 - scanner.pos += ret.length; // 95 - return ret; // 96 - }; // 97 - // 98 - var advance = function (amount) { // 99 - scanner.pos += amount; // 100 - }; // 101 - // 102 - var scanIdentifier = function (isFirstInPath) { // 103 - var id = BlazeTools.parseIdentifierName(scanner); // 104 - if (! id) // 105 - expected('IDENTIFIER'); // 106 - if (isFirstInPath && // 107 - (id === 'null' || id === 'true' || id === 'false')) // 108 - scanner.fatal("Can't use null, true, or false, as an identifier at start of path"); // 109 - // 110 - return id; // 111 - }; // 112 - // 113 - var scanPath = function () { // 114 - var segments = []; // 115 - // 116 - // handle initial `.`, `..`, `./`, `../`, `../..`, `../../`, etc // 117 - var dots; // 118 - if ((dots = run(/^[\.\/]+/))) { // 119 - var ancestorStr = '.'; // eg `../../..` maps to `....` // 120 - var endsWithSlash = /\/$/.test(dots); // 121 - // 122 - if (endsWithSlash) // 123 - dots = dots.slice(0, -1); // 124 - // 125 - _.each(dots.split('/'), function(dotClause, index) { // 126 - if (index === 0) { // 127 - if (dotClause !== '.' && dotClause !== '..') // 128 - expected("`.`, `..`, `./` or `../`"); // 129 - } else { // 130 - if (dotClause !== '..') // 131 - expected("`..` or `../`"); // 132 - } // 133 - // 134 - if (dotClause === '..') // 135 - ancestorStr += '.'; // 136 - }); // 137 - // 138 - segments.push(ancestorStr); // 139 - // 140 - if (!endsWithSlash) // 141 - return segments; // 142 - } // 143 - // 144 - while (true) { // 145 - // scan a path segment // 146 - // 147 - if (run(/^\[/)) { // 148 - var seg = run(/^[\s\S]*?\]/); // 149 - if (! seg) // 150 - error("Unterminated path segment"); // 151 - seg = seg.slice(0, -1); // 152 - if (! seg && ! segments.length) // 153 - error("Path can't start with empty string"); // 154 - segments.push(seg); // 155 - } else { // 156 - var id = scanIdentifier(! segments.length); // 157 - if (id === 'this') { // 158 - if (! segments.length) { // 159 - // initial `this` // 160 - segments.push('.'); // 161 - } else { // 162 - error("Can only use `this` at the beginning of a path.\nInstead of `foo.this` or `../this`, just write `foo` or `..`."); - } // 164 - } else { // 165 - segments.push(id); // 166 - } // 167 - } // 168 - // 169 - var sep = run(/^[\.\/]/); // 170 - if (! sep) // 171 - break; // 172 - } // 173 - // 174 - return segments; // 175 - }; // 176 - // 177 - // scan the keyword portion of a keyword argument // 178 - // (the "foo" portion in "foo=bar"). // 179 - // Result is either the keyword matched, or null // 180 - // if we're not at a keyword argument position. // 181 - var scanArgKeyword = function () { // 182 - var match = /^([^\{\}\(\)\>#=\s"'\[\]]+)\s*=\s*/.exec(scanner.rest()); // 183 - if (match) { // 184 - scanner.pos += match[0].length; // 185 - return match[1]; // 186 - } else { // 187 - return null; // 188 - } // 189 - }; // 190 - // 191 - // scan an argument; succeeds or errors. // 192 - // Result is an array of two or three items: // 193 - // type , value, and (indicating a keyword argument) // 194 - // keyword name. // 195 - var scanArg = function () { // 196 - var keyword = scanArgKeyword(); // null if not parsing a kwarg // 197 - var value = scanArgValue(); // 198 - return keyword ? value.concat(keyword) : value; // 199 - }; // 200 - // 201 - // scan an argument value (for keyword or positional arguments); // 202 - // succeeds or errors. Result is an array of type, value. // 203 - var scanArgValue = function () { // 204 - var startPos = scanner.pos; // 205 - var result; // 206 - if ((result = BlazeTools.parseNumber(scanner))) { // 207 - return ['NUMBER', result.value]; // 208 - } else if ((result = BlazeTools.parseStringLiteral(scanner))) { // 209 - return ['STRING', result.value]; // 210 - } else if (/^[\.\[]/.test(scanner.peek())) { // 211 - return ['PATH', scanPath()]; // 212 - } else if ((result = BlazeTools.parseIdentifierName(scanner))) { // 213 - var id = result; // 214 - if (id === 'null') { // 215 - return ['NULL', null]; // 216 - } else if (id === 'true' || id === 'false') { // 217 - return ['BOOLEAN', id === 'true']; // 218 - } else { // 219 - scanner.pos = startPos; // unconsume `id` // 220 - return ['PATH', scanPath()]; // 221 - } // 222 - } else { // 223 - expected('identifier, number, string, boolean, or null'); // 224 - } // 225 - }; // 226 - // 227 - var type; // 228 - // 229 - var error = function (msg) { // 230 - scanner.fatal(msg); // 231 - }; // 232 - // 233 - var expected = function (what) { // 234 - error('Expected ' + what); // 235 - }; // 236 - // 237 - // must do ESCAPE first, immediately followed by ELSE // 238 - // order of others doesn't matter // 239 - if (run(starts.ESCAPE)) type = 'ESCAPE'; // 240 - else if (run(starts.ELSE)) type = 'ELSE'; // 241 - else if (run(starts.DOUBLE)) type = 'DOUBLE'; // 242 - else if (run(starts.TRIPLE)) type = 'TRIPLE'; // 243 - else if (run(starts.BLOCKCOMMENT)) type = 'BLOCKCOMMENT'; // 244 - else if (run(starts.COMMENT)) type = 'COMMENT'; // 245 - else if (run(starts.INCLUSION)) type = 'INCLUSION'; // 246 - else if (run(starts.BLOCKOPEN)) type = 'BLOCKOPEN'; // 247 - else if (run(starts.BLOCKCLOSE)) type = 'BLOCKCLOSE'; // 248 - else // 249 - error('Unknown stache tag'); // 250 - // 251 - var tag = new TemplateTag; // 252 - tag.type = type; // 253 - // 254 - if (type === 'BLOCKCOMMENT') { // 255 - var result = run(/^[\s\S]*?--\s*?\}\}/); // 256 - if (! result) // 257 - error("Unclosed block comment"); // 258 - tag.value = result.slice(0, result.lastIndexOf('--')); // 259 - } else if (type === 'COMMENT') { // 260 - var result = run(/^[\s\S]*?\}\}/); // 261 - if (! result) // 262 - error("Unclosed comment"); // 263 - tag.value = result.slice(0, -2); // 264 - } else if (type === 'BLOCKCLOSE') { // 265 - tag.path = scanPath(); // 266 - if (! run(ends.DOUBLE)) // 267 - expected('`}}`'); // 268 - } else if (type === 'ELSE') { // 269 - if (! run(ends.DOUBLE)) // 270 - expected('`}}`'); // 271 - } else if (type === 'ESCAPE') { // 272 - var result = run(/^\{*\|/); // 273 - tag.value = '{{' + result.slice(0, -1); // 274 - } else { // 275 - // DOUBLE, TRIPLE, BLOCKOPEN, INCLUSION // 276 - tag.path = scanPath(); // 277 - tag.args = []; // 278 - var foundKwArg = false; // 279 - while (true) { // 280 - run(/^\s*/); // 281 - if (type === 'TRIPLE') { // 282 - if (run(ends.TRIPLE)) // 283 - break; // 284 - else if (scanner.peek() === '}') // 285 - expected('`}}}`'); // 286 - } else { // 287 - if (run(ends.DOUBLE)) // 288 - break; // 289 - else if (scanner.peek() === '}') // 290 - expected('`}}`'); // 291 - } // 292 - var newArg = scanArg(); // 293 - if (newArg.length === 3) { // 294 - foundKwArg = true; // 295 - } else { // 296 - if (foundKwArg) // 297 - error("Can't have a non-keyword argument after a keyword argument"); // 298 - } // 299 - tag.args.push(newArg); // 300 - // 301 - if (run(/^(?=[\s}])/) !== '') // 302 - expected('space'); // 303 - } // 304 - } // 305 - // 306 - return tag; // 307 -}; // 308 - // 309 -// Returns a SpacebarsCompiler.TemplateTag parsed from `scanner`, leaving scanner // 310 -// at its original position. // 311 -// // 312 -// An error will still be thrown if there is not a valid template tag at // 313 -// the current position. // 314 -TemplateTag.peek = function (scanner) { // 315 - var startPos = scanner.pos; // 316 - var result = TemplateTag.parse(scanner); // 317 - scanner.pos = startPos; // 318 - return result; // 319 -}; // 320 - // 321 -// Like `TemplateTag.parse`, but in the case of blocks, parse the complete // 322 -// `{{#foo}}...{{/foo}}` with `content` and possible `elseContent`, rather // 323 -// than just the BLOCKOPEN tag. // 324 -// // 325 -// In addition: // 326 -// // 327 -// - Throws an error if `{{else}}` or `{{/foo}}` tag is encountered. // 328 -// // 329 -// - Returns `null` for a COMMENT. (This case is distinguishable from // 330 -// parsing no tag by the fact that the scanner is advanced.) // 331 -// // 332 -// - Takes an HTMLTools.TEMPLATE_TAG_POSITION `position` and sets it as the // 333 -// TemplateTag's `.position` property. // 334 -// // 335 -// - Validates the tag's well-formedness and legality at in its position. // 336 -TemplateTag.parseCompleteTag = function (scannerOrString, position) { // 337 - var scanner = scannerOrString; // 338 - if (typeof scanner === 'string') // 339 - scanner = new HTMLTools.Scanner(scannerOrString); // 340 - // 341 - var startPos = scanner.pos; // for error messages // 342 - var result = TemplateTag.parse(scannerOrString); // 343 - if (! result) // 344 - return result; // 345 - // 346 - if (result.type === 'BLOCKCOMMENT') // 347 - return null; // 348 - // 349 - if (result.type === 'COMMENT') // 350 - return null; // 351 - // 352 - if (result.type === 'ELSE') // 353 - scanner.fatal("Unexpected {{else}}"); // 354 - // 355 - if (result.type === 'BLOCKCLOSE') // 356 - scanner.fatal("Unexpected closing template tag"); // 357 - // 358 - position = (position || TEMPLATE_TAG_POSITION.ELEMENT); // 359 - if (position !== TEMPLATE_TAG_POSITION.ELEMENT) // 360 - result.position = position; // 361 - // 362 - if (result.type === 'BLOCKOPEN') { // 363 - // parse block contents // 364 - // 365 - // Construct a string version of `.path` for comparing start and // 366 - // end tags. For example, `foo/[0]` was parsed into `["foo", "0"]` // 367 - // and now becomes `foo,0`. This form may also show up in error // 368 - // messages. // 369 - var blockName = result.path.join(','); // 370 - // 371 - var textMode = null; // 372 - if (blockName === 'markdown' || // 373 - position === TEMPLATE_TAG_POSITION.IN_RAWTEXT) { // 374 - textMode = HTML.TEXTMODE.STRING; // 375 - } else if (position === TEMPLATE_TAG_POSITION.IN_RCDATA || // 376 - position === TEMPLATE_TAG_POSITION.IN_ATTRIBUTE) { // 377 - textMode = HTML.TEXTMODE.RCDATA; // 378 - } // 379 - var parserOptions = { // 380 - getTemplateTag: TemplateTag.parseCompleteTag, // 381 - shouldStop: isAtBlockCloseOrElse, // 382 - textMode: textMode // 383 - }; // 384 - result.content = HTMLTools.parseFragment(scanner, parserOptions); // 385 - // 386 - if (scanner.rest().slice(0, 2) !== '{{') // 387 - scanner.fatal("Expected {{else}} or block close for " + blockName); // 388 - // 389 - var lastPos = scanner.pos; // save for error messages // 390 - var tmplTag = TemplateTag.parse(scanner); // {{else}} or {{/foo}} // 391 - // 392 - if (tmplTag.type === 'ELSE') { // 393 - // parse {{else}} and content up to close tag // 394 - result.elseContent = HTMLTools.parseFragment(scanner, parserOptions); // 395 - // 396 - if (scanner.rest().slice(0, 2) !== '{{') // 397 - scanner.fatal("Expected block close for " + blockName); // 398 - // 399 - lastPos = scanner.pos; // 400 - tmplTag = TemplateTag.parse(scanner); // 401 - } // 402 - // 403 - if (tmplTag.type === 'BLOCKCLOSE') { // 404 - var blockName2 = tmplTag.path.join(','); // 405 - if (blockName !== blockName2) { // 406 - scanner.pos = lastPos; // 407 - scanner.fatal('Expected tag to close ' + blockName + ', found ' + // 408 - blockName2); // 409 - } // 410 - } else { // 411 - scanner.pos = lastPos; // 412 - scanner.fatal('Expected tag to close ' + blockName + ', found ' + // 413 - tmplTag.type); // 414 - } // 415 - } // 416 - // 417 - var finalPos = scanner.pos; // 418 - scanner.pos = startPos; // 419 - validateTag(result, scanner); // 420 - scanner.pos = finalPos; // 421 - // 422 - return result; // 423 -}; // 424 - // 425 -var isAtBlockCloseOrElse = function (scanner) { // 426 - // Detect `{{else}}` or `{{/foo}}`. // 427 - // // 428 - // We do as much work ourselves before deferring to `TemplateTag.peek`, // 429 - // for efficiency (we're called for every input token) and to be // 430 - // less obtrusive, because `TemplateTag.peek` will throw an error if it // 431 - // sees `{{` followed by a malformed tag. // 432 - var rest, type; // 433 - return (scanner.peek() === '{' && // 434 - (rest = scanner.rest()).slice(0, 2) === '{{' && // 435 - /^\{\{\s*(\/|else\b)/.test(rest) && // 436 - (type = TemplateTag.peek(scanner).type) && // 437 - (type === 'BLOCKCLOSE' || type === 'ELSE')); // 438 -}; // 439 - // 440 -// Validate that `templateTag` is correctly formed and legal for its // 441 -// HTML position. Use `scanner` to report errors. On success, does // 442 -// nothing. // 443 -var validateTag = function (ttag, scanner) { // 444 - // 445 - if (ttag.type === 'INCLUSION' || ttag.type === 'BLOCKOPEN') { // 446 - var args = ttag.args; // 447 - if (args.length > 1 && args[0].length === 2 && args[0][0] !== 'PATH') { // 448 - // we have a positional argument that is not a PATH followed by // 449 - // other arguments // 450 - scanner.fatal("First argument must be a function, to be called on the rest of the arguments; found " + args[0][0]); - } // 452 - } // 453 - // 454 - var position = ttag.position || TEMPLATE_TAG_POSITION.ELEMENT; // 455 - if (position === TEMPLATE_TAG_POSITION.IN_ATTRIBUTE) { // 456 - if (ttag.type === 'DOUBLE' || ttag.type === 'ESCAPE') { // 457 - return; // 458 - } else if (ttag.type === 'BLOCKOPEN') { // 459 - var path = ttag.path; // 460 - var path0 = path[0]; // 461 - if (! (path.length === 1 && (path0 === 'if' || // 462 - path0 === 'unless' || // 463 - path0 === 'with' || // 464 - path0 === 'each'))) { // 465 - scanner.fatal("Custom block helpers are not allowed in an HTML attribute, only built-in ones like #each and #if"); - } // 467 - } else { // 468 - scanner.fatal(ttag.type + " template tag is not allowed in an HTML attribute"); // 469 - } // 470 - } else if (position === TEMPLATE_TAG_POSITION.IN_START_TAG) { // 471 - if (! (ttag.type === 'DOUBLE')) { // 472 - scanner.fatal("Reactive HTML attributes must either have a constant name or consist of a single {{helper}} providing a dictionary of names and values. A template tag of type " + ttag.type + " is not allowed here."); - } // 474 - if (scanner.peek() === '=') { // 475 - scanner.fatal("Template tags are not allowed in attribute names, only in attribute values or in the form of a single {{helper}} that evaluates to a dictionary of name=value pairs."); - } // 477 - } // 478 - // 479 -}; // 480 - // 481 -//////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/spacebars-compiler/optimizer.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////// - // -// Optimize parts of an HTMLjs tree into raw HTML strings when they don't // 1 -// contain template tags. // 2 - // 3 -var constant = function (value) { // 4 - return function () { return value; }; // 5 -}; // 6 - // 7 -var OPTIMIZABLE = { // 8 - NONE: 0, // 9 - PARTS: 1, // 10 - FULL: 2 // 11 -}; // 12 - // 13 -// We can only turn content into an HTML string if it contains no template // 14 -// tags and no "tricky" HTML tags. If we can optimize the entire content // 15 -// into a string, we return OPTIMIZABLE.FULL. If the we are given an // 16 -// unoptimizable node, we return OPTIMIZABLE.NONE. If we are given a tree // 17 -// that contains an unoptimizable node somewhere, we return OPTIMIZABLE.PARTS. // 18 -// // 19 -// For example, we always create SVG elements programmatically, since SVG // 20 -// doesn't have innerHTML. If we are given an SVG element, we return NONE. // 21 -// However, if we are given a big tree that contains SVG somewhere, we // 22 -// return PARTS so that the optimizer can descend into the tree and optimize // 23 -// other parts of it. // 24 -var CanOptimizeVisitor = HTML.Visitor.extend(); // 25 -CanOptimizeVisitor.def({ // 26 - visitNull: constant(OPTIMIZABLE.FULL), // 27 - visitPrimitive: constant(OPTIMIZABLE.FULL), // 28 - visitComment: constant(OPTIMIZABLE.FULL), // 29 - visitCharRef: constant(OPTIMIZABLE.FULL), // 30 - visitRaw: constant(OPTIMIZABLE.FULL), // 31 - visitObject: constant(OPTIMIZABLE.NONE), // 32 - visitFunction: constant(OPTIMIZABLE.NONE), // 33 - visitArray: function (x) { // 34 - for (var i = 0; i < x.length; i++) // 35 - if (this.visit(x[i]) !== OPTIMIZABLE.FULL) // 36 - return OPTIMIZABLE.PARTS; // 37 - return OPTIMIZABLE.FULL; // 38 - }, // 39 - visitTag: function (tag) { // 40 - var tagName = tag.tagName; // 41 - if (tagName === 'textarea') { // 42 - // optimizing into a TEXTAREA's RCDATA would require being a little // 43 - // more clever. // 44 - return OPTIMIZABLE.NONE; // 45 - } else if (! (HTML.isKnownElement(tagName) && // 46 - ! HTML.isKnownSVGElement(tagName))) { // 47 - // foreign elements like SVG can't be stringified for innerHTML. // 48 - return OPTIMIZABLE.NONE; // 49 - } else if (tagName === 'table') { // 50 - // Avoid ever producing HTML containing `...`, because the // 51 - // browser will insert a TBODY. If we just `createElement("table")` and // 52 - // `createElement("tr")`, on the other hand, no TBODY is necessary // 53 - // (assuming IE 8+). // 54 - return OPTIMIZABLE.NONE; // 55 - } // 56 - // 57 - var children = tag.children; // 58 - for (var i = 0; i < children.length; i++) // 59 - if (this.visit(children[i]) !== OPTIMIZABLE.FULL) // 60 - return OPTIMIZABLE.PARTS; // 61 - // 62 - if (this.visitAttributes(tag.attrs) !== OPTIMIZABLE.FULL) // 63 - return OPTIMIZABLE.PARTS; // 64 - // 65 - return OPTIMIZABLE.FULL; // 66 - }, // 67 - visitAttributes: function (attrs) { // 68 - if (attrs) { // 69 - var isArray = HTML.isArray(attrs); // 70 - for (var i = 0; i < (isArray ? attrs.length : 1); i++) { // 71 - var a = (isArray ? attrs[i] : attrs); // 72 - if ((typeof a !== 'object') || (a instanceof HTMLTools.TemplateTag)) // 73 - return OPTIMIZABLE.PARTS; // 74 - for (var k in a) // 75 - if (this.visit(a[k]) !== OPTIMIZABLE.FULL) // 76 - return OPTIMIZABLE.PARTS; // 77 - } // 78 - } // 79 - return OPTIMIZABLE.FULL; // 80 - } // 81 -}); // 82 - // 83 -var getOptimizability = function (content) { // 84 - return (new CanOptimizeVisitor).visit(content); // 85 -}; // 86 - // 87 -var toRaw = function (x) { // 88 - return HTML.Raw(HTML.toHTML(x)); // 89 -}; // 90 - // 91 -var TreeTransformer = HTML.TransformingVisitor.extend(); // 92 -TreeTransformer.def({ // 93 - visitAttributes: function (attrs/*, ...*/) { // 94 - // pass template tags through by default // 95 - if (attrs instanceof HTMLTools.TemplateTag) // 96 - return attrs; // 97 - // 98 - return HTML.TransformingVisitor.prototype.visitAttributes.apply( // 99 - this, arguments); // 100 - } // 101 -}); // 102 - // 103 -// Replace parts of the HTMLjs tree that have no template tags (or // 104 -// tricky HTML tags) with HTML.Raw objects containing raw HTML. // 105 -var OptimizingVisitor = TreeTransformer.extend(); // 106 -OptimizingVisitor.def({ // 107 - visitNull: toRaw, // 108 - visitPrimitive: toRaw, // 109 - visitComment: toRaw, // 110 - visitCharRef: toRaw, // 111 - visitArray: function (array) { // 112 - var optimizability = getOptimizability(array); // 113 - if (optimizability === OPTIMIZABLE.FULL) { // 114 - return toRaw(array); // 115 - } else if (optimizability === OPTIMIZABLE.PARTS) { // 116 - return TreeTransformer.prototype.visitArray.call(this, array); // 117 - } else { // 118 - return array; // 119 - } // 120 - }, // 121 - visitTag: function (tag) { // 122 - var optimizability = getOptimizability(tag); // 123 - if (optimizability === OPTIMIZABLE.FULL) { // 124 - return toRaw(tag); // 125 - } else if (optimizability === OPTIMIZABLE.PARTS) { // 126 - return TreeTransformer.prototype.visitTag.call(this, tag); // 127 - } else { // 128 - return tag; // 129 - } // 130 - }, // 131 - visitChildren: function (children) { // 132 - // don't optimize the children array into a Raw object! // 133 - return TreeTransformer.prototype.visitArray.call(this, children); // 134 - }, // 135 - visitAttributes: function (attrs) { // 136 - return attrs; // 137 - } // 138 -}); // 139 - // 140 -// Combine consecutive HTML.Raws. Remove empty ones. // 141 -var RawCompactingVisitor = TreeTransformer.extend(); // 142 -RawCompactingVisitor.def({ // 143 - visitArray: function (array) { // 144 - var result = []; // 145 - for (var i = 0; i < array.length; i++) { // 146 - var item = array[i]; // 147 - if ((item instanceof HTML.Raw) && // 148 - ((! item.value) || // 149 - (result.length && // 150 - (result[result.length - 1] instanceof HTML.Raw)))) { // 151 - // two cases: item is an empty Raw, or previous item is // 152 - // a Raw as well. In the latter case, replace the previous // 153 - // Raw with a longer one that includes the new Raw. // 154 - if (item.value) { // 155 - result[result.length - 1] = HTML.Raw( // 156 - result[result.length - 1].value + item.value); // 157 - } // 158 - } else { // 159 - result.push(item); // 160 - } // 161 - } // 162 - return result; // 163 - } // 164 -}); // 165 - // 166 -// Replace pointless Raws like `HTMl.Raw('foo')` that contain no special // 167 -// characters with simple strings. // 168 -var RawReplacingVisitor = TreeTransformer.extend(); // 169 -RawReplacingVisitor.def({ // 170 - visitRaw: function (raw) { // 171 - var html = raw.value; // 172 - if (html.indexOf('&') < 0 && html.indexOf('<') < 0) { // 173 - return html; // 174 - } else { // 175 - return raw; // 176 - } // 177 - } // 178 -}); // 179 - // 180 -SpacebarsCompiler.optimize = function (tree) { // 181 - tree = (new OptimizingVisitor).visit(tree); // 182 - tree = (new RawCompactingVisitor).visit(tree); // 183 - tree = (new RawReplacingVisitor).visit(tree); // 184 - return tree; // 185 -}; // 186 - // 187 -//////////////////////////////////////////////////////////////////////////////////////////// - -}).call(this); - - - - - - -(function () { - -//////////////////////////////////////////////////////////////////////////////////////////// -// // -// packages/spacebars-compiler/codegen.js // -// // -//////////////////////////////////////////////////////////////////////////////////////////// - // -// ============================================================ // 1 -// Code-generation of template tags // 2 - // 3 -// The `CodeGen` class currently has no instance state, but in theory // 4 -// it could be useful to track per-function state, like whether we // 5 -// need to emit `var self = this` or not. // 6 -var CodeGen = SpacebarsCompiler.CodeGen = function () {}; // 7 - // 8 -var builtInBlockHelpers = SpacebarsCompiler._builtInBlockHelpers = { // 9 - 'if': 'Blaze.If', // 10 - 'unless': 'Blaze.Unless', // 11 - 'with': 'Spacebars.With', // 12 - 'each': 'Blaze.Each' // 13 -}; // 14 - // 15 - // 16 -// Mapping of "macros" which, when preceded by `Template.`, expand // 17 -// to special code rather than following the lookup rules for dotted // 18 -// symbols. // 19 -var builtInTemplateMacros = { // 20 - // `view` is a local variable defined in the generated render // 21 - // function for the template in which `Template.contentBlock` or // 22 - // `Template.elseBlock` is invoked. // 23 - 'contentBlock': 'view.templateContentBlock', // 24 - 'elseBlock': 'view.templateElseBlock', // 25 - // 26 - // Confusingly, this makes `{{> Template.dynamic}}` an alias // 27 - // for `{{> __dynamic}}`, where "__dynamic" is the template that // 28 - // implements the dynamic template feature. // 29 - 'dynamic': 'Template.__dynamic', // 30 - // 31 - 'subscriptionsReady': 'view.templateInstance().subscriptionsReady()' // 32 -}; // 33 - // 34 -// A "reserved name" can't be used as a