(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.<String, Function>} 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: [<MethodInvoker for 'login'>]},                                                          // 110
  //    {wait: false, methods: [<MethodInvoker for 'foo'>,                                                             // 111
  //                            <MethodInvoker for 'bar'>]}]                                                           // 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