',
+ host: addressParts[0],
+ port: parseInt(addressParts[1], 10),
+ bson: server.s.bson,
+ connectionType: Connection
+ },
+ server.s.options,
+ this.options,
+
+ // force BSON serialization options
+ {
+ raw: false,
+ promoteLongs: true,
+ promoteValues: true,
+ promoteBuffers: true
+ }
+ )
+ );
+ }
+
+ connect() {
+ if (this.s.state !== STATE_CLOSED) {
+ return;
+ }
+
+ monitorServer(this);
+ }
+
+ requestCheck() {
+ if (INVALID_REQUEST_CHECK_STATES.has(this.s.state)) {
+ return;
+ }
+
+ const heartbeatFrequencyMS = this.options.heartbeatFrequencyMS;
+ const minHeartbeatFrequencyMS = this.options.minHeartbeatFrequencyMS;
+ const remainingTime = heartbeatFrequencyMS - calculateDurationInMs(this[kLastCheckTime]);
+ if (remainingTime > minHeartbeatFrequencyMS && this[kMonitorId]) {
+ clearTimeout(this[kMonitorId]);
+ rescheduleMonitoring(this, minHeartbeatFrequencyMS);
+ return;
+ }
+
+ if (this[kMonitorId]) {
+ clearTimeout(this[kMonitorId]);
+ }
+
+ monitorServer(this);
+ }
+
+ close() {
+ if (this.s.state === STATE_CLOSED || this.s.state === STATE_CLOSING) {
+ return;
+ }
+
+ stateTransition(this, STATE_CLOSING);
+ this[kCancellationToken].emit('cancel');
+ if (this[kMonitorId]) {
+ clearTimeout(this[kMonitorId]);
+ }
+
+ if (this[kConnection]) {
+ this[kConnection].destroy({ force: true });
+ }
+
+ this.emit('close');
+ stateTransition(this, STATE_CLOSED);
+ }
+}
+
+function checkServer(monitor, callback) {
+ if (monitor[kConnection] && monitor[kConnection].closed) {
+ monitor[kConnection] = undefined;
+ }
+
+ const start = process.hrtime();
+ monitor.emit('serverHeartbeatStarted', new ServerHeartbeatStartedEvent(monitor.address));
+
+ function failureHandler(err) {
+ monitor.emit(
+ 'serverHeartbeatFailed',
+ new ServerHeartbeatFailedEvent(calculateDurationInMs(start), err, monitor.address)
+ );
+
+ callback(err);
+ }
+
+ function successHandler(isMaster) {
+ monitor.emit(
+ 'serverHeartbeatSucceeded',
+ new ServerHeartbeatSucceededEvent(calculateDurationInMs(start), isMaster, monitor.address)
+ );
+
+ return callback(undefined, isMaster);
+ }
+
+ if (monitor[kConnection] != null) {
+ const connectTimeoutMS = monitor.options.connectTimeoutMS;
+ monitor[kConnection].command(
+ 'admin.$cmd',
+ { ismaster: true },
+ { socketTimeout: connectTimeoutMS },
+ (err, result) => {
+ if (err) {
+ failureHandler(err);
+ return;
+ }
+
+ successHandler(result.result);
+ }
+ );
+
+ return;
+ }
+
+ // connecting does an implicit `ismaster`
+ connect(monitor.connectOptions, monitor[kCancellationToken], (err, conn) => {
+ if (err) {
+ monitor[kConnection] = undefined;
+ failureHandler(err);
+ return;
+ }
+
+ if (monitor.s.state === STATE_CLOSING || monitor.s.state === STATE_CLOSED) {
+ conn.destroy({ force: true });
+ failureHandler(new MongoError('monitor was destroyed'));
+ return;
+ }
+
+ monitor[kConnection] = conn;
+ successHandler(conn.ismaster);
+ });
+}
+
+function monitorServer(monitor) {
+ stateTransition(monitor, STATE_MONITORING);
+
+ // TODO: the next line is a legacy event, remove in v4
+ process.nextTick(() => monitor.emit('monitoring', monitor[kServer]));
+
+ checkServer(monitor, e0 => {
+ if (e0 == null) {
+ rescheduleMonitoring(monitor);
+ return;
+ }
+
+ // otherwise an error occured on initial discovery, also bail
+ if (monitor[kServer].description.type === ServerType.Unknown) {
+ monitor.emit('resetServer', e0);
+ rescheduleMonitoring(monitor);
+ return;
+ }
+
+ // According to the SDAM specification's "Network error during server check" section, if
+ // an ismaster call fails we reset the server's pool. If a server was once connected,
+ // change its type to `Unknown` only after retrying once.
+ monitor.emit('resetConnectionPool');
+
+ checkServer(monitor, e1 => {
+ if (e1) {
+ monitor.emit('resetServer', e1);
+ }
+
+ rescheduleMonitoring(monitor);
+ });
+ });
+}
+
+function rescheduleMonitoring(monitor, ms) {
+ const heartbeatFrequencyMS = monitor.options.heartbeatFrequencyMS;
+ if (monitor.s.state === STATE_CLOSING || monitor.s.state === STATE_CLOSED) {
+ return;
+ }
+
+ stateTransition(monitor, STATE_IDLE);
+
+ monitor[kLastCheckTime] = process.hrtime();
+ monitor[kMonitorId] = setTimeout(() => {
+ monitor[kMonitorId] = undefined;
+ monitor.requestCheck();
+ }, ms || heartbeatFrequencyMS);
+}
+
+module.exports = {
+ Monitor
+};
diff --git a/node_modules/mongodb/lib/core/sdam/server.js b/node_modules/mongodb/lib/core/sdam/server.js
new file mode 100644
index 0000000..b371a03
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/server.js
@@ -0,0 +1,493 @@
+'use strict';
+const EventEmitter = require('events');
+const ConnectionPool = require('../../cmap/connection_pool').ConnectionPool;
+const CMAP_EVENT_NAMES = require('../../cmap/events').CMAP_EVENT_NAMES;
+const MongoError = require('../error').MongoError;
+const relayEvents = require('../utils').relayEvents;
+const BSON = require('../connection/utils').retrieveBSON();
+const Logger = require('../connection/logger');
+const ServerDescription = require('./server_description').ServerDescription;
+const ReadPreference = require('../topologies/read_preference');
+const Monitor = require('./monitor').Monitor;
+const MongoNetworkError = require('../error').MongoNetworkError;
+const collationNotSupported = require('../utils').collationNotSupported;
+const debugOptions = require('../connection/utils').debugOptions;
+const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
+const isNetworkTimeoutError = require('../error').isNetworkTimeoutError;
+const isNodeShuttingDownError = require('../error').isNodeShuttingDownError;
+const maxWireVersion = require('../utils').maxWireVersion;
+const makeStateMachine = require('../utils').makeStateMachine;
+const common = require('./common');
+
+// Used for filtering out fields for logging
+const DEBUG_FIELDS = [
+ 'reconnect',
+ 'reconnectTries',
+ 'reconnectInterval',
+ 'emitError',
+ 'cursorFactory',
+ 'host',
+ 'port',
+ 'size',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'noDelay',
+ 'connectionTimeout',
+ 'checkServerIdentity',
+ 'socketTimeout',
+ 'ssl',
+ 'ca',
+ 'crl',
+ 'cert',
+ 'key',
+ 'rejectUnauthorized',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'servername'
+];
+
+const STATE_CLOSING = common.STATE_CLOSING;
+const STATE_CLOSED = common.STATE_CLOSED;
+const STATE_CONNECTING = common.STATE_CONNECTING;
+const STATE_CONNECTED = common.STATE_CONNECTED;
+const stateTransition = makeStateMachine({
+ [STATE_CLOSED]: [STATE_CLOSED, STATE_CONNECTING],
+ [STATE_CONNECTING]: [STATE_CONNECTING, STATE_CLOSING, STATE_CONNECTED, STATE_CLOSED],
+ [STATE_CONNECTED]: [STATE_CONNECTED, STATE_CLOSING, STATE_CLOSED],
+ [STATE_CLOSING]: [STATE_CLOSING, STATE_CLOSED]
+});
+
+const kMonitor = Symbol('monitor');
+
+/**
+ *
+ * @fires Server#serverHeartbeatStarted
+ * @fires Server#serverHeartbeatSucceeded
+ * @fires Server#serverHeartbeatFailed
+ */
+class Server extends EventEmitter {
+ /**
+ * Create a server
+ *
+ * @param {ServerDescription} description
+ * @param {Object} options
+ */
+ constructor(description, options, topology) {
+ super();
+
+ this.s = {
+ // the server description
+ description,
+ // a saved copy of the incoming options
+ options,
+ // the server logger
+ logger: Logger('Server', options),
+ // the bson parser
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ]),
+ // the server state
+ state: STATE_CLOSED,
+ credentials: options.credentials,
+ topology
+ };
+
+ // create the connection pool
+ // NOTE: this used to happen in `connect`, we supported overriding pool options there
+ const addressParts = this.description.address.split(':');
+ const poolOptions = Object.assign(
+ { host: addressParts[0], port: parseInt(addressParts[1], 10), bson: this.s.bson },
+ options
+ );
+
+ this.s.pool = new ConnectionPool(poolOptions);
+ relayEvents(
+ this.s.pool,
+ this,
+ ['commandStarted', 'commandSucceeded', 'commandFailed'].concat(CMAP_EVENT_NAMES)
+ );
+
+ this.s.pool.on('clusterTimeReceived', clusterTime => {
+ this.clusterTime = clusterTime;
+ });
+
+ // create the monitor
+ this[kMonitor] = new Monitor(this, this.s.options);
+ relayEvents(this[kMonitor], this, [
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+
+ // legacy events
+ 'monitoring'
+ ]);
+
+ this[kMonitor].on('resetConnectionPool', () => {
+ this.s.pool.clear();
+ });
+
+ this[kMonitor].on('resetServer', error => markServerUnknown(this, error));
+ this[kMonitor].on('serverHeartbeatSucceeded', event => {
+ this.emit(
+ 'descriptionReceived',
+ new ServerDescription(this.description.address, event.reply, {
+ roundTripTime: calculateRoundTripTime(this.description.roundTripTime, event.duration)
+ })
+ );
+
+ if (this.s.state === STATE_CONNECTING) {
+ stateTransition(this, STATE_CONNECTED);
+ this.emit('connect', this);
+ }
+ });
+ }
+
+ get description() {
+ return this.s.description;
+ }
+
+ get name() {
+ return this.s.description.address;
+ }
+
+ get autoEncrypter() {
+ if (this.s.options && this.s.options.autoEncrypter) {
+ return this.s.options.autoEncrypter;
+ }
+ return null;
+ }
+
+ /**
+ * Initiate server connect
+ */
+ connect() {
+ if (this.s.state !== STATE_CLOSED) {
+ return;
+ }
+
+ stateTransition(this, STATE_CONNECTING);
+ this[kMonitor].connect();
+ }
+
+ /**
+ * Destroy the server connection
+ *
+ * @param {object} [options] Optional settings
+ * @param {Boolean} [options.force=false] Force destroy the pool
+ */
+ destroy(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = Object.assign({}, { force: false }, options);
+
+ if (this.s.state === STATE_CLOSED) {
+ if (typeof callback === 'function') {
+ callback();
+ }
+
+ return;
+ }
+
+ stateTransition(this, STATE_CLOSING);
+
+ this[kMonitor].close();
+ this.s.pool.close(options, err => {
+ stateTransition(this, STATE_CLOSED);
+ this.emit('closed');
+ if (typeof callback === 'function') {
+ callback(err);
+ }
+ });
+ }
+
+ /**
+ * Immediately schedule monitoring of this server. If there already an attempt being made
+ * this will be a no-op.
+ */
+ requestCheck() {
+ this[kMonitor].requestCheck();
+ }
+
+ /**
+ * Execute a command
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {object} [options] Optional settings
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.checkKeys=false] Specify if the bson parser should validate keys.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {Boolean} [options.fullResult=false] Return the full envelope instead of just the result document.
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ command(ns, cmd, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
+ callback(new MongoError('server is closed'));
+ return;
+ }
+
+ const error = basicReadValidations(this, options);
+ if (error) {
+ return callback(error);
+ }
+
+ // Clone the options
+ options = Object.assign({}, options, { wireProtocolCommand: false });
+
+ // Debug log
+ if (this.s.logger.isDebug()) {
+ this.s.logger.debug(
+ `executing command [${JSON.stringify({
+ ns,
+ cmd,
+ options: debugOptions(DEBUG_FIELDS, options)
+ })}] against ${this.name}`
+ );
+ }
+
+ // error if collation not supported
+ if (collationNotSupported(this, cmd)) {
+ callback(new MongoError(`server ${this.name} does not support collation`));
+ return;
+ }
+
+ this.s.pool.withConnection((err, conn, cb) => {
+ if (err) {
+ markServerUnknown(this, err);
+ return cb(err);
+ }
+
+ conn.command(ns, cmd, options, makeOperationHandler(this, options, cb));
+ }, callback);
+ }
+
+ /**
+ * Execute a query against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command document for the query
+ * @param {object} options Optional settings
+ * @param {function} callback
+ */
+ query(ns, cmd, cursorState, options, callback) {
+ if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
+ callback(new MongoError('server is closed'));
+ return;
+ }
+
+ this.s.pool.withConnection((err, conn, cb) => {
+ if (err) {
+ markServerUnknown(this, err);
+ return cb(err);
+ }
+
+ conn.query(ns, cmd, cursorState, options, makeOperationHandler(this, options, cb));
+ }, callback);
+ }
+
+ /**
+ * Execute a `getMore` against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cursorState State data associated with the cursor calling this method
+ * @param {object} options Optional settings
+ * @param {function} callback
+ */
+ getMore(ns, cursorState, batchSize, options, callback) {
+ if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
+ callback(new MongoError('server is closed'));
+ return;
+ }
+
+ this.s.pool.withConnection((err, conn, cb) => {
+ if (err) {
+ markServerUnknown(this, err);
+ return cb(err);
+ }
+
+ conn.getMore(ns, cursorState, batchSize, options, makeOperationHandler(this, options, cb));
+ }, callback);
+ }
+
+ /**
+ * Execute a `killCursors` command against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cursorState State data associated with the cursor calling this method
+ * @param {function} callback
+ */
+ killCursors(ns, cursorState, callback) {
+ if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
+ if (typeof callback === 'function') {
+ callback(new MongoError('server is closed'));
+ }
+
+ return;
+ }
+
+ this.s.pool.withConnection((err, conn, cb) => {
+ if (err) {
+ markServerUnknown(this, err);
+ return cb(err);
+ }
+
+ conn.killCursors(ns, cursorState, makeOperationHandler(this, null, cb));
+ }, callback);
+ }
+
+ /**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ insert(ns, ops, options, callback) {
+ executeWriteOperation({ server: this, op: 'insert', ns, ops }, options, callback);
+ }
+
+ /**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ update(ns, ops, options, callback) {
+ executeWriteOperation({ server: this, op: 'update', ns, ops }, options, callback);
+ }
+
+ /**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ remove(ns, ops, options, callback) {
+ executeWriteOperation({ server: this, op: 'remove', ns, ops }, options, callback);
+ }
+}
+
+Object.defineProperty(Server.prototype, 'clusterTime', {
+ get: function() {
+ return this.s.topology.clusterTime;
+ },
+ set: function(clusterTime) {
+ this.s.topology.clusterTime = clusterTime;
+ }
+});
+
+function calculateRoundTripTime(oldRtt, duration) {
+ const alpha = 0.2;
+ return alpha * duration + (1 - alpha) * oldRtt;
+}
+
+function basicReadValidations(server, options) {
+ if (options.readPreference && !(options.readPreference instanceof ReadPreference)) {
+ return new MongoError('readPreference must be an instance of ReadPreference');
+ }
+}
+
+function executeWriteOperation(args, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // TODO: once we drop Node 4, use destructuring either here or in arguments.
+ const server = args.server;
+ const op = args.op;
+ const ns = args.ns;
+ const ops = Array.isArray(args.ops) ? args.ops : [args.ops];
+
+ if (server.s.state === STATE_CLOSING || server.s.state === STATE_CLOSED) {
+ callback(new MongoError('server is closed'));
+ return;
+ }
+
+ if (collationNotSupported(server, options)) {
+ callback(new MongoError(`server ${server.name} does not support collation`));
+ return;
+ }
+
+ server.s.pool.withConnection((err, conn, cb) => {
+ if (err) {
+ markServerUnknown(server, err);
+ return cb(err);
+ }
+
+ conn[op](ns, ops, options, makeOperationHandler(server, options, cb));
+ }, callback);
+}
+
+function markServerUnknown(server, error) {
+ server.emit(
+ 'descriptionReceived',
+ new ServerDescription(server.description.address, null, { error })
+ );
+}
+
+function makeOperationHandler(server, options, callback) {
+ return function handleOperationResult(err, result) {
+ if (err) {
+ if (err instanceof MongoNetworkError) {
+ if (options && options.session) {
+ options.session.serverSession.isDirty = true;
+ }
+
+ if (!isNetworkTimeoutError(err)) {
+ markServerUnknown(server, err);
+ server.s.pool.clear();
+ }
+ } else if (isSDAMUnrecoverableError(err)) {
+ if (maxWireVersion(server) <= 7 || isNodeShuttingDownError(err)) {
+ server.s.pool.clear();
+ }
+
+ markServerUnknown(server, err);
+ process.nextTick(() => server.requestCheck());
+ }
+ }
+
+ callback(err, result);
+ };
+}
+
+module.exports = {
+ Server
+};
diff --git a/node_modules/mongodb/lib/core/sdam/server_description.js b/node_modules/mongodb/lib/core/sdam/server_description.js
new file mode 100644
index 0000000..1a26c06
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/server_description.js
@@ -0,0 +1,181 @@
+'use strict';
+
+const arrayStrictEqual = require('../utils').arrayStrictEqual;
+const tagsStrictEqual = require('../utils').tagsStrictEqual;
+const errorStrictEqual = require('../utils').errorStrictEqual;
+const ServerType = require('./common').ServerType;
+
+const WRITABLE_SERVER_TYPES = new Set([
+ ServerType.RSPrimary,
+ ServerType.Standalone,
+ ServerType.Mongos
+]);
+
+const DATA_BEARING_SERVER_TYPES = new Set([
+ ServerType.RSPrimary,
+ ServerType.RSSecondary,
+ ServerType.Mongos,
+ ServerType.Standalone
+]);
+
+const ISMASTER_FIELDS = [
+ 'minWireVersion',
+ 'maxWireVersion',
+ 'maxBsonObjectSize',
+ 'maxMessageSizeBytes',
+ 'maxWriteBatchSize',
+ 'compression',
+ 'me',
+ 'hosts',
+ 'passives',
+ 'arbiters',
+ 'tags',
+ 'setName',
+ 'setVersion',
+ 'electionId',
+ 'primary',
+ 'logicalSessionTimeoutMinutes',
+ 'saslSupportedMechs',
+ '__nodejs_mock_server__',
+ '$clusterTime'
+];
+
+/**
+ * The client's view of a single server, based on the most recent ismaster outcome.
+ *
+ * Internal type, not meant to be directly instantiated
+ */
+class ServerDescription {
+ /**
+ * Create a ServerDescription
+ * @param {String} address The address of the server
+ * @param {Object} [ismaster] An optional ismaster response for this server
+ * @param {Object} [options] Optional settings
+ * @param {Number} [options.roundTripTime] The round trip time to ping this server (in ms)
+ */
+ constructor(address, ismaster, options) {
+ options = options || {};
+ ismaster = Object.assign(
+ {
+ minWireVersion: 0,
+ maxWireVersion: 0,
+ hosts: [],
+ passives: [],
+ arbiters: [],
+ tags: []
+ },
+ ismaster
+ );
+
+ this.address = address;
+ this.error = options.error;
+ this.roundTripTime = options.roundTripTime || -1;
+ this.lastUpdateTime = Date.now();
+ this.lastWriteDate = ismaster.lastWrite ? ismaster.lastWrite.lastWriteDate : null;
+ this.opTime = ismaster.lastWrite ? ismaster.lastWrite.opTime : null;
+ this.type = parseServerType(ismaster);
+
+ // direct mappings
+ ISMASTER_FIELDS.forEach(field => {
+ if (typeof ismaster[field] !== 'undefined') this[field] = ismaster[field];
+ });
+
+ // normalize case for hosts
+ if (this.me) this.me = this.me.toLowerCase();
+ this.hosts = this.hosts.map(host => host.toLowerCase());
+ this.passives = this.passives.map(host => host.toLowerCase());
+ this.arbiters = this.arbiters.map(host => host.toLowerCase());
+ }
+
+ get allHosts() {
+ return this.hosts.concat(this.arbiters).concat(this.passives);
+ }
+
+ /**
+ * @return {Boolean} Is this server available for reads
+ */
+ get isReadable() {
+ return this.type === ServerType.RSSecondary || this.isWritable;
+ }
+
+ /**
+ * @return {Boolean} Is this server data bearing
+ */
+ get isDataBearing() {
+ return DATA_BEARING_SERVER_TYPES.has(this.type);
+ }
+
+ /**
+ * @return {Boolean} Is this server available for writes
+ */
+ get isWritable() {
+ return WRITABLE_SERVER_TYPES.has(this.type);
+ }
+
+ /**
+ * Determines if another `ServerDescription` is equal to this one per the rules defined
+ * in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
+ *
+ * @param {ServerDescription} other
+ * @return {Boolean}
+ */
+ equals(other) {
+ return (
+ other != null &&
+ errorStrictEqual(this.error, other.error) &&
+ this.type === other.type &&
+ this.minWireVersion === other.minWireVersion &&
+ this.me === other.me &&
+ arrayStrictEqual(this.hosts, other.hosts) &&
+ tagsStrictEqual(this.tags, other.tags) &&
+ this.setName === other.setName &&
+ this.setVersion === other.setVersion &&
+ (this.electionId
+ ? other.electionId && this.electionId.equals(other.electionId)
+ : this.electionId === other.electionId) &&
+ this.primary === other.primary &&
+ this.logicalSessionTimeoutMinutes === other.logicalSessionTimeoutMinutes
+ );
+ }
+}
+
+/**
+ * Parses an `ismaster` message and determines the server type
+ *
+ * @param {Object} ismaster The `ismaster` message to parse
+ * @return {ServerType}
+ */
+function parseServerType(ismaster) {
+ if (!ismaster || !ismaster.ok) {
+ return ServerType.Unknown;
+ }
+
+ if (ismaster.isreplicaset) {
+ return ServerType.RSGhost;
+ }
+
+ if (ismaster.msg && ismaster.msg === 'isdbgrid') {
+ return ServerType.Mongos;
+ }
+
+ if (ismaster.setName) {
+ if (ismaster.hidden) {
+ return ServerType.RSOther;
+ } else if (ismaster.ismaster) {
+ return ServerType.RSPrimary;
+ } else if (ismaster.secondary) {
+ return ServerType.RSSecondary;
+ } else if (ismaster.arbiterOnly) {
+ return ServerType.RSArbiter;
+ } else {
+ return ServerType.RSOther;
+ }
+ }
+
+ return ServerType.Standalone;
+}
+
+module.exports = {
+ ServerDescription,
+ parseServerType
+};
diff --git a/node_modules/mongodb/lib/core/sdam/server_selection.js b/node_modules/mongodb/lib/core/sdam/server_selection.js
new file mode 100644
index 0000000..5647f94
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/server_selection.js
@@ -0,0 +1,246 @@
+'use strict';
+const ServerType = require('./common').ServerType;
+const TopologyType = require('./common').TopologyType;
+const ReadPreference = require('../topologies/read_preference');
+const MongoError = require('../error').MongoError;
+
+// max staleness constants
+const IDLE_WRITE_PERIOD = 10000;
+const SMALLEST_MAX_STALENESS_SECONDS = 90;
+
+/**
+ * Returns a server selector that selects for writable servers
+ */
+function writableServerSelector() {
+ return function(topologyDescription, servers) {
+ return latencyWindowReducer(
+ topologyDescription,
+ servers.filter(s => s.isWritable)
+ );
+ };
+}
+
+/**
+ * Reduces the passed in array of servers by the rules of the "Max Staleness" specification
+ * found here: https://github.com/mongodb/specifications/blob/master/source/max-staleness/max-staleness.rst
+ *
+ * @param {ReadPreference} readPreference The read preference providing max staleness guidance
+ * @param {topologyDescription} topologyDescription The topology description
+ * @param {ServerDescription[]} servers The list of server descriptions to be reduced
+ * @return {ServerDescription[]} The list of servers that satisfy the requirements of max staleness
+ */
+function maxStalenessReducer(readPreference, topologyDescription, servers) {
+ if (readPreference.maxStalenessSeconds == null || readPreference.maxStalenessSeconds < 0) {
+ return servers;
+ }
+
+ const maxStaleness = readPreference.maxStalenessSeconds;
+ const maxStalenessVariance =
+ (topologyDescription.heartbeatFrequencyMS + IDLE_WRITE_PERIOD) / 1000;
+ if (maxStaleness < maxStalenessVariance) {
+ throw new MongoError(`maxStalenessSeconds must be at least ${maxStalenessVariance} seconds`);
+ }
+
+ if (maxStaleness < SMALLEST_MAX_STALENESS_SECONDS) {
+ throw new MongoError(
+ `maxStalenessSeconds must be at least ${SMALLEST_MAX_STALENESS_SECONDS} seconds`
+ );
+ }
+
+ if (topologyDescription.type === TopologyType.ReplicaSetWithPrimary) {
+ const primary = servers.filter(primaryFilter)[0];
+ return servers.reduce((result, server) => {
+ const stalenessMS =
+ server.lastUpdateTime -
+ server.lastWriteDate -
+ (primary.lastUpdateTime - primary.lastWriteDate) +
+ topologyDescription.heartbeatFrequencyMS;
+
+ const staleness = stalenessMS / 1000;
+ if (staleness <= readPreference.maxStalenessSeconds) result.push(server);
+ return result;
+ }, []);
+ } else if (topologyDescription.type === TopologyType.ReplicaSetNoPrimary) {
+ const sMax = servers.reduce((max, s) => (s.lastWriteDate > max.lastWriteDate ? s : max));
+ return servers.reduce((result, server) => {
+ const stalenessMS =
+ sMax.lastWriteDate - server.lastWriteDate + topologyDescription.heartbeatFrequencyMS;
+
+ const staleness = stalenessMS / 1000;
+ if (staleness <= readPreference.maxStalenessSeconds) result.push(server);
+ return result;
+ }, []);
+ }
+
+ return servers;
+}
+
+/**
+ * Determines whether a server's tags match a given set of tags
+ *
+ * @param {String[]} tagSet The requested tag set to match
+ * @param {String[]} serverTags The server's tags
+ */
+function tagSetMatch(tagSet, serverTags) {
+ const keys = Object.keys(tagSet);
+ const serverTagKeys = Object.keys(serverTags);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ if (serverTagKeys.indexOf(key) === -1 || serverTags[key] !== tagSet[key]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Reduces a set of server descriptions based on tags requested by the read preference
+ *
+ * @param {ReadPreference} readPreference The read preference providing the requested tags
+ * @param {ServerDescription[]} servers The list of server descriptions to reduce
+ * @return {ServerDescription[]} The list of servers matching the requested tags
+ */
+function tagSetReducer(readPreference, servers) {
+ if (
+ readPreference.tags == null ||
+ (Array.isArray(readPreference.tags) && readPreference.tags.length === 0)
+ ) {
+ return servers;
+ }
+
+ for (let i = 0; i < readPreference.tags.length; ++i) {
+ const tagSet = readPreference.tags[i];
+ const serversMatchingTagset = servers.reduce((matched, server) => {
+ if (tagSetMatch(tagSet, server.tags)) matched.push(server);
+ return matched;
+ }, []);
+
+ if (serversMatchingTagset.length) {
+ return serversMatchingTagset;
+ }
+ }
+
+ return [];
+}
+
+/**
+ * Reduces a list of servers to ensure they fall within an acceptable latency window. This is
+ * further specified in the "Server Selection" specification, found here:
+ * https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst
+ *
+ * @param {topologyDescription} topologyDescription The topology description
+ * @param {ServerDescription[]} servers The list of servers to reduce
+ * @returns {ServerDescription[]} The servers which fall within an acceptable latency window
+ */
+function latencyWindowReducer(topologyDescription, servers) {
+ const low = servers.reduce(
+ (min, server) => (min === -1 ? server.roundTripTime : Math.min(server.roundTripTime, min)),
+ -1
+ );
+
+ const high = low + topologyDescription.localThresholdMS;
+
+ return servers.reduce((result, server) => {
+ if (server.roundTripTime <= high && server.roundTripTime >= low) result.push(server);
+ return result;
+ }, []);
+}
+
+// filters
+function primaryFilter(server) {
+ return server.type === ServerType.RSPrimary;
+}
+
+function secondaryFilter(server) {
+ return server.type === ServerType.RSSecondary;
+}
+
+function nearestFilter(server) {
+ return server.type === ServerType.RSSecondary || server.type === ServerType.RSPrimary;
+}
+
+function knownFilter(server) {
+ return server.type !== ServerType.Unknown;
+}
+
+/**
+ * Returns a function which selects servers based on a provided read preference
+ *
+ * @param {ReadPreference} readPreference The read preference to select with
+ */
+function readPreferenceServerSelector(readPreference) {
+ if (!readPreference.isValid()) {
+ throw new TypeError('Invalid read preference specified');
+ }
+
+ return function(topologyDescription, servers) {
+ const commonWireVersion = topologyDescription.commonWireVersion;
+ if (
+ commonWireVersion &&
+ readPreference.minWireVersion &&
+ readPreference.minWireVersion > commonWireVersion
+ ) {
+ throw new MongoError(
+ `Minimum wire version '${readPreference.minWireVersion}' required, but found '${commonWireVersion}'`
+ );
+ }
+
+ if (
+ topologyDescription.type === TopologyType.Single ||
+ topologyDescription.type === TopologyType.Sharded
+ ) {
+ return latencyWindowReducer(topologyDescription, servers.filter(knownFilter));
+ }
+
+ if (readPreference.mode === ReadPreference.PRIMARY) {
+ return servers.filter(primaryFilter);
+ }
+
+ if (readPreference.mode === ReadPreference.SECONDARY) {
+ return latencyWindowReducer(
+ topologyDescription,
+ tagSetReducer(
+ readPreference,
+ maxStalenessReducer(readPreference, topologyDescription, servers)
+ )
+ ).filter(secondaryFilter);
+ } else if (readPreference.mode === ReadPreference.NEAREST) {
+ return latencyWindowReducer(
+ topologyDescription,
+ tagSetReducer(
+ readPreference,
+ maxStalenessReducer(readPreference, topologyDescription, servers)
+ )
+ ).filter(nearestFilter);
+ } else if (readPreference.mode === ReadPreference.SECONDARY_PREFERRED) {
+ const result = latencyWindowReducer(
+ topologyDescription,
+ tagSetReducer(
+ readPreference,
+ maxStalenessReducer(readPreference, topologyDescription, servers)
+ )
+ ).filter(secondaryFilter);
+
+ return result.length === 0 ? servers.filter(primaryFilter) : result;
+ } else if (readPreference.mode === ReadPreference.PRIMARY_PREFERRED) {
+ const result = servers.filter(primaryFilter);
+ if (result.length) {
+ return result;
+ }
+
+ return latencyWindowReducer(
+ topologyDescription,
+ tagSetReducer(
+ readPreference,
+ maxStalenessReducer(readPreference, topologyDescription, servers)
+ )
+ ).filter(secondaryFilter);
+ }
+ };
+}
+
+module.exports = {
+ writableServerSelector,
+ readPreferenceServerSelector
+};
diff --git a/node_modules/mongodb/lib/core/sdam/srv_polling.js b/node_modules/mongodb/lib/core/sdam/srv_polling.js
new file mode 100644
index 0000000..2c0b6ee
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/srv_polling.js
@@ -0,0 +1,135 @@
+'use strict';
+
+const Logger = require('../connection/logger');
+const EventEmitter = require('events').EventEmitter;
+const dns = require('dns');
+/**
+ * Determines whether a provided address matches the provided parent domain in order
+ * to avoid certain attack vectors.
+ *
+ * @param {String} srvAddress The address to check against a domain
+ * @param {String} parentDomain The domain to check the provided address against
+ * @return {Boolean} Whether the provided address matches the parent domain
+ */
+function matchesParentDomain(srvAddress, parentDomain) {
+ const regex = /^.*?\./;
+ const srv = `.${srvAddress.replace(regex, '')}`;
+ const parent = `.${parentDomain.replace(regex, '')}`;
+ return srv.endsWith(parent);
+}
+
+class SrvPollingEvent {
+ constructor(srvRecords) {
+ this.srvRecords = srvRecords;
+ }
+
+ addresses() {
+ return new Set(this.srvRecords.map(record => `${record.name}:${record.port}`));
+ }
+}
+
+class SrvPoller extends EventEmitter {
+ /**
+ * @param {object} options
+ * @param {string} options.srvHost
+ * @param {number} [options.heartbeatFrequencyMS]
+ * @param {function} [options.logger]
+ * @param {string} [options.loggerLevel]
+ */
+ constructor(options) {
+ super();
+
+ if (!options || !options.srvHost) {
+ throw new TypeError('options for SrvPoller must exist and include srvHost');
+ }
+
+ this.srvHost = options.srvHost;
+ this.rescanSrvIntervalMS = 60000;
+ this.heartbeatFrequencyMS = options.heartbeatFrequencyMS || 10000;
+ this.logger = Logger('srvPoller', options);
+
+ this.haMode = false;
+ this.generation = 0;
+
+ this._timeout = null;
+ }
+
+ get srvAddress() {
+ return `_mongodb._tcp.${this.srvHost}`;
+ }
+
+ get intervalMS() {
+ return this.haMode ? this.heartbeatFrequencyMS : this.rescanSrvIntervalMS;
+ }
+
+ start() {
+ if (!this._timeout) {
+ this.schedule();
+ }
+ }
+
+ stop() {
+ if (this._timeout) {
+ clearTimeout(this._timeout);
+ this.generation += 1;
+ this._timeout = null;
+ }
+ }
+
+ schedule() {
+ clearTimeout(this._timeout);
+ this._timeout = setTimeout(() => this._poll(), this.intervalMS);
+ }
+
+ success(srvRecords) {
+ this.haMode = false;
+ this.schedule();
+ this.emit('srvRecordDiscovery', new SrvPollingEvent(srvRecords));
+ }
+
+ failure(message, obj) {
+ this.logger.warn(message, obj);
+ this.haMode = true;
+ this.schedule();
+ }
+
+ parentDomainMismatch(srvRecord) {
+ this.logger.warn(
+ `parent domain mismatch on SRV record (${srvRecord.name}:${srvRecord.port})`,
+ srvRecord
+ );
+ }
+
+ _poll() {
+ const generation = this.generation;
+ dns.resolveSrv(this.srvAddress, (err, srvRecords) => {
+ if (generation !== this.generation) {
+ return;
+ }
+
+ if (err) {
+ this.failure('DNS error', err);
+ return;
+ }
+
+ const finalAddresses = [];
+ srvRecords.forEach(record => {
+ if (matchesParentDomain(record.name, this.srvHost)) {
+ finalAddresses.push(record);
+ } else {
+ this.parentDomainMismatch(record);
+ }
+ });
+
+ if (!finalAddresses.length) {
+ this.failure('No valid addresses found at host');
+ return;
+ }
+
+ this.success(finalAddresses);
+ });
+ }
+}
+
+module.exports.SrvPollingEvent = SrvPollingEvent;
+module.exports.SrvPoller = SrvPoller;
diff --git a/node_modules/mongodb/lib/core/sdam/topology.js b/node_modules/mongodb/lib/core/sdam/topology.js
new file mode 100644
index 0000000..cdd9a47
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/topology.js
@@ -0,0 +1,1131 @@
+'use strict';
+const Denque = require('denque');
+const EventEmitter = require('events');
+const ServerDescription = require('./server_description').ServerDescription;
+const ServerType = require('./common').ServerType;
+const TopologyDescription = require('./topology_description').TopologyDescription;
+const TopologyType = require('./common').TopologyType;
+const events = require('./events');
+const Server = require('./server').Server;
+const relayEvents = require('../utils').relayEvents;
+const ReadPreference = require('../topologies/read_preference');
+const isRetryableWritesSupported = require('../topologies/shared').isRetryableWritesSupported;
+const CoreCursor = require('../cursor').CoreCursor;
+const deprecate = require('util').deprecate;
+const BSON = require('../connection/utils').retrieveBSON();
+const createCompressionInfo = require('../topologies/shared').createCompressionInfo;
+const isRetryableError = require('../error').isRetryableError;
+const ClientSession = require('../sessions').ClientSession;
+const MongoError = require('../error').MongoError;
+const MongoServerSelectionError = require('../error').MongoServerSelectionError;
+const resolveClusterTime = require('../topologies/shared').resolveClusterTime;
+const SrvPoller = require('./srv_polling').SrvPoller;
+const getMMAPError = require('../topologies/shared').getMMAPError;
+const makeStateMachine = require('../utils').makeStateMachine;
+const eachAsync = require('../utils').eachAsync;
+const emitDeprecationWarning = require('../../utils').emitDeprecationWarning;
+const ServerSessionPool = require('../sessions').ServerSessionPool;
+const makeClientMetadata = require('../utils').makeClientMetadata;
+const CMAP_EVENT_NAMES = require('../../cmap/events').CMAP_EVENT_NAMES;
+
+const common = require('./common');
+const drainTimerQueue = common.drainTimerQueue;
+const clearAndRemoveTimerFrom = common.clearAndRemoveTimerFrom;
+
+const serverSelection = require('./server_selection');
+const readPreferenceServerSelector = serverSelection.readPreferenceServerSelector;
+const writableServerSelector = serverSelection.writableServerSelector;
+
+// Global state
+let globalTopologyCounter = 0;
+
+// events that we relay to the `Topology`
+const SERVER_RELAY_EVENTS = [
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed',
+
+ // NOTE: Legacy events
+ 'monitoring'
+].concat(CMAP_EVENT_NAMES);
+
+// all events we listen to from `Server` instances
+const LOCAL_SERVER_EVENTS = ['connect', 'descriptionReceived', 'close', 'ended'];
+
+const STATE_CLOSING = common.STATE_CLOSING;
+const STATE_CLOSED = common.STATE_CLOSED;
+const STATE_CONNECTING = common.STATE_CONNECTING;
+const STATE_CONNECTED = common.STATE_CONNECTED;
+const stateTransition = makeStateMachine({
+ [STATE_CLOSED]: [STATE_CLOSED, STATE_CONNECTING],
+ [STATE_CONNECTING]: [STATE_CONNECTING, STATE_CLOSING, STATE_CONNECTED, STATE_CLOSED],
+ [STATE_CONNECTED]: [STATE_CONNECTED, STATE_CLOSING, STATE_CLOSED],
+ [STATE_CLOSING]: [STATE_CLOSING, STATE_CLOSED]
+});
+
+const DEPRECATED_OPTIONS = new Set([
+ 'autoReconnect',
+ 'reconnectTries',
+ 'reconnectInterval',
+ 'bufferMaxEntries'
+]);
+
+const kCancelled = Symbol('cancelled');
+const kWaitQueue = Symbol('waitQueue');
+
+/**
+ * A container of server instances representing a connection to a MongoDB topology.
+ *
+ * @fires Topology#serverOpening
+ * @fires Topology#serverClosed
+ * @fires Topology#serverDescriptionChanged
+ * @fires Topology#topologyOpening
+ * @fires Topology#topologyClosed
+ * @fires Topology#topologyDescriptionChanged
+ * @fires Topology#serverHeartbeatStarted
+ * @fires Topology#serverHeartbeatSucceeded
+ * @fires Topology#serverHeartbeatFailed
+ */
+class Topology extends EventEmitter {
+ /**
+ * Create a topology
+ *
+ * @param {Array|String} [seedlist] a string list, or array of Server instances to connect to
+ * @param {Object} [options] Optional settings
+ * @param {Number} [options.localThresholdMS=15] The size of the latency window for selecting among multiple suitable servers
+ * @param {Number} [options.serverSelectionTimeoutMS=30000] How long to block for server selection before throwing an error
+ * @param {Number} [options.heartbeatFrequencyMS=10000] The frequency with which topology updates are scheduled
+ */
+ constructor(seedlist, options) {
+ super();
+ if (typeof options === 'undefined' && typeof seedlist !== 'string') {
+ options = seedlist;
+ seedlist = [];
+
+ // this is for legacy single server constructor support
+ if (options.host) {
+ seedlist.push({ host: options.host, port: options.port });
+ }
+ }
+
+ seedlist = seedlist || [];
+ if (typeof seedlist === 'string') {
+ seedlist = parseStringSeedlist(seedlist);
+ }
+
+ options = Object.assign({}, common.TOPOLOGY_DEFAULTS, options);
+ options = Object.freeze(
+ Object.assign(options, {
+ metadata: makeClientMetadata(options),
+ compression: { compressors: createCompressionInfo(options) }
+ })
+ );
+
+ DEPRECATED_OPTIONS.forEach(optionName => {
+ if (options[optionName]) {
+ emitDeprecationWarning(
+ `The option \`${optionName}\` is incompatible with the unified topology, please read more by visiting http://bit.ly/2D8WfT6`,
+ 'DeprecationWarning'
+ );
+ }
+ });
+
+ const topologyType = topologyTypeFromSeedlist(seedlist, options);
+ const topologyId = globalTopologyCounter++;
+ const serverDescriptions = seedlist.reduce((result, seed) => {
+ if (seed.domain_socket) seed.host = seed.domain_socket;
+ const address = seed.port ? `${seed.host}:${seed.port}` : `${seed.host}:27017`;
+ result.set(address, new ServerDescription(address));
+ return result;
+ }, new Map());
+
+ this[kWaitQueue] = new Denque();
+ this.s = {
+ // the id of this topology
+ id: topologyId,
+ // passed in options
+ options,
+ // initial seedlist of servers to connect to
+ seedlist: seedlist,
+ // initial state
+ state: STATE_CLOSED,
+ // the topology description
+ description: new TopologyDescription(
+ topologyType,
+ serverDescriptions,
+ options.replicaSet,
+ null,
+ null,
+ null,
+ options
+ ),
+ serverSelectionTimeoutMS: options.serverSelectionTimeoutMS,
+ heartbeatFrequencyMS: options.heartbeatFrequencyMS,
+ minHeartbeatFrequencyMS: options.minHeartbeatFrequencyMS,
+ // allow users to override the cursor factory
+ Cursor: options.cursorFactory || CoreCursor,
+ // the bson parser
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ]),
+ // a map of server instances to normalized addresses
+ servers: new Map(),
+ // Server Session Pool
+ sessionPool: new ServerSessionPool(this),
+ // Active client sessions
+ sessions: new Set(),
+ // Promise library
+ promiseLibrary: options.promiseLibrary || Promise,
+ credentials: options.credentials,
+ clusterTime: null,
+
+ // timer management
+ connectionTimers: new Set()
+ };
+
+ if (options.srvHost) {
+ this.s.srvPoller =
+ options.srvPoller ||
+ new SrvPoller({
+ heartbeatFrequencyMS: this.s.heartbeatFrequencyMS,
+ srvHost: options.srvHost, // TODO: GET THIS
+ logger: options.logger,
+ loggerLevel: options.loggerLevel
+ });
+ this.s.detectTopologyDescriptionChange = ev => {
+ const previousType = ev.previousDescription.type;
+ const newType = ev.newDescription.type;
+
+ if (previousType !== TopologyType.Sharded && newType === TopologyType.Sharded) {
+ this.s.handleSrvPolling = srvPollingHandler(this);
+ this.s.srvPoller.on('srvRecordDiscovery', this.s.handleSrvPolling);
+ this.s.srvPoller.start();
+ }
+ };
+
+ this.on('topologyDescriptionChanged', this.s.detectTopologyDescriptionChange);
+ }
+
+ // NOTE: remove this when NODE-1709 is resolved
+ this.setMaxListeners(Infinity);
+ }
+
+ /**
+ * @return A `TopologyDescription` for this topology
+ */
+ get description() {
+ return this.s.description;
+ }
+
+ get parserType() {
+ return BSON.native ? 'c++' : 'js';
+ }
+
+ /**
+ * Initiate server connect
+ *
+ * @param {Object} [options] Optional settings
+ * @param {Array} [options.auth=null] Array of auth options to apply on connect
+ * @param {function} [callback] An optional callback called once on the first connected server
+ */
+ connect(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ if (this.s.state === STATE_CONNECTED) {
+ if (typeof callback === 'function') {
+ callback();
+ }
+
+ return;
+ }
+
+ stateTransition(this, STATE_CONNECTING);
+
+ // emit SDAM monitoring events
+ this.emit('topologyOpening', new events.TopologyOpeningEvent(this.s.id));
+
+ // emit an event for the topology change
+ this.emit(
+ 'topologyDescriptionChanged',
+ new events.TopologyDescriptionChangedEvent(
+ this.s.id,
+ new TopologyDescription(TopologyType.Unknown), // initial is always Unknown
+ this.s.description
+ )
+ );
+
+ // connect all known servers, then attempt server selection to connect
+ connectServers(this, Array.from(this.s.description.servers.values()));
+
+ translateReadPreference(options);
+ const readPreference = options.readPreference || ReadPreference.primary;
+ this.selectServer(readPreferenceServerSelector(readPreference), options, err => {
+ if (err) {
+ this.close();
+
+ if (typeof callback === 'function') {
+ callback(err);
+ } else {
+ this.emit('error', err);
+ }
+
+ return;
+ }
+
+ stateTransition(this, STATE_CONNECTED);
+ this.emit('open', err, this);
+ this.emit('connect', this);
+
+ if (typeof callback === 'function') callback(err, this);
+ });
+ }
+
+ /**
+ * Close this topology
+ */
+ close(options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if (typeof options === 'boolean') {
+ options = { force: options };
+ }
+
+ options = options || {};
+ if (this.s.state === STATE_CLOSED || this.s.state === STATE_CLOSING) {
+ if (typeof callback === 'function') {
+ callback();
+ }
+
+ return;
+ }
+
+ stateTransition(this, STATE_CLOSING);
+
+ drainWaitQueue(this[kWaitQueue], new MongoError('Topology closed'));
+ drainTimerQueue(this.s.connectionTimers);
+
+ if (this.s.srvPoller) {
+ this.s.srvPoller.stop();
+ if (this.s.handleSrvPolling) {
+ this.s.srvPoller.removeListener('srvRecordDiscovery', this.s.handleSrvPolling);
+ delete this.s.handleSrvPolling;
+ }
+ }
+
+ if (this.s.detectTopologyDescriptionChange) {
+ this.removeListener('topologyDescriptionChanged', this.s.detectTopologyDescriptionChange);
+ delete this.s.detectTopologyDescriptionChange;
+ }
+
+ this.s.sessions.forEach(session => session.endSession());
+ this.s.sessionPool.endAllPooledSessions(() => {
+ eachAsync(
+ Array.from(this.s.servers.values()),
+ (server, cb) => destroyServer(server, this, options, cb),
+ err => {
+ this.s.servers.clear();
+
+ // emit an event for close
+ this.emit('topologyClosed', new events.TopologyClosedEvent(this.s.id));
+
+ stateTransition(this, STATE_CLOSED);
+ this.emit('close');
+
+ if (typeof callback === 'function') {
+ callback(err);
+ }
+ }
+ );
+ });
+ }
+
+ /**
+ * Selects a server according to the selection predicate provided
+ *
+ * @param {function} [selector] An optional selector to select servers by, defaults to a random selection within a latency window
+ * @param {object} [options] Optional settings related to server selection
+ * @param {number} [options.serverSelectionTimeoutMS] How long to block for server selection before throwing an error
+ * @param {function} callback The callback used to indicate success or failure
+ * @return {Server} An instance of a `Server` meeting the criteria of the predicate provided
+ */
+ selectServer(selector, options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ if (typeof selector !== 'function') {
+ options = selector;
+
+ let readPreference;
+ if (selector instanceof ReadPreference) {
+ readPreference = selector;
+ } else if (typeof selector === 'string') {
+ readPreference = new ReadPreference(selector);
+ } else {
+ translateReadPreference(options);
+ readPreference = options.readPreference || ReadPreference.primary;
+ }
+
+ selector = readPreferenceServerSelector(readPreference);
+ } else {
+ options = {};
+ }
+ }
+
+ options = Object.assign(
+ {},
+ { serverSelectionTimeoutMS: this.s.serverSelectionTimeoutMS },
+ options
+ );
+
+ const isSharded = this.description.type === TopologyType.Sharded;
+ const session = options.session;
+ const transaction = session && session.transaction;
+
+ if (isSharded && transaction && transaction.server) {
+ callback(undefined, transaction.server);
+ return;
+ }
+
+ // support server selection by options with readPreference
+ let serverSelector = selector;
+ if (typeof selector === 'object') {
+ const readPreference = selector.readPreference
+ ? selector.readPreference
+ : ReadPreference.primary;
+
+ serverSelector = readPreferenceServerSelector(readPreference);
+ }
+
+ const waitQueueMember = {
+ serverSelector,
+ transaction,
+ callback
+ };
+
+ const serverSelectionTimeoutMS = options.serverSelectionTimeoutMS;
+ if (serverSelectionTimeoutMS) {
+ waitQueueMember.timer = setTimeout(() => {
+ waitQueueMember[kCancelled] = true;
+ waitQueueMember.timer = undefined;
+ const timeoutError = new MongoServerSelectionError(
+ `Server selection timed out after ${serverSelectionTimeoutMS} ms`,
+ this.description
+ );
+
+ waitQueueMember.callback(timeoutError);
+ }, serverSelectionTimeoutMS);
+ }
+
+ this[kWaitQueue].push(waitQueueMember);
+ processWaitQueue(this);
+ }
+
+ // Sessions related methods
+
+ /**
+ * @return Whether the topology should initiate selection to determine session support
+ */
+ shouldCheckForSessionSupport() {
+ if (this.description.type === TopologyType.Single) {
+ return !this.description.hasKnownServers;
+ }
+
+ return !this.description.hasDataBearingServers;
+ }
+
+ /**
+ * @return Whether sessions are supported on the current topology
+ */
+ hasSessionSupport() {
+ return this.description.logicalSessionTimeoutMinutes != null;
+ }
+
+ /**
+ * Start a logical session
+ */
+ startSession(options, clientOptions) {
+ const session = new ClientSession(this, this.s.sessionPool, options, clientOptions);
+ session.once('ended', () => {
+ this.s.sessions.delete(session);
+ });
+
+ this.s.sessions.add(session);
+ return session;
+ }
+
+ /**
+ * Send endSessions command(s) with the given session ids
+ *
+ * @param {Array} sessions The sessions to end
+ * @param {function} [callback]
+ */
+ endSessions(sessions, callback) {
+ if (!Array.isArray(sessions)) {
+ sessions = [sessions];
+ }
+
+ this.command(
+ 'admin.$cmd',
+ { endSessions: sessions },
+ { readPreference: ReadPreference.primaryPreferred, noResponse: true },
+ () => {
+ // intentionally ignored, per spec
+ if (typeof callback === 'function') callback();
+ }
+ );
+ }
+
+ /**
+ * Update the internal TopologyDescription with a ServerDescription
+ *
+ * @param {object} serverDescription The server to update in the internal list of server descriptions
+ */
+ serverUpdateHandler(serverDescription) {
+ if (!this.s.description.hasServer(serverDescription.address)) {
+ return;
+ }
+
+ // these will be used for monitoring events later
+ const previousTopologyDescription = this.s.description;
+ const previousServerDescription = this.s.description.servers.get(serverDescription.address);
+
+ // Driver Sessions Spec: "Whenever a driver receives a cluster time from
+ // a server it MUST compare it to the current highest seen cluster time
+ // for the deployment. If the new cluster time is higher than the
+ // highest seen cluster time it MUST become the new highest seen cluster
+ // time. Two cluster times are compared using only the BsonTimestamp
+ // value of the clusterTime embedded field."
+ const clusterTime = serverDescription.$clusterTime;
+ if (clusterTime) {
+ resolveClusterTime(this, clusterTime);
+ }
+
+ // If we already know all the information contained in this updated description, then
+ // we don't need to emit SDAM events, but still need to update the description, in order
+ // to keep client-tracked attributes like last update time and round trip time up to date
+ const equalDescriptions =
+ previousServerDescription && previousServerDescription.equals(serverDescription);
+
+ // first update the TopologyDescription
+ this.s.description = this.s.description.update(serverDescription);
+ if (this.s.description.compatibilityError) {
+ this.emit('error', new MongoError(this.s.description.compatibilityError));
+ return;
+ }
+
+ // emit monitoring events for this change
+ if (!equalDescriptions) {
+ this.emit(
+ 'serverDescriptionChanged',
+ new events.ServerDescriptionChangedEvent(
+ this.s.id,
+ serverDescription.address,
+ previousServerDescription,
+ this.s.description.servers.get(serverDescription.address)
+ )
+ );
+ }
+
+ // update server list from updated descriptions
+ updateServers(this, serverDescription);
+
+ // attempt to resolve any outstanding server selection attempts
+ if (this[kWaitQueue].length > 0) {
+ processWaitQueue(this);
+ }
+
+ if (!equalDescriptions) {
+ this.emit(
+ 'topologyDescriptionChanged',
+ new events.TopologyDescriptionChangedEvent(
+ this.s.id,
+ previousTopologyDescription,
+ this.s.description
+ )
+ );
+ }
+ }
+
+ auth(credentials, callback) {
+ if (typeof credentials === 'function') (callback = credentials), (credentials = null);
+ if (typeof callback === 'function') callback(null, true);
+ }
+
+ logout(callback) {
+ if (typeof callback === 'function') callback(null, true);
+ }
+
+ // Basic operation support. Eventually this should be moved into command construction
+ // during the command refactor.
+
+ /**
+ * Insert one or more documents
+ *
+ * @param {String} ns The full qualified namespace for this operation
+ * @param {Array} ops An array of documents to insert
+ * @param {Boolean} [options.ordered=true] Execute in order or out of order
+ * @param {Object} [options.writeConcern] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ insert(ns, ops, options, callback) {
+ executeWriteOperation({ topology: this, op: 'insert', ns, ops }, options, callback);
+ }
+
+ /**
+ * Perform one or more update operations
+ *
+ * @param {string} ns The fully qualified namespace for this operation
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
+ * @param {ClientSession} [options.session] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ update(ns, ops, options, callback) {
+ executeWriteOperation({ topology: this, op: 'update', ns, ops }, options, callback);
+ }
+
+ /**
+ * Perform one or more remove operations
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ remove(ns, ops, options, callback) {
+ executeWriteOperation({ topology: this, op: 'remove', ns, ops }, options, callback);
+ }
+
+ /**
+ * Execute a command
+ *
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Connection} [options.connection] Specify connection object to execute command against
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ command(ns, cmd, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ translateReadPreference(options);
+ const readPreference = options.readPreference || ReadPreference.primary;
+
+ this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ const willRetryWrite =
+ !options.retrying &&
+ !!options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(this) &&
+ !options.session.inTransaction() &&
+ isWriteCommand(cmd);
+
+ const cb = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err)) {
+ return callback(err);
+ }
+
+ if (willRetryWrite) {
+ const newOptions = Object.assign({}, options, { retrying: true });
+ return this.command(ns, cmd, newOptions, callback);
+ }
+
+ return callback(err);
+ };
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ server.command(ns, cmd, options, cb);
+ });
+ }
+
+ /**
+ * Create a new cursor
+ *
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options] Options for the cursor
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {object} [options.topology] The internal topology of the created cursor
+ * @returns {Cursor}
+ */
+ cursor(ns, cmd, options) {
+ options = options || {};
+ const topology = options.topology || this;
+ const CursorClass = options.cursorFactory || this.s.Cursor;
+ translateReadPreference(options);
+
+ return new CursorClass(topology, ns, cmd, options);
+ }
+
+ get clientMetadata() {
+ return this.s.options.metadata;
+ }
+
+ isConnected() {
+ return this.s.state === STATE_CONNECTED;
+ }
+
+ isDestroyed() {
+ return this.s.state === STATE_CLOSED;
+ }
+
+ unref() {
+ console.log('not implemented: `unref`');
+ }
+
+ // NOTE: There are many places in code where we explicitly check the last isMaster
+ // to do feature support detection. This should be done any other way, but for
+ // now we will just return the first isMaster seen, which should suffice.
+ lastIsMaster() {
+ const serverDescriptions = Array.from(this.description.servers.values());
+ if (serverDescriptions.length === 0) return {};
+
+ const sd = serverDescriptions.filter(sd => sd.type !== ServerType.Unknown)[0];
+ const result = sd || { maxWireVersion: this.description.commonWireVersion };
+ return result;
+ }
+
+ get logicalSessionTimeoutMinutes() {
+ return this.description.logicalSessionTimeoutMinutes;
+ }
+
+ get bson() {
+ return this.s.bson;
+ }
+}
+
+Object.defineProperty(Topology.prototype, 'clusterTime', {
+ enumerable: true,
+ get: function() {
+ return this.s.clusterTime;
+ },
+ set: function(clusterTime) {
+ this.s.clusterTime = clusterTime;
+ }
+});
+
+// legacy aliases
+Topology.prototype.destroy = deprecate(
+ Topology.prototype.close,
+ 'destroy() is deprecated, please use close() instead'
+);
+
+const RETRYABLE_WRITE_OPERATIONS = ['findAndModify', 'insert', 'update', 'delete'];
+function isWriteCommand(command) {
+ return RETRYABLE_WRITE_OPERATIONS.some(op => command[op]);
+}
+
+/**
+ * Destroys a server, and removes all event listeners from the instance
+ *
+ * @param {Server} server
+ */
+function destroyServer(server, topology, options, callback) {
+ options = options || {};
+ LOCAL_SERVER_EVENTS.forEach(event => server.removeAllListeners(event));
+
+ server.destroy(options, () => {
+ topology.emit(
+ 'serverClosed',
+ new events.ServerClosedEvent(topology.s.id, server.description.address)
+ );
+
+ SERVER_RELAY_EVENTS.forEach(event => server.removeAllListeners(event));
+ if (typeof callback === 'function') {
+ callback();
+ }
+ });
+}
+
+/**
+ * Parses a basic seedlist in string form
+ *
+ * @param {string} seedlist The seedlist to parse
+ */
+function parseStringSeedlist(seedlist) {
+ return seedlist.split(',').map(seed => ({
+ host: seed.split(':')[0],
+ port: seed.split(':')[1] || 27017
+ }));
+}
+
+function topologyTypeFromSeedlist(seedlist, options) {
+ const replicaSet = options.replicaSet || options.setName || options.rs_name;
+ if (seedlist.length === 1 && !replicaSet) return TopologyType.Single;
+ if (replicaSet) return TopologyType.ReplicaSetNoPrimary;
+ return TopologyType.Unknown;
+}
+
+function randomSelection(array) {
+ return array[Math.floor(Math.random() * array.length)];
+}
+
+function createAndConnectServer(topology, serverDescription, connectDelay) {
+ topology.emit(
+ 'serverOpening',
+ new events.ServerOpeningEvent(topology.s.id, serverDescription.address)
+ );
+
+ const server = new Server(serverDescription, topology.s.options, topology);
+ relayEvents(server, topology, SERVER_RELAY_EVENTS);
+
+ server.on('descriptionReceived', topology.serverUpdateHandler.bind(topology));
+
+ if (connectDelay) {
+ const connectTimer = setTimeout(() => {
+ clearAndRemoveTimerFrom(connectTimer, topology.s.connectionTimers);
+ server.connect();
+ }, connectDelay);
+
+ topology.s.connectionTimers.add(connectTimer);
+ return server;
+ }
+
+ server.connect();
+ return server;
+}
+
+/**
+ * Create `Server` instances for all initially known servers, connect them, and assign
+ * them to the passed in `Topology`.
+ *
+ * @param {Topology} topology The topology responsible for the servers
+ * @param {ServerDescription[]} serverDescriptions A list of server descriptions to connect
+ */
+function connectServers(topology, serverDescriptions) {
+ topology.s.servers = serverDescriptions.reduce((servers, serverDescription) => {
+ const server = createAndConnectServer(topology, serverDescription);
+ servers.set(serverDescription.address, server);
+ return servers;
+ }, new Map());
+}
+
+function updateServers(topology, incomingServerDescription) {
+ // update the internal server's description
+ if (incomingServerDescription && topology.s.servers.has(incomingServerDescription.address)) {
+ const server = topology.s.servers.get(incomingServerDescription.address);
+ server.s.description = incomingServerDescription;
+ }
+
+ // add new servers for all descriptions we currently don't know about locally
+ for (const serverDescription of topology.description.servers.values()) {
+ if (!topology.s.servers.has(serverDescription.address)) {
+ const server = createAndConnectServer(topology, serverDescription);
+ topology.s.servers.set(serverDescription.address, server);
+ }
+ }
+
+ // for all servers no longer known, remove their descriptions and destroy their instances
+ for (const entry of topology.s.servers) {
+ const serverAddress = entry[0];
+ if (topology.description.hasServer(serverAddress)) {
+ continue;
+ }
+
+ const server = topology.s.servers.get(serverAddress);
+ topology.s.servers.delete(serverAddress);
+
+ // prepare server for garbage collection
+ destroyServer(server, topology);
+ }
+}
+
+function executeWriteOperation(args, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // TODO: once we drop Node 4, use destructuring either here or in arguments.
+ const topology = args.topology;
+ const op = args.op;
+ const ns = args.ns;
+ const ops = args.ops;
+
+ const willRetryWrite =
+ !args.retrying &&
+ !!options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(topology) &&
+ !options.session.inTransaction();
+
+ topology.selectServer(writableServerSelector(), options, (err, server) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ const handler = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err)) {
+ err = getMMAPError(err);
+ return callback(err);
+ }
+
+ if (willRetryWrite) {
+ const newArgs = Object.assign({}, args, { retrying: true });
+ return executeWriteOperation(newArgs, options, callback);
+ }
+
+ return callback(err);
+ };
+
+ if (callback.operationId) {
+ handler.operationId = callback.operationId;
+ }
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ // execute the write operation
+ server[op](ns, ops, options, handler);
+ });
+}
+
+function translateReadPreference(options) {
+ if (options.readPreference == null) {
+ return;
+ }
+
+ let r = options.readPreference;
+ if (typeof r === 'string') {
+ options.readPreference = new ReadPreference(r);
+ } else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
+ const mode = r.mode || r.preference;
+ if (mode && typeof mode === 'string') {
+ options.readPreference = new ReadPreference(mode, r.tags, {
+ maxStalenessSeconds: r.maxStalenessSeconds
+ });
+ }
+ } else if (!(r instanceof ReadPreference)) {
+ throw new TypeError('Invalid read preference: ' + r);
+ }
+
+ return options;
+}
+
+function srvPollingHandler(topology) {
+ return function handleSrvPolling(ev) {
+ const previousTopologyDescription = topology.s.description;
+ topology.s.description = topology.s.description.updateFromSrvPollingEvent(ev);
+ if (topology.s.description === previousTopologyDescription) {
+ // Nothing changed, so return
+ return;
+ }
+
+ updateServers(topology);
+
+ topology.emit(
+ 'topologyDescriptionChanged',
+ new events.TopologyDescriptionChangedEvent(
+ topology.s.id,
+ previousTopologyDescription,
+ topology.s.description
+ )
+ );
+ };
+}
+
+function drainWaitQueue(queue, err) {
+ while (queue.length) {
+ const waitQueueMember = queue.shift();
+ clearTimeout(waitQueueMember.timer);
+ if (!waitQueueMember[kCancelled]) {
+ waitQueueMember.callback(err);
+ }
+ }
+}
+
+function processWaitQueue(topology) {
+ if (topology.s.state === STATE_CLOSED) {
+ drainWaitQueue(topology[kWaitQueue], new MongoError('Topology is closed, please connect'));
+ return;
+ }
+
+ const serverDescriptions = Array.from(topology.description.servers.values());
+ const membersToProcess = topology[kWaitQueue].length;
+ for (let i = 0; i < membersToProcess && topology[kWaitQueue].length; ++i) {
+ const waitQueueMember = topology[kWaitQueue].shift();
+ if (waitQueueMember[kCancelled]) {
+ continue;
+ }
+
+ let selectedDescriptions;
+ try {
+ const serverSelector = waitQueueMember.serverSelector;
+ selectedDescriptions = serverSelector
+ ? serverSelector(topology.description, serverDescriptions)
+ : serverDescriptions;
+ } catch (e) {
+ clearTimeout(waitQueueMember.timer);
+ waitQueueMember.callback(e);
+ continue;
+ }
+
+ if (selectedDescriptions.length === 0) {
+ topology[kWaitQueue].push(waitQueueMember);
+ continue;
+ }
+
+ const selectedServerDescription = randomSelection(selectedDescriptions);
+ const selectedServer = topology.s.servers.get(selectedServerDescription.address);
+ const transaction = waitQueueMember.transaction;
+ const isSharded = topology.description.type === TopologyType.Sharded;
+ if (isSharded && transaction && transaction.isActive) {
+ transaction.pinServer(selectedServer);
+ }
+
+ clearTimeout(waitQueueMember.timer);
+ waitQueueMember.callback(undefined, selectedServer);
+ }
+
+ if (topology[kWaitQueue].length > 0) {
+ // ensure all server monitors attempt monitoring soon
+ topology.s.servers.forEach(server => process.nextTick(() => server.requestCheck()));
+ }
+}
+
+/**
+ * A server opening SDAM monitoring event
+ *
+ * @event Topology#serverOpening
+ * @type {ServerOpeningEvent}
+ */
+
+/**
+ * A server closed SDAM monitoring event
+ *
+ * @event Topology#serverClosed
+ * @type {ServerClosedEvent}
+ */
+
+/**
+ * A server description SDAM change monitoring event
+ *
+ * @event Topology#serverDescriptionChanged
+ * @type {ServerDescriptionChangedEvent}
+ */
+
+/**
+ * A topology open SDAM event
+ *
+ * @event Topology#topologyOpening
+ * @type {TopologyOpeningEvent}
+ */
+
+/**
+ * A topology closed SDAM event
+ *
+ * @event Topology#topologyClosed
+ * @type {TopologyClosedEvent}
+ */
+
+/**
+ * A topology structure SDAM change event
+ *
+ * @event Topology#topologyDescriptionChanged
+ * @type {TopologyDescriptionChangedEvent}
+ */
+
+/**
+ * A topology serverHeartbeatStarted SDAM event
+ *
+ * @event Topology#serverHeartbeatStarted
+ * @type {ServerHeartbeatStartedEvent}
+ */
+
+/**
+ * A topology serverHeartbeatFailed SDAM event
+ *
+ * @event Topology#serverHeartbeatFailed
+ * @type {ServerHearbeatFailedEvent}
+ */
+
+/**
+ * A topology serverHeartbeatSucceeded SDAM change event
+ *
+ * @event Topology#serverHeartbeatSucceeded
+ * @type {ServerHeartbeatSucceededEvent}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event Topology#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event Topology#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event Topology#commandFailed
+ * @type {object}
+ */
+
+module.exports = {
+ Topology
+};
diff --git a/node_modules/mongodb/lib/core/sdam/topology_description.js b/node_modules/mongodb/lib/core/sdam/topology_description.js
new file mode 100644
index 0000000..d1beb22
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sdam/topology_description.js
@@ -0,0 +1,423 @@
+'use strict';
+const ServerType = require('./common').ServerType;
+const ServerDescription = require('./server_description').ServerDescription;
+const WIRE_CONSTANTS = require('../wireprotocol/constants');
+const TopologyType = require('./common').TopologyType;
+
+// contstants related to compatability checks
+const MIN_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_SERVER_VERSION;
+const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION;
+const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION;
+const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION;
+
+// Representation of a deployment of servers
+class TopologyDescription {
+ /**
+ * Create a TopologyDescription
+ *
+ * @param {string} topologyType
+ * @param {Map} serverDescriptions the a map of address to ServerDescription
+ * @param {string} setName
+ * @param {number} maxSetVersion
+ * @param {ObjectId} maxElectionId
+ */
+ constructor(
+ topologyType,
+ serverDescriptions,
+ setName,
+ maxSetVersion,
+ maxElectionId,
+ commonWireVersion,
+ options
+ ) {
+ options = options || {};
+
+ // TODO: consider assigning all these values to a temporary value `s` which
+ // we use `Object.freeze` on, ensuring the internal state of this type
+ // is immutable.
+ this.type = topologyType || TopologyType.Unknown;
+ this.setName = setName || null;
+ this.maxSetVersion = maxSetVersion || null;
+ this.maxElectionId = maxElectionId || null;
+ this.servers = serverDescriptions || new Map();
+ this.stale = false;
+ this.compatible = true;
+ this.compatibilityError = null;
+ this.logicalSessionTimeoutMinutes = null;
+ this.heartbeatFrequencyMS = options.heartbeatFrequencyMS || 0;
+ this.localThresholdMS = options.localThresholdMS || 0;
+ this.commonWireVersion = commonWireVersion || null;
+
+ // save this locally, but don't display when printing the instance out
+ Object.defineProperty(this, 'options', { value: options, enumberable: false });
+
+ // determine server compatibility
+ for (const serverDescription of this.servers.values()) {
+ if (serverDescription.type === ServerType.Unknown) continue;
+
+ if (serverDescription.minWireVersion > MAX_SUPPORTED_WIRE_VERSION) {
+ this.compatible = false;
+ this.compatibilityError = `Server at ${serverDescription.address} requires wire version ${serverDescription.minWireVersion}, but this version of the driver only supports up to ${MAX_SUPPORTED_WIRE_VERSION} (MongoDB ${MAX_SUPPORTED_SERVER_VERSION})`;
+ }
+
+ if (serverDescription.maxWireVersion < MIN_SUPPORTED_WIRE_VERSION) {
+ this.compatible = false;
+ this.compatibilityError = `Server at ${serverDescription.address} reports wire version ${serverDescription.maxWireVersion}, but this version of the driver requires at least ${MIN_SUPPORTED_WIRE_VERSION} (MongoDB ${MIN_SUPPORTED_SERVER_VERSION}).`;
+ break;
+ }
+ }
+
+ // Whenever a client updates the TopologyDescription from an ismaster response, it MUST set
+ // TopologyDescription.logicalSessionTimeoutMinutes to the smallest logicalSessionTimeoutMinutes
+ // value among ServerDescriptions of all data-bearing server types. If any have a null
+ // logicalSessionTimeoutMinutes, then TopologyDescription.logicalSessionTimeoutMinutes MUST be
+ // set to null.
+ const readableServers = Array.from(this.servers.values()).filter(s => s.isReadable);
+ this.logicalSessionTimeoutMinutes = readableServers.reduce((result, server) => {
+ if (server.logicalSessionTimeoutMinutes == null) return null;
+ if (result == null) return server.logicalSessionTimeoutMinutes;
+ return Math.min(result, server.logicalSessionTimeoutMinutes);
+ }, null);
+ }
+
+ /**
+ * Returns a new TopologyDescription based on the SrvPollingEvent
+ * @param {SrvPollingEvent} ev The event
+ */
+ updateFromSrvPollingEvent(ev) {
+ const newAddresses = ev.addresses();
+ const serverDescriptions = new Map(this.servers);
+ for (const server of this.servers) {
+ if (newAddresses.has(server[0])) {
+ newAddresses.delete(server[0]);
+ } else {
+ serverDescriptions.delete(server[0]);
+ }
+ }
+
+ if (serverDescriptions.size === this.servers.size && newAddresses.size === 0) {
+ return this;
+ }
+
+ for (const address of newAddresses) {
+ serverDescriptions.set(address, new ServerDescription(address));
+ }
+
+ return new TopologyDescription(
+ this.type,
+ serverDescriptions,
+ this.setName,
+ this.maxSetVersion,
+ this.maxElectionId,
+ this.commonWireVersion,
+ this.options,
+ null
+ );
+ }
+
+ /**
+ * Returns a copy of this description updated with a given ServerDescription
+ *
+ * @param {ServerDescription} serverDescription
+ */
+ update(serverDescription) {
+ const address = serverDescription.address;
+ // NOTE: there are a number of prime targets for refactoring here
+ // once we support destructuring assignments
+
+ // potentially mutated values
+ let topologyType = this.type;
+ let setName = this.setName;
+ let maxSetVersion = this.maxSetVersion;
+ let maxElectionId = this.maxElectionId;
+ let commonWireVersion = this.commonWireVersion;
+
+ const serverType = serverDescription.type;
+ let serverDescriptions = new Map(this.servers);
+
+ // update common wire version
+ if (serverDescription.maxWireVersion !== 0) {
+ if (commonWireVersion == null) {
+ commonWireVersion = serverDescription.maxWireVersion;
+ } else {
+ commonWireVersion = Math.min(commonWireVersion, serverDescription.maxWireVersion);
+ }
+ }
+
+ // update the actual server description
+ serverDescriptions.set(address, serverDescription);
+
+ if (topologyType === TopologyType.Single) {
+ // once we are defined as single, that never changes
+ return new TopologyDescription(
+ TopologyType.Single,
+ serverDescriptions,
+ setName,
+ maxSetVersion,
+ maxElectionId,
+ commonWireVersion,
+ this.options
+ );
+ }
+
+ if (topologyType === TopologyType.Unknown) {
+ if (serverType === ServerType.Standalone) {
+ serverDescriptions.delete(address);
+ } else {
+ topologyType = topologyTypeForServerType(serverType);
+ }
+ }
+
+ if (topologyType === TopologyType.Sharded) {
+ if ([ServerType.Mongos, ServerType.Unknown].indexOf(serverType) === -1) {
+ serverDescriptions.delete(address);
+ }
+ }
+
+ if (topologyType === TopologyType.ReplicaSetNoPrimary) {
+ if ([ServerType.Standalone, ServerType.Mongos].indexOf(serverType) >= 0) {
+ serverDescriptions.delete(address);
+ }
+
+ if (serverType === ServerType.RSPrimary) {
+ const result = updateRsFromPrimary(
+ serverDescriptions,
+ setName,
+ serverDescription,
+ maxSetVersion,
+ maxElectionId
+ );
+
+ (topologyType = result[0]),
+ (setName = result[1]),
+ (maxSetVersion = result[2]),
+ (maxElectionId = result[3]);
+ } else if (
+ [ServerType.RSSecondary, ServerType.RSArbiter, ServerType.RSOther].indexOf(serverType) >= 0
+ ) {
+ const result = updateRsNoPrimaryFromMember(serverDescriptions, setName, serverDescription);
+ (topologyType = result[0]), (setName = result[1]);
+ }
+ }
+
+ if (topologyType === TopologyType.ReplicaSetWithPrimary) {
+ if ([ServerType.Standalone, ServerType.Mongos].indexOf(serverType) >= 0) {
+ serverDescriptions.delete(address);
+ topologyType = checkHasPrimary(serverDescriptions);
+ } else if (serverType === ServerType.RSPrimary) {
+ const result = updateRsFromPrimary(
+ serverDescriptions,
+ setName,
+ serverDescription,
+ maxSetVersion,
+ maxElectionId
+ );
+
+ (topologyType = result[0]),
+ (setName = result[1]),
+ (maxSetVersion = result[2]),
+ (maxElectionId = result[3]);
+ } else if (
+ [ServerType.RSSecondary, ServerType.RSArbiter, ServerType.RSOther].indexOf(serverType) >= 0
+ ) {
+ topologyType = updateRsWithPrimaryFromMember(
+ serverDescriptions,
+ setName,
+ serverDescription
+ );
+ } else {
+ topologyType = checkHasPrimary(serverDescriptions);
+ }
+ }
+
+ return new TopologyDescription(
+ topologyType,
+ serverDescriptions,
+ setName,
+ maxSetVersion,
+ maxElectionId,
+ commonWireVersion,
+ this.options
+ );
+ }
+
+ get error() {
+ const descriptionsWithError = Array.from(this.servers.values()).filter(sd => sd.error);
+ if (descriptionsWithError.length > 0) {
+ return descriptionsWithError[0].error;
+ }
+ }
+
+ /**
+ * Determines if the topology description has any known servers
+ */
+ get hasKnownServers() {
+ return Array.from(this.servers.values()).some(sd => sd.type !== ServerType.Unknown);
+ }
+
+ /**
+ * Determines if this topology description has a data-bearing server available.
+ */
+ get hasDataBearingServers() {
+ return Array.from(this.servers.values()).some(sd => sd.isDataBearing);
+ }
+
+ /**
+ * Determines if the topology has a definition for the provided address
+ *
+ * @param {String} address
+ * @return {Boolean} Whether the topology knows about this server
+ */
+ hasServer(address) {
+ return this.servers.has(address);
+ }
+}
+
+function topologyTypeForServerType(serverType) {
+ if (serverType === ServerType.Mongos) return TopologyType.Sharded;
+ if (serverType === ServerType.RSPrimary) return TopologyType.ReplicaSetWithPrimary;
+ return TopologyType.ReplicaSetNoPrimary;
+}
+
+function compareObjectId(oid1, oid2) {
+ if (oid1 == null) {
+ return -1;
+ }
+
+ if (oid2 == null) {
+ return 1;
+ }
+
+ if (oid1.id instanceof Buffer && oid2.id instanceof Buffer) {
+ const oid1Buffer = oid1.id;
+ const oid2Buffer = oid2.id;
+ return oid1Buffer.compare(oid2Buffer);
+ }
+
+ const oid1String = oid1.toString();
+ const oid2String = oid2.toString();
+ return oid1String.localeCompare(oid2String);
+}
+
+function updateRsFromPrimary(
+ serverDescriptions,
+ setName,
+ serverDescription,
+ maxSetVersion,
+ maxElectionId
+) {
+ setName = setName || serverDescription.setName;
+ if (setName !== serverDescription.setName) {
+ serverDescriptions.delete(serverDescription.address);
+ return [checkHasPrimary(serverDescriptions), setName, maxSetVersion, maxElectionId];
+ }
+
+ const electionId = serverDescription.electionId ? serverDescription.electionId : null;
+ if (serverDescription.setVersion && electionId) {
+ if (maxSetVersion && maxElectionId) {
+ if (
+ maxSetVersion > serverDescription.setVersion ||
+ compareObjectId(maxElectionId, electionId) > 0
+ ) {
+ // this primary is stale, we must remove it
+ serverDescriptions.set(
+ serverDescription.address,
+ new ServerDescription(serverDescription.address)
+ );
+
+ return [checkHasPrimary(serverDescriptions), setName, maxSetVersion, maxElectionId];
+ }
+ }
+
+ maxElectionId = serverDescription.electionId;
+ }
+
+ if (
+ serverDescription.setVersion != null &&
+ (maxSetVersion == null || serverDescription.setVersion > maxSetVersion)
+ ) {
+ maxSetVersion = serverDescription.setVersion;
+ }
+
+ // We've heard from the primary. Is it the same primary as before?
+ for (const address of serverDescriptions.keys()) {
+ const server = serverDescriptions.get(address);
+
+ if (server.type === ServerType.RSPrimary && server.address !== serverDescription.address) {
+ // Reset old primary's type to Unknown.
+ serverDescriptions.set(address, new ServerDescription(server.address));
+
+ // There can only be one primary
+ break;
+ }
+ }
+
+ // Discover new hosts from this primary's response.
+ serverDescription.allHosts.forEach(address => {
+ if (!serverDescriptions.has(address)) {
+ serverDescriptions.set(address, new ServerDescription(address));
+ }
+ });
+
+ // Remove hosts not in the response.
+ const currentAddresses = Array.from(serverDescriptions.keys());
+ const responseAddresses = serverDescription.allHosts;
+ currentAddresses
+ .filter(addr => responseAddresses.indexOf(addr) === -1)
+ .forEach(address => {
+ serverDescriptions.delete(address);
+ });
+
+ return [checkHasPrimary(serverDescriptions), setName, maxSetVersion, maxElectionId];
+}
+
+function updateRsWithPrimaryFromMember(serverDescriptions, setName, serverDescription) {
+ if (setName == null) {
+ throw new TypeError('setName is required');
+ }
+
+ if (
+ setName !== serverDescription.setName ||
+ (serverDescription.me && serverDescription.address !== serverDescription.me)
+ ) {
+ serverDescriptions.delete(serverDescription.address);
+ }
+
+ return checkHasPrimary(serverDescriptions);
+}
+
+function updateRsNoPrimaryFromMember(serverDescriptions, setName, serverDescription) {
+ let topologyType = TopologyType.ReplicaSetNoPrimary;
+
+ setName = setName || serverDescription.setName;
+ if (setName !== serverDescription.setName) {
+ serverDescriptions.delete(serverDescription.address);
+ return [topologyType, setName];
+ }
+
+ serverDescription.allHosts.forEach(address => {
+ if (!serverDescriptions.has(address)) {
+ serverDescriptions.set(address, new ServerDescription(address));
+ }
+ });
+
+ if (serverDescription.me && serverDescription.address !== serverDescription.me) {
+ serverDescriptions.delete(serverDescription.address);
+ }
+
+ return [topologyType, setName];
+}
+
+function checkHasPrimary(serverDescriptions) {
+ for (const addr of serverDescriptions.keys()) {
+ if (serverDescriptions.get(addr).type === ServerType.RSPrimary) {
+ return TopologyType.ReplicaSetWithPrimary;
+ }
+ }
+
+ return TopologyType.ReplicaSetNoPrimary;
+}
+
+module.exports = {
+ TopologyDescription
+};
diff --git a/node_modules/mongodb/lib/core/sessions.js b/node_modules/mongodb/lib/core/sessions.js
new file mode 100644
index 0000000..fcd3384
--- /dev/null
+++ b/node_modules/mongodb/lib/core/sessions.js
@@ -0,0 +1,777 @@
+'use strict';
+
+const retrieveBSON = require('./connection/utils').retrieveBSON;
+const EventEmitter = require('events');
+const BSON = retrieveBSON();
+const Binary = BSON.Binary;
+const uuidV4 = require('./utils').uuidV4;
+const MongoError = require('./error').MongoError;
+const isRetryableError = require('././error').isRetryableError;
+const MongoNetworkError = require('./error').MongoNetworkError;
+const MongoWriteConcernError = require('./error').MongoWriteConcernError;
+const Transaction = require('./transactions').Transaction;
+const TxnState = require('./transactions').TxnState;
+const isPromiseLike = require('./utils').isPromiseLike;
+const ReadPreference = require('./topologies/read_preference');
+const isTransactionCommand = require('./transactions').isTransactionCommand;
+const resolveClusterTime = require('./topologies/shared').resolveClusterTime;
+const isSharded = require('./wireprotocol/shared').isSharded;
+const maxWireVersion = require('./utils').maxWireVersion;
+
+const minWireVersionForShardedTransactions = 8;
+
+function assertAlive(session, callback) {
+ if (session.serverSession == null) {
+ const error = new MongoError('Cannot use a session that has ended');
+ if (typeof callback === 'function') {
+ callback(error, null);
+ return false;
+ }
+
+ throw error;
+ }
+
+ return true;
+}
+
+/**
+ * Options to pass when creating a Client Session
+ * @typedef {Object} SessionOptions
+ * @property {boolean} [causalConsistency=true] Whether causal consistency should be enabled on this session
+ * @property {TransactionOptions} [defaultTransactionOptions] The default TransactionOptions to use for transactions started on this session.
+ */
+
+/**
+ * A BSON document reflecting the lsid of a {@link ClientSession}
+ * @typedef {Object} SessionId
+ */
+
+/**
+ * A class representing a client session on the server
+ * WARNING: not meant to be instantiated directly.
+ * @class
+ * @hideconstructor
+ */
+class ClientSession extends EventEmitter {
+ /**
+ * Create a client session.
+ * WARNING: not meant to be instantiated directly
+ *
+ * @param {Topology} topology The current client's topology (Internal Class)
+ * @param {ServerSessionPool} sessionPool The server session pool (Internal Class)
+ * @param {SessionOptions} [options] Optional settings
+ * @param {Object} [clientOptions] Optional settings provided when creating a client in the porcelain driver
+ */
+ constructor(topology, sessionPool, options, clientOptions) {
+ super();
+
+ if (topology == null) {
+ throw new Error('ClientSession requires a topology');
+ }
+
+ if (sessionPool == null || !(sessionPool instanceof ServerSessionPool)) {
+ throw new Error('ClientSession requires a ServerSessionPool');
+ }
+
+ options = options || {};
+ clientOptions = clientOptions || {};
+
+ this.topology = topology;
+ this.sessionPool = sessionPool;
+ this.hasEnded = false;
+ this.serverSession = sessionPool.acquire();
+ this.clientOptions = clientOptions;
+
+ this.supports = {
+ causalConsistency:
+ typeof options.causalConsistency !== 'undefined' ? options.causalConsistency : true
+ };
+
+ this.clusterTime = options.initialClusterTime;
+
+ this.operationTime = null;
+ this.explicit = !!options.explicit;
+ this.owner = options.owner;
+ this.defaultTransactionOptions = Object.assign({}, options.defaultTransactionOptions);
+ this.transaction = new Transaction();
+ }
+
+ /**
+ * The server id associated with this session
+ * @type {SessionId}
+ */
+ get id() {
+ return this.serverSession.id;
+ }
+
+ /**
+ * Ends this session on the server
+ *
+ * @param {Object} [options] Optional settings. Currently reserved for future use
+ * @param {Function} [callback] Optional callback for completion of this operation
+ */
+ endSession(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ if (this.hasEnded) {
+ if (typeof callback === 'function') callback(null, null);
+ return;
+ }
+
+ if (this.serverSession && this.inTransaction()) {
+ this.abortTransaction(); // pass in callback?
+ }
+
+ // mark the session as ended, and emit a signal
+ this.hasEnded = true;
+ this.emit('ended', this);
+
+ // release the server session back to the pool
+ this.sessionPool.release(this.serverSession);
+ this.serverSession = null;
+
+ // spec indicates that we should ignore all errors for `endSessions`
+ if (typeof callback === 'function') callback(null, null);
+ }
+
+ /**
+ * Advances the operationTime for a ClientSession.
+ *
+ * @param {Timestamp} operationTime the `BSON.Timestamp` of the operation type it is desired to advance to
+ */
+ advanceOperationTime(operationTime) {
+ if (this.operationTime == null) {
+ this.operationTime = operationTime;
+ return;
+ }
+
+ if (operationTime.greaterThan(this.operationTime)) {
+ this.operationTime = operationTime;
+ }
+ }
+
+ /**
+ * Used to determine if this session equals another
+ * @param {ClientSession} session
+ * @return {boolean} true if the sessions are equal
+ */
+ equals(session) {
+ if (!(session instanceof ClientSession)) {
+ return false;
+ }
+
+ return this.id.id.buffer.equals(session.id.id.buffer);
+ }
+
+ /**
+ * Increment the transaction number on the internal ServerSession
+ */
+ incrementTransactionNumber() {
+ this.serverSession.txnNumber++;
+ }
+
+ /**
+ * @returns {boolean} whether this session is currently in a transaction or not
+ */
+ inTransaction() {
+ return this.transaction.isActive;
+ }
+
+ /**
+ * Starts a new transaction with the given options.
+ *
+ * @param {TransactionOptions} options Options for the transaction
+ */
+ startTransaction(options) {
+ assertAlive(this);
+ if (this.inTransaction()) {
+ throw new MongoError('Transaction already in progress');
+ }
+
+ const topologyMaxWireVersion = maxWireVersion(this.topology);
+ if (
+ isSharded(this.topology) &&
+ topologyMaxWireVersion != null &&
+ topologyMaxWireVersion < minWireVersionForShardedTransactions
+ ) {
+ throw new MongoError('Transactions are not supported on sharded clusters in MongoDB < 4.2.');
+ }
+
+ // increment txnNumber
+ this.incrementTransactionNumber();
+
+ // create transaction state
+ this.transaction = new Transaction(
+ Object.assign({}, this.clientOptions, options || this.defaultTransactionOptions)
+ );
+
+ this.transaction.transition(TxnState.STARTING_TRANSACTION);
+ }
+
+ /**
+ * Commits the currently active transaction in this session.
+ *
+ * @param {Function} [callback] optional callback for completion of this operation
+ * @return {Promise} A promise is returned if no callback is provided
+ */
+ commitTransaction(callback) {
+ if (typeof callback === 'function') {
+ endTransaction(this, 'commitTransaction', callback);
+ return;
+ }
+
+ return new Promise((resolve, reject) => {
+ endTransaction(this, 'commitTransaction', (err, reply) =>
+ err ? reject(err) : resolve(reply)
+ );
+ });
+ }
+
+ /**
+ * Aborts the currently active transaction in this session.
+ *
+ * @param {Function} [callback] optional callback for completion of this operation
+ * @return {Promise} A promise is returned if no callback is provided
+ */
+ abortTransaction(callback) {
+ if (typeof callback === 'function') {
+ endTransaction(this, 'abortTransaction', callback);
+ return;
+ }
+
+ return new Promise((resolve, reject) => {
+ endTransaction(this, 'abortTransaction', (err, reply) =>
+ err ? reject(err) : resolve(reply)
+ );
+ });
+ }
+
+ /**
+ * This is here to ensure that ClientSession is never serialized to BSON.
+ * @ignore
+ */
+ toBSON() {
+ throw new Error('ClientSession cannot be serialized to BSON.');
+ }
+
+ /**
+ * A user provided function to be run within a transaction
+ *
+ * @callback WithTransactionCallback
+ * @param {ClientSession} session The parent session of the transaction running the operation. This should be passed into each operation within the lambda.
+ * @returns {Promise} The resulting Promise of operations run within this transaction
+ */
+
+ /**
+ * Runs a provided lambda within a transaction, retrying either the commit operation
+ * or entire transaction as needed (and when the error permits) to better ensure that
+ * the transaction can complete successfully.
+ *
+ * IMPORTANT: This method requires the user to return a Promise, all lambdas that do not
+ * return a Promise will result in undefined behavior.
+ *
+ * @param {WithTransactionCallback} fn
+ * @param {TransactionOptions} [options] Optional settings for the transaction
+ */
+ withTransaction(fn, options) {
+ const startTime = Date.now();
+ return attemptTransaction(this, startTime, fn, options);
+ }
+}
+
+const MAX_WITH_TRANSACTION_TIMEOUT = 120000;
+const UNSATISFIABLE_WRITE_CONCERN_CODE = 100;
+const UNKNOWN_REPL_WRITE_CONCERN_CODE = 79;
+const MAX_TIME_MS_EXPIRED_CODE = 50;
+const NON_DETERMINISTIC_WRITE_CONCERN_ERRORS = new Set([
+ 'CannotSatisfyWriteConcern',
+ 'UnknownReplWriteConcern',
+ 'UnsatisfiableWriteConcern'
+]);
+
+function hasNotTimedOut(startTime, max) {
+ return Date.now() - startTime < max;
+}
+
+function isUnknownTransactionCommitResult(err) {
+ return (
+ isMaxTimeMSExpiredError(err) ||
+ (!NON_DETERMINISTIC_WRITE_CONCERN_ERRORS.has(err.codeName) &&
+ err.code !== UNSATISFIABLE_WRITE_CONCERN_CODE &&
+ err.code !== UNKNOWN_REPL_WRITE_CONCERN_CODE)
+ );
+}
+
+function isMaxTimeMSExpiredError(err) {
+ return (
+ err.code === MAX_TIME_MS_EXPIRED_CODE ||
+ (err.writeConcernError && err.writeConcernError.code === MAX_TIME_MS_EXPIRED_CODE)
+ );
+}
+
+function attemptTransactionCommit(session, startTime, fn, options) {
+ return session.commitTransaction().catch(err => {
+ if (
+ err instanceof MongoError &&
+ hasNotTimedOut(startTime, MAX_WITH_TRANSACTION_TIMEOUT) &&
+ !isMaxTimeMSExpiredError(err)
+ ) {
+ if (err.hasErrorLabel('UnknownTransactionCommitResult')) {
+ return attemptTransactionCommit(session, startTime, fn, options);
+ }
+
+ if (err.hasErrorLabel('TransientTransactionError')) {
+ return attemptTransaction(session, startTime, fn, options);
+ }
+ }
+
+ throw err;
+ });
+}
+
+const USER_EXPLICIT_TXN_END_STATES = new Set([
+ TxnState.NO_TRANSACTION,
+ TxnState.TRANSACTION_COMMITTED,
+ TxnState.TRANSACTION_ABORTED
+]);
+
+function userExplicitlyEndedTransaction(session) {
+ return USER_EXPLICIT_TXN_END_STATES.has(session.transaction.state);
+}
+
+function attemptTransaction(session, startTime, fn, options) {
+ session.startTransaction(options);
+
+ let promise;
+ try {
+ promise = fn(session);
+ } catch (err) {
+ promise = Promise.reject(err);
+ }
+
+ if (!isPromiseLike(promise)) {
+ session.abortTransaction();
+ throw new TypeError('Function provided to `withTransaction` must return a Promise');
+ }
+
+ return promise
+ .then(() => {
+ if (userExplicitlyEndedTransaction(session)) {
+ return;
+ }
+
+ return attemptTransactionCommit(session, startTime, fn, options);
+ })
+ .catch(err => {
+ function maybeRetryOrThrow(err) {
+ if (
+ err instanceof MongoError &&
+ err.hasErrorLabel('TransientTransactionError') &&
+ hasNotTimedOut(startTime, MAX_WITH_TRANSACTION_TIMEOUT)
+ ) {
+ return attemptTransaction(session, startTime, fn, options);
+ }
+
+ if (isMaxTimeMSExpiredError(err)) {
+ if (err.errorLabels == null) {
+ err.errorLabels = [];
+ }
+ err.errorLabels.push('UnknownTransactionCommitResult');
+ }
+
+ throw err;
+ }
+
+ if (session.transaction.isActive) {
+ return session.abortTransaction().then(() => maybeRetryOrThrow(err));
+ }
+
+ return maybeRetryOrThrow(err);
+ });
+}
+
+function endTransaction(session, commandName, callback) {
+ if (!assertAlive(session, callback)) {
+ // checking result in case callback was called
+ return;
+ }
+
+ // handle any initial problematic cases
+ let txnState = session.transaction.state;
+
+ if (txnState === TxnState.NO_TRANSACTION) {
+ callback(new MongoError('No transaction started'));
+ return;
+ }
+
+ if (commandName === 'commitTransaction') {
+ if (
+ txnState === TxnState.STARTING_TRANSACTION ||
+ txnState === TxnState.TRANSACTION_COMMITTED_EMPTY
+ ) {
+ // the transaction was never started, we can safely exit here
+ session.transaction.transition(TxnState.TRANSACTION_COMMITTED_EMPTY);
+ callback(null, null);
+ return;
+ }
+
+ if (txnState === TxnState.TRANSACTION_ABORTED) {
+ callback(new MongoError('Cannot call commitTransaction after calling abortTransaction'));
+ return;
+ }
+ } else {
+ if (txnState === TxnState.STARTING_TRANSACTION) {
+ // the transaction was never started, we can safely exit here
+ session.transaction.transition(TxnState.TRANSACTION_ABORTED);
+ callback(null, null);
+ return;
+ }
+
+ if (txnState === TxnState.TRANSACTION_ABORTED) {
+ callback(new MongoError('Cannot call abortTransaction twice'));
+ return;
+ }
+
+ if (
+ txnState === TxnState.TRANSACTION_COMMITTED ||
+ txnState === TxnState.TRANSACTION_COMMITTED_EMPTY
+ ) {
+ callback(new MongoError('Cannot call abortTransaction after calling commitTransaction'));
+ return;
+ }
+ }
+
+ // construct and send the command
+ const command = { [commandName]: 1 };
+
+ // apply a writeConcern if specified
+ let writeConcern;
+ if (session.transaction.options.writeConcern) {
+ writeConcern = Object.assign({}, session.transaction.options.writeConcern);
+ } else if (session.clientOptions && session.clientOptions.w) {
+ writeConcern = { w: session.clientOptions.w };
+ }
+
+ if (txnState === TxnState.TRANSACTION_COMMITTED) {
+ writeConcern = Object.assign({ wtimeout: 10000 }, writeConcern, { w: 'majority' });
+ }
+
+ if (writeConcern) {
+ Object.assign(command, { writeConcern });
+ }
+
+ if (commandName === 'commitTransaction' && session.transaction.options.maxTimeMS) {
+ Object.assign(command, { maxTimeMS: session.transaction.options.maxTimeMS });
+ }
+
+ function commandHandler(e, r) {
+ if (commandName === 'commitTransaction') {
+ session.transaction.transition(TxnState.TRANSACTION_COMMITTED);
+
+ if (
+ e &&
+ (e instanceof MongoNetworkError ||
+ e instanceof MongoWriteConcernError ||
+ isRetryableError(e) ||
+ isMaxTimeMSExpiredError(e))
+ ) {
+ if (e.errorLabels) {
+ const idx = e.errorLabels.indexOf('TransientTransactionError');
+ if (idx !== -1) {
+ e.errorLabels.splice(idx, 1);
+ }
+ } else {
+ e.errorLabels = [];
+ }
+
+ if (isUnknownTransactionCommitResult(e)) {
+ e.errorLabels.push('UnknownTransactionCommitResult');
+
+ // per txns spec, must unpin session in this case
+ session.transaction.unpinServer();
+ }
+ }
+ } else {
+ session.transaction.transition(TxnState.TRANSACTION_ABORTED);
+ }
+
+ callback(e, r);
+ }
+
+ // The spec indicates that we should ignore all errors on `abortTransaction`
+ function transactionError(err) {
+ return commandName === 'commitTransaction' ? err : null;
+ }
+
+ if (
+ // Assumption here that commandName is "commitTransaction" or "abortTransaction"
+ session.transaction.recoveryToken &&
+ supportsRecoveryToken(session)
+ ) {
+ command.recoveryToken = session.transaction.recoveryToken;
+ }
+
+ // send the command
+ session.topology.command('admin.$cmd', command, { session }, (err, reply) => {
+ if (err && isRetryableError(err)) {
+ // SPEC-1185: apply majority write concern when retrying commitTransaction
+ if (command.commitTransaction) {
+ // per txns spec, must unpin session in this case
+ session.transaction.unpinServer();
+
+ command.writeConcern = Object.assign({ wtimeout: 10000 }, command.writeConcern, {
+ w: 'majority'
+ });
+ }
+
+ return session.topology.command('admin.$cmd', command, { session }, (_err, _reply) =>
+ commandHandler(transactionError(_err), _reply)
+ );
+ }
+
+ commandHandler(transactionError(err), reply);
+ });
+}
+
+function supportsRecoveryToken(session) {
+ const topology = session.topology;
+ return !!topology.s.options.useRecoveryToken;
+}
+
+/**
+ * Reflects the existence of a session on the server. Can be reused by the session pool.
+ * WARNING: not meant to be instantiated directly. For internal use only.
+ * @ignore
+ */
+class ServerSession {
+ constructor() {
+ this.id = { id: new Binary(uuidV4(), Binary.SUBTYPE_UUID) };
+ this.lastUse = Date.now();
+ this.txnNumber = 0;
+ this.isDirty = false;
+ }
+
+ /**
+ * Determines if the server session has timed out.
+ * @ignore
+ * @param {Date} sessionTimeoutMinutes The server's "logicalSessionTimeoutMinutes"
+ * @return {boolean} true if the session has timed out.
+ */
+ hasTimedOut(sessionTimeoutMinutes) {
+ // Take the difference of the lastUse timestamp and now, which will result in a value in
+ // milliseconds, and then convert milliseconds to minutes to compare to `sessionTimeoutMinutes`
+ const idleTimeMinutes = Math.round(
+ (((Date.now() - this.lastUse) % 86400000) % 3600000) / 60000
+ );
+
+ return idleTimeMinutes > sessionTimeoutMinutes - 1;
+ }
+}
+
+/**
+ * Maintains a pool of Server Sessions.
+ * For internal use only
+ * @ignore
+ */
+class ServerSessionPool {
+ constructor(topology) {
+ if (topology == null) {
+ throw new Error('ServerSessionPool requires a topology');
+ }
+
+ this.topology = topology;
+ this.sessions = [];
+ }
+
+ /**
+ * Ends all sessions in the session pool.
+ * @ignore
+ */
+ endAllPooledSessions(callback) {
+ if (this.sessions.length) {
+ this.topology.endSessions(
+ this.sessions.map(session => session.id),
+ () => {
+ this.sessions = [];
+ if (typeof callback === 'function') {
+ callback();
+ }
+ }
+ );
+
+ return;
+ }
+
+ if (typeof callback === 'function') {
+ callback();
+ }
+ }
+
+ /**
+ * Acquire a Server Session from the pool.
+ * Iterates through each session in the pool, removing any stale sessions
+ * along the way. The first non-stale session found is removed from the
+ * pool and returned. If no non-stale session is found, a new ServerSession
+ * is created.
+ * @ignore
+ * @returns {ServerSession}
+ */
+ acquire() {
+ const sessionTimeoutMinutes = this.topology.logicalSessionTimeoutMinutes;
+ while (this.sessions.length) {
+ const session = this.sessions.shift();
+ if (!session.hasTimedOut(sessionTimeoutMinutes)) {
+ return session;
+ }
+ }
+
+ return new ServerSession();
+ }
+
+ /**
+ * Release a session to the session pool
+ * Adds the session back to the session pool if the session has not timed out yet.
+ * This method also removes any stale sessions from the pool.
+ * @ignore
+ * @param {ServerSession} session The session to release to the pool
+ */
+ release(session) {
+ const sessionTimeoutMinutes = this.topology.logicalSessionTimeoutMinutes;
+ while (this.sessions.length) {
+ const pooledSession = this.sessions[this.sessions.length - 1];
+ if (pooledSession.hasTimedOut(sessionTimeoutMinutes)) {
+ this.sessions.pop();
+ } else {
+ break;
+ }
+ }
+
+ if (!session.hasTimedOut(sessionTimeoutMinutes)) {
+ if (session.isDirty) {
+ return;
+ }
+
+ // otherwise, readd this session to the session pool
+ this.sessions.unshift(session);
+ }
+ }
+}
+
+// TODO: this should be codified in command construction
+// @see https://github.com/mongodb/specifications/blob/master/source/read-write-concern/read-write-concern.rst#read-concern
+function commandSupportsReadConcern(command, options) {
+ if (
+ command.aggregate ||
+ command.count ||
+ command.distinct ||
+ command.find ||
+ command.parallelCollectionScan ||
+ command.geoNear ||
+ command.geoSearch
+ ) {
+ return true;
+ }
+
+ if (command.mapReduce && options.out && (options.out.inline === 1 || options.out === 'inline')) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Optionally decorate a command with sessions specific keys
+ *
+ * @ignore
+ * @param {ClientSession} session the session tracking transaction state
+ * @param {Object} command the command to decorate
+ * @param {Object} topology the topology for tracking the cluster time
+ * @param {Object} [options] Optional settings passed to calling operation
+ * @return {MongoError|null} An error, if some error condition was met
+ */
+function applySession(session, command, options) {
+ const serverSession = session.serverSession;
+ if (serverSession == null) {
+ // TODO: merge this with `assertAlive`, did not want to throw a try/catch here
+ return new MongoError('Cannot use a session that has ended');
+ }
+
+ // mark the last use of this session, and apply the `lsid`
+ serverSession.lastUse = Date.now();
+ command.lsid = serverSession.id;
+
+ // first apply non-transaction-specific sessions data
+ const inTransaction = session.inTransaction() || isTransactionCommand(command);
+ const isRetryableWrite = options.willRetryWrite;
+ const shouldApplyReadConcern = commandSupportsReadConcern(command);
+
+ if (serverSession.txnNumber && (isRetryableWrite || inTransaction)) {
+ command.txnNumber = BSON.Long.fromNumber(serverSession.txnNumber);
+ }
+
+ // now attempt to apply transaction-specific sessions data
+ if (!inTransaction) {
+ if (session.transaction.state !== TxnState.NO_TRANSACTION) {
+ session.transaction.transition(TxnState.NO_TRANSACTION);
+ }
+
+ // TODO: the following should only be applied to read operation per spec.
+ // for causal consistency
+ if (session.supports.causalConsistency && session.operationTime && shouldApplyReadConcern) {
+ command.readConcern = command.readConcern || {};
+ Object.assign(command.readConcern, { afterClusterTime: session.operationTime });
+ }
+
+ return;
+ }
+
+ if (options.readPreference && !options.readPreference.equals(ReadPreference.primary)) {
+ return new MongoError(
+ `Read preference in a transaction must be primary, not: ${options.readPreference.mode}`
+ );
+ }
+
+ // `autocommit` must always be false to differentiate from retryable writes
+ command.autocommit = false;
+
+ if (session.transaction.state === TxnState.STARTING_TRANSACTION) {
+ session.transaction.transition(TxnState.TRANSACTION_IN_PROGRESS);
+ command.startTransaction = true;
+
+ const readConcern =
+ session.transaction.options.readConcern || session.clientOptions.readConcern;
+ if (readConcern) {
+ command.readConcern = readConcern;
+ }
+
+ if (session.supports.causalConsistency && session.operationTime) {
+ command.readConcern = command.readConcern || {};
+ Object.assign(command.readConcern, { afterClusterTime: session.operationTime });
+ }
+ }
+}
+
+function updateSessionFromResponse(session, document) {
+ if (document.$clusterTime) {
+ resolveClusterTime(session, document.$clusterTime);
+ }
+
+ if (document.operationTime && session && session.supports.causalConsistency) {
+ session.advanceOperationTime(document.operationTime);
+ }
+
+ if (document.recoveryToken && session && session.inTransaction()) {
+ session.transaction._recoveryToken = document.recoveryToken;
+ }
+}
+
+module.exports = {
+ ClientSession,
+ ServerSession,
+ ServerSessionPool,
+ TxnState,
+ applySession,
+ updateSessionFromResponse,
+ commandSupportsReadConcern
+};
diff --git a/node_modules/mongodb/lib/core/tools/smoke_plugin.js b/node_modules/mongodb/lib/core/tools/smoke_plugin.js
new file mode 100644
index 0000000..22d0298
--- /dev/null
+++ b/node_modules/mongodb/lib/core/tools/smoke_plugin.js
@@ -0,0 +1,61 @@
+'use strict';
+
+var fs = require('fs');
+
+/* Note: because this plugin uses process.on('uncaughtException'), only one
+ * of these can exist at any given time. This plugin and anything else that
+ * uses process.on('uncaughtException') will conflict. */
+exports.attachToRunner = function(runner, outputFile) {
+ var smokeOutput = { results: [] };
+ var runningTests = {};
+
+ var integraPlugin = {
+ beforeTest: function(test, callback) {
+ test.startTime = Date.now();
+ runningTests[test.name] = test;
+ callback();
+ },
+ afterTest: function(test, callback) {
+ smokeOutput.results.push({
+ status: test.status,
+ start: test.startTime,
+ end: Date.now(),
+ test_file: test.name,
+ exit_code: 0,
+ url: ''
+ });
+ delete runningTests[test.name];
+ callback();
+ },
+ beforeExit: function(obj, callback) {
+ fs.writeFile(outputFile, JSON.stringify(smokeOutput), function() {
+ callback();
+ });
+ }
+ };
+
+ // In case of exception, make sure we write file
+ process.on('uncaughtException', function(err) {
+ // Mark all currently running tests as failed
+ for (var testName in runningTests) {
+ smokeOutput.results.push({
+ status: 'fail',
+ start: runningTests[testName].startTime,
+ end: Date.now(),
+ test_file: testName,
+ exit_code: 0,
+ url: ''
+ });
+ }
+
+ // write file
+ fs.writeFileSync(outputFile, JSON.stringify(smokeOutput));
+
+ // Standard NodeJS uncaught exception handler
+ console.error(err.stack);
+ process.exit(1);
+ });
+
+ runner.plugin(integraPlugin);
+ return integraPlugin;
+};
diff --git a/node_modules/mongodb/lib/core/topologies/mongos.js b/node_modules/mongodb/lib/core/topologies/mongos.js
new file mode 100644
index 0000000..2937193
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/mongos.js
@@ -0,0 +1,1384 @@
+'use strict';
+
+const inherits = require('util').inherits;
+const f = require('util').format;
+const EventEmitter = require('events').EventEmitter;
+const CoreCursor = require('../cursor').CoreCursor;
+const Logger = require('../connection/logger');
+const retrieveBSON = require('../connection/utils').retrieveBSON;
+const MongoError = require('../error').MongoError;
+const Server = require('./server');
+const diff = require('./shared').diff;
+const cloneOptions = require('./shared').cloneOptions;
+const SessionMixins = require('./shared').SessionMixins;
+const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
+const relayEvents = require('../utils').relayEvents;
+const isRetryableError = require('../error').isRetryableError;
+const BSON = retrieveBSON();
+const getMMAPError = require('./shared').getMMAPError;
+const makeClientMetadata = require('../utils').makeClientMetadata;
+
+/**
+ * @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
+ * used to construct connections.
+ */
+
+//
+// States
+var DISCONNECTED = 'disconnected';
+var CONNECTING = 'connecting';
+var CONNECTED = 'connected';
+var UNREFERENCED = 'unreferenced';
+var DESTROYING = 'destroying';
+var DESTROYED = 'destroyed';
+
+function stateTransition(self, newState) {
+ var legalTransitions = {
+ disconnected: [CONNECTING, DESTROYING, DESTROYED, DISCONNECTED],
+ connecting: [CONNECTING, DESTROYING, DESTROYED, CONNECTED, DISCONNECTED],
+ connected: [CONNECTED, DISCONNECTED, DESTROYING, DESTROYED, UNREFERENCED],
+ unreferenced: [UNREFERENCED, DESTROYING, DESTROYED],
+ destroyed: [DESTROYED]
+ };
+
+ // Get current state
+ var legalStates = legalTransitions[self.state];
+ if (legalStates && legalStates.indexOf(newState) !== -1) {
+ self.state = newState;
+ } else {
+ self.s.logger.error(
+ f(
+ 'Mongos with id [%s] failed attempted illegal state transition from [%s] to [%s] only following state allowed [%s]',
+ self.id,
+ self.state,
+ newState,
+ legalStates
+ )
+ );
+ }
+}
+
+//
+// ReplSet instance id
+var id = 1;
+var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
+
+/**
+ * Creates a new Mongos instance
+ * @class
+ * @param {array} seedlist A list of seeds for the replicaset
+ * @param {number} [options.haInterval=5000] The High availability period for replicaset inquiry
+ * @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
+ * @param {number} [options.size=5] Server connection pool size
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
+ * @param {number} [options.localThresholdMS=15] Cutoff latency point in MS for MongoS proxy selection
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {number} [options.connectionTimeout=1000] TCP Connection timeout setting
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
+ * @param {boolean} [options.ssl=false] Use SSL for connection
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {Buffer} [options.ca] SSL Certificate store binary buffer
+ * @param {Buffer} [options.crl] SSL Certificate revocation store binary buffer
+ * @param {Buffer} [options.cert] SSL Certificate binary buffer
+ * @param {Buffer} [options.key] SSL Key file binary buffer
+ * @param {string} [options.passphrase] SSL Certificate pass phrase
+ * @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
+ * @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
+ * @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @return {Mongos} A cursor instance
+ * @fires Mongos#connect
+ * @fires Mongos#reconnect
+ * @fires Mongos#joined
+ * @fires Mongos#left
+ * @fires Mongos#failed
+ * @fires Mongos#fullsetup
+ * @fires Mongos#all
+ * @fires Mongos#serverHeartbeatStarted
+ * @fires Mongos#serverHeartbeatSucceeded
+ * @fires Mongos#serverHeartbeatFailed
+ * @fires Mongos#topologyOpening
+ * @fires Mongos#topologyClosed
+ * @fires Mongos#topologyDescriptionChanged
+ * @property {string} type the topology type.
+ * @property {string} parserType the parser type used (c++ or js).
+ */
+var Mongos = function(seedlist, options) {
+ options = options || {};
+
+ // Get replSet Id
+ this.id = id++;
+
+ // Internal state
+ this.s = {
+ options: Object.assign({ metadata: makeClientMetadata(options) }, options),
+ // BSON instance
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ]),
+ // Factory overrides
+ Cursor: options.cursorFactory || CoreCursor,
+ // Logger instance
+ logger: Logger('Mongos', options),
+ // Seedlist
+ seedlist: seedlist,
+ // Ha interval
+ haInterval: options.haInterval ? options.haInterval : 10000,
+ // Disconnect handler
+ disconnectHandler: options.disconnectHandler,
+ // Server selection index
+ index: 0,
+ // Connect function options passed in
+ connectOptions: {},
+ // Are we running in debug mode
+ debug: typeof options.debug === 'boolean' ? options.debug : false,
+ // localThresholdMS
+ localThresholdMS: options.localThresholdMS || 15
+ };
+
+ // Log info warning if the socketTimeout < haInterval as it will cause
+ // a lot of recycled connections to happen.
+ if (
+ this.s.logger.isWarn() &&
+ this.s.options.socketTimeout !== 0 &&
+ this.s.options.socketTimeout < this.s.haInterval
+ ) {
+ this.s.logger.warn(
+ f(
+ 'warning socketTimeout %s is less than haInterval %s. This might cause unnecessary server reconnections due to socket timeouts',
+ this.s.options.socketTimeout,
+ this.s.haInterval
+ )
+ );
+ }
+
+ // Disconnected state
+ this.state = DISCONNECTED;
+
+ // Current proxies we are connecting to
+ this.connectingProxies = [];
+ // Currently connected proxies
+ this.connectedProxies = [];
+ // Disconnected proxies
+ this.disconnectedProxies = [];
+ // Index of proxy to run operations against
+ this.index = 0;
+ // High availability timeout id
+ this.haTimeoutId = null;
+ // Last ismaster
+ this.ismaster = null;
+
+ // Description of the Replicaset
+ this.topologyDescription = {
+ topologyType: 'Unknown',
+ servers: []
+ };
+
+ // Highest clusterTime seen in responses from the current deployment
+ this.clusterTime = null;
+
+ // Add event listener
+ EventEmitter.call(this);
+};
+
+inherits(Mongos, EventEmitter);
+Object.assign(Mongos.prototype, SessionMixins);
+
+Object.defineProperty(Mongos.prototype, 'type', {
+ enumerable: true,
+ get: function() {
+ return 'mongos';
+ }
+});
+
+Object.defineProperty(Mongos.prototype, 'parserType', {
+ enumerable: true,
+ get: function() {
+ return BSON.native ? 'c++' : 'js';
+ }
+});
+
+Object.defineProperty(Mongos.prototype, 'logicalSessionTimeoutMinutes', {
+ enumerable: true,
+ get: function() {
+ if (!this.ismaster) return null;
+ return this.ismaster.logicalSessionTimeoutMinutes || null;
+ }
+});
+
+/**
+ * Emit event if it exists
+ * @method
+ */
+function emitSDAMEvent(self, event, description) {
+ if (self.listeners(event).length > 0) {
+ self.emit(event, description);
+ }
+}
+
+const SERVER_EVENTS = ['serverDescriptionChanged', 'error', 'close', 'timeout', 'parseError'];
+function destroyServer(server, options, callback) {
+ options = options || {};
+ SERVER_EVENTS.forEach(event => server.removeAllListeners(event));
+ server.destroy(options, callback);
+}
+
+/**
+ * Initiate server connect
+ */
+Mongos.prototype.connect = function(options) {
+ var self = this;
+ // Add any connect level options to the internal state
+ this.s.connectOptions = options || {};
+
+ // Set connecting state
+ stateTransition(this, CONNECTING);
+
+ // Create server instances
+ var servers = this.s.seedlist.map(function(x) {
+ const server = new Server(
+ Object.assign({}, self.s.options, x, options, {
+ reconnect: false,
+ monitoring: false,
+ parent: self
+ })
+ );
+
+ relayEvents(server, self, ['serverDescriptionChanged']);
+ return server;
+ });
+
+ // Emit the topology opening event
+ emitSDAMEvent(this, 'topologyOpening', { topologyId: this.id });
+
+ // Start all server connections
+ connectProxies(self, servers);
+};
+
+/**
+ * Authenticate the topology.
+ * @method
+ * @param {MongoCredentials} credentials The credentials for authentication we are using
+ * @param {authResultCallback} callback A callback function
+ */
+Mongos.prototype.auth = function(credentials, callback) {
+ if (typeof callback === 'function') callback(null, null);
+};
+
+function handleEvent(self) {
+ return function() {
+ if (self.state === DESTROYED || self.state === DESTROYING) {
+ return;
+ }
+
+ // Move to list of disconnectedProxies
+ moveServerFrom(self.connectedProxies, self.disconnectedProxies, this);
+ // Emit the initial topology
+ emitTopologyDescriptionChanged(self);
+ // Emit the left signal
+ self.emit('left', 'mongos', this);
+ // Emit the sdam event
+ self.emit('serverClosed', {
+ topologyId: self.id,
+ address: this.name
+ });
+ };
+}
+
+function handleInitialConnectEvent(self, event) {
+ return function() {
+ var _this = this;
+
+ // Destroy the instance
+ if (self.state === DESTROYED) {
+ // Emit the initial topology
+ emitTopologyDescriptionChanged(self);
+ // Move from connectingProxies
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, this);
+ return this.destroy();
+ }
+
+ // Check the type of server
+ if (event === 'connect') {
+ // Get last known ismaster
+ self.ismaster = _this.lastIsMaster();
+
+ // Is this not a proxy, remove t
+ if (self.ismaster.msg === 'isdbgrid') {
+ // Add to the connectd list
+ for (let i = 0; i < self.connectedProxies.length; i++) {
+ if (self.connectedProxies[i].name === _this.name) {
+ // Move from connectingProxies
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, _this);
+ // Emit the initial topology
+ emitTopologyDescriptionChanged(self);
+ _this.destroy();
+ return self.emit('failed', _this);
+ }
+ }
+
+ // Remove the handlers
+ for (let i = 0; i < handlers.length; i++) {
+ _this.removeAllListeners(handlers[i]);
+ }
+
+ // Add stable state handlers
+ _this.on('error', handleEvent(self, 'error'));
+ _this.on('close', handleEvent(self, 'close'));
+ _this.on('timeout', handleEvent(self, 'timeout'));
+ _this.on('parseError', handleEvent(self, 'parseError'));
+
+ // Move from connecting proxies connected
+ moveServerFrom(self.connectingProxies, self.connectedProxies, _this);
+ // Emit the joined event
+ self.emit('joined', 'mongos', _this);
+ } else {
+ // Print warning if we did not find a mongos proxy
+ if (self.s.logger.isWarn()) {
+ var message = 'expected mongos proxy, but found replicaset member mongod for server %s';
+ // We have a standalone server
+ if (!self.ismaster.hosts) {
+ message = 'expected mongos proxy, but found standalone mongod for server %s';
+ }
+
+ self.s.logger.warn(f(message, _this.name));
+ }
+
+ // This is not a mongos proxy, destroy and remove it completely
+ _this.destroy(true);
+ removeProxyFrom(self.connectingProxies, _this);
+ // Emit the left event
+ self.emit('left', 'server', _this);
+ // Emit failed event
+ self.emit('failed', _this);
+ }
+ } else {
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, this);
+ // Emit the left event
+ self.emit('left', 'mongos', this);
+ // Emit failed event
+ self.emit('failed', this);
+ }
+
+ // Emit the initial topology
+ emitTopologyDescriptionChanged(self);
+
+ // Trigger topologyMonitor
+ if (self.connectingProxies.length === 0) {
+ // Emit connected if we are connected
+ if (self.connectedProxies.length > 0 && self.state === CONNECTING) {
+ // Set the state to connected
+ stateTransition(self, CONNECTED);
+ // Emit the connect event
+ self.emit('connect', self);
+ self.emit('fullsetup', self);
+ self.emit('all', self);
+ } else if (self.disconnectedProxies.length === 0) {
+ // Print warning if we did not find a mongos proxy
+ if (self.s.logger.isWarn()) {
+ self.s.logger.warn(
+ f('no mongos proxies found in seed list, did you mean to connect to a replicaset')
+ );
+ }
+
+ // Emit the error that no proxies were found
+ return self.emit('error', new MongoError('no mongos proxies found in seed list'));
+ }
+
+ // Topology monitor
+ topologyMonitor(self, { firstConnect: true });
+ }
+ };
+}
+
+function connectProxies(self, servers) {
+ // Update connectingProxies
+ self.connectingProxies = self.connectingProxies.concat(servers);
+
+ // Index used to interleaf the server connects, avoiding
+ // runtime issues on io constrained vm's
+ var timeoutInterval = 0;
+
+ function connect(server, timeoutInterval) {
+ setTimeout(function() {
+ // Emit opening server event
+ self.emit('serverOpening', {
+ topologyId: self.id,
+ address: server.name
+ });
+
+ // Emit the initial topology
+ emitTopologyDescriptionChanged(self);
+
+ // Add event handlers
+ server.once('close', handleInitialConnectEvent(self, 'close'));
+ server.once('timeout', handleInitialConnectEvent(self, 'timeout'));
+ server.once('parseError', handleInitialConnectEvent(self, 'parseError'));
+ server.once('error', handleInitialConnectEvent(self, 'error'));
+ server.once('connect', handleInitialConnectEvent(self, 'connect'));
+
+ // Command Monitoring events
+ relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
+
+ // Start connection
+ server.connect(self.s.connectOptions);
+ }, timeoutInterval);
+ }
+
+ // Start all the servers
+ servers.forEach(server => connect(server, timeoutInterval++));
+}
+
+function pickProxy(self, session) {
+ // TODO: Destructure :)
+ const transaction = session && session.transaction;
+
+ if (transaction && transaction.server) {
+ if (transaction.server.isConnected()) {
+ return transaction.server;
+ } else {
+ transaction.unpinServer();
+ }
+ }
+
+ // Get the currently connected Proxies
+ var connectedProxies = self.connectedProxies.slice(0);
+
+ // Set lower bound
+ var lowerBoundLatency = Number.MAX_VALUE;
+
+ // Determine the lower bound for the Proxies
+ for (var i = 0; i < connectedProxies.length; i++) {
+ if (connectedProxies[i].lastIsMasterMS < lowerBoundLatency) {
+ lowerBoundLatency = connectedProxies[i].lastIsMasterMS;
+ }
+ }
+
+ // Filter out the possible servers
+ connectedProxies = connectedProxies.filter(function(server) {
+ if (
+ server.lastIsMasterMS <= lowerBoundLatency + self.s.localThresholdMS &&
+ server.isConnected()
+ ) {
+ return true;
+ }
+ });
+
+ let proxy;
+
+ // We have no connectedProxies pick first of the connected ones
+ if (connectedProxies.length === 0) {
+ proxy = self.connectedProxies[0];
+ } else {
+ // Get proxy
+ proxy = connectedProxies[self.index % connectedProxies.length];
+ // Update the index
+ self.index = (self.index + 1) % connectedProxies.length;
+ }
+
+ if (transaction && transaction.isActive && proxy && proxy.isConnected()) {
+ transaction.pinServer(proxy);
+ }
+
+ // Return the proxy
+ return proxy;
+}
+
+function moveServerFrom(from, to, proxy) {
+ for (var i = 0; i < from.length; i++) {
+ if (from[i].name === proxy.name) {
+ from.splice(i, 1);
+ }
+ }
+
+ for (i = 0; i < to.length; i++) {
+ if (to[i].name === proxy.name) {
+ to.splice(i, 1);
+ }
+ }
+
+ to.push(proxy);
+}
+
+function removeProxyFrom(from, proxy) {
+ for (var i = 0; i < from.length; i++) {
+ if (from[i].name === proxy.name) {
+ from.splice(i, 1);
+ }
+ }
+}
+
+function reconnectProxies(self, proxies, callback) {
+ // Count lefts
+ var count = proxies.length;
+
+ // Handle events
+ var _handleEvent = function(self, event) {
+ return function() {
+ var _self = this;
+ count = count - 1;
+
+ // Destroyed
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
+ return this.destroy();
+ }
+
+ if (event === 'connect') {
+ // Destroyed
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
+ return _self.destroy();
+ }
+
+ // Remove the handlers
+ for (var i = 0; i < handlers.length; i++) {
+ _self.removeAllListeners(handlers[i]);
+ }
+
+ // Add stable state handlers
+ _self.on('error', handleEvent(self, 'error'));
+ _self.on('close', handleEvent(self, 'close'));
+ _self.on('timeout', handleEvent(self, 'timeout'));
+ _self.on('parseError', handleEvent(self, 'parseError'));
+
+ // Move to the connected servers
+ moveServerFrom(self.connectingProxies, self.connectedProxies, _self);
+ // Emit topology Change
+ emitTopologyDescriptionChanged(self);
+ // Emit joined event
+ self.emit('joined', 'mongos', _self);
+ } else {
+ // Move from connectingProxies
+ moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
+ this.destroy();
+ }
+
+ // Are we done finish up callback
+ if (count === 0) {
+ callback();
+ }
+ };
+ };
+
+ // No new servers
+ if (count === 0) {
+ return callback();
+ }
+
+ // Execute method
+ function execute(_server, i) {
+ setTimeout(function() {
+ // Destroyed
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ return;
+ }
+
+ // Create a new server instance
+ var server = new Server(
+ Object.assign({}, self.s.options, {
+ host: _server.name.split(':')[0],
+ port: parseInt(_server.name.split(':')[1], 10),
+ reconnect: false,
+ monitoring: false,
+ parent: self
+ })
+ );
+
+ destroyServer(_server, { force: true });
+ removeProxyFrom(self.disconnectedProxies, _server);
+
+ // Relay the server description change
+ relayEvents(server, self, ['serverDescriptionChanged']);
+
+ // Emit opening server event
+ self.emit('serverOpening', {
+ topologyId: server.s.topologyId !== -1 ? server.s.topologyId : self.id,
+ address: server.name
+ });
+
+ // Add temp handlers
+ server.once('connect', _handleEvent(self, 'connect'));
+ server.once('close', _handleEvent(self, 'close'));
+ server.once('timeout', _handleEvent(self, 'timeout'));
+ server.once('error', _handleEvent(self, 'error'));
+ server.once('parseError', _handleEvent(self, 'parseError'));
+
+ // Command Monitoring events
+ relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
+
+ // Connect to proxy
+ self.connectingProxies.push(server);
+ server.connect(self.s.connectOptions);
+ }, i);
+ }
+
+ // Create new instances
+ for (var i = 0; i < proxies.length; i++) {
+ execute(proxies[i], i);
+ }
+}
+
+function topologyMonitor(self, options) {
+ options = options || {};
+
+ // no need to set up the monitor if we're already closed
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ return;
+ }
+
+ // Set momitoring timeout
+ self.haTimeoutId = setTimeout(function() {
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ return;
+ }
+
+ // If we have a primary and a disconnect handler, execute
+ // buffered operations
+ if (self.isConnected() && self.s.disconnectHandler) {
+ self.s.disconnectHandler.execute();
+ }
+
+ // Get the connectingServers
+ var proxies = self.connectedProxies.slice(0);
+ // Get the count
+ var count = proxies.length;
+
+ // If the count is zero schedule a new fast
+ function pingServer(_self, _server, cb) {
+ // Measure running time
+ var start = new Date().getTime();
+
+ // Emit the server heartbeat start
+ emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: _server.name });
+
+ // Execute ismaster
+ _server.command(
+ 'admin.$cmd',
+ {
+ ismaster: true
+ },
+ {
+ monitoring: true,
+ socketTimeout: self.s.options.connectionTimeout || 2000
+ },
+ function(err, r) {
+ if (
+ self.state === DESTROYED ||
+ self.state === DESTROYING ||
+ self.state === UNREFERENCED
+ ) {
+ // Move from connectingProxies
+ moveServerFrom(self.connectedProxies, self.disconnectedProxies, _server);
+ _server.destroy();
+ return cb(err, r);
+ }
+
+ // Calculate latency
+ var latencyMS = new Date().getTime() - start;
+
+ // We had an error, remove it from the state
+ if (err) {
+ // Emit the server heartbeat failure
+ emitSDAMEvent(self, 'serverHeartbeatFailed', {
+ durationMS: latencyMS,
+ failure: err,
+ connectionId: _server.name
+ });
+ // Move from connected proxies to disconnected proxies
+ moveServerFrom(self.connectedProxies, self.disconnectedProxies, _server);
+ } else {
+ // Update the server ismaster
+ _server.ismaster = r.result;
+ _server.lastIsMasterMS = latencyMS;
+
+ // Server heart beat event
+ emitSDAMEvent(self, 'serverHeartbeatSucceeded', {
+ durationMS: latencyMS,
+ reply: r.result,
+ connectionId: _server.name
+ });
+ }
+
+ cb(err, r);
+ }
+ );
+ }
+
+ // No proxies initiate monitor again
+ if (proxies.length === 0) {
+ // Emit close event if any listeners registered
+ if (self.listeners('close').length > 0 && self.state === CONNECTING) {
+ self.emit('error', new MongoError('no mongos proxy available'));
+ } else {
+ self.emit('close', self);
+ }
+
+ // Attempt to connect to any unknown servers
+ return reconnectProxies(self, self.disconnectedProxies, function() {
+ if (self.state === DESTROYED || self.state === DESTROYING || self.state === UNREFERENCED) {
+ return;
+ }
+
+ // Are we connected ? emit connect event
+ if (self.state === CONNECTING && options.firstConnect) {
+ self.emit('connect', self);
+ self.emit('fullsetup', self);
+ self.emit('all', self);
+ } else if (self.isConnected()) {
+ self.emit('reconnect', self);
+ } else if (!self.isConnected() && self.listeners('close').length > 0) {
+ self.emit('close', self);
+ }
+
+ // Perform topology monitor
+ topologyMonitor(self);
+ });
+ }
+
+ // Ping all servers
+ for (var i = 0; i < proxies.length; i++) {
+ pingServer(self, proxies[i], function() {
+ count = count - 1;
+
+ if (count === 0) {
+ if (
+ self.state === DESTROYED ||
+ self.state === DESTROYING ||
+ self.state === UNREFERENCED
+ ) {
+ return;
+ }
+
+ // Attempt to connect to any unknown servers
+ reconnectProxies(self, self.disconnectedProxies, function() {
+ if (
+ self.state === DESTROYED ||
+ self.state === DESTROYING ||
+ self.state === UNREFERENCED
+ ) {
+ return;
+ }
+
+ // Perform topology monitor
+ topologyMonitor(self);
+ });
+ }
+ });
+ }
+ }, self.s.haInterval);
+}
+
+/**
+ * Returns the last known ismaster document for this server
+ * @method
+ * @return {object}
+ */
+Mongos.prototype.lastIsMaster = function() {
+ return this.ismaster;
+};
+
+/**
+ * Unref all connections belong to this server
+ * @method
+ */
+Mongos.prototype.unref = function() {
+ // Transition state
+ stateTransition(this, UNREFERENCED);
+ // Get all proxies
+ var proxies = this.connectedProxies.concat(this.connectingProxies);
+ proxies.forEach(function(x) {
+ x.unref();
+ });
+
+ clearTimeout(this.haTimeoutId);
+};
+
+/**
+ * Destroy the server connection
+ * @param {boolean} [options.force=false] Force destroy the pool
+ * @method
+ */
+Mongos.prototype.destroy = function(options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || {};
+
+ stateTransition(this, DESTROYING);
+ if (this.haTimeoutId) {
+ clearTimeout(this.haTimeoutId);
+ }
+
+ const proxies = this.connectedProxies.concat(this.connectingProxies);
+ let serverCount = proxies.length;
+ const serverDestroyed = () => {
+ serverCount--;
+ if (serverCount > 0) {
+ return;
+ }
+
+ emitTopologyDescriptionChanged(this);
+ emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
+ stateTransition(this, DESTROYED);
+ if (typeof callback === 'function') {
+ callback(null, null);
+ }
+ };
+
+ if (serverCount === 0) {
+ serverDestroyed();
+ return;
+ }
+
+ // Destroy all connecting servers
+ proxies.forEach(server => {
+ // Emit the sdam event
+ this.emit('serverClosed', {
+ topologyId: this.id,
+ address: server.name
+ });
+
+ destroyServer(server, options, serverDestroyed);
+ moveServerFrom(this.connectedProxies, this.disconnectedProxies, server);
+ });
+};
+
+/**
+ * Figure out if the server is connected
+ * @method
+ * @return {boolean}
+ */
+Mongos.prototype.isConnected = function() {
+ return this.connectedProxies.length > 0;
+};
+
+/**
+ * Figure out if the server instance was destroyed by calling destroy
+ * @method
+ * @return {boolean}
+ */
+Mongos.prototype.isDestroyed = function() {
+ return this.state === DESTROYED;
+};
+
+//
+// Operations
+//
+
+function executeWriteOperation(args, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // TODO: once we drop Node 4, use destructuring either here or in arguments.
+ const self = args.self;
+ const op = args.op;
+ const ns = args.ns;
+ const ops = args.ops;
+
+ // Pick a server
+ let server = pickProxy(self, options.session);
+ // No server found error out
+ if (!server) return callback(new MongoError('no mongos proxy available'));
+
+ const willRetryWrite =
+ !args.retrying &&
+ !!options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(self) &&
+ !options.session.inTransaction();
+
+ const handler = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err) || !willRetryWrite) {
+ err = getMMAPError(err);
+ return callback(err);
+ }
+
+ // Pick another server
+ server = pickProxy(self, options.session);
+
+ // No server found error out with original error
+ if (!server) {
+ return callback(err);
+ }
+
+ const newArgs = Object.assign({}, args, { retrying: true });
+ return executeWriteOperation(newArgs, options, callback);
+ };
+
+ if (callback.operationId) {
+ handler.operationId = callback.operationId;
+ }
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ // rerun the operation
+ server[op](ns, ops, options, handler);
+}
+
+/**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.insert = function(ns, ops, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.state === DESTROYED) {
+ return callback(new MongoError(f('topology was destroyed')));
+ }
+
+ // Not connected but we have a disconnecthandler
+ if (!this.isConnected() && this.s.disconnectHandler != null) {
+ return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
+ }
+
+ // No mongos proxy available
+ if (!this.isConnected()) {
+ return callback(new MongoError('no mongos proxy available'));
+ }
+
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'insert', ns, ops }, options, callback);
+};
+
+/**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.update = function(ns, ops, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.state === DESTROYED) {
+ return callback(new MongoError(f('topology was destroyed')));
+ }
+
+ // Not connected but we have a disconnecthandler
+ if (!this.isConnected() && this.s.disconnectHandler != null) {
+ return this.s.disconnectHandler.add('update', ns, ops, options, callback);
+ }
+
+ // No mongos proxy available
+ if (!this.isConnected()) {
+ return callback(new MongoError('no mongos proxy available'));
+ }
+
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'update', ns, ops }, options, callback);
+};
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.remove = function(ns, ops, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.state === DESTROYED) {
+ return callback(new MongoError(f('topology was destroyed')));
+ }
+
+ // Not connected but we have a disconnecthandler
+ if (!this.isConnected() && this.s.disconnectHandler != null) {
+ return this.s.disconnectHandler.add('remove', ns, ops, options, callback);
+ }
+
+ // No mongos proxy available
+ if (!this.isConnected()) {
+ return callback(new MongoError('no mongos proxy available'));
+ }
+
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'remove', ns, ops }, options, callback);
+};
+
+const RETRYABLE_WRITE_OPERATIONS = ['findAndModify', 'insert', 'update', 'delete'];
+
+function isWriteCommand(command) {
+ return RETRYABLE_WRITE_OPERATIONS.some(op => command[op]);
+}
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Connection} [options.connection] Specify connection object to execute command against
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.command = function(ns, cmd, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.state === DESTROYED) {
+ return callback(new MongoError(f('topology was destroyed')));
+ }
+
+ var self = this;
+
+ // Pick a proxy
+ var server = pickProxy(self, options.session);
+
+ // Topology is not connected, save the call in the provided store to be
+ // Executed at some point when the handler deems it's reconnected
+ if ((server == null || !server.isConnected()) && this.s.disconnectHandler != null) {
+ return this.s.disconnectHandler.add('command', ns, cmd, options, callback);
+ }
+
+ // No server returned we had an error
+ if (server == null) {
+ return callback(new MongoError('no mongos proxy available'));
+ }
+
+ // Cloned options
+ var clonedOptions = cloneOptions(options);
+ clonedOptions.topology = self;
+
+ const willRetryWrite =
+ !options.retrying &&
+ options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(self) &&
+ !options.session.inTransaction() &&
+ isWriteCommand(cmd);
+
+ const cb = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err)) {
+ return callback(err);
+ }
+
+ if (willRetryWrite) {
+ const newOptions = Object.assign({}, clonedOptions, { retrying: true });
+ return this.command(ns, cmd, newOptions, callback);
+ }
+
+ return callback(err);
+ };
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ // Execute the command
+ server.command(ns, cmd, clonedOptions, cb);
+};
+
+/**
+ * Get a new cursor
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options] Options for the cursor
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {object} [options.topology] The internal topology of the created cursor
+ * @returns {Cursor}
+ */
+Mongos.prototype.cursor = function(ns, cmd, options) {
+ options = options || {};
+ const topology = options.topology || this;
+
+ // Set up final cursor type
+ var FinalCursor = options.cursorFactory || this.s.Cursor;
+
+ // Return the cursor
+ return new FinalCursor(topology, ns, cmd, options);
+};
+
+/**
+ * Selects a server
+ *
+ * @method
+ * @param {function} selector Unused
+ * @param {ReadPreference} [options.readPreference] Unused
+ * @param {ClientSession} [options.session] Specify a session if it is being used
+ * @param {function} callback
+ */
+Mongos.prototype.selectServer = function(selector, options, callback) {
+ if (typeof selector === 'function' && typeof callback === 'undefined')
+ (callback = selector), (selector = undefined), (options = {});
+ if (typeof options === 'function')
+ (callback = options), (options = selector), (selector = undefined);
+ options = options || {};
+
+ const server = pickProxy(this, options.session);
+ if (server == null) {
+ callback(new MongoError('server selection failed'));
+ return;
+ }
+
+ if (this.s.debug) this.emit('pickedServer', null, server);
+ callback(null, server);
+};
+
+/**
+ * All raw connections
+ * @method
+ * @return {Connection[]}
+ */
+Mongos.prototype.connections = function() {
+ var connections = [];
+
+ for (var i = 0; i < this.connectedProxies.length; i++) {
+ connections = connections.concat(this.connectedProxies[i].connections());
+ }
+
+ return connections;
+};
+
+function emitTopologyDescriptionChanged(self) {
+ if (self.listeners('topologyDescriptionChanged').length > 0) {
+ var topology = 'Unknown';
+ if (self.connectedProxies.length > 0) {
+ topology = 'Sharded';
+ }
+
+ // Generate description
+ var description = {
+ topologyType: topology,
+ servers: []
+ };
+
+ // All proxies
+ var proxies = self.disconnectedProxies.concat(self.connectingProxies);
+
+ // Add all the disconnected proxies
+ description.servers = description.servers.concat(
+ proxies.map(function(x) {
+ var description = x.getDescription();
+ description.type = 'Unknown';
+ return description;
+ })
+ );
+
+ // Add all the connected proxies
+ description.servers = description.servers.concat(
+ self.connectedProxies.map(function(x) {
+ var description = x.getDescription();
+ description.type = 'Mongos';
+ return description;
+ })
+ );
+
+ // Get the diff
+ var diffResult = diff(self.topologyDescription, description);
+
+ // Create the result
+ var result = {
+ topologyId: self.id,
+ previousDescription: self.topologyDescription,
+ newDescription: description,
+ diff: diffResult
+ };
+
+ // Emit the topologyDescription change
+ if (diffResult.servers.length > 0) {
+ self.emit('topologyDescriptionChanged', result);
+ }
+
+ // Set the new description
+ self.topologyDescription = description;
+ }
+}
+
+/**
+ * A mongos connect event, used to verify that the connection is up and running
+ *
+ * @event Mongos#connect
+ * @type {Mongos}
+ */
+
+/**
+ * A mongos reconnect event, used to verify that the mongos topology has reconnected
+ *
+ * @event Mongos#reconnect
+ * @type {Mongos}
+ */
+
+/**
+ * A mongos fullsetup event, used to signal that all topology members have been contacted.
+ *
+ * @event Mongos#fullsetup
+ * @type {Mongos}
+ */
+
+/**
+ * A mongos all event, used to signal that all topology members have been contacted.
+ *
+ * @event Mongos#all
+ * @type {Mongos}
+ */
+
+/**
+ * A server member left the mongos list
+ *
+ * @event Mongos#left
+ * @type {Mongos}
+ * @param {string} type The type of member that left (mongos)
+ * @param {Server} server The server object that left
+ */
+
+/**
+ * A server member joined the mongos list
+ *
+ * @event Mongos#joined
+ * @type {Mongos}
+ * @param {string} type The type of member that left (mongos)
+ * @param {Server} server The server object that joined
+ */
+
+/**
+ * A server opening SDAM monitoring event
+ *
+ * @event Mongos#serverOpening
+ * @type {object}
+ */
+
+/**
+ * A server closed SDAM monitoring event
+ *
+ * @event Mongos#serverClosed
+ * @type {object}
+ */
+
+/**
+ * A server description SDAM change monitoring event
+ *
+ * @event Mongos#serverDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology open SDAM event
+ *
+ * @event Mongos#topologyOpening
+ * @type {object}
+ */
+
+/**
+ * A topology closed SDAM event
+ *
+ * @event Mongos#topologyClosed
+ * @type {object}
+ */
+
+/**
+ * A topology structure SDAM change event
+ *
+ * @event Mongos#topologyDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatStarted SDAM event
+ *
+ * @event Mongos#serverHeartbeatStarted
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatFailed SDAM event
+ *
+ * @event Mongos#serverHeartbeatFailed
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatSucceeded SDAM change event
+ *
+ * @event Mongos#serverHeartbeatSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event Mongos#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event Mongos#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event Mongos#commandFailed
+ * @type {object}
+ */
+
+module.exports = Mongos;
diff --git a/node_modules/mongodb/lib/core/topologies/read_preference.js b/node_modules/mongodb/lib/core/topologies/read_preference.js
new file mode 100644
index 0000000..a813ec4
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/read_preference.js
@@ -0,0 +1,202 @@
+'use strict';
+
+/**
+ * The **ReadPreference** class is a class that represents a MongoDB ReadPreference and is
+ * used to construct connections.
+ * @class
+ * @param {string} mode A string describing the read preference mode (primary|primaryPreferred|secondary|secondaryPreferred|nearest)
+ * @param {array} tags The tags object
+ * @param {object} [options] Additional read preference options
+ * @param {number} [options.maxStalenessSeconds] Max secondary read staleness in seconds, Minimum value is 90 seconds.
+ * @see https://docs.mongodb.com/manual/core/read-preference/
+ * @return {ReadPreference}
+ */
+const ReadPreference = function(mode, tags, options) {
+ if (!ReadPreference.isValid(mode)) {
+ throw new TypeError(`Invalid read preference mode ${mode}`);
+ }
+
+ // TODO(major): tags MUST be an array of tagsets
+ if (tags && !Array.isArray(tags)) {
+ console.warn(
+ 'ReadPreference tags must be an array, this will change in the next major version'
+ );
+
+ if (typeof tags.maxStalenessSeconds !== 'undefined') {
+ // this is likely an options object
+ options = tags;
+ tags = undefined;
+ } else {
+ tags = [tags];
+ }
+ }
+
+ this.mode = mode;
+ this.tags = tags;
+
+ options = options || {};
+ if (options.maxStalenessSeconds != null) {
+ if (options.maxStalenessSeconds <= 0) {
+ throw new TypeError('maxStalenessSeconds must be a positive integer');
+ }
+
+ this.maxStalenessSeconds = options.maxStalenessSeconds;
+
+ // NOTE: The minimum required wire version is 5 for this read preference. If the existing
+ // topology has a lower value then a MongoError will be thrown during server selection.
+ this.minWireVersion = 5;
+ }
+
+ if (this.mode === ReadPreference.PRIMARY) {
+ if (this.tags && Array.isArray(this.tags) && this.tags.length > 0) {
+ throw new TypeError('Primary read preference cannot be combined with tags');
+ }
+
+ if (this.maxStalenessSeconds) {
+ throw new TypeError('Primary read preference cannot be combined with maxStalenessSeconds');
+ }
+ }
+};
+
+// Support the deprecated `preference` property introduced in the porcelain layer
+Object.defineProperty(ReadPreference.prototype, 'preference', {
+ enumerable: true,
+ get: function() {
+ return this.mode;
+ }
+});
+
+/*
+ * Read preference mode constants
+ */
+ReadPreference.PRIMARY = 'primary';
+ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
+ReadPreference.SECONDARY = 'secondary';
+ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
+ReadPreference.NEAREST = 'nearest';
+
+const VALID_MODES = [
+ ReadPreference.PRIMARY,
+ ReadPreference.PRIMARY_PREFERRED,
+ ReadPreference.SECONDARY,
+ ReadPreference.SECONDARY_PREFERRED,
+ ReadPreference.NEAREST,
+ null
+];
+
+/**
+ * Construct a ReadPreference given an options object.
+ *
+ * @param {object} options The options object from which to extract the read preference.
+ * @return {ReadPreference}
+ */
+ReadPreference.fromOptions = function(options) {
+ const readPreference = options.readPreference;
+ const readPreferenceTags = options.readPreferenceTags;
+
+ if (readPreference == null) {
+ return null;
+ }
+
+ if (typeof readPreference === 'string') {
+ return new ReadPreference(readPreference, readPreferenceTags);
+ } else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
+ const mode = readPreference.mode || readPreference.preference;
+ if (mode && typeof mode === 'string') {
+ return new ReadPreference(mode, readPreference.tags, {
+ maxStalenessSeconds: readPreference.maxStalenessSeconds
+ });
+ }
+ }
+
+ return readPreference;
+};
+
+/**
+ * Validate if a mode is legal
+ *
+ * @method
+ * @param {string} mode The string representing the read preference mode.
+ * @return {boolean} True if a mode is valid
+ */
+ReadPreference.isValid = function(mode) {
+ return VALID_MODES.indexOf(mode) !== -1;
+};
+
+/**
+ * Validate if a mode is legal
+ *
+ * @method
+ * @param {string} mode The string representing the read preference mode.
+ * @return {boolean} True if a mode is valid
+ */
+ReadPreference.prototype.isValid = function(mode) {
+ return ReadPreference.isValid(typeof mode === 'string' ? mode : this.mode);
+};
+
+const needSlaveOk = ['primaryPreferred', 'secondary', 'secondaryPreferred', 'nearest'];
+
+/**
+ * Indicates that this readPreference needs the "slaveOk" bit when sent over the wire
+ * @method
+ * @return {boolean}
+ * @see https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#op-query
+ */
+ReadPreference.prototype.slaveOk = function() {
+ return needSlaveOk.indexOf(this.mode) !== -1;
+};
+
+/**
+ * Are the two read preference equal
+ * @method
+ * @param {ReadPreference} readPreference The read preference with which to check equality
+ * @return {boolean} True if the two ReadPreferences are equivalent
+ */
+ReadPreference.prototype.equals = function(readPreference) {
+ return readPreference.mode === this.mode;
+};
+
+/**
+ * Return JSON representation
+ * @method
+ * @return {Object} A JSON representation of the ReadPreference
+ */
+ReadPreference.prototype.toJSON = function() {
+ const readPreference = { mode: this.mode };
+ if (Array.isArray(this.tags)) readPreference.tags = this.tags;
+ if (this.maxStalenessSeconds) readPreference.maxStalenessSeconds = this.maxStalenessSeconds;
+ return readPreference;
+};
+
+/**
+ * Primary read preference
+ * @member
+ * @type {ReadPreference}
+ */
+ReadPreference.primary = new ReadPreference('primary');
+/**
+ * Primary Preferred read preference
+ * @member
+ * @type {ReadPreference}
+ */
+ReadPreference.primaryPreferred = new ReadPreference('primaryPreferred');
+/**
+ * Secondary read preference
+ * @member
+ * @type {ReadPreference}
+ */
+ReadPreference.secondary = new ReadPreference('secondary');
+/**
+ * Secondary Preferred read preference
+ * @member
+ * @type {ReadPreference}
+ */
+ReadPreference.secondaryPreferred = new ReadPreference('secondaryPreferred');
+/**
+ * Nearest read preference
+ * @member
+ * @type {ReadPreference}
+ */
+ReadPreference.nearest = new ReadPreference('nearest');
+
+module.exports = ReadPreference;
diff --git a/node_modules/mongodb/lib/core/topologies/replset.js b/node_modules/mongodb/lib/core/topologies/replset.js
new file mode 100644
index 0000000..b289d59
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/replset.js
@@ -0,0 +1,1559 @@
+'use strict';
+
+const inherits = require('util').inherits;
+const f = require('util').format;
+const EventEmitter = require('events').EventEmitter;
+const ReadPreference = require('./read_preference');
+const CoreCursor = require('../cursor').CoreCursor;
+const retrieveBSON = require('../connection/utils').retrieveBSON;
+const Logger = require('../connection/logger');
+const MongoError = require('../error').MongoError;
+const Server = require('./server');
+const ReplSetState = require('./replset_state');
+const Timeout = require('./shared').Timeout;
+const Interval = require('./shared').Interval;
+const SessionMixins = require('./shared').SessionMixins;
+const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
+const relayEvents = require('../utils').relayEvents;
+const isRetryableError = require('../error').isRetryableError;
+const BSON = retrieveBSON();
+const calculateDurationInMs = require('../utils').calculateDurationInMs;
+const getMMAPError = require('./shared').getMMAPError;
+const makeClientMetadata = require('../utils').makeClientMetadata;
+
+//
+// States
+var DISCONNECTED = 'disconnected';
+var CONNECTING = 'connecting';
+var CONNECTED = 'connected';
+var UNREFERENCED = 'unreferenced';
+var DESTROYED = 'destroyed';
+
+function stateTransition(self, newState) {
+ var legalTransitions = {
+ disconnected: [CONNECTING, DESTROYED, DISCONNECTED],
+ connecting: [CONNECTING, DESTROYED, CONNECTED, DISCONNECTED],
+ connected: [CONNECTED, DISCONNECTED, DESTROYED, UNREFERENCED],
+ unreferenced: [UNREFERENCED, DESTROYED],
+ destroyed: [DESTROYED]
+ };
+
+ // Get current state
+ var legalStates = legalTransitions[self.state];
+ if (legalStates && legalStates.indexOf(newState) !== -1) {
+ self.state = newState;
+ } else {
+ self.s.logger.error(
+ f(
+ 'Pool with id [%s] failed attempted illegal state transition from [%s] to [%s] only following state allowed [%s]',
+ self.id,
+ self.state,
+ newState,
+ legalStates
+ )
+ );
+ }
+}
+
+//
+// ReplSet instance id
+var id = 1;
+var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
+
+/**
+ * Creates a new Replset instance
+ * @class
+ * @param {array} seedlist A list of seeds for the replicaset
+ * @param {boolean} options.setName The Replicaset set name
+ * @param {boolean} [options.secondaryOnlyConnectionAllowed=false] Allow connection to a secondary only replicaset
+ * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
+ * @param {boolean} [options.emitError=false] Server will emit errors events
+ * @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
+ * @param {number} [options.size=5] Server connection pool size
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {number} [options.connectionTimeout=10000] TCP Connection timeout setting
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
+ * @param {boolean} [options.ssl=false] Use SSL for connection
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {Buffer} [options.ca] SSL Certificate store binary buffer
+ * @param {Buffer} [options.crl] SSL Certificate revocation store binary buffer
+ * @param {Buffer} [options.cert] SSL Certificate binary buffer
+ * @param {Buffer} [options.key] SSL Key file binary buffer
+ * @param {string} [options.passphrase] SSL Certificate pass phrase
+ * @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
+ * @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
+ * @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
+ * @param {number} [options.pingInterval=5000] Ping interval to check the response time to the different servers
+ * @param {number} [options.localThresholdMS=15] Cutoff latency point in MS for Replicaset member selection
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @return {ReplSet} A cursor instance
+ * @fires ReplSet#connect
+ * @fires ReplSet#ha
+ * @fires ReplSet#joined
+ * @fires ReplSet#left
+ * @fires ReplSet#failed
+ * @fires ReplSet#fullsetup
+ * @fires ReplSet#all
+ * @fires ReplSet#error
+ * @fires ReplSet#serverHeartbeatStarted
+ * @fires ReplSet#serverHeartbeatSucceeded
+ * @fires ReplSet#serverHeartbeatFailed
+ * @fires ReplSet#topologyOpening
+ * @fires ReplSet#topologyClosed
+ * @fires ReplSet#topologyDescriptionChanged
+ * @property {string} type the topology type.
+ * @property {string} parserType the parser type used (c++ or js).
+ */
+var ReplSet = function(seedlist, options) {
+ var self = this;
+ options = options || {};
+
+ // Validate seedlist
+ if (!Array.isArray(seedlist)) throw new MongoError('seedlist must be an array');
+ // Validate list
+ if (seedlist.length === 0) throw new MongoError('seedlist must contain at least one entry');
+ // Validate entries
+ seedlist.forEach(function(e) {
+ if (typeof e.host !== 'string' || typeof e.port !== 'number')
+ throw new MongoError('seedlist entry must contain a host and port');
+ });
+
+ // Add event listener
+ EventEmitter.call(this);
+
+ // Get replSet Id
+ this.id = id++;
+
+ // Get the localThresholdMS
+ var localThresholdMS = options.localThresholdMS || 15;
+ // Backward compatibility
+ if (options.acceptableLatency) localThresholdMS = options.acceptableLatency;
+
+ // Create a logger
+ var logger = Logger('ReplSet', options);
+
+ // Internal state
+ this.s = {
+ options: Object.assign({ metadata: makeClientMetadata(options) }, options),
+ // BSON instance
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ]),
+ // Factory overrides
+ Cursor: options.cursorFactory || CoreCursor,
+ // Logger instance
+ logger: logger,
+ // Seedlist
+ seedlist: seedlist,
+ // Replicaset state
+ replicaSetState: new ReplSetState({
+ id: this.id,
+ setName: options.setName,
+ acceptableLatency: localThresholdMS,
+ heartbeatFrequencyMS: options.haInterval ? options.haInterval : 10000,
+ logger: logger
+ }),
+ // Current servers we are connecting to
+ connectingServers: [],
+ // Ha interval
+ haInterval: options.haInterval ? options.haInterval : 10000,
+ // Minimum heartbeat frequency used if we detect a server close
+ minHeartbeatFrequencyMS: 500,
+ // Disconnect handler
+ disconnectHandler: options.disconnectHandler,
+ // Server selection index
+ index: 0,
+ // Connect function options passed in
+ connectOptions: {},
+ // Are we running in debug mode
+ debug: typeof options.debug === 'boolean' ? options.debug : false
+ };
+
+ // Add handler for topology change
+ this.s.replicaSetState.on('topologyDescriptionChanged', function(r) {
+ self.emit('topologyDescriptionChanged', r);
+ });
+
+ // Log info warning if the socketTimeout < haInterval as it will cause
+ // a lot of recycled connections to happen.
+ if (
+ this.s.logger.isWarn() &&
+ this.s.options.socketTimeout !== 0 &&
+ this.s.options.socketTimeout < this.s.haInterval
+ ) {
+ this.s.logger.warn(
+ f(
+ 'warning socketTimeout %s is less than haInterval %s. This might cause unnecessary server reconnections due to socket timeouts',
+ this.s.options.socketTimeout,
+ this.s.haInterval
+ )
+ );
+ }
+
+ // Add forwarding of events from state handler
+ var types = ['joined', 'left'];
+ types.forEach(function(x) {
+ self.s.replicaSetState.on(x, function(t, s) {
+ self.emit(x, t, s);
+ });
+ });
+
+ // Connect stat
+ this.initialConnectState = {
+ connect: false,
+ fullsetup: false,
+ all: false
+ };
+
+ // Disconnected state
+ this.state = DISCONNECTED;
+ this.haTimeoutId = null;
+ // Last ismaster
+ this.ismaster = null;
+ // Contains the intervalId
+ this.intervalIds = [];
+
+ // Highest clusterTime seen in responses from the current deployment
+ this.clusterTime = null;
+};
+
+inherits(ReplSet, EventEmitter);
+Object.assign(ReplSet.prototype, SessionMixins);
+
+Object.defineProperty(ReplSet.prototype, 'type', {
+ enumerable: true,
+ get: function() {
+ return 'replset';
+ }
+});
+
+Object.defineProperty(ReplSet.prototype, 'parserType', {
+ enumerable: true,
+ get: function() {
+ return BSON.native ? 'c++' : 'js';
+ }
+});
+
+Object.defineProperty(ReplSet.prototype, 'logicalSessionTimeoutMinutes', {
+ enumerable: true,
+ get: function() {
+ return this.s.replicaSetState.logicalSessionTimeoutMinutes || null;
+ }
+});
+
+function rexecuteOperations(self) {
+ // If we have a primary and a disconnect handler, execute
+ // buffered operations
+ if (self.s.replicaSetState.hasPrimaryAndSecondary() && self.s.disconnectHandler) {
+ self.s.disconnectHandler.execute();
+ } else if (self.s.replicaSetState.hasPrimary() && self.s.disconnectHandler) {
+ self.s.disconnectHandler.execute({ executePrimary: true });
+ } else if (self.s.replicaSetState.hasSecondary() && self.s.disconnectHandler) {
+ self.s.disconnectHandler.execute({ executeSecondary: true });
+ }
+}
+
+function connectNewServers(self, servers, callback) {
+ // No new servers
+ if (servers.length === 0) {
+ return callback();
+ }
+
+ // Count lefts
+ var count = servers.length;
+ var error = null;
+
+ function done() {
+ count = count - 1;
+ if (count === 0) {
+ callback(error);
+ }
+ }
+
+ // Handle events
+ var _handleEvent = function(self, event) {
+ return function(err) {
+ var _self = this;
+
+ // Destroyed
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ this.destroy({ force: true });
+ return done();
+ }
+
+ if (event === 'connect') {
+ // Update the state
+ var result = self.s.replicaSetState.update(_self);
+ // Update the state with the new server
+ if (result) {
+ // Primary lastIsMaster store it
+ if (_self.lastIsMaster() && _self.lastIsMaster().ismaster) {
+ self.ismaster = _self.lastIsMaster();
+ }
+
+ // Remove the handlers
+ for (let i = 0; i < handlers.length; i++) {
+ _self.removeAllListeners(handlers[i]);
+ }
+
+ // Add stable state handlers
+ _self.on('error', handleEvent(self, 'error'));
+ _self.on('close', handleEvent(self, 'close'));
+ _self.on('timeout', handleEvent(self, 'timeout'));
+ _self.on('parseError', handleEvent(self, 'parseError'));
+
+ // Enalbe the monitoring of the new server
+ monitorServer(_self.lastIsMaster().me, self, {});
+
+ // Rexecute any stalled operation
+ rexecuteOperations(self);
+ } else {
+ _self.destroy({ force: true });
+ }
+ } else if (event === 'error') {
+ error = err;
+ }
+
+ // Rexecute any stalled operation
+ rexecuteOperations(self);
+ done();
+ };
+ };
+
+ // Execute method
+ function execute(_server, i) {
+ setTimeout(function() {
+ // Destroyed
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ return;
+ }
+
+ // remove existing connecting server if it's failed to connect, otherwise
+ // wait for that server to connect
+ const existingServerIdx = self.s.connectingServers.findIndex(s => s.name === _server);
+ if (existingServerIdx >= 0) {
+ const connectingServer = self.s.connectingServers[existingServerIdx];
+ connectingServer.destroy({ force: true });
+
+ self.s.connectingServers.splice(existingServerIdx, 1);
+ return done();
+ }
+
+ // Create a new server instance
+ var server = new Server(
+ Object.assign({}, self.s.options, {
+ host: _server.split(':')[0],
+ port: parseInt(_server.split(':')[1], 10),
+ reconnect: false,
+ monitoring: false,
+ parent: self
+ })
+ );
+
+ // Add temp handlers
+ server.once('connect', _handleEvent(self, 'connect'));
+ server.once('close', _handleEvent(self, 'close'));
+ server.once('timeout', _handleEvent(self, 'timeout'));
+ server.once('error', _handleEvent(self, 'error'));
+ server.once('parseError', _handleEvent(self, 'parseError'));
+
+ // SDAM Monitoring events
+ server.on('serverOpening', e => self.emit('serverOpening', e));
+ server.on('serverDescriptionChanged', e => self.emit('serverDescriptionChanged', e));
+ server.on('serverClosed', e => self.emit('serverClosed', e));
+
+ // Command Monitoring events
+ relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
+
+ self.s.connectingServers.push(server);
+ server.connect(self.s.connectOptions);
+ }, i);
+ }
+
+ // Create new instances
+ for (var i = 0; i < servers.length; i++) {
+ execute(servers[i], i);
+ }
+}
+
+// Ping the server
+var pingServer = function(self, server, cb) {
+ // Measure running time
+ var start = new Date().getTime();
+
+ // Emit the server heartbeat start
+ emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: server.name });
+
+ // Execute ismaster
+ // Set the socketTimeout for a monitoring message to a low number
+ // Ensuring ismaster calls are timed out quickly
+ server.command(
+ 'admin.$cmd',
+ {
+ ismaster: true
+ },
+ {
+ monitoring: true,
+ socketTimeout: self.s.options.connectionTimeout || 2000
+ },
+ function(err, r) {
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ server.destroy({ force: true });
+ return cb(err, r);
+ }
+
+ // Calculate latency
+ var latencyMS = new Date().getTime() - start;
+
+ // Set the last updatedTime
+ var hrtime = process.hrtime();
+ server.lastUpdateTime = (hrtime[0] * 1e9 + hrtime[1]) / 1e6;
+
+ // We had an error, remove it from the state
+ if (err) {
+ // Emit the server heartbeat failure
+ emitSDAMEvent(self, 'serverHeartbeatFailed', {
+ durationMS: latencyMS,
+ failure: err,
+ connectionId: server.name
+ });
+
+ // Remove server from the state
+ self.s.replicaSetState.remove(server);
+ } else {
+ // Update the server ismaster
+ server.ismaster = r.result;
+
+ // Check if we have a lastWriteDate convert it to MS
+ // and store on the server instance for later use
+ if (server.ismaster.lastWrite && server.ismaster.lastWrite.lastWriteDate) {
+ server.lastWriteDate = server.ismaster.lastWrite.lastWriteDate.getTime();
+ }
+
+ // Do we have a brand new server
+ if (server.lastIsMasterMS === -1) {
+ server.lastIsMasterMS = latencyMS;
+ } else if (server.lastIsMasterMS) {
+ // After the first measurement, average RTT MUST be computed using an
+ // exponentially-weighted moving average formula, with a weighting factor (alpha) of 0.2.
+ // If the prior average is denoted old_rtt, then the new average (new_rtt) is
+ // computed from a new RTT measurement (x) using the following formula:
+ // alpha = 0.2
+ // new_rtt = alpha * x + (1 - alpha) * old_rtt
+ server.lastIsMasterMS = 0.2 * latencyMS + (1 - 0.2) * server.lastIsMasterMS;
+ }
+
+ if (self.s.replicaSetState.update(server)) {
+ // Primary lastIsMaster store it
+ if (server.lastIsMaster() && server.lastIsMaster().ismaster) {
+ self.ismaster = server.lastIsMaster();
+ }
+ }
+
+ // Server heart beat event
+ emitSDAMEvent(self, 'serverHeartbeatSucceeded', {
+ durationMS: latencyMS,
+ reply: r.result,
+ connectionId: server.name
+ });
+ }
+
+ // Calculate the staleness for this server
+ self.s.replicaSetState.updateServerMaxStaleness(server, self.s.haInterval);
+
+ // Callback
+ cb(err, r);
+ }
+ );
+};
+
+// Each server is monitored in parallel in their own timeout loop
+var monitorServer = function(host, self, options) {
+ // If this is not the initial scan
+ // Is this server already being monitoried, then skip monitoring
+ if (!options.haInterval) {
+ for (var i = 0; i < self.intervalIds.length; i++) {
+ if (self.intervalIds[i].__host === host) {
+ return;
+ }
+ }
+ }
+
+ // Get the haInterval
+ var _process = options.haInterval ? Timeout : Interval;
+ var _haInterval = options.haInterval ? options.haInterval : self.s.haInterval;
+
+ // Create the interval
+ var intervalId = new _process(function() {
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ // clearInterval(intervalId);
+ intervalId.stop();
+ return;
+ }
+
+ // Do we already have server connection available for this host
+ var _server = self.s.replicaSetState.get(host);
+
+ // Check if we have a known server connection and reuse
+ if (_server) {
+ // Ping the server
+ return pingServer(self, _server, function(err) {
+ if (err) {
+ // NOTE: should something happen here?
+ return;
+ }
+
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ intervalId.stop();
+ return;
+ }
+
+ // Filter out all called intervaliIds
+ self.intervalIds = self.intervalIds.filter(function(intervalId) {
+ return intervalId.isRunning();
+ });
+
+ // Initial sweep
+ if (_process === Timeout) {
+ if (
+ self.state === CONNECTING &&
+ ((self.s.replicaSetState.hasSecondary() &&
+ self.s.options.secondaryOnlyConnectionAllowed) ||
+ self.s.replicaSetState.hasPrimary())
+ ) {
+ self.state = CONNECTED;
+
+ // Emit connected sign
+ process.nextTick(function() {
+ self.emit('connect', self);
+ });
+
+ // Start topology interval check
+ topologyMonitor(self, {});
+ }
+ } else {
+ if (
+ self.state === DISCONNECTED &&
+ ((self.s.replicaSetState.hasSecondary() &&
+ self.s.options.secondaryOnlyConnectionAllowed) ||
+ self.s.replicaSetState.hasPrimary())
+ ) {
+ self.state = CONNECTED;
+
+ // Rexecute any stalled operation
+ rexecuteOperations(self);
+
+ // Emit connected sign
+ process.nextTick(function() {
+ self.emit('reconnect', self);
+ });
+ }
+ }
+
+ if (
+ self.initialConnectState.connect &&
+ !self.initialConnectState.fullsetup &&
+ self.s.replicaSetState.hasPrimaryAndSecondary()
+ ) {
+ // Set initial connect state
+ self.initialConnectState.fullsetup = true;
+ self.initialConnectState.all = true;
+
+ process.nextTick(function() {
+ self.emit('fullsetup', self);
+ self.emit('all', self);
+ });
+ }
+ });
+ }
+ }, _haInterval);
+
+ // Start the interval
+ intervalId.start();
+ // Add the intervalId host name
+ intervalId.__host = host;
+ // Add the intervalId to our list of intervalIds
+ self.intervalIds.push(intervalId);
+};
+
+function topologyMonitor(self, options) {
+ if (self.state === DESTROYED || self.state === UNREFERENCED) return;
+ options = options || {};
+
+ // Get the servers
+ var servers = Object.keys(self.s.replicaSetState.set);
+
+ // Get the haInterval
+ var _process = options.haInterval ? Timeout : Interval;
+ var _haInterval = options.haInterval ? options.haInterval : self.s.haInterval;
+
+ if (_process === Timeout) {
+ return connectNewServers(self, self.s.replicaSetState.unknownServers, function(err) {
+ // Don't emit errors if the connection was already
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ return;
+ }
+
+ if (!self.s.replicaSetState.hasPrimary() && !self.s.options.secondaryOnlyConnectionAllowed) {
+ if (err) {
+ return self.emit('error', err);
+ }
+
+ self.emit(
+ 'error',
+ new MongoError('no primary found in replicaset or invalid replica set name')
+ );
+ return self.destroy({ force: true });
+ } else if (
+ !self.s.replicaSetState.hasSecondary() &&
+ self.s.options.secondaryOnlyConnectionAllowed
+ ) {
+ if (err) {
+ return self.emit('error', err);
+ }
+
+ self.emit(
+ 'error',
+ new MongoError('no secondary found in replicaset or invalid replica set name')
+ );
+ return self.destroy({ force: true });
+ }
+
+ for (var i = 0; i < servers.length; i++) {
+ monitorServer(servers[i], self, options);
+ }
+ });
+ } else {
+ for (var i = 0; i < servers.length; i++) {
+ monitorServer(servers[i], self, options);
+ }
+ }
+
+ // Run the reconnect process
+ function executeReconnect(self) {
+ return function() {
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ return;
+ }
+
+ connectNewServers(self, self.s.replicaSetState.unknownServers, function() {
+ var monitoringFrequencey = self.s.replicaSetState.hasPrimary()
+ ? _haInterval
+ : self.s.minHeartbeatFrequencyMS;
+
+ // Create a timeout
+ self.intervalIds.push(new Timeout(executeReconnect(self), monitoringFrequencey).start());
+ });
+ };
+ }
+
+ // Decide what kind of interval to use
+ var intervalTime = !self.s.replicaSetState.hasPrimary()
+ ? self.s.minHeartbeatFrequencyMS
+ : _haInterval;
+
+ self.intervalIds.push(new Timeout(executeReconnect(self), intervalTime).start());
+}
+
+function addServerToList(list, server) {
+ for (var i = 0; i < list.length; i++) {
+ if (list[i].name.toLowerCase() === server.name.toLowerCase()) return true;
+ }
+
+ list.push(server);
+}
+
+function handleEvent(self, event) {
+ return function() {
+ if (self.state === DESTROYED || self.state === UNREFERENCED) return;
+ // Debug log
+ if (self.s.logger.isDebug()) {
+ self.s.logger.debug(
+ f('handleEvent %s from server %s in replset with id %s', event, this.name, self.id)
+ );
+ }
+
+ // Remove from the replicaset state
+ self.s.replicaSetState.remove(this);
+
+ // Are we in a destroyed state return
+ if (self.state === DESTROYED || self.state === UNREFERENCED) return;
+
+ // If no primary and secondary available
+ if (
+ !self.s.replicaSetState.hasPrimary() &&
+ !self.s.replicaSetState.hasSecondary() &&
+ self.s.options.secondaryOnlyConnectionAllowed
+ ) {
+ stateTransition(self, DISCONNECTED);
+ } else if (!self.s.replicaSetState.hasPrimary()) {
+ stateTransition(self, DISCONNECTED);
+ }
+
+ addServerToList(self.s.connectingServers, this);
+ };
+}
+
+function shouldTriggerConnect(self) {
+ const isConnecting = self.state === CONNECTING;
+ const hasPrimary = self.s.replicaSetState.hasPrimary();
+ const hasSecondary = self.s.replicaSetState.hasSecondary();
+ const secondaryOnlyConnectionAllowed = self.s.options.secondaryOnlyConnectionAllowed;
+ const readPreferenceSecondary =
+ self.s.connectOptions.readPreference &&
+ self.s.connectOptions.readPreference.equals(ReadPreference.secondary);
+
+ return (
+ (isConnecting &&
+ ((readPreferenceSecondary && hasSecondary) || (!readPreferenceSecondary && hasPrimary))) ||
+ (hasSecondary && secondaryOnlyConnectionAllowed)
+ );
+}
+
+function handleInitialConnectEvent(self, event) {
+ return function() {
+ var _this = this;
+ // Debug log
+ if (self.s.logger.isDebug()) {
+ self.s.logger.debug(
+ f(
+ 'handleInitialConnectEvent %s from server %s in replset with id %s',
+ event,
+ this.name,
+ self.id
+ )
+ );
+ }
+
+ // Destroy the instance
+ if (self.state === DESTROYED || self.state === UNREFERENCED) {
+ return this.destroy({ force: true });
+ }
+
+ // Check the type of server
+ if (event === 'connect') {
+ // Update the state
+ var result = self.s.replicaSetState.update(_this);
+ if (result === true) {
+ // Primary lastIsMaster store it
+ if (_this.lastIsMaster() && _this.lastIsMaster().ismaster) {
+ self.ismaster = _this.lastIsMaster();
+ }
+
+ // Debug log
+ if (self.s.logger.isDebug()) {
+ self.s.logger.debug(
+ f(
+ 'handleInitialConnectEvent %s from server %s in replset with id %s has state [%s]',
+ event,
+ _this.name,
+ self.id,
+ JSON.stringify(self.s.replicaSetState.set)
+ )
+ );
+ }
+
+ // Remove the handlers
+ for (let i = 0; i < handlers.length; i++) {
+ _this.removeAllListeners(handlers[i]);
+ }
+
+ // Add stable state handlers
+ _this.on('error', handleEvent(self, 'error'));
+ _this.on('close', handleEvent(self, 'close'));
+ _this.on('timeout', handleEvent(self, 'timeout'));
+ _this.on('parseError', handleEvent(self, 'parseError'));
+
+ // Do we have a primary or primaryAndSecondary
+ if (shouldTriggerConnect(self)) {
+ // We are connected
+ self.state = CONNECTED;
+
+ // Set initial connect state
+ self.initialConnectState.connect = true;
+ // Emit connect event
+ process.nextTick(function() {
+ self.emit('connect', self);
+ });
+
+ topologyMonitor(self, {});
+ }
+ } else if (result instanceof MongoError) {
+ _this.destroy({ force: true });
+ self.destroy({ force: true });
+ return self.emit('error', result);
+ } else {
+ _this.destroy({ force: true });
+ }
+ } else {
+ // Emit failure to connect
+ self.emit('failed', this);
+
+ addServerToList(self.s.connectingServers, this);
+ // Remove from the state
+ self.s.replicaSetState.remove(this);
+ }
+
+ if (
+ self.initialConnectState.connect &&
+ !self.initialConnectState.fullsetup &&
+ self.s.replicaSetState.hasPrimaryAndSecondary()
+ ) {
+ // Set initial connect state
+ self.initialConnectState.fullsetup = true;
+ self.initialConnectState.all = true;
+
+ process.nextTick(function() {
+ self.emit('fullsetup', self);
+ self.emit('all', self);
+ });
+ }
+
+ // Remove from the list from connectingServers
+ for (var i = 0; i < self.s.connectingServers.length; i++) {
+ if (self.s.connectingServers[i].equals(this)) {
+ self.s.connectingServers.splice(i, 1);
+ }
+ }
+
+ // Trigger topologyMonitor
+ if (self.s.connectingServers.length === 0 && self.state === CONNECTING) {
+ topologyMonitor(self, { haInterval: 1 });
+ }
+ };
+}
+
+function connectServers(self, servers) {
+ // Update connectingServers
+ self.s.connectingServers = self.s.connectingServers.concat(servers);
+
+ // Index used to interleaf the server connects, avoiding
+ // runtime issues on io constrained vm's
+ var timeoutInterval = 0;
+
+ function connect(server, timeoutInterval) {
+ setTimeout(function() {
+ // Add the server to the state
+ if (self.s.replicaSetState.update(server)) {
+ // Primary lastIsMaster store it
+ if (server.lastIsMaster() && server.lastIsMaster().ismaster) {
+ self.ismaster = server.lastIsMaster();
+ }
+ }
+
+ // Add event handlers
+ server.once('close', handleInitialConnectEvent(self, 'close'));
+ server.once('timeout', handleInitialConnectEvent(self, 'timeout'));
+ server.once('parseError', handleInitialConnectEvent(self, 'parseError'));
+ server.once('error', handleInitialConnectEvent(self, 'error'));
+ server.once('connect', handleInitialConnectEvent(self, 'connect'));
+
+ // SDAM Monitoring events
+ server.on('serverOpening', e => self.emit('serverOpening', e));
+ server.on('serverDescriptionChanged', e => self.emit('serverDescriptionChanged', e));
+ server.on('serverClosed', e => self.emit('serverClosed', e));
+
+ // Command Monitoring events
+ relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
+
+ // Start connection
+ server.connect(self.s.connectOptions);
+ }, timeoutInterval);
+ }
+
+ // Start all the servers
+ while (servers.length > 0) {
+ connect(servers.shift(), timeoutInterval++);
+ }
+}
+
+/**
+ * Emit event if it exists
+ * @method
+ */
+function emitSDAMEvent(self, event, description) {
+ if (self.listeners(event).length > 0) {
+ self.emit(event, description);
+ }
+}
+
+/**
+ * Initiate server connect
+ */
+ReplSet.prototype.connect = function(options) {
+ var self = this;
+ // Add any connect level options to the internal state
+ this.s.connectOptions = options || {};
+
+ // Set connecting state
+ stateTransition(this, CONNECTING);
+
+ // Create server instances
+ var servers = this.s.seedlist.map(function(x) {
+ return new Server(
+ Object.assign({}, self.s.options, x, options, {
+ reconnect: false,
+ monitoring: false,
+ parent: self
+ })
+ );
+ });
+
+ // Error out as high availbility interval must be < than socketTimeout
+ if (
+ this.s.options.socketTimeout > 0 &&
+ this.s.options.socketTimeout <= this.s.options.haInterval
+ ) {
+ return self.emit(
+ 'error',
+ new MongoError(
+ f(
+ 'haInterval [%s] MS must be set to less than socketTimeout [%s] MS',
+ this.s.options.haInterval,
+ this.s.options.socketTimeout
+ )
+ )
+ );
+ }
+
+ // Emit the topology opening event
+ emitSDAMEvent(this, 'topologyOpening', { topologyId: this.id });
+ // Start all server connections
+ connectServers(self, servers);
+};
+
+/**
+ * Authenticate the topology.
+ * @method
+ * @param {MongoCredentials} credentials The credentials for authentication we are using
+ * @param {authResultCallback} callback A callback function
+ */
+ReplSet.prototype.auth = function(credentials, callback) {
+ if (typeof callback === 'function') callback(null, null);
+};
+
+/**
+ * Destroy the server connection
+ * @param {boolean} [options.force=false] Force destroy the pool
+ * @method
+ */
+ReplSet.prototype.destroy = function(options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || {};
+
+ let destroyCount = this.s.connectingServers.length + 1; // +1 for the callback from `replicaSetState.destroy`
+ const serverDestroyed = () => {
+ destroyCount--;
+ if (destroyCount > 0) {
+ return;
+ }
+
+ // Emit toplogy closing event
+ emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
+
+ // Transition state
+ stateTransition(this, DESTROYED);
+
+ if (typeof callback === 'function') {
+ callback(null, null);
+ }
+ };
+
+ // Clear out any monitoring process
+ if (this.haTimeoutId) clearTimeout(this.haTimeoutId);
+
+ // Clear out all monitoring
+ for (var i = 0; i < this.intervalIds.length; i++) {
+ this.intervalIds[i].stop();
+ }
+
+ // Reset list of intervalIds
+ this.intervalIds = [];
+
+ if (destroyCount === 0) {
+ serverDestroyed();
+ return;
+ }
+
+ // Destroy the replicaset
+ this.s.replicaSetState.destroy(options, serverDestroyed);
+
+ // Destroy all connecting servers
+ this.s.connectingServers.forEach(function(x) {
+ x.destroy(options, serverDestroyed);
+ });
+};
+
+/**
+ * Unref all connections belong to this server
+ * @method
+ */
+ReplSet.prototype.unref = function() {
+ // Transition state
+ stateTransition(this, UNREFERENCED);
+
+ this.s.replicaSetState.allServers().forEach(function(x) {
+ x.unref();
+ });
+
+ clearTimeout(this.haTimeoutId);
+};
+
+/**
+ * Returns the last known ismaster document for this server
+ * @method
+ * @return {object}
+ */
+ReplSet.prototype.lastIsMaster = function() {
+ // If secondaryOnlyConnectionAllowed and no primary but secondary
+ // return the secondaries ismaster result.
+ if (
+ this.s.options.secondaryOnlyConnectionAllowed &&
+ !this.s.replicaSetState.hasPrimary() &&
+ this.s.replicaSetState.hasSecondary()
+ ) {
+ return this.s.replicaSetState.secondaries[0].lastIsMaster();
+ }
+
+ return this.s.replicaSetState.primary
+ ? this.s.replicaSetState.primary.lastIsMaster()
+ : this.ismaster;
+};
+
+/**
+ * All raw connections
+ * @method
+ * @return {Connection[]}
+ */
+ReplSet.prototype.connections = function() {
+ var servers = this.s.replicaSetState.allServers();
+ var connections = [];
+ for (var i = 0; i < servers.length; i++) {
+ connections = connections.concat(servers[i].connections());
+ }
+
+ return connections;
+};
+
+/**
+ * Figure out if the server is connected
+ * @method
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @return {boolean}
+ */
+ReplSet.prototype.isConnected = function(options) {
+ options = options || {};
+
+ // If we specified a read preference check if we are connected to something
+ // than can satisfy this
+ if (options.readPreference && options.readPreference.equals(ReadPreference.secondary)) {
+ return this.s.replicaSetState.hasSecondary();
+ }
+
+ if (options.readPreference && options.readPreference.equals(ReadPreference.primary)) {
+ return this.s.replicaSetState.hasPrimary();
+ }
+
+ if (options.readPreference && options.readPreference.equals(ReadPreference.primaryPreferred)) {
+ return this.s.replicaSetState.hasSecondary() || this.s.replicaSetState.hasPrimary();
+ }
+
+ if (options.readPreference && options.readPreference.equals(ReadPreference.secondaryPreferred)) {
+ return this.s.replicaSetState.hasSecondary() || this.s.replicaSetState.hasPrimary();
+ }
+
+ if (this.s.options.secondaryOnlyConnectionAllowed && this.s.replicaSetState.hasSecondary()) {
+ return true;
+ }
+
+ return this.s.replicaSetState.hasPrimary();
+};
+
+/**
+ * Figure out if the replicaset instance was destroyed by calling destroy
+ * @method
+ * @return {boolean}
+ */
+ReplSet.prototype.isDestroyed = function() {
+ return this.state === DESTROYED;
+};
+
+const SERVER_SELECTION_TIMEOUT_MS = 10000; // hardcoded `serverSelectionTimeoutMS` for legacy topology
+const SERVER_SELECTION_INTERVAL_MS = 1000; // time to wait between selection attempts
+/**
+ * Selects a server
+ *
+ * @method
+ * @param {function} selector Unused
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {ClientSession} [options.session] Unused
+ * @param {function} callback
+ */
+ReplSet.prototype.selectServer = function(selector, options, callback) {
+ if (typeof selector === 'function' && typeof callback === 'undefined')
+ (callback = selector), (selector = undefined), (options = {});
+ if (typeof options === 'function') (callback = options), (options = selector);
+ options = options || {};
+
+ let readPreference;
+ if (selector instanceof ReadPreference) {
+ readPreference = selector;
+ } else {
+ readPreference = options.readPreference || ReadPreference.primary;
+ }
+
+ let lastError;
+ const start = process.hrtime();
+ const _selectServer = () => {
+ if (calculateDurationInMs(start) >= SERVER_SELECTION_TIMEOUT_MS) {
+ if (lastError != null) {
+ callback(lastError, null);
+ } else {
+ callback(new MongoError('Server selection timed out'));
+ }
+
+ return;
+ }
+
+ const server = this.s.replicaSetState.pickServer(readPreference);
+ if (server == null) {
+ setTimeout(_selectServer, SERVER_SELECTION_INTERVAL_MS);
+ return;
+ }
+
+ if (!(server instanceof Server)) {
+ lastError = server;
+ setTimeout(_selectServer, SERVER_SELECTION_INTERVAL_MS);
+ return;
+ }
+
+ if (this.s.debug) this.emit('pickedServer', options.readPreference, server);
+ callback(null, server);
+ };
+
+ _selectServer();
+};
+
+/**
+ * Get all connected servers
+ * @method
+ * @return {Server[]}
+ */
+ReplSet.prototype.getServers = function() {
+ return this.s.replicaSetState.allServers();
+};
+
+//
+// Execute write operation
+function executeWriteOperation(args, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // TODO: once we drop Node 4, use destructuring either here or in arguments.
+ const self = args.self;
+ const op = args.op;
+ const ns = args.ns;
+ const ops = args.ops;
+
+ if (self.state === DESTROYED) {
+ return callback(new MongoError(f('topology was destroyed')));
+ }
+
+ const willRetryWrite =
+ !args.retrying &&
+ !!options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(self) &&
+ !options.session.inTransaction();
+
+ if (!self.s.replicaSetState.hasPrimary()) {
+ if (self.s.disconnectHandler) {
+ // Not connected but we have a disconnecthandler
+ return self.s.disconnectHandler.add(op, ns, ops, options, callback);
+ } else if (!willRetryWrite) {
+ // No server returned we had an error
+ return callback(new MongoError('no primary server found'));
+ }
+ }
+
+ const handler = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err)) {
+ err = getMMAPError(err);
+ return callback(err);
+ }
+
+ if (willRetryWrite) {
+ const newArgs = Object.assign({}, args, { retrying: true });
+ return executeWriteOperation(newArgs, options, callback);
+ }
+
+ // Per SDAM, remove primary from replicaset
+ if (self.s.replicaSetState.primary) {
+ self.s.replicaSetState.primary.destroy();
+ self.s.replicaSetState.remove(self.s.replicaSetState.primary, { force: true });
+ }
+
+ return callback(err);
+ };
+
+ if (callback.operationId) {
+ handler.operationId = callback.operationId;
+ }
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ self.s.replicaSetState.primary[op](ns, ops, options, handler);
+}
+
+/**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ReplSet.prototype.insert = function(ns, ops, options, callback) {
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'insert', ns, ops }, options, callback);
+};
+
+/**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ReplSet.prototype.update = function(ns, ops, options, callback) {
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'update', ns, ops }, options, callback);
+};
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {boolean} [options.retryWrites] Enable retryable writes for this operation
+ * @param {opResultCallback} callback A callback function
+ */
+ReplSet.prototype.remove = function(ns, ops, options, callback) {
+ // Execute write operation
+ executeWriteOperation({ self: this, op: 'remove', ns, ops }, options, callback);
+};
+
+const RETRYABLE_WRITE_OPERATIONS = ['findAndModify', 'insert', 'update', 'delete'];
+
+function isWriteCommand(command) {
+ return RETRYABLE_WRITE_OPERATIONS.some(op => command[op]);
+}
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Connection} [options.connection] Specify connection object to execute command against
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+ReplSet.prototype.command = function(ns, cmd, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ if (this.state === DESTROYED) return callback(new MongoError(f('topology was destroyed')));
+ var self = this;
+
+ // Establish readPreference
+ var readPreference = options.readPreference ? options.readPreference : ReadPreference.primary;
+
+ // If the readPreference is primary and we have no primary, store it
+ if (
+ readPreference.preference === 'primary' &&
+ !this.s.replicaSetState.hasPrimary() &&
+ this.s.disconnectHandler != null
+ ) {
+ return this.s.disconnectHandler.add('command', ns, cmd, options, callback);
+ } else if (
+ readPreference.preference === 'secondary' &&
+ !this.s.replicaSetState.hasSecondary() &&
+ this.s.disconnectHandler != null
+ ) {
+ return this.s.disconnectHandler.add('command', ns, cmd, options, callback);
+ } else if (
+ readPreference.preference !== 'primary' &&
+ !this.s.replicaSetState.hasSecondary() &&
+ !this.s.replicaSetState.hasPrimary() &&
+ this.s.disconnectHandler != null
+ ) {
+ return this.s.disconnectHandler.add('command', ns, cmd, options, callback);
+ }
+
+ // Pick a server
+ var server = this.s.replicaSetState.pickServer(readPreference);
+ // We received an error, return it
+ if (!(server instanceof Server)) return callback(server);
+ // Emit debug event
+ if (self.s.debug) self.emit('pickedServer', ReadPreference.primary, server);
+
+ // No server returned we had an error
+ if (server == null) {
+ return callback(
+ new MongoError(
+ f('no server found that matches the provided readPreference %s', readPreference)
+ )
+ );
+ }
+
+ const willRetryWrite =
+ !options.retrying &&
+ !!options.retryWrites &&
+ options.session &&
+ isRetryableWritesSupported(self) &&
+ !options.session.inTransaction() &&
+ isWriteCommand(cmd);
+
+ const cb = (err, result) => {
+ if (!err) return callback(null, result);
+ if (!isRetryableError(err)) {
+ return callback(err);
+ }
+
+ if (willRetryWrite) {
+ const newOptions = Object.assign({}, options, { retrying: true });
+ return this.command(ns, cmd, newOptions, callback);
+ }
+
+ // Per SDAM, remove primary from replicaset
+ if (this.s.replicaSetState.primary) {
+ this.s.replicaSetState.primary.destroy();
+ this.s.replicaSetState.remove(this.s.replicaSetState.primary, { force: true });
+ }
+
+ return callback(err);
+ };
+
+ // increment and assign txnNumber
+ if (willRetryWrite) {
+ options.session.incrementTransactionNumber();
+ options.willRetryWrite = willRetryWrite;
+ }
+
+ // Execute the command
+ server.command(ns, cmd, options, cb);
+};
+
+/**
+ * Get a new cursor
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options] Options for the cursor
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {object} [options.topology] The internal topology of the created cursor
+ * @returns {Cursor}
+ */
+ReplSet.prototype.cursor = function(ns, cmd, options) {
+ options = options || {};
+ const topology = options.topology || this;
+
+ // Set up final cursor type
+ var FinalCursor = options.cursorFactory || this.s.Cursor;
+
+ // Return the cursor
+ return new FinalCursor(topology, ns, cmd, options);
+};
+
+/**
+ * A replset connect event, used to verify that the connection is up and running
+ *
+ * @event ReplSet#connect
+ * @type {ReplSet}
+ */
+
+/**
+ * A replset reconnect event, used to verify that the topology reconnected
+ *
+ * @event ReplSet#reconnect
+ * @type {ReplSet}
+ */
+
+/**
+ * A replset fullsetup event, used to signal that all topology members have been contacted.
+ *
+ * @event ReplSet#fullsetup
+ * @type {ReplSet}
+ */
+
+/**
+ * A replset all event, used to signal that all topology members have been contacted.
+ *
+ * @event ReplSet#all
+ * @type {ReplSet}
+ */
+
+/**
+ * A replset failed event, used to signal that initial replset connection failed.
+ *
+ * @event ReplSet#failed
+ * @type {ReplSet}
+ */
+
+/**
+ * A server member left the replicaset
+ *
+ * @event ReplSet#left
+ * @type {function}
+ * @param {string} type The type of member that left (primary|secondary|arbiter)
+ * @param {Server} server The server object that left
+ */
+
+/**
+ * A server member joined the replicaset
+ *
+ * @event ReplSet#joined
+ * @type {function}
+ * @param {string} type The type of member that joined (primary|secondary|arbiter)
+ * @param {Server} server The server object that joined
+ */
+
+/**
+ * A server opening SDAM monitoring event
+ *
+ * @event ReplSet#serverOpening
+ * @type {object}
+ */
+
+/**
+ * A server closed SDAM monitoring event
+ *
+ * @event ReplSet#serverClosed
+ * @type {object}
+ */
+
+/**
+ * A server description SDAM change monitoring event
+ *
+ * @event ReplSet#serverDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology open SDAM event
+ *
+ * @event ReplSet#topologyOpening
+ * @type {object}
+ */
+
+/**
+ * A topology closed SDAM event
+ *
+ * @event ReplSet#topologyClosed
+ * @type {object}
+ */
+
+/**
+ * A topology structure SDAM change event
+ *
+ * @event ReplSet#topologyDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatStarted SDAM event
+ *
+ * @event ReplSet#serverHeartbeatStarted
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatFailed SDAM event
+ *
+ * @event ReplSet#serverHeartbeatFailed
+ * @type {object}
+ */
+
+/**
+ * A topology serverHeartbeatSucceeded SDAM change event
+ *
+ * @event ReplSet#serverHeartbeatSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event ReplSet#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event ReplSet#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event ReplSet#commandFailed
+ * @type {object}
+ */
+
+module.exports = ReplSet;
diff --git a/node_modules/mongodb/lib/core/topologies/replset_state.js b/node_modules/mongodb/lib/core/topologies/replset_state.js
new file mode 100644
index 0000000..24c16d6
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/replset_state.js
@@ -0,0 +1,1121 @@
+'use strict';
+
+var inherits = require('util').inherits,
+ f = require('util').format,
+ diff = require('./shared').diff,
+ EventEmitter = require('events').EventEmitter,
+ Logger = require('../connection/logger'),
+ ReadPreference = require('./read_preference'),
+ MongoError = require('../error').MongoError,
+ Buffer = require('safe-buffer').Buffer;
+
+var TopologyType = {
+ Single: 'Single',
+ ReplicaSetNoPrimary: 'ReplicaSetNoPrimary',
+ ReplicaSetWithPrimary: 'ReplicaSetWithPrimary',
+ Sharded: 'Sharded',
+ Unknown: 'Unknown'
+};
+
+var ServerType = {
+ Standalone: 'Standalone',
+ Mongos: 'Mongos',
+ PossiblePrimary: 'PossiblePrimary',
+ RSPrimary: 'RSPrimary',
+ RSSecondary: 'RSSecondary',
+ RSArbiter: 'RSArbiter',
+ RSOther: 'RSOther',
+ RSGhost: 'RSGhost',
+ Unknown: 'Unknown'
+};
+
+var ReplSetState = function(options) {
+ options = options || {};
+ // Add event listener
+ EventEmitter.call(this);
+ // Topology state
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ this.setName = options.setName;
+
+ // Server set
+ this.set = {};
+
+ // Unpacked options
+ this.id = options.id;
+ this.setName = options.setName;
+
+ // Replicaset logger
+ this.logger = options.logger || Logger('ReplSet', options);
+
+ // Server selection index
+ this.index = 0;
+ // Acceptable latency
+ this.acceptableLatency = options.acceptableLatency || 15;
+
+ // heartbeatFrequencyMS
+ this.heartbeatFrequencyMS = options.heartbeatFrequencyMS || 10000;
+
+ // Server side
+ this.primary = null;
+ this.secondaries = [];
+ this.arbiters = [];
+ this.passives = [];
+ this.ghosts = [];
+ // Current unknown hosts
+ this.unknownServers = [];
+ // In set status
+ this.set = {};
+ // Status
+ this.maxElectionId = null;
+ this.maxSetVersion = 0;
+ // Description of the Replicaset
+ this.replicasetDescription = {
+ topologyType: 'Unknown',
+ servers: []
+ };
+
+ this.logicalSessionTimeoutMinutes = undefined;
+};
+
+inherits(ReplSetState, EventEmitter);
+
+ReplSetState.prototype.hasPrimaryAndSecondary = function() {
+ return this.primary != null && this.secondaries.length > 0;
+};
+
+ReplSetState.prototype.hasPrimaryOrSecondary = function() {
+ return this.hasPrimary() || this.hasSecondary();
+};
+
+ReplSetState.prototype.hasPrimary = function() {
+ return this.primary != null;
+};
+
+ReplSetState.prototype.hasSecondary = function() {
+ return this.secondaries.length > 0;
+};
+
+ReplSetState.prototype.get = function(host) {
+ var servers = this.allServers();
+
+ for (var i = 0; i < servers.length; i++) {
+ if (servers[i].name.toLowerCase() === host.toLowerCase()) {
+ return servers[i];
+ }
+ }
+
+ return null;
+};
+
+ReplSetState.prototype.allServers = function(options) {
+ options = options || {};
+ var servers = this.primary ? [this.primary] : [];
+ servers = servers.concat(this.secondaries);
+ if (!options.ignoreArbiters) servers = servers.concat(this.arbiters);
+ servers = servers.concat(this.passives);
+ return servers;
+};
+
+ReplSetState.prototype.destroy = function(options, callback) {
+ const serversToDestroy = this.secondaries
+ .concat(this.arbiters)
+ .concat(this.passives)
+ .concat(this.ghosts);
+ if (this.primary) serversToDestroy.push(this.primary);
+
+ let serverCount = serversToDestroy.length;
+ const serverDestroyed = () => {
+ serverCount--;
+ if (serverCount > 0) {
+ return;
+ }
+
+ // Clear out the complete state
+ this.secondaries = [];
+ this.arbiters = [];
+ this.passives = [];
+ this.ghosts = [];
+ this.unknownServers = [];
+ this.set = {};
+ this.primary = null;
+
+ // Emit the topology changed
+ emitTopologyDescriptionChanged(this);
+
+ if (typeof callback === 'function') {
+ callback(null, null);
+ }
+ };
+
+ if (serverCount === 0) {
+ serverDestroyed();
+ return;
+ }
+
+ serversToDestroy.forEach(server => server.destroy(options, serverDestroyed));
+};
+
+ReplSetState.prototype.remove = function(server, options) {
+ options = options || {};
+
+ // Get the server name and lowerCase it
+ var serverName = server.name.toLowerCase();
+
+ // Only remove if the current server is not connected
+ var servers = this.primary ? [this.primary] : [];
+ servers = servers.concat(this.secondaries);
+ servers = servers.concat(this.arbiters);
+ servers = servers.concat(this.passives);
+
+ // Check if it's active and this is just a failed connection attempt
+ for (var i = 0; i < servers.length; i++) {
+ if (
+ !options.force &&
+ servers[i].equals(server) &&
+ servers[i].isConnected &&
+ servers[i].isConnected()
+ ) {
+ return;
+ }
+ }
+
+ // If we have it in the set remove it
+ if (this.set[serverName]) {
+ this.set[serverName].type = ServerType.Unknown;
+ this.set[serverName].electionId = null;
+ this.set[serverName].setName = null;
+ this.set[serverName].setVersion = null;
+ }
+
+ // Remove type
+ var removeType = null;
+
+ // Remove from any lists
+ if (this.primary && this.primary.equals(server)) {
+ this.primary = null;
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ removeType = 'primary';
+ }
+
+ // Remove from any other server lists
+ removeType = removeFrom(server, this.secondaries) ? 'secondary' : removeType;
+ removeType = removeFrom(server, this.arbiters) ? 'arbiter' : removeType;
+ removeType = removeFrom(server, this.passives) ? 'secondary' : removeType;
+ removeFrom(server, this.ghosts);
+ removeFrom(server, this.unknownServers);
+
+ // Push to unknownServers
+ this.unknownServers.push(serverName);
+
+ // Do we have a removeType
+ if (removeType) {
+ this.emit('left', removeType, server);
+ }
+};
+
+const isArbiter = ismaster => ismaster.arbiterOnly && ismaster.setName;
+
+ReplSetState.prototype.update = function(server) {
+ var self = this;
+ // Get the current ismaster
+ var ismaster = server.lastIsMaster();
+
+ // Get the server name and lowerCase it
+ var serverName = server.name.toLowerCase();
+
+ //
+ // Add any hosts
+ //
+ if (ismaster) {
+ // Join all the possible new hosts
+ var hosts = Array.isArray(ismaster.hosts) ? ismaster.hosts : [];
+ hosts = hosts.concat(Array.isArray(ismaster.arbiters) ? ismaster.arbiters : []);
+ hosts = hosts.concat(Array.isArray(ismaster.passives) ? ismaster.passives : []);
+ hosts = hosts.map(function(s) {
+ return s.toLowerCase();
+ });
+
+ // Add all hosts as unknownServers
+ for (var i = 0; i < hosts.length; i++) {
+ // Add to the list of unknown server
+ if (
+ this.unknownServers.indexOf(hosts[i]) === -1 &&
+ (!this.set[hosts[i]] || this.set[hosts[i]].type === ServerType.Unknown)
+ ) {
+ this.unknownServers.push(hosts[i].toLowerCase());
+ }
+
+ if (!this.set[hosts[i]]) {
+ this.set[hosts[i]] = {
+ type: ServerType.Unknown,
+ electionId: null,
+ setName: null,
+ setVersion: null
+ };
+ }
+ }
+ }
+
+ //
+ // Unknown server
+ //
+ if (!ismaster && !inList(ismaster, server, this.unknownServers)) {
+ self.set[serverName] = {
+ type: ServerType.Unknown,
+ setVersion: null,
+ electionId: null,
+ setName: null
+ };
+ // Update set information about the server instance
+ self.set[serverName].type = ServerType.Unknown;
+ self.set[serverName].electionId = ismaster ? ismaster.electionId : ismaster;
+ self.set[serverName].setName = ismaster ? ismaster.setName : ismaster;
+ self.set[serverName].setVersion = ismaster ? ismaster.setVersion : ismaster;
+
+ if (self.unknownServers.indexOf(server.name) === -1) {
+ self.unknownServers.push(serverName);
+ }
+
+ // Set the topology
+ return false;
+ }
+
+ // Update logicalSessionTimeoutMinutes
+ if (ismaster.logicalSessionTimeoutMinutes !== undefined && !isArbiter(ismaster)) {
+ if (
+ self.logicalSessionTimeoutMinutes === undefined ||
+ ismaster.logicalSessionTimeoutMinutes === null
+ ) {
+ self.logicalSessionTimeoutMinutes = ismaster.logicalSessionTimeoutMinutes;
+ } else {
+ self.logicalSessionTimeoutMinutes = Math.min(
+ self.logicalSessionTimeoutMinutes,
+ ismaster.logicalSessionTimeoutMinutes
+ );
+ }
+ }
+
+ //
+ // Is this a mongos
+ //
+ if (ismaster && ismaster.msg === 'isdbgrid') {
+ if (this.primary && this.primary.name === serverName) {
+ this.primary = null;
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ }
+
+ return false;
+ }
+
+ // A RSGhost instance
+ if (ismaster.isreplicaset) {
+ self.set[serverName] = {
+ type: ServerType.RSGhost,
+ setVersion: null,
+ electionId: null,
+ setName: ismaster.setName
+ };
+
+ if (this.primary && this.primary.name === serverName) {
+ this.primary = null;
+ }
+
+ // Set the topology
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+
+ // Set the topology
+ return false;
+ }
+
+ // A RSOther instance
+ if (
+ (ismaster.setName && ismaster.hidden) ||
+ (ismaster.setName &&
+ !ismaster.ismaster &&
+ !ismaster.secondary &&
+ !ismaster.arbiterOnly &&
+ !ismaster.passive)
+ ) {
+ self.set[serverName] = {
+ type: ServerType.RSOther,
+ setVersion: null,
+ electionId: null,
+ setName: ismaster.setName
+ };
+
+ // Set the topology
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ return false;
+ }
+
+ //
+ // Standalone server, destroy and return
+ //
+ if (ismaster && ismaster.ismaster && !ismaster.setName) {
+ this.topologyType = this.primary ? TopologyType.ReplicaSetWithPrimary : TopologyType.Unknown;
+ this.remove(server, { force: true });
+ return false;
+ }
+
+ //
+ // Server in maintanance mode
+ //
+ if (ismaster && !ismaster.ismaster && !ismaster.secondary && !ismaster.arbiterOnly) {
+ this.remove(server, { force: true });
+ return false;
+ }
+
+ //
+ // If the .me field does not match the passed in server
+ //
+ if (ismaster.me && ismaster.me.toLowerCase() !== serverName) {
+ if (this.logger.isWarn()) {
+ this.logger.warn(
+ f(
+ 'the seedlist server was removed due to its address %s not matching its ismaster.me address %s',
+ server.name,
+ ismaster.me
+ )
+ );
+ }
+
+ // Delete from the set
+ delete this.set[serverName];
+ // Delete unknown servers
+ removeFrom(server, self.unknownServers);
+
+ // Destroy the instance
+ server.destroy({ force: true });
+
+ // Set the type of topology we have
+ if (this.primary && !this.primary.equals(server)) {
+ this.topologyType = TopologyType.ReplicaSetWithPrimary;
+ } else {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ }
+
+ //
+ // We have a potential primary
+ //
+ if (!this.primary && ismaster.primary) {
+ this.set[ismaster.primary.toLowerCase()] = {
+ type: ServerType.PossiblePrimary,
+ setName: null,
+ electionId: null,
+ setVersion: null
+ };
+ }
+
+ return false;
+ }
+
+ //
+ // Primary handling
+ //
+ if (!this.primary && ismaster.ismaster && ismaster.setName) {
+ var ismasterElectionId = server.lastIsMaster().electionId;
+ if (this.setName && this.setName !== ismaster.setName) {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ return new MongoError(
+ f(
+ 'setName from ismaster does not match provided connection setName [%s] != [%s]',
+ ismaster.setName,
+ this.setName
+ )
+ );
+ }
+
+ if (!this.maxElectionId && ismasterElectionId) {
+ this.maxElectionId = ismasterElectionId;
+ } else if (this.maxElectionId && ismasterElectionId) {
+ var result = compareObjectIds(this.maxElectionId, ismasterElectionId);
+ // Get the electionIds
+ var ismasterSetVersion = server.lastIsMaster().setVersion;
+
+ if (result === 1) {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ return false;
+ } else if (result === 0 && ismasterSetVersion) {
+ if (ismasterSetVersion < this.maxSetVersion) {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ return false;
+ }
+ }
+
+ this.maxSetVersion = ismasterSetVersion;
+ this.maxElectionId = ismasterElectionId;
+ }
+
+ // Hande normalization of server names
+ var normalizedHosts = ismaster.hosts.map(function(x) {
+ return x.toLowerCase();
+ });
+ var locationIndex = normalizedHosts.indexOf(serverName);
+
+ // Validate that the server exists in the host list
+ if (locationIndex !== -1) {
+ self.primary = server;
+ self.set[serverName] = {
+ type: ServerType.RSPrimary,
+ setVersion: ismaster.setVersion,
+ electionId: ismaster.electionId,
+ setName: ismaster.setName
+ };
+
+ // Set the topology
+ this.topologyType = TopologyType.ReplicaSetWithPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ removeFrom(server, self.unknownServers);
+ removeFrom(server, self.secondaries);
+ removeFrom(server, self.passives);
+ self.emit('joined', 'primary', server);
+ } else {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ }
+
+ emitTopologyDescriptionChanged(self);
+ return true;
+ } else if (ismaster.ismaster && ismaster.setName) {
+ // Get the electionIds
+ var currentElectionId = self.set[self.primary.name.toLowerCase()].electionId;
+ var currentSetVersion = self.set[self.primary.name.toLowerCase()].setVersion;
+ var currentSetName = self.set[self.primary.name.toLowerCase()].setName;
+ ismasterElectionId = server.lastIsMaster().electionId;
+ ismasterSetVersion = server.lastIsMaster().setVersion;
+ var ismasterSetName = server.lastIsMaster().setName;
+
+ // Is it the same server instance
+ if (this.primary.equals(server) && currentSetName === ismasterSetName) {
+ return false;
+ }
+
+ // If we do not have the same rs name
+ if (currentSetName && currentSetName !== ismasterSetName) {
+ if (!this.primary.equals(server)) {
+ this.topologyType = TopologyType.ReplicaSetWithPrimary;
+ } else {
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ }
+
+ return false;
+ }
+
+ // Check if we need to replace the server
+ if (currentElectionId && ismasterElectionId) {
+ result = compareObjectIds(currentElectionId, ismasterElectionId);
+
+ if (result === 1) {
+ return false;
+ } else if (result === 0 && currentSetVersion > ismasterSetVersion) {
+ return false;
+ }
+ } else if (!currentElectionId && ismasterElectionId && ismasterSetVersion) {
+ if (ismasterSetVersion < this.maxSetVersion) {
+ return false;
+ }
+ }
+
+ if (!this.maxElectionId && ismasterElectionId) {
+ this.maxElectionId = ismasterElectionId;
+ } else if (this.maxElectionId && ismasterElectionId) {
+ result = compareObjectIds(this.maxElectionId, ismasterElectionId);
+
+ if (result === 1) {
+ return false;
+ } else if (result === 0 && currentSetVersion && ismasterSetVersion) {
+ if (ismasterSetVersion < this.maxSetVersion) {
+ return false;
+ }
+ } else {
+ if (ismasterSetVersion < this.maxSetVersion) {
+ return false;
+ }
+ }
+
+ this.maxElectionId = ismasterElectionId;
+ this.maxSetVersion = ismasterSetVersion;
+ } else {
+ this.maxSetVersion = ismasterSetVersion;
+ }
+
+ // Modify the entry to unknown
+ self.set[self.primary.name.toLowerCase()] = {
+ type: ServerType.Unknown,
+ setVersion: null,
+ electionId: null,
+ setName: null
+ };
+
+ // Signal primary left
+ self.emit('left', 'primary', this.primary);
+ // Destroy the instance
+ self.primary.destroy({ force: true });
+ // Set the new instance
+ self.primary = server;
+ // Set the set information
+ self.set[serverName] = {
+ type: ServerType.RSPrimary,
+ setVersion: ismaster.setVersion,
+ electionId: ismaster.electionId,
+ setName: ismaster.setName
+ };
+
+ // Set the topology
+ this.topologyType = TopologyType.ReplicaSetWithPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ removeFrom(server, self.unknownServers);
+ removeFrom(server, self.secondaries);
+ removeFrom(server, self.passives);
+ self.emit('joined', 'primary', server);
+ emitTopologyDescriptionChanged(self);
+ return true;
+ }
+
+ // A possible instance
+ if (!this.primary && ismaster.primary) {
+ self.set[ismaster.primary.toLowerCase()] = {
+ type: ServerType.PossiblePrimary,
+ setVersion: null,
+ electionId: null,
+ setName: null
+ };
+ }
+
+ //
+ // Secondary handling
+ //
+ if (
+ ismaster.secondary &&
+ ismaster.setName &&
+ !inList(ismaster, server, this.secondaries) &&
+ this.setName &&
+ this.setName === ismaster.setName
+ ) {
+ addToList(self, ServerType.RSSecondary, ismaster, server, this.secondaries);
+ // Set the topology
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ removeFrom(server, self.unknownServers);
+
+ // Remove primary
+ if (this.primary && this.primary.name.toLowerCase() === serverName) {
+ server.destroy({ force: true });
+ this.primary = null;
+ self.emit('left', 'primary', server);
+ }
+
+ // Emit secondary joined replicaset
+ self.emit('joined', 'secondary', server);
+ emitTopologyDescriptionChanged(self);
+ return true;
+ }
+
+ //
+ // Arbiter handling
+ //
+ if (
+ isArbiter(ismaster) &&
+ !inList(ismaster, server, this.arbiters) &&
+ this.setName &&
+ this.setName === ismaster.setName
+ ) {
+ addToList(self, ServerType.RSArbiter, ismaster, server, this.arbiters);
+ // Set the topology
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ removeFrom(server, self.unknownServers);
+ self.emit('joined', 'arbiter', server);
+ emitTopologyDescriptionChanged(self);
+ return true;
+ }
+
+ //
+ // Passive handling
+ //
+ if (
+ ismaster.passive &&
+ ismaster.setName &&
+ !inList(ismaster, server, this.passives) &&
+ this.setName &&
+ this.setName === ismaster.setName
+ ) {
+ addToList(self, ServerType.RSSecondary, ismaster, server, this.passives);
+ // Set the topology
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ if (ismaster.setName) this.setName = ismaster.setName;
+ removeFrom(server, self.unknownServers);
+
+ // Remove primary
+ if (this.primary && this.primary.name.toLowerCase() === serverName) {
+ server.destroy({ force: true });
+ this.primary = null;
+ self.emit('left', 'primary', server);
+ }
+
+ self.emit('joined', 'secondary', server);
+ emitTopologyDescriptionChanged(self);
+ return true;
+ }
+
+ //
+ // Remove the primary
+ //
+ if (this.set[serverName] && this.set[serverName].type === ServerType.RSPrimary) {
+ self.emit('left', 'primary', this.primary);
+ this.primary.destroy({ force: true });
+ this.primary = null;
+ this.topologyType = TopologyType.ReplicaSetNoPrimary;
+ return false;
+ }
+
+ this.topologyType = this.primary
+ ? TopologyType.ReplicaSetWithPrimary
+ : TopologyType.ReplicaSetNoPrimary;
+ return false;
+};
+
+/**
+ * Recalculate single server max staleness
+ * @method
+ */
+ReplSetState.prototype.updateServerMaxStaleness = function(server, haInterval) {
+ // Locate the max secondary lastwrite
+ var max = 0;
+ // Go over all secondaries
+ for (var i = 0; i < this.secondaries.length; i++) {
+ max = Math.max(max, this.secondaries[i].lastWriteDate);
+ }
+
+ // Perform this servers staleness calculation
+ if (server.ismaster.maxWireVersion >= 5 && server.ismaster.secondary && this.hasPrimary()) {
+ server.staleness =
+ server.lastUpdateTime -
+ server.lastWriteDate -
+ (this.primary.lastUpdateTime - this.primary.lastWriteDate) +
+ haInterval;
+ } else if (server.ismaster.maxWireVersion >= 5 && server.ismaster.secondary) {
+ server.staleness = max - server.lastWriteDate + haInterval;
+ }
+};
+
+/**
+ * Recalculate all the staleness values for secodaries
+ * @method
+ */
+ReplSetState.prototype.updateSecondariesMaxStaleness = function(haInterval) {
+ for (var i = 0; i < this.secondaries.length; i++) {
+ this.updateServerMaxStaleness(this.secondaries[i], haInterval);
+ }
+};
+
+/**
+ * Pick a server by the passed in ReadPreference
+ * @method
+ * @param {ReadPreference} readPreference The ReadPreference instance to use
+ */
+ReplSetState.prototype.pickServer = function(readPreference) {
+ // If no read Preference set to primary by default
+ readPreference = readPreference || ReadPreference.primary;
+
+ // maxStalenessSeconds is not allowed with a primary read
+ if (readPreference.preference === 'primary' && readPreference.maxStalenessSeconds != null) {
+ return new MongoError('primary readPreference incompatible with maxStalenessSeconds');
+ }
+
+ // Check if we have any non compatible servers for maxStalenessSeconds
+ var allservers = this.primary ? [this.primary] : [];
+ allservers = allservers.concat(this.secondaries);
+
+ // Does any of the servers not support the right wire protocol version
+ // for maxStalenessSeconds when maxStalenessSeconds specified on readPreference. Then error out
+ if (readPreference.maxStalenessSeconds != null) {
+ for (var i = 0; i < allservers.length; i++) {
+ if (allservers[i].ismaster.maxWireVersion < 5) {
+ return new MongoError(
+ 'maxStalenessSeconds not supported by at least one of the replicaset members'
+ );
+ }
+ }
+ }
+
+ // Do we have the nearest readPreference
+ if (readPreference.preference === 'nearest' && readPreference.maxStalenessSeconds == null) {
+ return pickNearest(this, readPreference);
+ } else if (
+ readPreference.preference === 'nearest' &&
+ readPreference.maxStalenessSeconds != null
+ ) {
+ return pickNearestMaxStalenessSeconds(this, readPreference);
+ }
+
+ // Get all the secondaries
+ var secondaries = this.secondaries;
+
+ // Check if we can satisfy and of the basic read Preferences
+ if (readPreference.equals(ReadPreference.secondary) && secondaries.length === 0) {
+ return new MongoError('no secondary server available');
+ }
+
+ if (
+ readPreference.equals(ReadPreference.secondaryPreferred) &&
+ secondaries.length === 0 &&
+ this.primary == null
+ ) {
+ return new MongoError('no secondary or primary server available');
+ }
+
+ if (readPreference.equals(ReadPreference.primary) && this.primary == null) {
+ return new MongoError('no primary server available');
+ }
+
+ // Secondary preferred or just secondaries
+ if (
+ readPreference.equals(ReadPreference.secondaryPreferred) ||
+ readPreference.equals(ReadPreference.secondary)
+ ) {
+ if (secondaries.length > 0 && readPreference.maxStalenessSeconds == null) {
+ // Pick nearest of any other servers available
+ var server = pickNearest(this, readPreference);
+ // No server in the window return primary
+ if (server) {
+ return server;
+ }
+ } else if (secondaries.length > 0 && readPreference.maxStalenessSeconds != null) {
+ // Pick nearest of any other servers available
+ server = pickNearestMaxStalenessSeconds(this, readPreference);
+ // No server in the window return primary
+ if (server) {
+ return server;
+ }
+ }
+
+ if (readPreference.equals(ReadPreference.secondaryPreferred)) {
+ return this.primary;
+ }
+
+ return null;
+ }
+
+ // Primary preferred
+ if (readPreference.equals(ReadPreference.primaryPreferred)) {
+ server = null;
+
+ // We prefer the primary if it's available
+ if (this.primary) {
+ return this.primary;
+ }
+
+ // Pick a secondary
+ if (secondaries.length > 0 && readPreference.maxStalenessSeconds == null) {
+ server = pickNearest(this, readPreference);
+ } else if (secondaries.length > 0 && readPreference.maxStalenessSeconds != null) {
+ server = pickNearestMaxStalenessSeconds(this, readPreference);
+ }
+
+ // Did we find a server
+ if (server) return server;
+ }
+
+ // Return the primary
+ return this.primary;
+};
+
+//
+// Filter serves by tags
+var filterByTags = function(readPreference, servers) {
+ if (readPreference.tags == null) return servers;
+ var filteredServers = [];
+ var tagsArray = Array.isArray(readPreference.tags) ? readPreference.tags : [readPreference.tags];
+
+ // Iterate over the tags
+ for (var j = 0; j < tagsArray.length; j++) {
+ var tags = tagsArray[j];
+
+ // Iterate over all the servers
+ for (var i = 0; i < servers.length; i++) {
+ var serverTag = servers[i].lastIsMaster().tags || {};
+
+ // Did we find the a matching server
+ var found = true;
+ // Check if the server is valid
+ for (var name in tags) {
+ if (serverTag[name] !== tags[name]) {
+ found = false;
+ }
+ }
+
+ // Add to candidate list
+ if (found) {
+ filteredServers.push(servers[i]);
+ }
+ }
+ }
+
+ // Returned filtered servers
+ return filteredServers;
+};
+
+function pickNearestMaxStalenessSeconds(self, readPreference) {
+ // Only get primary and secondaries as seeds
+ var servers = [];
+
+ // Get the maxStalenessMS
+ var maxStalenessMS = readPreference.maxStalenessSeconds * 1000;
+
+ // Check if the maxStalenessMS > 90 seconds
+ if (maxStalenessMS < 90 * 1000) {
+ return new MongoError('maxStalenessSeconds must be set to at least 90 seconds');
+ }
+
+ // Add primary to list if not a secondary read preference
+ if (
+ self.primary &&
+ readPreference.preference !== 'secondary' &&
+ readPreference.preference !== 'secondaryPreferred'
+ ) {
+ servers.push(self.primary);
+ }
+
+ // Add all the secondaries
+ for (var i = 0; i < self.secondaries.length; i++) {
+ servers.push(self.secondaries[i]);
+ }
+
+ // If we have a secondaryPreferred readPreference and no server add the primary
+ if (self.primary && servers.length === 0 && readPreference.preference !== 'secondaryPreferred') {
+ servers.push(self.primary);
+ }
+
+ // Filter by tags
+ servers = filterByTags(readPreference, servers);
+
+ // Filter by latency
+ servers = servers.filter(function(s) {
+ return s.staleness <= maxStalenessMS;
+ });
+
+ // Sort by time
+ servers.sort(function(a, b) {
+ return a.lastIsMasterMS - b.lastIsMasterMS;
+ });
+
+ // No servers, default to primary
+ if (servers.length === 0) {
+ return null;
+ }
+
+ // Ensure index does not overflow the number of available servers
+ self.index = self.index % servers.length;
+
+ // Get the server
+ var server = servers[self.index];
+ // Add to the index
+ self.index = self.index + 1;
+ // Return the first server of the sorted and filtered list
+ return server;
+}
+
+function pickNearest(self, readPreference) {
+ // Only get primary and secondaries as seeds
+ var servers = [];
+
+ // Add primary to list if not a secondary read preference
+ if (
+ self.primary &&
+ readPreference.preference !== 'secondary' &&
+ readPreference.preference !== 'secondaryPreferred'
+ ) {
+ servers.push(self.primary);
+ }
+
+ // Add all the secondaries
+ for (var i = 0; i < self.secondaries.length; i++) {
+ servers.push(self.secondaries[i]);
+ }
+
+ // If we have a secondaryPreferred readPreference and no server add the primary
+ if (servers.length === 0 && self.primary && readPreference.preference !== 'secondaryPreferred') {
+ servers.push(self.primary);
+ }
+
+ // Filter by tags
+ servers = filterByTags(readPreference, servers);
+
+ // Sort by time
+ servers.sort(function(a, b) {
+ return a.lastIsMasterMS - b.lastIsMasterMS;
+ });
+
+ // Locate lowest time (picked servers are lowest time + acceptable Latency margin)
+ var lowest = servers.length > 0 ? servers[0].lastIsMasterMS : 0;
+
+ // Filter by latency
+ servers = servers.filter(function(s) {
+ return s.lastIsMasterMS <= lowest + self.acceptableLatency;
+ });
+
+ // No servers, default to primary
+ if (servers.length === 0) {
+ return null;
+ }
+
+ // Ensure index does not overflow the number of available servers
+ self.index = self.index % servers.length;
+ // Get the server
+ var server = servers[self.index];
+ // Add to the index
+ self.index = self.index + 1;
+ // Return the first server of the sorted and filtered list
+ return server;
+}
+
+function inList(ismaster, server, list) {
+ for (var i = 0; i < list.length; i++) {
+ if (list[i] && list[i].name && list[i].name.toLowerCase() === server.name.toLowerCase())
+ return true;
+ }
+
+ return false;
+}
+
+function addToList(self, type, ismaster, server, list) {
+ var serverName = server.name.toLowerCase();
+ // Update set information about the server instance
+ self.set[serverName].type = type;
+ self.set[serverName].electionId = ismaster ? ismaster.electionId : ismaster;
+ self.set[serverName].setName = ismaster ? ismaster.setName : ismaster;
+ self.set[serverName].setVersion = ismaster ? ismaster.setVersion : ismaster;
+ // Add to the list
+ list.push(server);
+}
+
+function compareObjectIds(id1, id2) {
+ var a = Buffer.from(id1.toHexString(), 'hex');
+ var b = Buffer.from(id2.toHexString(), 'hex');
+
+ if (a === b) {
+ return 0;
+ }
+
+ if (typeof Buffer.compare === 'function') {
+ return Buffer.compare(a, b);
+ }
+
+ var x = a.length;
+ var y = b.length;
+ var len = Math.min(x, y);
+
+ for (var i = 0; i < len; i++) {
+ if (a[i] !== b[i]) {
+ break;
+ }
+ }
+
+ if (i !== len) {
+ x = a[i];
+ y = b[i];
+ }
+
+ return x < y ? -1 : y < x ? 1 : 0;
+}
+
+function removeFrom(server, list) {
+ for (var i = 0; i < list.length; i++) {
+ if (list[i].equals && list[i].equals(server)) {
+ list.splice(i, 1);
+ return true;
+ } else if (typeof list[i] === 'string' && list[i].toLowerCase() === server.name.toLowerCase()) {
+ list.splice(i, 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function emitTopologyDescriptionChanged(self) {
+ if (self.listeners('topologyDescriptionChanged').length > 0) {
+ var topology = 'Unknown';
+ var setName = self.setName;
+
+ if (self.hasPrimaryAndSecondary()) {
+ topology = 'ReplicaSetWithPrimary';
+ } else if (!self.hasPrimary() && self.hasSecondary()) {
+ topology = 'ReplicaSetNoPrimary';
+ }
+
+ // Generate description
+ var description = {
+ topologyType: topology,
+ setName: setName,
+ servers: []
+ };
+
+ // Add the primary to the list
+ if (self.hasPrimary()) {
+ var desc = self.primary.getDescription();
+ desc.type = 'RSPrimary';
+ description.servers.push(desc);
+ }
+
+ // Add all the secondaries
+ description.servers = description.servers.concat(
+ self.secondaries.map(function(x) {
+ var description = x.getDescription();
+ description.type = 'RSSecondary';
+ return description;
+ })
+ );
+
+ // Add all the arbiters
+ description.servers = description.servers.concat(
+ self.arbiters.map(function(x) {
+ var description = x.getDescription();
+ description.type = 'RSArbiter';
+ return description;
+ })
+ );
+
+ // Add all the passives
+ description.servers = description.servers.concat(
+ self.passives.map(function(x) {
+ var description = x.getDescription();
+ description.type = 'RSSecondary';
+ return description;
+ })
+ );
+
+ // Get the diff
+ var diffResult = diff(self.replicasetDescription, description);
+
+ // Create the result
+ var result = {
+ topologyId: self.id,
+ previousDescription: self.replicasetDescription,
+ newDescription: description,
+ diff: diffResult
+ };
+
+ // Emit the topologyDescription change
+ // if(diffResult.servers.length > 0) {
+ self.emit('topologyDescriptionChanged', result);
+ // }
+
+ // Set the new description
+ self.replicasetDescription = description;
+ }
+}
+
+module.exports = ReplSetState;
diff --git a/node_modules/mongodb/lib/core/topologies/server.js b/node_modules/mongodb/lib/core/topologies/server.js
new file mode 100644
index 0000000..6f6de12
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/server.js
@@ -0,0 +1,990 @@
+'use strict';
+
+var inherits = require('util').inherits,
+ f = require('util').format,
+ EventEmitter = require('events').EventEmitter,
+ ReadPreference = require('./read_preference'),
+ Logger = require('../connection/logger'),
+ debugOptions = require('../connection/utils').debugOptions,
+ retrieveBSON = require('../connection/utils').retrieveBSON,
+ Pool = require('../connection/pool'),
+ MongoError = require('../error').MongoError,
+ MongoNetworkError = require('../error').MongoNetworkError,
+ wireProtocol = require('../wireprotocol'),
+ CoreCursor = require('../cursor').CoreCursor,
+ sdam = require('./shared'),
+ createCompressionInfo = require('./shared').createCompressionInfo,
+ resolveClusterTime = require('./shared').resolveClusterTime,
+ SessionMixins = require('./shared').SessionMixins,
+ relayEvents = require('../utils').relayEvents;
+
+const collationNotSupported = require('../utils').collationNotSupported;
+const makeClientMetadata = require('../utils').makeClientMetadata;
+
+// Used for filtering out fields for loggin
+var debugFields = [
+ 'reconnect',
+ 'reconnectTries',
+ 'reconnectInterval',
+ 'emitError',
+ 'cursorFactory',
+ 'host',
+ 'port',
+ 'size',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'noDelay',
+ 'connectionTimeout',
+ 'checkServerIdentity',
+ 'socketTimeout',
+ 'ssl',
+ 'ca',
+ 'crl',
+ 'cert',
+ 'key',
+ 'rejectUnauthorized',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'servername'
+];
+
+// Server instance id
+var id = 0;
+var serverAccounting = false;
+var servers = {};
+var BSON = retrieveBSON();
+
+function topologyId(server) {
+ return server.s.parent == null ? server.id : server.s.parent.id;
+}
+
+/**
+ * Creates a new Server instance
+ * @class
+ * @param {boolean} [options.reconnect=true] Server will attempt to reconnect on loss of connection
+ * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
+ * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
+ * @param {number} [options.monitoring=true] Enable the server state monitoring (calling ismaster at monitoringInterval)
+ * @param {number} [options.monitoringInterval=5000] The interval of calling ismaster when monitoring is enabled.
+ * @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
+ * @param {string} options.host The server host
+ * @param {number} options.port The server port
+ * @param {number} [options.size=5] Server connection pool size
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=300000] Initial delay before TCP keep alive enabled
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
+ * @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
+ * @param {boolean} [options.ssl=false] Use SSL for connection
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {Buffer} [options.ca] SSL Certificate store binary buffer
+ * @param {Buffer} [options.crl] SSL Certificate revocation store binary buffer
+ * @param {Buffer} [options.cert] SSL Certificate binary buffer
+ * @param {Buffer} [options.key] SSL Key file binary buffer
+ * @param {string} [options.passphrase] SSL Certificate pass phrase
+ * @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
+ * @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
+ * @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
+ * @param {string} [options.appname=null] Application name, passed in on ismaster call and logged in mongod server logs. Maximum size 128 bytes.
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @return {Server} A cursor instance
+ * @fires Server#connect
+ * @fires Server#close
+ * @fires Server#error
+ * @fires Server#timeout
+ * @fires Server#parseError
+ * @fires Server#reconnect
+ * @fires Server#reconnectFailed
+ * @fires Server#serverHeartbeatStarted
+ * @fires Server#serverHeartbeatSucceeded
+ * @fires Server#serverHeartbeatFailed
+ * @fires Server#topologyOpening
+ * @fires Server#topologyClosed
+ * @fires Server#topologyDescriptionChanged
+ * @property {string} type the topology type.
+ * @property {string} parserType the parser type used (c++ or js).
+ */
+var Server = function(options) {
+ options = options || {};
+
+ // Add event listener
+ EventEmitter.call(this);
+
+ // Server instance id
+ this.id = id++;
+
+ // Internal state
+ this.s = {
+ // Options
+ options: Object.assign({ metadata: makeClientMetadata(options) }, options),
+ // Logger
+ logger: Logger('Server', options),
+ // Factory overrides
+ Cursor: options.cursorFactory || CoreCursor,
+ // BSON instance
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ]),
+ // Pool
+ pool: null,
+ // Disconnect handler
+ disconnectHandler: options.disconnectHandler,
+ // Monitor thread (keeps the connection alive)
+ monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : true,
+ // Is the server in a topology
+ inTopology: !!options.parent,
+ // Monitoring timeout
+ monitoringInterval:
+ typeof options.monitoringInterval === 'number' ? options.monitoringInterval : 5000,
+ compression: { compressors: createCompressionInfo(options) },
+ // Optional parent topology
+ parent: options.parent
+ };
+
+ // If this is a single deployment we need to track the clusterTime here
+ if (!this.s.parent) {
+ this.s.clusterTime = null;
+ }
+
+ // Curent ismaster
+ this.ismaster = null;
+ // Current ping time
+ this.lastIsMasterMS = -1;
+ // The monitoringProcessId
+ this.monitoringProcessId = null;
+ // Initial connection
+ this.initialConnect = true;
+ // Default type
+ this._type = 'server';
+
+ // Max Stalleness values
+ // last time we updated the ismaster state
+ this.lastUpdateTime = 0;
+ // Last write time
+ this.lastWriteDate = 0;
+ // Stalleness
+ this.staleness = 0;
+};
+
+inherits(Server, EventEmitter);
+Object.assign(Server.prototype, SessionMixins);
+
+Object.defineProperty(Server.prototype, 'type', {
+ enumerable: true,
+ get: function() {
+ return this._type;
+ }
+});
+
+Object.defineProperty(Server.prototype, 'parserType', {
+ enumerable: true,
+ get: function() {
+ return BSON.native ? 'c++' : 'js';
+ }
+});
+
+Object.defineProperty(Server.prototype, 'logicalSessionTimeoutMinutes', {
+ enumerable: true,
+ get: function() {
+ if (!this.ismaster) return null;
+ return this.ismaster.logicalSessionTimeoutMinutes || null;
+ }
+});
+
+Object.defineProperty(Server.prototype, 'clientMetadata', {
+ enumerable: true,
+ get: function() {
+ return this.s.options.metadata;
+ }
+});
+
+// In single server deployments we track the clusterTime directly on the topology, however
+// in Mongos and ReplSet deployments we instead need to delegate the clusterTime up to the
+// tracking objects so we can ensure we are gossiping the maximum time received from the
+// server.
+Object.defineProperty(Server.prototype, 'clusterTime', {
+ enumerable: true,
+ set: function(clusterTime) {
+ const settings = this.s.parent ? this.s.parent : this.s;
+ resolveClusterTime(settings, clusterTime);
+ },
+ get: function() {
+ const settings = this.s.parent ? this.s.parent : this.s;
+ return settings.clusterTime || null;
+ }
+});
+
+Server.enableServerAccounting = function() {
+ serverAccounting = true;
+ servers = {};
+};
+
+Server.disableServerAccounting = function() {
+ serverAccounting = false;
+};
+
+Server.servers = function() {
+ return servers;
+};
+
+Object.defineProperty(Server.prototype, 'name', {
+ enumerable: true,
+ get: function() {
+ return this.s.options.host + ':' + this.s.options.port;
+ }
+});
+
+function disconnectHandler(self, type, ns, cmd, options, callback) {
+ // Topology is not connected, save the call in the provided store to be
+ // Executed at some point when the handler deems it's reconnected
+ if (
+ !self.s.pool.isConnected() &&
+ self.s.options.reconnect &&
+ self.s.disconnectHandler != null &&
+ !options.monitoring
+ ) {
+ self.s.disconnectHandler.add(type, ns, cmd, options, callback);
+ return true;
+ }
+
+ // If we have no connection error
+ if (!self.s.pool.isConnected()) {
+ callback(new MongoError(f('no connection available to server %s', self.name)));
+ return true;
+ }
+}
+
+function monitoringProcess(self) {
+ return function() {
+ // Pool was destroyed do not continue process
+ if (self.s.pool.isDestroyed()) return;
+ // Emit monitoring Process event
+ self.emit('monitoring', self);
+ // Perform ismaster call
+ // Get start time
+ var start = new Date().getTime();
+
+ // Execute the ismaster query
+ self.command(
+ 'admin.$cmd',
+ { ismaster: true },
+ {
+ socketTimeout:
+ typeof self.s.options.connectionTimeout !== 'number'
+ ? 2000
+ : self.s.options.connectionTimeout,
+ monitoring: true
+ },
+ (err, result) => {
+ // Set initial lastIsMasterMS
+ self.lastIsMasterMS = new Date().getTime() - start;
+ if (self.s.pool.isDestroyed()) return;
+ // Update the ismaster view if we have a result
+ if (result) {
+ self.ismaster = result.result;
+ }
+ // Re-schedule the monitoring process
+ self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
+ }
+ );
+ };
+}
+
+var eventHandler = function(self, event) {
+ return function(err, conn) {
+ // Log information of received information if in info mode
+ if (self.s.logger.isInfo()) {
+ var object = err instanceof MongoError ? JSON.stringify(err) : {};
+ self.s.logger.info(
+ f('server %s fired event %s out with message %s', self.name, event, object)
+ );
+ }
+
+ // Handle connect event
+ if (event === 'connect') {
+ self.initialConnect = false;
+ self.ismaster = conn.ismaster;
+ self.lastIsMasterMS = conn.lastIsMasterMS;
+ if (conn.agreedCompressor) {
+ self.s.pool.options.agreedCompressor = conn.agreedCompressor;
+ }
+
+ if (conn.zlibCompressionLevel) {
+ self.s.pool.options.zlibCompressionLevel = conn.zlibCompressionLevel;
+ }
+
+ if (conn.ismaster.$clusterTime) {
+ const $clusterTime = conn.ismaster.$clusterTime;
+ self.clusterTime = $clusterTime;
+ }
+
+ // It's a proxy change the type so
+ // the wireprotocol will send $readPreference
+ if (self.ismaster.msg === 'isdbgrid') {
+ self._type = 'mongos';
+ }
+
+ // Have we defined self monitoring
+ if (self.s.monitoring) {
+ self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
+ }
+
+ // Emit server description changed if something listening
+ sdam.emitServerDescriptionChanged(self, {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: sdam.getTopologyType(self)
+ });
+
+ if (!self.s.inTopology) {
+ // Emit topology description changed if something listening
+ sdam.emitTopologyDescriptionChanged(self, {
+ topologyType: 'Single',
+ servers: [
+ {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: sdam.getTopologyType(self)
+ }
+ ]
+ });
+ }
+
+ // Log the ismaster if available
+ if (self.s.logger.isInfo()) {
+ self.s.logger.info(
+ f('server %s connected with ismaster [%s]', self.name, JSON.stringify(self.ismaster))
+ );
+ }
+
+ // Emit connect
+ self.emit('connect', self);
+ } else if (
+ event === 'error' ||
+ event === 'parseError' ||
+ event === 'close' ||
+ event === 'timeout' ||
+ event === 'reconnect' ||
+ event === 'attemptReconnect' ||
+ 'reconnectFailed'
+ ) {
+ // Remove server instance from accounting
+ if (
+ serverAccounting &&
+ ['close', 'timeout', 'error', 'parseError', 'reconnectFailed'].indexOf(event) !== -1
+ ) {
+ // Emit toplogy opening event if not in topology
+ if (!self.s.inTopology) {
+ self.emit('topologyOpening', { topologyId: self.id });
+ }
+
+ delete servers[self.id];
+ }
+
+ if (event === 'close') {
+ // Closing emits a server description changed event going to unknown.
+ sdam.emitServerDescriptionChanged(self, {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: 'Unknown'
+ });
+ }
+
+ // Reconnect failed return error
+ if (event === 'reconnectFailed') {
+ self.emit('reconnectFailed', err);
+ // Emit error if any listeners
+ if (self.listeners('error').length > 0) {
+ self.emit('error', err);
+ }
+ // Terminate
+ return;
+ }
+
+ // On first connect fail
+ if (
+ ['disconnected', 'connecting'].indexOf(self.s.pool.state) !== -1 &&
+ self.initialConnect &&
+ ['close', 'timeout', 'error', 'parseError'].indexOf(event) !== -1
+ ) {
+ self.initialConnect = false;
+ return self.emit(
+ 'error',
+ new MongoNetworkError(
+ f('failed to connect to server [%s] on first connect [%s]', self.name, err)
+ )
+ );
+ }
+
+ // Reconnect event, emit the server
+ if (event === 'reconnect') {
+ // Reconnecting emits a server description changed event going from unknown to the
+ // current server type.
+ sdam.emitServerDescriptionChanged(self, {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: sdam.getTopologyType(self)
+ });
+ return self.emit(event, self);
+ }
+
+ // Emit the event
+ self.emit(event, err);
+ }
+ };
+};
+
+/**
+ * Initiate server connect
+ */
+Server.prototype.connect = function(options) {
+ var self = this;
+ options = options || {};
+
+ // Set the connections
+ if (serverAccounting) servers[this.id] = this;
+
+ // Do not allow connect to be called on anything that's not disconnected
+ if (self.s.pool && !self.s.pool.isDisconnected() && !self.s.pool.isDestroyed()) {
+ throw new MongoError(f('server instance in invalid state %s', self.s.pool.state));
+ }
+
+ // Create a pool
+ self.s.pool = new Pool(this, Object.assign(self.s.options, options, { bson: this.s.bson }));
+
+ // Set up listeners
+ self.s.pool.on('close', eventHandler(self, 'close'));
+ self.s.pool.on('error', eventHandler(self, 'error'));
+ self.s.pool.on('timeout', eventHandler(self, 'timeout'));
+ self.s.pool.on('parseError', eventHandler(self, 'parseError'));
+ self.s.pool.on('connect', eventHandler(self, 'connect'));
+ self.s.pool.on('reconnect', eventHandler(self, 'reconnect'));
+ self.s.pool.on('reconnectFailed', eventHandler(self, 'reconnectFailed'));
+
+ // Set up listeners for command monitoring
+ relayEvents(self.s.pool, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
+
+ // Emit toplogy opening event if not in topology
+ if (!self.s.inTopology) {
+ this.emit('topologyOpening', { topologyId: topologyId(self) });
+ }
+
+ // Emit opening server event
+ self.emit('serverOpening', { topologyId: topologyId(self), address: self.name });
+
+ self.s.pool.connect();
+};
+
+/**
+ * Authenticate the topology.
+ * @method
+ * @param {MongoCredentials} credentials The credentials for authentication we are using
+ * @param {authResultCallback} callback A callback function
+ */
+Server.prototype.auth = function(credentials, callback) {
+ if (typeof callback === 'function') callback(null, null);
+};
+
+/**
+ * Get the server description
+ * @method
+ * @return {object}
+ */
+Server.prototype.getDescription = function() {
+ var ismaster = this.ismaster || {};
+ var description = {
+ type: sdam.getTopologyType(this),
+ address: this.name
+ };
+
+ // Add fields if available
+ if (ismaster.hosts) description.hosts = ismaster.hosts;
+ if (ismaster.arbiters) description.arbiters = ismaster.arbiters;
+ if (ismaster.passives) description.passives = ismaster.passives;
+ if (ismaster.setName) description.setName = ismaster.setName;
+ return description;
+};
+
+/**
+ * Returns the last known ismaster document for this server
+ * @method
+ * @return {object}
+ */
+Server.prototype.lastIsMaster = function() {
+ return this.ismaster;
+};
+
+/**
+ * Unref all connections belong to this server
+ * @method
+ */
+Server.prototype.unref = function() {
+ this.s.pool.unref();
+};
+
+/**
+ * Figure out if the server is connected
+ * @method
+ * @return {boolean}
+ */
+Server.prototype.isConnected = function() {
+ if (!this.s.pool) return false;
+ return this.s.pool.isConnected();
+};
+
+/**
+ * Figure out if the server instance was destroyed by calling destroy
+ * @method
+ * @return {boolean}
+ */
+Server.prototype.isDestroyed = function() {
+ if (!this.s.pool) return false;
+ return this.s.pool.isDestroyed();
+};
+
+function basicWriteValidations(self) {
+ if (!self.s.pool) return new MongoError('server instance is not connected');
+ if (self.s.pool.isDestroyed()) return new MongoError('server instance pool was destroyed');
+}
+
+function basicReadValidations(self, options) {
+ basicWriteValidations(self, options);
+
+ if (options.readPreference && !(options.readPreference instanceof ReadPreference)) {
+ throw new Error('readPreference must be an instance of ReadPreference');
+ }
+}
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.checkKeys=false] Specify if the bson parser should validate keys.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {Boolean} [options.fullResult=false] Return the full envelope instead of just the result document.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.command = function(ns, cmd, options, callback) {
+ var self = this;
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ var result = basicReadValidations(self, options);
+ if (result) return callback(result);
+
+ // Clone the options
+ options = Object.assign({}, options, { wireProtocolCommand: false });
+
+ // Debug log
+ if (self.s.logger.isDebug())
+ self.s.logger.debug(
+ f(
+ 'executing command [%s] against %s',
+ JSON.stringify({
+ ns: ns,
+ cmd: cmd,
+ options: debugOptions(debugFields, options)
+ }),
+ self.name
+ )
+ );
+
+ // If we are not connected or have a disconnectHandler specified
+ if (disconnectHandler(self, 'command', ns, cmd, options, callback)) return;
+
+ // error if collation not supported
+ if (collationNotSupported(this, cmd)) {
+ return callback(new MongoError(`server ${this.name} does not support collation`));
+ }
+
+ wireProtocol.command(self, ns, cmd, options, callback);
+};
+
+/**
+ * Execute a query against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command document for the query
+ * @param {object} options Optional settings
+ * @param {function} callback
+ */
+Server.prototype.query = function(ns, cmd, cursorState, options, callback) {
+ wireProtocol.query(this, ns, cmd, cursorState, options, callback);
+};
+
+/**
+ * Execute a `getMore` against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cursorState State data associated with the cursor calling this method
+ * @param {object} options Optional settings
+ * @param {function} callback
+ */
+Server.prototype.getMore = function(ns, cursorState, batchSize, options, callback) {
+ wireProtocol.getMore(this, ns, cursorState, batchSize, options, callback);
+};
+
+/**
+ * Execute a `killCursors` command against the server
+ *
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cursorState State data associated with the cursor calling this method
+ * @param {function} callback
+ */
+Server.prototype.killCursors = function(ns, cursorState, callback) {
+ wireProtocol.killCursors(this, ns, cursorState, callback);
+};
+
+/**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.insert = function(ns, ops, options, callback) {
+ var self = this;
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ var result = basicWriteValidations(self, options);
+ if (result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if (disconnectHandler(self, 'insert', ns, ops, options, callback)) return;
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+
+ // Execute write
+ return wireProtocol.insert(self, ns, ops, options, callback);
+};
+
+/**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.update = function(ns, ops, options, callback) {
+ var self = this;
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ var result = basicWriteValidations(self, options);
+ if (result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if (disconnectHandler(self, 'update', ns, ops, options, callback)) return;
+
+ // error if collation not supported
+ if (collationNotSupported(this, options)) {
+ return callback(new MongoError(`server ${this.name} does not support collation`));
+ }
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+ // Execute write
+ return wireProtocol.update(self, ns, ops, options, callback);
+};
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {opResultCallback} callback A callback function
+ */
+Server.prototype.remove = function(ns, ops, options, callback) {
+ var self = this;
+ if (typeof options === 'function') {
+ (callback = options), (options = {}), (options = options || {});
+ }
+
+ var result = basicWriteValidations(self, options);
+ if (result) return callback(result);
+
+ // If we are not connected or have a disconnectHandler specified
+ if (disconnectHandler(self, 'remove', ns, ops, options, callback)) return;
+
+ // error if collation not supported
+ if (collationNotSupported(this, options)) {
+ return callback(new MongoError(`server ${this.name} does not support collation`));
+ }
+
+ // Setup the docs as an array
+ ops = Array.isArray(ops) ? ops : [ops];
+ // Execute write
+ return wireProtocol.remove(self, ns, ops, options, callback);
+};
+
+/**
+ * Get a new cursor
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options] Options for the cursor
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {ClientSession} [options.session=null] Session to use for the operation
+ * @param {object} [options.topology] The internal topology of the created cursor
+ * @returns {Cursor}
+ */
+Server.prototype.cursor = function(ns, cmd, options) {
+ options = options || {};
+ const topology = options.topology || this;
+
+ // Set up final cursor type
+ var FinalCursor = options.cursorFactory || this.s.Cursor;
+
+ // Return the cursor
+ return new FinalCursor(topology, ns, cmd, options);
+};
+
+/**
+ * Compare two server instances
+ * @method
+ * @param {Server} server Server to compare equality against
+ * @return {boolean}
+ */
+Server.prototype.equals = function(server) {
+ if (typeof server === 'string') return this.name.toLowerCase() === server.toLowerCase();
+ if (server.name) return this.name.toLowerCase() === server.name.toLowerCase();
+ return false;
+};
+
+/**
+ * All raw connections
+ * @method
+ * @return {Connection[]}
+ */
+Server.prototype.connections = function() {
+ return this.s.pool.allConnections();
+};
+
+/**
+ * Selects a server
+ * @method
+ * @param {function} selector Unused
+ * @param {ReadPreference} [options.readPreference] Unused
+ * @param {ClientSession} [options.session] Unused
+ * @return {Server}
+ */
+Server.prototype.selectServer = function(selector, options, callback) {
+ if (typeof selector === 'function' && typeof callback === 'undefined')
+ (callback = selector), (selector = undefined), (options = {});
+ if (typeof options === 'function')
+ (callback = options), (options = selector), (selector = undefined);
+
+ callback(null, this);
+};
+
+var listeners = ['close', 'error', 'timeout', 'parseError', 'connect'];
+
+/**
+ * Destroy the server connection
+ * @method
+ * @param {boolean} [options.emitClose=false] Emit close event on destroy
+ * @param {boolean} [options.emitDestroy=false] Emit destroy event on destroy
+ * @param {boolean} [options.force=false] Force destroy the pool
+ */
+Server.prototype.destroy = function(options, callback) {
+ if (this._destroyed) {
+ if (typeof callback === 'function') callback(null, null);
+ return;
+ }
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || {};
+ var self = this;
+
+ // Set the connections
+ if (serverAccounting) delete servers[this.id];
+
+ // Destroy the monitoring process if any
+ if (this.monitoringProcessId) {
+ clearTimeout(this.monitoringProcessId);
+ }
+
+ // No pool, return
+ if (!self.s.pool) {
+ this._destroyed = true;
+ if (typeof callback === 'function') callback(null, null);
+ return;
+ }
+
+ // Emit close event
+ if (options.emitClose) {
+ self.emit('close', self);
+ }
+
+ // Emit destroy event
+ if (options.emitDestroy) {
+ self.emit('destroy', self);
+ }
+
+ // Remove all listeners
+ listeners.forEach(function(event) {
+ self.s.pool.removeAllListeners(event);
+ });
+
+ // Emit opening server event
+ if (self.listeners('serverClosed').length > 0)
+ self.emit('serverClosed', { topologyId: topologyId(self), address: self.name });
+
+ // Emit toplogy opening event if not in topology
+ if (self.listeners('topologyClosed').length > 0 && !self.s.inTopology) {
+ self.emit('topologyClosed', { topologyId: topologyId(self) });
+ }
+
+ if (self.s.logger.isDebug()) {
+ self.s.logger.debug(f('destroy called on server %s', self.name));
+ }
+
+ // Destroy the pool
+ this.s.pool.destroy(options.force, callback);
+ this._destroyed = true;
+};
+
+/**
+ * A server connect event, used to verify that the connection is up and running
+ *
+ * @event Server#connect
+ * @type {Server}
+ */
+
+/**
+ * A server reconnect event, used to verify that the server topology has reconnected
+ *
+ * @event Server#reconnect
+ * @type {Server}
+ */
+
+/**
+ * A server opening SDAM monitoring event
+ *
+ * @event Server#serverOpening
+ * @type {object}
+ */
+
+/**
+ * A server closed SDAM monitoring event
+ *
+ * @event Server#serverClosed
+ * @type {object}
+ */
+
+/**
+ * A server description SDAM change monitoring event
+ *
+ * @event Server#serverDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * A topology open SDAM event
+ *
+ * @event Server#topologyOpening
+ * @type {object}
+ */
+
+/**
+ * A topology closed SDAM event
+ *
+ * @event Server#topologyClosed
+ * @type {object}
+ */
+
+/**
+ * A topology structure SDAM change event
+ *
+ * @event Server#topologyDescriptionChanged
+ * @type {object}
+ */
+
+/**
+ * Server reconnect failed
+ *
+ * @event Server#reconnectFailed
+ * @type {Error}
+ */
+
+/**
+ * Server connection pool closed
+ *
+ * @event Server#close
+ * @type {object}
+ */
+
+/**
+ * Server connection pool caused an error
+ *
+ * @event Server#error
+ * @type {Error}
+ */
+
+/**
+ * Server destroyed was called
+ *
+ * @event Server#destroy
+ * @type {Server}
+ */
+
+module.exports = Server;
diff --git a/node_modules/mongodb/lib/core/topologies/shared.js b/node_modules/mongodb/lib/core/topologies/shared.js
new file mode 100644
index 0000000..590004b
--- /dev/null
+++ b/node_modules/mongodb/lib/core/topologies/shared.js
@@ -0,0 +1,433 @@
+'use strict';
+const ReadPreference = require('./read_preference');
+const TopologyType = require('../sdam/common').TopologyType;
+const MongoError = require('../error').MongoError;
+
+const MMAPv1_RETRY_WRITES_ERROR_CODE = 20;
+
+/**
+ * Emit event if it exists
+ * @method
+ */
+function emitSDAMEvent(self, event, description) {
+ if (self.listeners(event).length > 0) {
+ self.emit(event, description);
+ }
+}
+
+function createCompressionInfo(options) {
+ if (!options.compression || !options.compression.compressors) {
+ return [];
+ }
+
+ // Check that all supplied compressors are valid
+ options.compression.compressors.forEach(function(compressor) {
+ if (compressor !== 'snappy' && compressor !== 'zlib') {
+ throw new Error('compressors must be at least one of snappy or zlib');
+ }
+ });
+
+ return options.compression.compressors;
+}
+
+function clone(object) {
+ return JSON.parse(JSON.stringify(object));
+}
+
+var getPreviousDescription = function(self) {
+ if (!self.s.serverDescription) {
+ self.s.serverDescription = {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: 'Unknown'
+ };
+ }
+
+ return self.s.serverDescription;
+};
+
+var emitServerDescriptionChanged = function(self, description) {
+ if (self.listeners('serverDescriptionChanged').length > 0) {
+ // Emit the server description changed events
+ self.emit('serverDescriptionChanged', {
+ topologyId: self.s.topologyId !== -1 ? self.s.topologyId : self.id,
+ address: self.name,
+ previousDescription: getPreviousDescription(self),
+ newDescription: description
+ });
+
+ self.s.serverDescription = description;
+ }
+};
+
+var getPreviousTopologyDescription = function(self) {
+ if (!self.s.topologyDescription) {
+ self.s.topologyDescription = {
+ topologyType: 'Unknown',
+ servers: [
+ {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: 'Unknown'
+ }
+ ]
+ };
+ }
+
+ return self.s.topologyDescription;
+};
+
+var emitTopologyDescriptionChanged = function(self, description) {
+ if (self.listeners('topologyDescriptionChanged').length > 0) {
+ // Emit the server description changed events
+ self.emit('topologyDescriptionChanged', {
+ topologyId: self.s.topologyId !== -1 ? self.s.topologyId : self.id,
+ address: self.name,
+ previousDescription: getPreviousTopologyDescription(self),
+ newDescription: description
+ });
+
+ self.s.serverDescription = description;
+ }
+};
+
+var changedIsMaster = function(self, currentIsmaster, ismaster) {
+ var currentType = getTopologyType(self, currentIsmaster);
+ var newType = getTopologyType(self, ismaster);
+ if (newType !== currentType) return true;
+ return false;
+};
+
+var getTopologyType = function(self, ismaster) {
+ if (!ismaster) {
+ ismaster = self.ismaster;
+ }
+
+ if (!ismaster) return 'Unknown';
+ if (ismaster.ismaster && ismaster.msg === 'isdbgrid') return 'Mongos';
+ if (ismaster.ismaster && !ismaster.hosts) return 'Standalone';
+ if (ismaster.ismaster) return 'RSPrimary';
+ if (ismaster.secondary) return 'RSSecondary';
+ if (ismaster.arbiterOnly) return 'RSArbiter';
+ return 'Unknown';
+};
+
+var inquireServerState = function(self) {
+ return function(callback) {
+ if (self.s.state === 'destroyed') return;
+ // Record response time
+ var start = new Date().getTime();
+
+ // emitSDAMEvent
+ emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: self.name });
+
+ // Attempt to execute ismaster command
+ self.command('admin.$cmd', { ismaster: true }, { monitoring: true }, function(err, r) {
+ if (!err) {
+ // Legacy event sender
+ self.emit('ismaster', r, self);
+
+ // Calculate latencyMS
+ var latencyMS = new Date().getTime() - start;
+
+ // Server heart beat event
+ emitSDAMEvent(self, 'serverHeartbeatSucceeded', {
+ durationMS: latencyMS,
+ reply: r.result,
+ connectionId: self.name
+ });
+
+ // Did the server change
+ if (changedIsMaster(self, self.s.ismaster, r.result)) {
+ // Emit server description changed if something listening
+ emitServerDescriptionChanged(self, {
+ address: self.name,
+ arbiters: [],
+ hosts: [],
+ passives: [],
+ type: !self.s.inTopology ? 'Standalone' : getTopologyType(self)
+ });
+ }
+
+ // Updat ismaster view
+ self.s.ismaster = r.result;
+
+ // Set server response time
+ self.s.isMasterLatencyMS = latencyMS;
+ } else {
+ emitSDAMEvent(self, 'serverHeartbeatFailed', {
+ durationMS: latencyMS,
+ failure: err,
+ connectionId: self.name
+ });
+ }
+
+ // Peforming an ismaster monitoring callback operation
+ if (typeof callback === 'function') {
+ return callback(err, r);
+ }
+
+ // Perform another sweep
+ self.s.inquireServerStateTimeout = setTimeout(inquireServerState(self), self.s.haInterval);
+ });
+ };
+};
+
+//
+// Clone the options
+var cloneOptions = function(options) {
+ var opts = {};
+ for (var name in options) {
+ opts[name] = options[name];
+ }
+ return opts;
+};
+
+function Interval(fn, time) {
+ var timer = false;
+
+ this.start = function() {
+ if (!this.isRunning()) {
+ timer = setInterval(fn, time);
+ }
+
+ return this;
+ };
+
+ this.stop = function() {
+ clearInterval(timer);
+ timer = false;
+ return this;
+ };
+
+ this.isRunning = function() {
+ return timer !== false;
+ };
+}
+
+function Timeout(fn, time) {
+ var timer = false;
+ var func = () => {
+ if (timer) {
+ clearTimeout(timer);
+ timer = false;
+
+ fn();
+ }
+ };
+
+ this.start = function() {
+ if (!this.isRunning()) {
+ timer = setTimeout(func, time);
+ }
+ return this;
+ };
+
+ this.stop = function() {
+ clearTimeout(timer);
+ timer = false;
+ return this;
+ };
+
+ this.isRunning = function() {
+ return timer !== false;
+ };
+}
+
+function diff(previous, current) {
+ // Difference document
+ var diff = {
+ servers: []
+ };
+
+ // Previous entry
+ if (!previous) {
+ previous = { servers: [] };
+ }
+
+ // Check if we have any previous servers missing in the current ones
+ for (var i = 0; i < previous.servers.length; i++) {
+ var found = false;
+
+ for (var j = 0; j < current.servers.length; j++) {
+ if (current.servers[j].address.toLowerCase() === previous.servers[i].address.toLowerCase()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // Add to the diff
+ diff.servers.push({
+ address: previous.servers[i].address,
+ from: previous.servers[i].type,
+ to: 'Unknown'
+ });
+ }
+ }
+
+ // Check if there are any severs that don't exist
+ for (j = 0; j < current.servers.length; j++) {
+ found = false;
+
+ // Go over all the previous servers
+ for (i = 0; i < previous.servers.length; i++) {
+ if (previous.servers[i].address.toLowerCase() === current.servers[j].address.toLowerCase()) {
+ found = true;
+ break;
+ }
+ }
+
+ // Add the server to the diff
+ if (!found) {
+ diff.servers.push({
+ address: current.servers[j].address,
+ from: 'Unknown',
+ to: current.servers[j].type
+ });
+ }
+ }
+
+ // Got through all the servers
+ for (i = 0; i < previous.servers.length; i++) {
+ var prevServer = previous.servers[i];
+
+ // Go through all current servers
+ for (j = 0; j < current.servers.length; j++) {
+ var currServer = current.servers[j];
+
+ // Matching server
+ if (prevServer.address.toLowerCase() === currServer.address.toLowerCase()) {
+ // We had a change in state
+ if (prevServer.type !== currServer.type) {
+ diff.servers.push({
+ address: prevServer.address,
+ from: prevServer.type,
+ to: currServer.type
+ });
+ }
+ }
+ }
+ }
+
+ // Return difference
+ return diff;
+}
+
+/**
+ * Shared function to determine clusterTime for a given topology
+ *
+ * @param {*} topology
+ * @param {*} clusterTime
+ */
+function resolveClusterTime(topology, $clusterTime) {
+ if (topology.clusterTime == null) {
+ topology.clusterTime = $clusterTime;
+ } else {
+ if ($clusterTime.clusterTime.greaterThan(topology.clusterTime.clusterTime)) {
+ topology.clusterTime = $clusterTime;
+ }
+ }
+}
+
+// NOTE: this is a temporary move until the topologies can be more formally refactored
+// to share code.
+const SessionMixins = {
+ endSessions: function(sessions, callback) {
+ if (!Array.isArray(sessions)) {
+ sessions = [sessions];
+ }
+
+ // TODO:
+ // When connected to a sharded cluster the endSessions command
+ // can be sent to any mongos. When connected to a replica set the
+ // endSessions command MUST be sent to the primary if the primary
+ // is available, otherwise it MUST be sent to any available secondary.
+ // Is it enough to use: ReadPreference.primaryPreferred ?
+ this.command(
+ 'admin.$cmd',
+ { endSessions: sessions },
+ { readPreference: ReadPreference.primaryPreferred },
+ () => {
+ // intentionally ignored, per spec
+ if (typeof callback === 'function') callback();
+ }
+ );
+ }
+};
+
+function topologyType(topology) {
+ if (topology.description) {
+ return topology.description.type;
+ }
+
+ if (topology.type === 'mongos') {
+ return TopologyType.Sharded;
+ } else if (topology.type === 'replset') {
+ return TopologyType.ReplicaSetWithPrimary;
+ }
+
+ return TopologyType.Single;
+}
+
+const RETRYABLE_WIRE_VERSION = 6;
+
+/**
+ * Determines whether the provided topology supports retryable writes
+ *
+ * @param {Mongos|Replset} topology
+ */
+const isRetryableWritesSupported = function(topology) {
+ const maxWireVersion = topology.lastIsMaster().maxWireVersion;
+ if (maxWireVersion < RETRYABLE_WIRE_VERSION) {
+ return false;
+ }
+
+ if (!topology.logicalSessionTimeoutMinutes) {
+ return false;
+ }
+
+ if (topologyType(topology) === TopologyType.Single) {
+ return false;
+ }
+
+ return true;
+};
+
+const MMAPv1_RETRY_WRITES_ERROR_MESSAGE =
+ 'This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.';
+
+function getMMAPError(err) {
+ if (err.code !== MMAPv1_RETRY_WRITES_ERROR_CODE || !err.errmsg.includes('Transaction numbers')) {
+ return err;
+ }
+
+ // According to the retryable writes spec, we must replace the error message in this case.
+ // We need to replace err.message so the thrown message is correct and we need to replace err.errmsg to meet the spec requirement.
+ const newErr = new MongoError({
+ message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
+ errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
+ originalError: err
+ });
+ return newErr;
+}
+
+module.exports.SessionMixins = SessionMixins;
+module.exports.resolveClusterTime = resolveClusterTime;
+module.exports.inquireServerState = inquireServerState;
+module.exports.getTopologyType = getTopologyType;
+module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
+module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
+module.exports.cloneOptions = cloneOptions;
+module.exports.createCompressionInfo = createCompressionInfo;
+module.exports.clone = clone;
+module.exports.diff = diff;
+module.exports.Interval = Interval;
+module.exports.Timeout = Timeout;
+module.exports.isRetryableWritesSupported = isRetryableWritesSupported;
+module.exports.getMMAPError = getMMAPError;
+module.exports.topologyType = topologyType;
diff --git a/node_modules/mongodb/lib/core/transactions.js b/node_modules/mongodb/lib/core/transactions.js
new file mode 100644
index 0000000..d0b0b73
--- /dev/null
+++ b/node_modules/mongodb/lib/core/transactions.js
@@ -0,0 +1,179 @@
+'use strict';
+const MongoError = require('./error').MongoError;
+const ReadPreference = require('./topologies/read_preference');
+const ReadConcern = require('../read_concern');
+const WriteConcern = require('../write_concern');
+
+let TxnState;
+let stateMachine;
+
+(() => {
+ const NO_TRANSACTION = 'NO_TRANSACTION';
+ const STARTING_TRANSACTION = 'STARTING_TRANSACTION';
+ const TRANSACTION_IN_PROGRESS = 'TRANSACTION_IN_PROGRESS';
+ const TRANSACTION_COMMITTED = 'TRANSACTION_COMMITTED';
+ const TRANSACTION_COMMITTED_EMPTY = 'TRANSACTION_COMMITTED_EMPTY';
+ const TRANSACTION_ABORTED = 'TRANSACTION_ABORTED';
+
+ TxnState = {
+ NO_TRANSACTION,
+ STARTING_TRANSACTION,
+ TRANSACTION_IN_PROGRESS,
+ TRANSACTION_COMMITTED,
+ TRANSACTION_COMMITTED_EMPTY,
+ TRANSACTION_ABORTED
+ };
+
+ stateMachine = {
+ [NO_TRANSACTION]: [NO_TRANSACTION, STARTING_TRANSACTION],
+ [STARTING_TRANSACTION]: [
+ TRANSACTION_IN_PROGRESS,
+ TRANSACTION_COMMITTED,
+ TRANSACTION_COMMITTED_EMPTY,
+ TRANSACTION_ABORTED
+ ],
+ [TRANSACTION_IN_PROGRESS]: [
+ TRANSACTION_IN_PROGRESS,
+ TRANSACTION_COMMITTED,
+ TRANSACTION_ABORTED
+ ],
+ [TRANSACTION_COMMITTED]: [
+ TRANSACTION_COMMITTED,
+ TRANSACTION_COMMITTED_EMPTY,
+ STARTING_TRANSACTION,
+ NO_TRANSACTION
+ ],
+ [TRANSACTION_ABORTED]: [STARTING_TRANSACTION, NO_TRANSACTION],
+ [TRANSACTION_COMMITTED_EMPTY]: [TRANSACTION_COMMITTED_EMPTY, NO_TRANSACTION]
+ };
+})();
+
+/**
+ * The MongoDB ReadConcern, which allows for control of the consistency and isolation properties
+ * of the data read from replica sets and replica set shards.
+ * @typedef {Object} ReadConcern
+ * @property {'local'|'available'|'majority'|'linearizable'|'snapshot'} level The readConcern Level
+ * @see https://docs.mongodb.com/manual/reference/read-concern/
+ */
+
+/**
+ * A MongoDB WriteConcern, which describes the level of acknowledgement
+ * requested from MongoDB for write operations.
+ * @typedef {Object} WriteConcern
+ * @property {number|'majority'|string} [w=1] requests acknowledgement that the write operation has
+ * propagated to a specified number of mongod hosts
+ * @property {boolean} [j=false] requests acknowledgement from MongoDB that the write operation has
+ * been written to the journal
+ * @property {number} [wtimeout] a time limit, in milliseconds, for the write concern
+ * @see https://docs.mongodb.com/manual/reference/write-concern/
+ */
+
+/**
+ * Configuration options for a transaction.
+ * @typedef {Object} TransactionOptions
+ * @property {ReadConcern} [readConcern] A default read concern for commands in this transaction
+ * @property {WriteConcern} [writeConcern] A default writeConcern for commands in this transaction
+ * @property {ReadPreference} [readPreference] A default read preference for commands in this transaction
+ */
+
+/**
+ * A class maintaining state related to a server transaction. Internal Only
+ * @ignore
+ */
+class Transaction {
+ /**
+ * Create a transaction
+ *
+ * @ignore
+ * @param {TransactionOptions} [options] Optional settings
+ */
+ constructor(options) {
+ options = options || {};
+
+ this.state = TxnState.NO_TRANSACTION;
+ this.options = {};
+
+ const writeConcern = WriteConcern.fromOptions(options);
+ if (writeConcern) {
+ if (writeConcern.w <= 0) {
+ throw new MongoError('Transactions do not support unacknowledged write concern');
+ }
+
+ this.options.writeConcern = writeConcern;
+ }
+
+ if (options.readConcern) {
+ this.options.readConcern = ReadConcern.fromOptions(options);
+ }
+
+ if (options.readPreference) {
+ this.options.readPreference = ReadPreference.fromOptions(options);
+ }
+
+ if (options.maxCommitTimeMS) {
+ this.options.maxTimeMS = options.maxCommitTimeMS;
+ }
+
+ // TODO: This isn't technically necessary
+ this._pinnedServer = undefined;
+ this._recoveryToken = undefined;
+ }
+
+ get server() {
+ return this._pinnedServer;
+ }
+
+ get recoveryToken() {
+ return this._recoveryToken;
+ }
+
+ get isPinned() {
+ return !!this.server;
+ }
+
+ /**
+ * @ignore
+ * @return Whether this session is presently in a transaction
+ */
+ get isActive() {
+ return (
+ [TxnState.STARTING_TRANSACTION, TxnState.TRANSACTION_IN_PROGRESS].indexOf(this.state) !== -1
+ );
+ }
+
+ /**
+ * Transition the transaction in the state machine
+ * @ignore
+ * @param {TxnState} state The new state to transition to
+ */
+ transition(nextState) {
+ const nextStates = stateMachine[this.state];
+ if (nextStates && nextStates.indexOf(nextState) !== -1) {
+ this.state = nextState;
+ if (this.state === TxnState.NO_TRANSACTION || this.state === TxnState.STARTING_TRANSACTION) {
+ this.unpinServer();
+ }
+ return;
+ }
+
+ throw new MongoError(
+ `Attempted illegal state transition from [${this.state}] to [${nextState}]`
+ );
+ }
+
+ pinServer(server) {
+ if (this.isActive) {
+ this._pinnedServer = server;
+ }
+ }
+
+ unpinServer() {
+ this._pinnedServer = undefined;
+ }
+}
+
+function isTransactionCommand(command) {
+ return !!(command.commitTransaction || command.abortTransaction);
+}
+
+module.exports = { TxnState, Transaction, isTransactionCommand };
diff --git a/node_modules/mongodb/lib/core/uri_parser.js b/node_modules/mongodb/lib/core/uri_parser.js
new file mode 100644
index 0000000..92c9a87
--- /dev/null
+++ b/node_modules/mongodb/lib/core/uri_parser.js
@@ -0,0 +1,688 @@
+'use strict';
+const URL = require('url');
+const qs = require('querystring');
+const dns = require('dns');
+const MongoParseError = require('./error').MongoParseError;
+const ReadPreference = require('./topologies/read_preference');
+
+/**
+ * The following regular expression validates a connection string and breaks the
+ * provide string into the following capture groups: [protocol, username, password, hosts]
+ */
+const HOSTS_RX = /(mongodb(?:\+srv|)):\/\/(?: (?:[^:]*) (?: : ([^@]*) )? @ )?([^/?]*)(?:\/|)(.*)/;
+
+/**
+ * Determines whether a provided address matches the provided parent domain in order
+ * to avoid certain attack vectors.
+ *
+ * @param {String} srvAddress The address to check against a domain
+ * @param {String} parentDomain The domain to check the provided address against
+ * @return {Boolean} Whether the provided address matches the parent domain
+ */
+function matchesParentDomain(srvAddress, parentDomain) {
+ const regex = /^.*?\./;
+ const srv = `.${srvAddress.replace(regex, '')}`;
+ const parent = `.${parentDomain.replace(regex, '')}`;
+ return srv.endsWith(parent);
+}
+
+/**
+ * Lookup a `mongodb+srv` connection string, combine the parts and reparse it as a normal
+ * connection string.
+ *
+ * @param {string} uri The connection string to parse
+ * @param {object} options Optional user provided connection string options
+ * @param {function} callback
+ */
+function parseSrvConnectionString(uri, options, callback) {
+ const result = URL.parse(uri, true);
+
+ if (result.hostname.split('.').length < 3) {
+ return callback(new MongoParseError('URI does not have hostname, domain name and tld'));
+ }
+
+ result.domainLength = result.hostname.split('.').length;
+ if (result.pathname && result.pathname.match(',')) {
+ return callback(new MongoParseError('Invalid URI, cannot contain multiple hostnames'));
+ }
+
+ if (result.port) {
+ return callback(new MongoParseError(`Ports not accepted with '${PROTOCOL_MONGODB_SRV}' URIs`));
+ }
+
+ // Resolve the SRV record and use the result as the list of hosts to connect to.
+ const lookupAddress = result.host;
+ dns.resolveSrv(`_mongodb._tcp.${lookupAddress}`, (err, addresses) => {
+ if (err) return callback(err);
+
+ if (addresses.length === 0) {
+ return callback(new MongoParseError('No addresses found at host'));
+ }
+
+ for (let i = 0; i < addresses.length; i++) {
+ if (!matchesParentDomain(addresses[i].name, result.hostname, result.domainLength)) {
+ return callback(
+ new MongoParseError('Server record does not share hostname with parent URI')
+ );
+ }
+ }
+
+ // Convert the original URL to a non-SRV URL.
+ result.protocol = 'mongodb';
+ result.host = addresses.map(address => `${address.name}:${address.port}`).join(',');
+
+ // Default to SSL true if it's not specified.
+ if (
+ !('ssl' in options) &&
+ (!result.search || !('ssl' in result.query) || result.query.ssl === null)
+ ) {
+ result.query.ssl = true;
+ }
+
+ // Resolve TXT record and add options from there if they exist.
+ dns.resolveTxt(lookupAddress, (err, record) => {
+ if (err) {
+ if (err.code !== 'ENODATA') {
+ return callback(err);
+ }
+ record = null;
+ }
+
+ if (record) {
+ if (record.length > 1) {
+ return callback(new MongoParseError('Multiple text records not allowed'));
+ }
+
+ record = qs.parse(record[0].join(''));
+ if (Object.keys(record).some(key => key !== 'authSource' && key !== 'replicaSet')) {
+ return callback(
+ new MongoParseError('Text record must only set `authSource` or `replicaSet`')
+ );
+ }
+
+ result.query = Object.assign({}, record, result.query);
+ }
+
+ // Set completed options back into the URL object.
+ result.search = qs.stringify(result.query);
+
+ const finalString = URL.format(result);
+ parseConnectionString(finalString, options, (err, ret) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ callback(null, Object.assign({}, ret, { srvHost: lookupAddress }));
+ });
+ });
+ });
+}
+
+/**
+ * Parses a query string item according to the connection string spec
+ *
+ * @param {string} key The key for the parsed value
+ * @param {Array|String} value The value to parse
+ * @return {Array|Object|String} The parsed value
+ */
+function parseQueryStringItemValue(key, value) {
+ if (Array.isArray(value)) {
+ // deduplicate and simplify arrays
+ value = value.filter((v, idx) => value.indexOf(v) === idx);
+ if (value.length === 1) value = value[0];
+ } else if (value.indexOf(':') > 0) {
+ value = value.split(',').reduce((result, pair) => {
+ const parts = pair.split(':');
+ result[parts[0]] = parseQueryStringItemValue(key, parts[1]);
+ return result;
+ }, {});
+ } else if (value.indexOf(',') > 0) {
+ value = value.split(',').map(v => {
+ return parseQueryStringItemValue(key, v);
+ });
+ } else if (value.toLowerCase() === 'true' || value.toLowerCase() === 'false') {
+ value = value.toLowerCase() === 'true';
+ } else if (!Number.isNaN(value) && !STRING_OPTIONS.has(key)) {
+ const numericValue = parseFloat(value);
+ if (!Number.isNaN(numericValue)) {
+ value = parseFloat(value);
+ }
+ }
+
+ return value;
+}
+
+// Options that are known boolean types
+const BOOLEAN_OPTIONS = new Set([
+ 'slaveok',
+ 'slave_ok',
+ 'sslvalidate',
+ 'fsync',
+ 'safe',
+ 'retrywrites',
+ 'j'
+]);
+
+// Known string options, only used to bypass Number coercion in `parseQueryStringItemValue`
+const STRING_OPTIONS = new Set(['authsource', 'replicaset']);
+
+// Supported text representations of auth mechanisms
+// NOTE: this list exists in native already, if it is merged here we should deduplicate
+const AUTH_MECHANISMS = new Set([
+ 'GSSAPI',
+ 'MONGODB-X509',
+ 'MONGODB-CR',
+ 'DEFAULT',
+ 'SCRAM-SHA-1',
+ 'SCRAM-SHA-256',
+ 'PLAIN'
+]);
+
+// Lookup table used to translate normalized (lower-cased) forms of connection string
+// options to their expected camelCase version
+const CASE_TRANSLATION = {
+ replicaset: 'replicaSet',
+ connecttimeoutms: 'connectTimeoutMS',
+ sockettimeoutms: 'socketTimeoutMS',
+ maxpoolsize: 'maxPoolSize',
+ minpoolsize: 'minPoolSize',
+ maxidletimems: 'maxIdleTimeMS',
+ waitqueuemultiple: 'waitQueueMultiple',
+ waitqueuetimeoutms: 'waitQueueTimeoutMS',
+ wtimeoutms: 'wtimeoutMS',
+ readconcern: 'readConcern',
+ readconcernlevel: 'readConcernLevel',
+ readpreference: 'readPreference',
+ maxstalenessseconds: 'maxStalenessSeconds',
+ readpreferencetags: 'readPreferenceTags',
+ authsource: 'authSource',
+ authmechanism: 'authMechanism',
+ authmechanismproperties: 'authMechanismProperties',
+ gssapiservicename: 'gssapiServiceName',
+ localthresholdms: 'localThresholdMS',
+ serverselectiontimeoutms: 'serverSelectionTimeoutMS',
+ serverselectiontryonce: 'serverSelectionTryOnce',
+ heartbeatfrequencyms: 'heartbeatFrequencyMS',
+ retrywrites: 'retryWrites',
+ uuidrepresentation: 'uuidRepresentation',
+ zlibcompressionlevel: 'zlibCompressionLevel',
+ tlsallowinvalidcertificates: 'tlsAllowInvalidCertificates',
+ tlsallowinvalidhostnames: 'tlsAllowInvalidHostnames',
+ tlsinsecure: 'tlsInsecure',
+ tlscafile: 'tlsCAFile',
+ tlscertificatekeyfile: 'tlsCertificateKeyFile',
+ tlscertificatekeyfilepassword: 'tlsCertificateKeyFilePassword',
+ wtimeout: 'wTimeoutMS',
+ j: 'journal'
+};
+
+/**
+ * Sets the value for `key`, allowing for any required translation
+ *
+ * @param {object} obj The object to set the key on
+ * @param {string} key The key to set the value for
+ * @param {*} value The value to set
+ * @param {object} options The options used for option parsing
+ */
+function applyConnectionStringOption(obj, key, value, options) {
+ // simple key translation
+ if (key === 'journal') {
+ key = 'j';
+ } else if (key === 'wtimeoutms') {
+ key = 'wtimeout';
+ }
+
+ // more complicated translation
+ if (BOOLEAN_OPTIONS.has(key)) {
+ value = value === 'true' || value === true;
+ } else if (key === 'appname') {
+ value = decodeURIComponent(value);
+ } else if (key === 'readconcernlevel') {
+ obj['readConcernLevel'] = value;
+ key = 'readconcern';
+ value = { level: value };
+ }
+
+ // simple validation
+ if (key === 'compressors') {
+ value = Array.isArray(value) ? value : [value];
+
+ if (!value.every(c => c === 'snappy' || c === 'zlib')) {
+ throw new MongoParseError(
+ 'Value for `compressors` must be at least one of: `snappy`, `zlib`'
+ );
+ }
+ }
+
+ if (key === 'authmechanism' && !AUTH_MECHANISMS.has(value)) {
+ throw new MongoParseError(
+ 'Value for `authMechanism` must be one of: `DEFAULT`, `GSSAPI`, `PLAIN`, `MONGODB-X509`, `SCRAM-SHA-1`, `SCRAM-SHA-256`'
+ );
+ }
+
+ if (key === 'readpreference' && !ReadPreference.isValid(value)) {
+ throw new MongoParseError(
+ 'Value for `readPreference` must be one of: `primary`, `primaryPreferred`, `secondary`, `secondaryPreferred`, `nearest`'
+ );
+ }
+
+ if (key === 'zlibcompressionlevel' && (value < -1 || value > 9)) {
+ throw new MongoParseError('zlibCompressionLevel must be an integer between -1 and 9');
+ }
+
+ // special cases
+ if (key === 'compressors' || key === 'zlibcompressionlevel') {
+ obj.compression = obj.compression || {};
+ obj = obj.compression;
+ }
+
+ if (key === 'authmechanismproperties') {
+ if (typeof value.SERVICE_NAME === 'string') obj.gssapiServiceName = value.SERVICE_NAME;
+ if (typeof value.SERVICE_REALM === 'string') obj.gssapiServiceRealm = value.SERVICE_REALM;
+ if (typeof value.CANONICALIZE_HOST_NAME !== 'undefined') {
+ obj.gssapiCanonicalizeHostName = value.CANONICALIZE_HOST_NAME;
+ }
+ }
+
+ if (key === 'readpreferencetags' && Array.isArray(value)) {
+ value = splitArrayOfMultipleReadPreferenceTags(value);
+ }
+
+ // set the actual value
+ if (options.caseTranslate && CASE_TRANSLATION[key]) {
+ obj[CASE_TRANSLATION[key]] = value;
+ return;
+ }
+
+ obj[key] = value;
+}
+
+const USERNAME_REQUIRED_MECHANISMS = new Set([
+ 'GSSAPI',
+ 'MONGODB-CR',
+ 'PLAIN',
+ 'SCRAM-SHA-1',
+ 'SCRAM-SHA-256'
+]);
+
+function splitArrayOfMultipleReadPreferenceTags(value) {
+ const parsedTags = [];
+
+ for (let i = 0; i < value.length; i++) {
+ parsedTags[i] = {};
+ value[i].split(',').forEach(individualTag => {
+ const splitTag = individualTag.split(':');
+ parsedTags[i][splitTag[0]] = splitTag[1];
+ });
+ }
+
+ return parsedTags;
+}
+
+/**
+ * Modifies the parsed connection string object taking into account expectations we
+ * have for authentication-related options.
+ *
+ * @param {object} parsed The parsed connection string result
+ * @return The parsed connection string result possibly modified for auth expectations
+ */
+function applyAuthExpectations(parsed) {
+ if (parsed.options == null) {
+ return;
+ }
+
+ const options = parsed.options;
+ const authSource = options.authsource || options.authSource;
+ if (authSource != null) {
+ parsed.auth = Object.assign({}, parsed.auth, { db: authSource });
+ }
+
+ const authMechanism = options.authmechanism || options.authMechanism;
+ if (authMechanism != null) {
+ if (
+ USERNAME_REQUIRED_MECHANISMS.has(authMechanism) &&
+ (!parsed.auth || parsed.auth.username == null)
+ ) {
+ throw new MongoParseError(`Username required for mechanism \`${authMechanism}\``);
+ }
+
+ if (authMechanism === 'GSSAPI') {
+ if (authSource != null && authSource !== '$external') {
+ throw new MongoParseError(
+ `Invalid source \`${authSource}\` for mechanism \`${authMechanism}\` specified.`
+ );
+ }
+
+ parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
+ }
+
+ if (authMechanism === 'MONGODB-X509') {
+ if (parsed.auth && parsed.auth.password != null) {
+ throw new MongoParseError(`Password not allowed for mechanism \`${authMechanism}\``);
+ }
+
+ if (authSource != null && authSource !== '$external') {
+ throw new MongoParseError(
+ `Invalid source \`${authSource}\` for mechanism \`${authMechanism}\` specified.`
+ );
+ }
+
+ parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
+ }
+
+ if (authMechanism === 'PLAIN') {
+ if (parsed.auth && parsed.auth.db == null) {
+ parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
+ }
+ }
+ }
+
+ // default to `admin` if nothing else was resolved
+ if (parsed.auth && parsed.auth.db == null) {
+ parsed.auth = Object.assign({}, parsed.auth, { db: 'admin' });
+ }
+
+ return parsed;
+}
+
+/**
+ * Parses a query string according the connection string spec.
+ *
+ * @param {String} query The query string to parse
+ * @param {object} [options] The options used for options parsing
+ * @return {Object|Error} The parsed query string as an object, or an error if one was encountered
+ */
+function parseQueryString(query, options) {
+ const result = {};
+ let parsedQueryString = qs.parse(query);
+
+ checkTLSOptions(parsedQueryString);
+
+ for (const key in parsedQueryString) {
+ const value = parsedQueryString[key];
+ if (value === '' || value == null) {
+ throw new MongoParseError('Incomplete key value pair for option');
+ }
+
+ const normalizedKey = key.toLowerCase();
+ const parsedValue = parseQueryStringItemValue(normalizedKey, value);
+ applyConnectionStringOption(result, normalizedKey, parsedValue, options);
+ }
+
+ // special cases for known deprecated options
+ if (result.wtimeout && result.wtimeoutms) {
+ delete result.wtimeout;
+ console.warn('Unsupported option `wtimeout` specified');
+ }
+
+ return Object.keys(result).length ? result : null;
+}
+
+/// Adds support for modern `tls` variants of out `ssl` options
+function translateTLSOptions(queryString) {
+ if (queryString.tls) {
+ queryString.ssl = queryString.tls;
+ }
+
+ if (queryString.tlsInsecure) {
+ queryString.checkServerIdentity = false;
+ queryString.sslValidate = false;
+ } else {
+ Object.assign(queryString, {
+ checkServerIdentity: queryString.tlsAllowInvalidHostnames ? false : true,
+ sslValidate: queryString.tlsAllowInvalidCertificates ? false : true
+ });
+ }
+
+ if (queryString.tlsCAFile) {
+ queryString.ssl = true;
+ queryString.sslCA = queryString.tlsCAFile;
+ }
+
+ if (queryString.tlsCertificateKeyFile) {
+ queryString.ssl = true;
+ if (queryString.tlsCertificateFile) {
+ queryString.sslCert = queryString.tlsCertificateFile;
+ queryString.sslKey = queryString.tlsCertificateKeyFile;
+ } else {
+ queryString.sslKey = queryString.tlsCertificateKeyFile;
+ queryString.sslCert = queryString.tlsCertificateKeyFile;
+ }
+ }
+
+ if (queryString.tlsCertificateKeyFilePassword) {
+ queryString.ssl = true;
+ queryString.sslPass = queryString.tlsCertificateKeyFilePassword;
+ }
+
+ return queryString;
+}
+
+/**
+ * Checks a query string for invalid tls options according to the URI options spec.
+ *
+ * @param {string} queryString The query string to check
+ * @throws {MongoParseError}
+ */
+function checkTLSOptions(queryString) {
+ const queryStringKeys = Object.keys(queryString);
+ if (
+ queryStringKeys.indexOf('tlsInsecure') !== -1 &&
+ (queryStringKeys.indexOf('tlsAllowInvalidCertificates') !== -1 ||
+ queryStringKeys.indexOf('tlsAllowInvalidHostnames') !== -1)
+ ) {
+ throw new MongoParseError(
+ 'The `tlsInsecure` option cannot be used with `tlsAllowInvalidCertificates` or `tlsAllowInvalidHostnames`.'
+ );
+ }
+
+ const tlsValue = assertTlsOptionsAreEqual('tls', queryString, queryStringKeys);
+ const sslValue = assertTlsOptionsAreEqual('ssl', queryString, queryStringKeys);
+
+ if (tlsValue != null && sslValue != null) {
+ if (tlsValue !== sslValue) {
+ throw new MongoParseError('All values of `tls` and `ssl` must be the same.');
+ }
+ }
+}
+
+/**
+ * Checks a query string to ensure all tls/ssl options are the same.
+ *
+ * @param {string} key The key (tls or ssl) to check
+ * @param {string} queryString The query string to check
+ * @throws {MongoParseError}
+ * @return The value of the tls/ssl option
+ */
+function assertTlsOptionsAreEqual(optionName, queryString, queryStringKeys) {
+ const queryStringHasTLSOption = queryStringKeys.indexOf(optionName) !== -1;
+
+ let optionValue;
+ if (Array.isArray(queryString[optionName])) {
+ optionValue = queryString[optionName][0];
+ } else {
+ optionValue = queryString[optionName];
+ }
+
+ if (queryStringHasTLSOption) {
+ if (Array.isArray(queryString[optionName])) {
+ const firstValue = queryString[optionName][0];
+ queryString[optionName].forEach(tlsValue => {
+ if (tlsValue !== firstValue) {
+ throw new MongoParseError(`All values of ${optionName} must be the same.`);
+ }
+ });
+ }
+ }
+
+ return optionValue;
+}
+
+const PROTOCOL_MONGODB = 'mongodb';
+const PROTOCOL_MONGODB_SRV = 'mongodb+srv';
+const SUPPORTED_PROTOCOLS = [PROTOCOL_MONGODB, PROTOCOL_MONGODB_SRV];
+
+/**
+ * Parses a MongoDB connection string
+ *
+ * @param {*} uri the MongoDB connection string to parse
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.caseTranslate] Whether the parser should translate options back into camelCase after normalization
+ * @param {parseCallback} callback
+ */
+function parseConnectionString(uri, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = Object.assign({}, { caseTranslate: true }, options);
+
+ // Check for bad uris before we parse
+ try {
+ URL.parse(uri);
+ } catch (e) {
+ return callback(new MongoParseError('URI malformed, cannot be parsed'));
+ }
+
+ const cap = uri.match(HOSTS_RX);
+ if (!cap) {
+ return callback(new MongoParseError('Invalid connection string'));
+ }
+
+ const protocol = cap[1];
+ if (SUPPORTED_PROTOCOLS.indexOf(protocol) === -1) {
+ return callback(new MongoParseError('Invalid protocol provided'));
+ }
+
+ if (protocol === PROTOCOL_MONGODB_SRV) {
+ return parseSrvConnectionString(uri, options, callback);
+ }
+
+ const dbAndQuery = cap[4].split('?');
+ const db = dbAndQuery.length > 0 ? dbAndQuery[0] : null;
+ const query = dbAndQuery.length > 1 ? dbAndQuery[1] : null;
+
+ let parsedOptions;
+ try {
+ parsedOptions = parseQueryString(query, options);
+ } catch (parseError) {
+ return callback(parseError);
+ }
+
+ parsedOptions = Object.assign({}, parsedOptions, options);
+ const auth = { username: null, password: null, db: db && db !== '' ? qs.unescape(db) : null };
+ if (parsedOptions.auth) {
+ // maintain support for legacy options passed into `MongoClient`
+ if (parsedOptions.auth.username) auth.username = parsedOptions.auth.username;
+ if (parsedOptions.auth.user) auth.username = parsedOptions.auth.user;
+ if (parsedOptions.auth.password) auth.password = parsedOptions.auth.password;
+ } else {
+ if (parsedOptions.username) auth.username = parsedOptions.username;
+ if (parsedOptions.user) auth.username = parsedOptions.user;
+ if (parsedOptions.password) auth.password = parsedOptions.password;
+ }
+
+ if (cap[4].split('?')[0].indexOf('@') !== -1) {
+ return callback(new MongoParseError('Unescaped slash in userinfo section'));
+ }
+
+ const authorityParts = cap[3].split('@');
+ if (authorityParts.length > 2) {
+ return callback(new MongoParseError('Unescaped at-sign in authority section'));
+ }
+
+ if (authorityParts[0] == null || authorityParts[0] === '') {
+ return callback(new MongoParseError('No username provided in authority section'));
+ }
+
+ if (authorityParts.length > 1) {
+ const authParts = authorityParts.shift().split(':');
+ if (authParts.length > 2) {
+ return callback(new MongoParseError('Unescaped colon in authority section'));
+ }
+
+ if (authParts[0] === '') {
+ return callback(new MongoParseError('Invalid empty username provided'));
+ }
+
+ if (!auth.username) auth.username = qs.unescape(authParts[0]);
+ if (!auth.password) auth.password = authParts[1] ? qs.unescape(authParts[1]) : null;
+ }
+
+ let hostParsingError = null;
+ const hosts = authorityParts
+ .shift()
+ .split(',')
+ .map(host => {
+ let parsedHost = URL.parse(`mongodb://${host}`);
+ if (parsedHost.path === '/:') {
+ hostParsingError = new MongoParseError('Double colon in host identifier');
+ return null;
+ }
+
+ // heuristically determine if we're working with a domain socket
+ if (host.match(/\.sock/)) {
+ parsedHost.hostname = qs.unescape(host);
+ parsedHost.port = null;
+ }
+
+ if (Number.isNaN(parsedHost.port)) {
+ hostParsingError = new MongoParseError('Invalid port (non-numeric string)');
+ return;
+ }
+
+ const result = {
+ host: parsedHost.hostname,
+ port: parsedHost.port ? parseInt(parsedHost.port) : 27017
+ };
+
+ if (result.port === 0) {
+ hostParsingError = new MongoParseError('Invalid port (zero) with hostname');
+ return;
+ }
+
+ if (result.port > 65535) {
+ hostParsingError = new MongoParseError('Invalid port (larger than 65535) with hostname');
+ return;
+ }
+
+ if (result.port < 0) {
+ hostParsingError = new MongoParseError('Invalid port (negative number)');
+ return;
+ }
+
+ return result;
+ })
+ .filter(host => !!host);
+
+ if (hostParsingError) {
+ return callback(hostParsingError);
+ }
+
+ if (hosts.length === 0 || hosts[0].host === '' || hosts[0].host === null) {
+ return callback(new MongoParseError('No hostname or hostnames provided in connection string'));
+ }
+
+ const result = {
+ hosts: hosts,
+ auth: auth.db || auth.username ? auth : null,
+ options: Object.keys(parsedOptions).length ? parsedOptions : null
+ };
+
+ if (result.auth && result.auth.db) {
+ result.defaultDatabase = result.auth.db;
+ } else {
+ result.defaultDatabase = 'test';
+ }
+
+ // support modern `tls` variants to SSL options
+ result.options = translateTLSOptions(result.options);
+
+ try {
+ applyAuthExpectations(result);
+ } catch (authError) {
+ return callback(authError);
+ }
+
+ callback(null, result);
+}
+
+module.exports = parseConnectionString;
diff --git a/node_modules/mongodb/lib/core/utils.js b/node_modules/mongodb/lib/core/utils.js
new file mode 100644
index 0000000..ab778bf
--- /dev/null
+++ b/node_modules/mongodb/lib/core/utils.js
@@ -0,0 +1,277 @@
+'use strict';
+const os = require('os');
+const crypto = require('crypto');
+const requireOptional = require('require_optional');
+
+/**
+ * Generate a UUIDv4
+ */
+const uuidV4 = () => {
+ const result = crypto.randomBytes(16);
+ result[6] = (result[6] & 0x0f) | 0x40;
+ result[8] = (result[8] & 0x3f) | 0x80;
+ return result;
+};
+
+/**
+ * Returns the duration calculated from two high resolution timers in milliseconds
+ *
+ * @param {Object} started A high resolution timestamp created from `process.hrtime()`
+ * @returns {Number} The duration in milliseconds
+ */
+const calculateDurationInMs = started => {
+ const hrtime = process.hrtime(started);
+ return (hrtime[0] * 1e9 + hrtime[1]) / 1e6;
+};
+
+/**
+ * Relays events for a given listener and emitter
+ *
+ * @param {EventEmitter} listener the EventEmitter to listen to the events from
+ * @param {EventEmitter} emitter the EventEmitter to relay the events to
+ */
+function relayEvents(listener, emitter, events) {
+ events.forEach(eventName => listener.on(eventName, event => emitter.emit(eventName, event)));
+}
+
+function retrieveKerberos() {
+ let kerberos;
+
+ try {
+ kerberos = requireOptional('kerberos');
+ } catch (err) {
+ if (err.code === 'MODULE_NOT_FOUND') {
+ throw new Error('The `kerberos` module was not found. Please install it and try again.');
+ }
+
+ throw err;
+ }
+
+ return kerberos;
+}
+
+// Throw an error if an attempt to use EJSON is made when it is not installed
+const noEJSONError = function() {
+ throw new Error('The `mongodb-extjson` module was not found. Please install it and try again.');
+};
+
+// Facilitate loading EJSON optionally
+function retrieveEJSON() {
+ let EJSON = null;
+ try {
+ EJSON = requireOptional('mongodb-extjson');
+ } catch (error) {} // eslint-disable-line
+ if (!EJSON) {
+ EJSON = {
+ parse: noEJSONError,
+ deserialize: noEJSONError,
+ serialize: noEJSONError,
+ stringify: noEJSONError,
+ setBSONModule: noEJSONError,
+ BSON: noEJSONError
+ };
+ }
+
+ return EJSON;
+}
+
+/**
+ * A helper function for determining `maxWireVersion` between legacy and new topology
+ * instances
+ *
+ * @private
+ * @param {(Topology|Server)} topologyOrServer
+ */
+function maxWireVersion(topologyOrServer) {
+ if (topologyOrServer.ismaster) {
+ return topologyOrServer.ismaster.maxWireVersion;
+ }
+
+ if (typeof topologyOrServer.lastIsMaster === 'function') {
+ const lastIsMaster = topologyOrServer.lastIsMaster();
+ if (lastIsMaster) {
+ return lastIsMaster.maxWireVersion;
+ }
+ }
+
+ if (topologyOrServer.description) {
+ return topologyOrServer.description.maxWireVersion;
+ }
+
+ return null;
+}
+
+/*
+ * Checks that collation is supported by server.
+ *
+ * @param {Server} [server] to check against
+ * @param {object} [cmd] object where collation may be specified
+ * @param {function} [callback] callback function
+ * @return true if server does not support collation
+ */
+function collationNotSupported(server, cmd) {
+ return cmd && cmd.collation && maxWireVersion(server) < 5;
+}
+
+/**
+ * Checks if a given value is a Promise
+ *
+ * @param {*} maybePromise
+ * @return true if the provided value is a Promise
+ */
+function isPromiseLike(maybePromise) {
+ return maybePromise && typeof maybePromise.then === 'function';
+}
+
+/**
+ * Applies the function `eachFn` to each item in `arr`, in parallel.
+ *
+ * @param {array} arr an array of items to asynchronusly iterate over
+ * @param {function} eachFn A function to call on each item of the array. The callback signature is `(item, callback)`, where the callback indicates iteration is complete.
+ * @param {function} callback The callback called after every item has been iterated
+ */
+function eachAsync(arr, eachFn, callback) {
+ arr = arr || [];
+
+ let idx = 0;
+ let awaiting = 0;
+ for (idx = 0; idx < arr.length; ++idx) {
+ awaiting++;
+ eachFn(arr[idx], eachCallback);
+ }
+
+ if (awaiting === 0) {
+ callback();
+ return;
+ }
+
+ function eachCallback(err) {
+ awaiting--;
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ if (idx === arr.length && awaiting <= 0) {
+ callback();
+ }
+ }
+}
+
+function isUnifiedTopology(topology) {
+ return topology.description != null;
+}
+
+function arrayStrictEqual(arr, arr2) {
+ if (!Array.isArray(arr) || !Array.isArray(arr2)) {
+ return false;
+ }
+
+ return arr.length === arr2.length && arr.every((elt, idx) => elt === arr2[idx]);
+}
+
+function tagsStrictEqual(tags, tags2) {
+ const tagsKeys = Object.keys(tags);
+ const tags2Keys = Object.keys(tags2);
+ return tagsKeys.length === tags2Keys.length && tagsKeys.every(key => tags2[key] === tags[key]);
+}
+
+function errorStrictEqual(lhs, rhs) {
+ if (lhs === rhs) {
+ return true;
+ }
+
+ if ((lhs == null && rhs != null) || (lhs != null && rhs == null)) {
+ return false;
+ }
+
+ if (lhs.constructor.name !== rhs.constructor.name) {
+ return false;
+ }
+
+ if (lhs.message !== rhs.message) {
+ return false;
+ }
+
+ return true;
+}
+
+function makeStateMachine(stateTable) {
+ return function stateTransition(target, newState) {
+ const legalStates = stateTable[target.s.state];
+ if (legalStates && legalStates.indexOf(newState) < 0) {
+ throw new TypeError(
+ `illegal state transition from [${target.s.state}] => [${newState}], allowed: [${legalStates}]`
+ );
+ }
+
+ target.emit('stateChanged', target.s.state, newState);
+ target.s.state = newState;
+ };
+}
+
+function makeClientMetadata(options) {
+ options = options || {};
+
+ const metadata = {
+ driver: {
+ name: 'nodejs',
+ version: require('../../package.json').version
+ },
+ os: {
+ type: os.type(),
+ name: process.platform,
+ architecture: process.arch,
+ version: os.release()
+ },
+ platform: `'Node.js ${process.version}, ${os.endianness} (${
+ options.useUnifiedTopology ? 'unified' : 'legacy'
+ })`
+ };
+
+ // support optionally provided wrapping driver info
+ if (options.driverInfo) {
+ if (options.driverInfo.name) {
+ metadata.driver.name = `${metadata.driver.name}|${options.driverInfo.name}`;
+ }
+
+ if (options.driverInfo.version) {
+ metadata.version = `${metadata.driver.version}|${options.driverInfo.version}`;
+ }
+
+ if (options.driverInfo.platform) {
+ metadata.platform = `${metadata.platform}|${options.driverInfo.platform}`;
+ }
+ }
+
+ if (options.appname) {
+ // MongoDB requires the appname not exceed a byte length of 128
+ const buffer = Buffer.from(options.appname);
+ metadata.application = {
+ name: buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname
+ };
+ }
+
+ return metadata;
+}
+
+const noop = () => {};
+
+module.exports = {
+ uuidV4,
+ calculateDurationInMs,
+ relayEvents,
+ collationNotSupported,
+ retrieveEJSON,
+ retrieveKerberos,
+ maxWireVersion,
+ isPromiseLike,
+ eachAsync,
+ isUnifiedTopology,
+ arrayStrictEqual,
+ tagsStrictEqual,
+ errorStrictEqual,
+ makeStateMachine,
+ makeClientMetadata,
+ noop
+};
diff --git a/node_modules/mongodb/lib/core/wireprotocol/command.js b/node_modules/mongodb/lib/core/wireprotocol/command.js
new file mode 100644
index 0000000..214385b
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/command.js
@@ -0,0 +1,185 @@
+'use strict';
+
+const Query = require('../connection/commands').Query;
+const Msg = require('../connection/msg').Msg;
+const MongoError = require('../error').MongoError;
+const getReadPreference = require('./shared').getReadPreference;
+const isSharded = require('./shared').isSharded;
+const databaseNamespace = require('./shared').databaseNamespace;
+const isTransactionCommand = require('../transactions').isTransactionCommand;
+const applySession = require('../sessions').applySession;
+const MongoNetworkError = require('../error').MongoNetworkError;
+const maxWireVersion = require('../utils').maxWireVersion;
+
+function isClientEncryptionEnabled(server) {
+ const wireVersion = maxWireVersion(server);
+ return wireVersion && server.autoEncrypter;
+}
+
+function command(server, ns, cmd, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ if (cmd == null) {
+ return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
+ }
+
+ if (!isClientEncryptionEnabled(server)) {
+ _command(server, ns, cmd, options, callback);
+ return;
+ }
+
+ const wireVersion = maxWireVersion(server);
+ if (typeof wireVersion !== 'number' || wireVersion < 8) {
+ callback(new MongoError('Auto-encryption requires a minimum MongoDB version of 4.2'));
+ return;
+ }
+
+ _cryptCommand(server, ns, cmd, options, callback);
+}
+
+function _command(server, ns, cmd, options, callback) {
+ const bson = server.s.bson;
+ const pool = server.s.pool;
+ const readPreference = getReadPreference(cmd, options);
+ const shouldUseOpMsg = supportsOpMsg(server);
+ const session = options.session;
+
+ let clusterTime = server.clusterTime;
+ let finalCmd = Object.assign({}, cmd);
+ if (hasSessionSupport(server) && session) {
+ if (
+ session.clusterTime &&
+ session.clusterTime.clusterTime.greaterThan(clusterTime.clusterTime)
+ ) {
+ clusterTime = session.clusterTime;
+ }
+
+ const err = applySession(session, finalCmd, options);
+ if (err) {
+ return callback(err);
+ }
+ }
+
+ // if we have a known cluster time, gossip it
+ if (clusterTime) {
+ finalCmd.$clusterTime = clusterTime;
+ }
+
+ if (
+ isSharded(server) &&
+ !shouldUseOpMsg &&
+ readPreference &&
+ readPreference.preference !== 'primary'
+ ) {
+ finalCmd = {
+ $query: finalCmd,
+ $readPreference: readPreference.toJSON()
+ };
+ }
+
+ const commandOptions = Object.assign(
+ {
+ command: true,
+ numberToSkip: 0,
+ numberToReturn: -1,
+ checkKeys: false
+ },
+ options
+ );
+
+ // This value is not overridable
+ commandOptions.slaveOk = readPreference.slaveOk();
+
+ const cmdNs = `${databaseNamespace(ns)}.$cmd`;
+ const message = shouldUseOpMsg
+ ? new Msg(bson, cmdNs, finalCmd, commandOptions)
+ : new Query(bson, cmdNs, finalCmd, commandOptions);
+
+ const inTransaction = session && (session.inTransaction() || isTransactionCommand(finalCmd));
+ const commandResponseHandler = inTransaction
+ ? function(err) {
+ // We need to add a TransientTransactionError errorLabel, as stated in the transaction spec.
+ if (
+ err &&
+ err instanceof MongoNetworkError &&
+ !err.hasErrorLabel('TransientTransactionError')
+ ) {
+ if (err.errorLabels == null) {
+ err.errorLabels = [];
+ }
+ err.errorLabels.push('TransientTransactionError');
+ }
+
+ if (
+ !cmd.commitTransaction &&
+ err &&
+ err instanceof MongoError &&
+ err.hasErrorLabel('TransientTransactionError')
+ ) {
+ session.transaction.unpinServer();
+ }
+
+ return callback.apply(null, arguments);
+ }
+ : callback;
+
+ try {
+ pool.write(message, commandOptions, commandResponseHandler);
+ } catch (err) {
+ commandResponseHandler(err);
+ }
+}
+
+function hasSessionSupport(topology) {
+ if (topology == null) return false;
+ if (topology.description) {
+ return topology.description.maxWireVersion >= 6;
+ }
+
+ return topology.ismaster == null ? false : topology.ismaster.maxWireVersion >= 6;
+}
+
+function supportsOpMsg(topologyOrServer) {
+ const description = topologyOrServer.ismaster
+ ? topologyOrServer.ismaster
+ : topologyOrServer.description;
+
+ if (description == null) {
+ return false;
+ }
+
+ return description.maxWireVersion >= 6 && description.__nodejs_mock_server__ == null;
+}
+
+function _cryptCommand(server, ns, cmd, options, callback) {
+ const autoEncrypter = server.autoEncrypter;
+ function commandResponseHandler(err, response) {
+ if (err || response == null) {
+ callback(err, response);
+ return;
+ }
+
+ autoEncrypter.decrypt(response.result, options, (err, decrypted) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ response.result = decrypted;
+ response.message.documents = [decrypted];
+ callback(null, response);
+ });
+ }
+
+ autoEncrypter.encrypt(ns, cmd, options, (err, encrypted) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ _command(server, ns, encrypted, options, commandResponseHandler);
+ });
+}
+
+module.exports = command;
diff --git a/node_modules/mongodb/lib/core/wireprotocol/compression.js b/node_modules/mongodb/lib/core/wireprotocol/compression.js
new file mode 100644
index 0000000..b1e1583
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/compression.js
@@ -0,0 +1,73 @@
+'use strict';
+
+const Snappy = require('../connection/utils').retrieveSnappy();
+const zlib = require('zlib');
+
+const compressorIDs = {
+ snappy: 1,
+ zlib: 2
+};
+
+const uncompressibleCommands = new Set([
+ 'ismaster',
+ 'saslStart',
+ 'saslContinue',
+ 'getnonce',
+ 'authenticate',
+ 'createUser',
+ 'updateUser',
+ 'copydbSaslStart',
+ 'copydbgetnonce',
+ 'copydb'
+]);
+
+// Facilitate compressing a message using an agreed compressor
+function compress(self, dataToBeCompressed, callback) {
+ switch (self.options.agreedCompressor) {
+ case 'snappy':
+ Snappy.compress(dataToBeCompressed, callback);
+ break;
+ case 'zlib':
+ // Determine zlibCompressionLevel
+ var zlibOptions = {};
+ if (self.options.zlibCompressionLevel) {
+ zlibOptions.level = self.options.zlibCompressionLevel;
+ }
+ zlib.deflate(dataToBeCompressed, zlibOptions, callback);
+ break;
+ default:
+ throw new Error(
+ 'Attempt to compress message using unknown compressor "' +
+ self.options.agreedCompressor +
+ '".'
+ );
+ }
+}
+
+// Decompress a message using the given compressor
+function decompress(compressorID, compressedData, callback) {
+ if (compressorID < 0 || compressorID > compressorIDs.length) {
+ throw new Error(
+ 'Server sent message compressed using an unsupported compressor. (Received compressor ID ' +
+ compressorID +
+ ')'
+ );
+ }
+ switch (compressorID) {
+ case compressorIDs.snappy:
+ Snappy.uncompress(compressedData, callback);
+ break;
+ case compressorIDs.zlib:
+ zlib.inflate(compressedData, callback);
+ break;
+ default:
+ callback(null, compressedData);
+ }
+}
+
+module.exports = {
+ compressorIDs,
+ uncompressibleCommands,
+ compress,
+ decompress
+};
diff --git a/node_modules/mongodb/lib/core/wireprotocol/constants.js b/node_modules/mongodb/lib/core/wireprotocol/constants.js
new file mode 100644
index 0000000..df2293b
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/constants.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const MIN_SUPPORTED_SERVER_VERSION = '2.6';
+const MAX_SUPPORTED_SERVER_VERSION = '4.2';
+const MIN_SUPPORTED_WIRE_VERSION = 2;
+const MAX_SUPPORTED_WIRE_VERSION = 8;
+
+module.exports = {
+ MIN_SUPPORTED_SERVER_VERSION,
+ MAX_SUPPORTED_SERVER_VERSION,
+ MIN_SUPPORTED_WIRE_VERSION,
+ MAX_SUPPORTED_WIRE_VERSION
+};
diff --git a/node_modules/mongodb/lib/core/wireprotocol/get_more.js b/node_modules/mongodb/lib/core/wireprotocol/get_more.js
new file mode 100644
index 0000000..b2db320
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/get_more.js
@@ -0,0 +1,90 @@
+'use strict';
+
+const GetMore = require('../connection/commands').GetMore;
+const retrieveBSON = require('../connection/utils').retrieveBSON;
+const MongoError = require('../error').MongoError;
+const MongoNetworkError = require('../error').MongoNetworkError;
+const BSON = retrieveBSON();
+const Long = BSON.Long;
+const collectionNamespace = require('./shared').collectionNamespace;
+const maxWireVersion = require('../utils').maxWireVersion;
+const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
+const command = require('./command');
+
+function getMore(server, ns, cursorState, batchSize, options, callback) {
+ options = options || {};
+
+ const wireVersion = maxWireVersion(server);
+ function queryCallback(err, result) {
+ if (err) return callback(err);
+ const response = result.message;
+
+ // If we have a timed out query or a cursor that was killed
+ if (response.cursorNotFound) {
+ return callback(new MongoNetworkError('cursor killed or timed out'), null);
+ }
+
+ if (wireVersion < 4) {
+ const cursorId =
+ typeof response.cursorId === 'number'
+ ? Long.fromNumber(response.cursorId)
+ : response.cursorId;
+
+ cursorState.documents = response.documents;
+ cursorState.cursorId = cursorId;
+
+ callback(null, null, response.connection);
+ return;
+ }
+
+ // We have an error detected
+ if (response.documents[0].ok === 0) {
+ return callback(new MongoError(response.documents[0]));
+ }
+
+ // Ensure we have a Long valid cursor id
+ const cursorId =
+ typeof response.documents[0].cursor.id === 'number'
+ ? Long.fromNumber(response.documents[0].cursor.id)
+ : response.documents[0].cursor.id;
+
+ cursorState.documents = response.documents[0].cursor.nextBatch;
+ cursorState.cursorId = cursorId;
+
+ callback(null, response.documents[0], response.connection);
+ }
+
+ if (wireVersion < 4) {
+ const bson = server.s.bson;
+ const getMoreOp = new GetMore(bson, ns, cursorState.cursorId, { numberToReturn: batchSize });
+ const queryOptions = applyCommonQueryOptions({}, cursorState);
+ server.s.pool.write(getMoreOp, queryOptions, queryCallback);
+ return;
+ }
+
+ const getMoreCmd = {
+ getMore: cursorState.cursorId,
+ collection: collectionNamespace(ns),
+ batchSize: Math.abs(batchSize)
+ };
+
+ if (cursorState.cmd.tailable && typeof cursorState.cmd.maxAwaitTimeMS === 'number') {
+ getMoreCmd.maxTimeMS = cursorState.cmd.maxAwaitTimeMS;
+ }
+
+ const commandOptions = Object.assign(
+ {
+ returnFieldSelector: null,
+ documentsReturnedIn: 'nextBatch'
+ },
+ options
+ );
+
+ if (cursorState.session) {
+ commandOptions.session = cursorState.session;
+ }
+
+ command(server, ns, getMoreCmd, commandOptions, queryCallback);
+}
+
+module.exports = getMore;
diff --git a/node_modules/mongodb/lib/core/wireprotocol/index.js b/node_modules/mongodb/lib/core/wireprotocol/index.js
new file mode 100644
index 0000000..b6ffda7
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/index.js
@@ -0,0 +1,18 @@
+'use strict';
+const writeCommand = require('./write_command');
+
+module.exports = {
+ insert: function insert(server, ns, ops, options, callback) {
+ writeCommand(server, 'insert', 'documents', ns, ops, options, callback);
+ },
+ update: function update(server, ns, ops, options, callback) {
+ writeCommand(server, 'update', 'updates', ns, ops, options, callback);
+ },
+ remove: function remove(server, ns, ops, options, callback) {
+ writeCommand(server, 'delete', 'deletes', ns, ops, options, callback);
+ },
+ killCursors: require('./kill_cursors'),
+ getMore: require('./get_more'),
+ query: require('./query'),
+ command: require('./command')
+};
diff --git a/node_modules/mongodb/lib/core/wireprotocol/kill_cursors.js b/node_modules/mongodb/lib/core/wireprotocol/kill_cursors.js
new file mode 100644
index 0000000..bb13477
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/kill_cursors.js
@@ -0,0 +1,70 @@
+'use strict';
+
+const KillCursor = require('../connection/commands').KillCursor;
+const MongoError = require('../error').MongoError;
+const MongoNetworkError = require('../error').MongoNetworkError;
+const collectionNamespace = require('./shared').collectionNamespace;
+const maxWireVersion = require('../utils').maxWireVersion;
+const command = require('./command');
+
+function killCursors(server, ns, cursorState, callback) {
+ callback = typeof callback === 'function' ? callback : () => {};
+ const cursorId = cursorState.cursorId;
+
+ if (maxWireVersion(server) < 4) {
+ const bson = server.s.bson;
+ const pool = server.s.pool;
+ const killCursor = new KillCursor(bson, ns, [cursorId]);
+ const options = {
+ immediateRelease: true,
+ noResponse: true
+ };
+
+ if (typeof cursorState.session === 'object') {
+ options.session = cursorState.session;
+ }
+
+ if (pool && pool.isConnected()) {
+ try {
+ pool.write(killCursor, options, callback);
+ } catch (err) {
+ if (typeof callback === 'function') {
+ callback(err, null);
+ } else {
+ console.warn(err);
+ }
+ }
+ }
+
+ return;
+ }
+
+ const killCursorCmd = {
+ killCursors: collectionNamespace(ns),
+ cursors: [cursorId]
+ };
+
+ const options = {};
+ if (typeof cursorState.session === 'object') options.session = cursorState.session;
+
+ command(server, ns, killCursorCmd, options, (err, result) => {
+ if (err) {
+ return callback(err);
+ }
+
+ const response = result.message;
+ if (response.cursorNotFound) {
+ return callback(new MongoNetworkError('cursor killed or timed out'), null);
+ }
+
+ if (!Array.isArray(response.documents) || response.documents.length === 0) {
+ return callback(
+ new MongoError(`invalid killCursors result returned for cursor id ${cursorId}`)
+ );
+ }
+
+ callback(null, response.documents[0]);
+ });
+}
+
+module.exports = killCursors;
diff --git a/node_modules/mongodb/lib/core/wireprotocol/query.js b/node_modules/mongodb/lib/core/wireprotocol/query.js
new file mode 100644
index 0000000..c501b50
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/query.js
@@ -0,0 +1,231 @@
+'use strict';
+
+const Query = require('../connection/commands').Query;
+const MongoError = require('../error').MongoError;
+const getReadPreference = require('./shared').getReadPreference;
+const collectionNamespace = require('./shared').collectionNamespace;
+const isSharded = require('./shared').isSharded;
+const maxWireVersion = require('../utils').maxWireVersion;
+const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
+const command = require('./command');
+
+function query(server, ns, cmd, cursorState, options, callback) {
+ options = options || {};
+ if (cursorState.cursorId != null) {
+ return callback();
+ }
+
+ if (cmd == null) {
+ return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
+ }
+
+ if (maxWireVersion(server) < 4) {
+ const query = prepareLegacyFindQuery(server, ns, cmd, cursorState, options);
+ const queryOptions = applyCommonQueryOptions({}, cursorState);
+ if (typeof query.documentsReturnedIn === 'string') {
+ queryOptions.documentsReturnedIn = query.documentsReturnedIn;
+ }
+
+ server.s.pool.write(query, queryOptions, callback);
+ return;
+ }
+
+ const readPreference = getReadPreference(cmd, options);
+ const findCmd = prepareFindCommand(server, ns, cmd, cursorState, options);
+
+ // NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
+ // side-effect. Change this ASAP
+ cmd.virtual = false;
+
+ const commandOptions = Object.assign(
+ {
+ documentsReturnedIn: 'firstBatch',
+ numberToReturn: 1,
+ slaveOk: readPreference.slaveOk()
+ },
+ options
+ );
+
+ if (cmd.readPreference) {
+ commandOptions.readPreference = readPreference;
+ }
+
+ if (cursorState.session) {
+ commandOptions.session = cursorState.session;
+ }
+
+ command(server, ns, findCmd, commandOptions, callback);
+}
+
+function prepareFindCommand(server, ns, cmd, cursorState) {
+ cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
+ let findCmd = {
+ find: collectionNamespace(ns)
+ };
+
+ if (cmd.query) {
+ if (cmd.query['$query']) {
+ findCmd.filter = cmd.query['$query'];
+ } else {
+ findCmd.filter = cmd.query;
+ }
+ }
+
+ let sortValue = cmd.sort;
+ if (Array.isArray(sortValue)) {
+ const sortObject = {};
+
+ if (sortValue.length > 0 && !Array.isArray(sortValue[0])) {
+ let sortDirection = sortValue[1];
+ if (sortDirection === 'asc') {
+ sortDirection = 1;
+ } else if (sortDirection === 'desc') {
+ sortDirection = -1;
+ }
+
+ sortObject[sortValue[0]] = sortDirection;
+ } else {
+ for (let i = 0; i < sortValue.length; i++) {
+ let sortDirection = sortValue[i][1];
+ if (sortDirection === 'asc') {
+ sortDirection = 1;
+ } else if (sortDirection === 'desc') {
+ sortDirection = -1;
+ }
+
+ sortObject[sortValue[i][0]] = sortDirection;
+ }
+ }
+
+ sortValue = sortObject;
+ }
+
+ if (cmd.sort) findCmd.sort = sortValue;
+ if (cmd.fields) findCmd.projection = cmd.fields;
+ if (cmd.hint) findCmd.hint = cmd.hint;
+ if (cmd.skip) findCmd.skip = cmd.skip;
+ if (cmd.limit) findCmd.limit = cmd.limit;
+ if (cmd.limit < 0) {
+ findCmd.limit = Math.abs(cmd.limit);
+ findCmd.singleBatch = true;
+ }
+
+ if (typeof cmd.batchSize === 'number') {
+ if (cmd.batchSize < 0) {
+ if (cmd.limit !== 0 && Math.abs(cmd.batchSize) < Math.abs(cmd.limit)) {
+ findCmd.limit = Math.abs(cmd.batchSize);
+ }
+
+ findCmd.singleBatch = true;
+ }
+
+ findCmd.batchSize = Math.abs(cmd.batchSize);
+ }
+
+ if (cmd.comment) findCmd.comment = cmd.comment;
+ if (cmd.maxScan) findCmd.maxScan = cmd.maxScan;
+ if (cmd.maxTimeMS) findCmd.maxTimeMS = cmd.maxTimeMS;
+ if (cmd.min) findCmd.min = cmd.min;
+ if (cmd.max) findCmd.max = cmd.max;
+ findCmd.returnKey = cmd.returnKey ? cmd.returnKey : false;
+ findCmd.showRecordId = cmd.showDiskLoc ? cmd.showDiskLoc : false;
+ if (cmd.snapshot) findCmd.snapshot = cmd.snapshot;
+ if (cmd.tailable) findCmd.tailable = cmd.tailable;
+ if (cmd.oplogReplay) findCmd.oplogReplay = cmd.oplogReplay;
+ if (cmd.noCursorTimeout) findCmd.noCursorTimeout = cmd.noCursorTimeout;
+ if (cmd.awaitData) findCmd.awaitData = cmd.awaitData;
+ if (cmd.awaitdata) findCmd.awaitData = cmd.awaitdata;
+ if (cmd.partial) findCmd.partial = cmd.partial;
+ if (cmd.collation) findCmd.collation = cmd.collation;
+ if (cmd.readConcern) findCmd.readConcern = cmd.readConcern;
+
+ // If we have explain, we need to rewrite the find command
+ // to wrap it in the explain command
+ if (cmd.explain) {
+ findCmd = {
+ explain: findCmd
+ };
+ }
+
+ return findCmd;
+}
+
+function prepareLegacyFindQuery(server, ns, cmd, cursorState, options) {
+ options = options || {};
+ const bson = server.s.bson;
+ const readPreference = getReadPreference(cmd, options);
+ cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
+
+ let numberToReturn = 0;
+ if (
+ cursorState.limit < 0 ||
+ (cursorState.limit !== 0 && cursorState.limit < cursorState.batchSize) ||
+ (cursorState.limit > 0 && cursorState.batchSize === 0)
+ ) {
+ numberToReturn = cursorState.limit;
+ } else {
+ numberToReturn = cursorState.batchSize;
+ }
+
+ const numberToSkip = cursorState.skip || 0;
+
+ const findCmd = {};
+ if (isSharded(server) && readPreference) {
+ findCmd['$readPreference'] = readPreference.toJSON();
+ }
+
+ if (cmd.sort) findCmd['$orderby'] = cmd.sort;
+ if (cmd.hint) findCmd['$hint'] = cmd.hint;
+ if (cmd.snapshot) findCmd['$snapshot'] = cmd.snapshot;
+ if (typeof cmd.returnKey !== 'undefined') findCmd['$returnKey'] = cmd.returnKey;
+ if (cmd.maxScan) findCmd['$maxScan'] = cmd.maxScan;
+ if (cmd.min) findCmd['$min'] = cmd.min;
+ if (cmd.max) findCmd['$max'] = cmd.max;
+ if (typeof cmd.showDiskLoc !== 'undefined') findCmd['$showDiskLoc'] = cmd.showDiskLoc;
+ if (cmd.comment) findCmd['$comment'] = cmd.comment;
+ if (cmd.maxTimeMS) findCmd['$maxTimeMS'] = cmd.maxTimeMS;
+ if (cmd.explain) {
+ // nToReturn must be 0 (match all) or negative (match N and close cursor)
+ // nToReturn > 0 will give explain results equivalent to limit(0)
+ numberToReturn = -Math.abs(cmd.limit || 0);
+ findCmd['$explain'] = true;
+ }
+
+ findCmd['$query'] = cmd.query;
+ if (cmd.readConcern && cmd.readConcern.level !== 'local') {
+ throw new MongoError(
+ `server find command does not support a readConcern level of ${cmd.readConcern.level}`
+ );
+ }
+
+ if (cmd.readConcern) {
+ cmd = Object.assign({}, cmd);
+ delete cmd['readConcern'];
+ }
+
+ const serializeFunctions =
+ typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
+ const ignoreUndefined =
+ typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
+
+ const query = new Query(bson, ns, findCmd, {
+ numberToSkip: numberToSkip,
+ numberToReturn: numberToReturn,
+ pre32Limit: typeof cmd.limit !== 'undefined' ? cmd.limit : undefined,
+ checkKeys: false,
+ returnFieldSelector: cmd.fields,
+ serializeFunctions: serializeFunctions,
+ ignoreUndefined: ignoreUndefined
+ });
+
+ if (typeof cmd.tailable === 'boolean') query.tailable = cmd.tailable;
+ if (typeof cmd.oplogReplay === 'boolean') query.oplogReplay = cmd.oplogReplay;
+ if (typeof cmd.noCursorTimeout === 'boolean') query.noCursorTimeout = cmd.noCursorTimeout;
+ if (typeof cmd.awaitData === 'boolean') query.awaitData = cmd.awaitData;
+ if (typeof cmd.partial === 'boolean') query.partial = cmd.partial;
+
+ query.slaveOk = readPreference.slaveOk();
+ return query;
+}
+
+module.exports = query;
diff --git a/node_modules/mongodb/lib/core/wireprotocol/shared.js b/node_modules/mongodb/lib/core/wireprotocol/shared.js
new file mode 100644
index 0000000..c586f05
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/shared.js
@@ -0,0 +1,115 @@
+'use strict';
+
+const ReadPreference = require('../topologies/read_preference');
+const MongoError = require('../error').MongoError;
+const ServerType = require('../sdam/common').ServerType;
+const TopologyDescription = require('../sdam/topology_description').TopologyDescription;
+
+const MESSAGE_HEADER_SIZE = 16;
+const COMPRESSION_DETAILS_SIZE = 9; // originalOpcode + uncompressedSize, compressorID
+
+// OPCODE Numbers
+// Defined at https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#request-opcodes
+var opcodes = {
+ OP_REPLY: 1,
+ OP_UPDATE: 2001,
+ OP_INSERT: 2002,
+ OP_QUERY: 2004,
+ OP_GETMORE: 2005,
+ OP_DELETE: 2006,
+ OP_KILL_CURSORS: 2007,
+ OP_COMPRESSED: 2012,
+ OP_MSG: 2013
+};
+
+var getReadPreference = function(cmd, options) {
+ // Default to command version of the readPreference
+ var readPreference = cmd.readPreference || new ReadPreference('primary');
+ // If we have an option readPreference override the command one
+ if (options.readPreference) {
+ readPreference = options.readPreference;
+ }
+
+ if (typeof readPreference === 'string') {
+ readPreference = new ReadPreference(readPreference);
+ }
+
+ if (!(readPreference instanceof ReadPreference)) {
+ throw new MongoError('read preference must be a ReadPreference instance');
+ }
+
+ return readPreference;
+};
+
+// Parses the header of a wire protocol message
+var parseHeader = function(message) {
+ return {
+ length: message.readInt32LE(0),
+ requestId: message.readInt32LE(4),
+ responseTo: message.readInt32LE(8),
+ opCode: message.readInt32LE(12)
+ };
+};
+
+function applyCommonQueryOptions(queryOptions, options) {
+ Object.assign(queryOptions, {
+ raw: typeof options.raw === 'boolean' ? options.raw : false,
+ promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
+ promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
+ promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
+ monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : false,
+ fullResult: typeof options.fullResult === 'boolean' ? options.fullResult : false
+ });
+
+ if (typeof options.socketTimeout === 'number') {
+ queryOptions.socketTimeout = options.socketTimeout;
+ }
+
+ if (options.session) {
+ queryOptions.session = options.session;
+ }
+
+ if (typeof options.documentsReturnedIn === 'string') {
+ queryOptions.documentsReturnedIn = options.documentsReturnedIn;
+ }
+
+ return queryOptions;
+}
+
+function isSharded(topologyOrServer) {
+ if (topologyOrServer.type === 'mongos') return true;
+ if (topologyOrServer.description && topologyOrServer.description.type === ServerType.Mongos) {
+ return true;
+ }
+
+ // NOTE: This is incredibly inefficient, and should be removed once command construction
+ // happens based on `Server` not `Topology`.
+ if (topologyOrServer.description && topologyOrServer.description instanceof TopologyDescription) {
+ const servers = Array.from(topologyOrServer.description.servers.values());
+ return servers.some(server => server.type === ServerType.Mongos);
+ }
+
+ return false;
+}
+
+function databaseNamespace(ns) {
+ return ns.split('.')[0];
+}
+function collectionNamespace(ns) {
+ return ns
+ .split('.')
+ .slice(1)
+ .join('.');
+}
+
+module.exports = {
+ getReadPreference,
+ MESSAGE_HEADER_SIZE,
+ COMPRESSION_DETAILS_SIZE,
+ opcodes,
+ parseHeader,
+ applyCommonQueryOptions,
+ isSharded,
+ databaseNamespace,
+ collectionNamespace
+};
diff --git a/node_modules/mongodb/lib/core/wireprotocol/write_command.js b/node_modules/mongodb/lib/core/wireprotocol/write_command.js
new file mode 100644
index 0000000..e334d51
--- /dev/null
+++ b/node_modules/mongodb/lib/core/wireprotocol/write_command.js
@@ -0,0 +1,50 @@
+'use strict';
+
+const MongoError = require('../error').MongoError;
+const collectionNamespace = require('./shared').collectionNamespace;
+const command = require('./command');
+
+function writeCommand(server, type, opsField, ns, ops, options, callback) {
+ if (ops.length === 0) throw new MongoError(`${type} must contain at least one document`);
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || {};
+ const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
+ const writeConcern = options.writeConcern;
+
+ const writeCommand = {};
+ writeCommand[type] = collectionNamespace(ns);
+ writeCommand[opsField] = ops;
+ writeCommand.ordered = ordered;
+
+ if (writeConcern && Object.keys(writeConcern).length > 0) {
+ writeCommand.writeConcern = writeConcern;
+ }
+
+ if (options.collation) {
+ for (let i = 0; i < writeCommand[opsField].length; i++) {
+ if (!writeCommand[opsField][i].collation) {
+ writeCommand[opsField][i].collation = options.collation;
+ }
+ }
+ }
+
+ if (options.bypassDocumentValidation === true) {
+ writeCommand.bypassDocumentValidation = options.bypassDocumentValidation;
+ }
+
+ const commandOptions = Object.assign(
+ {
+ checkKeys: type === 'insert',
+ numberToReturn: 1
+ },
+ options
+ );
+
+ command(server, ns, writeCommand, commandOptions, callback);
+}
+
+module.exports = writeCommand;
diff --git a/node_modules/mongodb/lib/cursor.js b/node_modules/mongodb/lib/cursor.js
new file mode 100644
index 0000000..1a39a2e
--- /dev/null
+++ b/node_modules/mongodb/lib/cursor.js
@@ -0,0 +1,1163 @@
+'use strict';
+
+const Transform = require('stream').Transform;
+const PassThrough = require('stream').PassThrough;
+const deprecate = require('util').deprecate;
+const handleCallback = require('./utils').handleCallback;
+const ReadPreference = require('./core').ReadPreference;
+const MongoError = require('./core').MongoError;
+const CoreCursor = require('./core/cursor').CoreCursor;
+const CursorState = require('./core/cursor').CursorState;
+const Map = require('./core').BSON.Map;
+const maybePromise = require('./utils').maybePromise;
+const executeOperation = require('./operations/execute_operation');
+const formattedOrderClause = require('./utils').formattedOrderClause;
+
+const each = require('./operations/cursor_ops').each;
+const CountOperation = require('./operations/count');
+
+/**
+ * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
+ * allowing for iteration over the results returned from the underlying query. It supports
+ * one by one document iteration, conversion to an array or can be iterated as a Node 4.X
+ * or higher stream
+ *
+ * **CURSORS Cannot directly be instantiated**
+ * @example
+ * const MongoClient = require('mongodb').MongoClient;
+ * const test = require('assert');
+ * // Connection url
+ * const url = 'mongodb://localhost:27017';
+ * // Database Name
+ * const dbName = 'test';
+ * // Connect using MongoClient
+ * MongoClient.connect(url, function(err, client) {
+ * // Create a collection we want to drop later
+ * const col = client.db(dbName).collection('createIndexExample1');
+ * // Insert a bunch of documents
+ * col.insert([{a:1, b:1}
+ * , {a:2, b:2}, {a:3, b:3}
+ * , {a:4, b:4}], {w:1}, function(err, result) {
+ * test.equal(null, err);
+ * // Show that duplicate records got dropped
+ * col.find({}).toArray(function(err, items) {
+ * test.equal(null, err);
+ * test.equal(4, items.length);
+ * client.close();
+ * });
+ * });
+ * });
+ */
+
+/**
+ * Namespace provided by the code module
+ * @external CoreCursor
+ * @external Readable
+ */
+
+// Flags allowed for cursor
+const flags = ['tailable', 'oplogReplay', 'noCursorTimeout', 'awaitData', 'exhaust', 'partial'];
+const fields = ['numberOfRetries', 'tailableRetryInterval'];
+
+/**
+ * Creates a new Cursor instance (INTERNAL TYPE, do not instantiate directly)
+ * @class Cursor
+ * @extends external:CoreCursor
+ * @extends external:Readable
+ * @property {string} sortValue Cursor query sort setting.
+ * @property {boolean} timeout Is Cursor able to time out.
+ * @property {ReadPreference} readPreference Get cursor ReadPreference.
+ * @fires Cursor#data
+ * @fires Cursor#end
+ * @fires Cursor#close
+ * @fires Cursor#readable
+ * @return {Cursor} a Cursor instance.
+ * @example
+ * Cursor cursor options.
+ *
+ * collection.find({}).project({a:1}) // Create a projection of field a
+ * collection.find({}).skip(1).limit(10) // Skip 1 and limit 10
+ * collection.find({}).batchSize(5) // Set batchSize on cursor to 5
+ * collection.find({}).filter({a:1}) // Set query on the cursor
+ * collection.find({}).comment('add a comment') // Add a comment to the query, allowing to correlate queries
+ * collection.find({}).addCursorFlag('tailable', true) // Set cursor as tailable
+ * collection.find({}).addCursorFlag('oplogReplay', true) // Set cursor as oplogReplay
+ * collection.find({}).addCursorFlag('noCursorTimeout', true) // Set cursor as noCursorTimeout
+ * collection.find({}).addCursorFlag('awaitData', true) // Set cursor as awaitData
+ * collection.find({}).addCursorFlag('partial', true) // Set cursor as partial
+ * collection.find({}).addQueryModifier('$orderby', {a:1}) // Set $orderby {a:1}
+ * collection.find({}).max(10) // Set the cursor max
+ * collection.find({}).maxTimeMS(1000) // Set the cursor maxTimeMS
+ * collection.find({}).min(100) // Set the cursor min
+ * collection.find({}).returnKey(true) // Set the cursor returnKey
+ * collection.find({}).setReadPreference(ReadPreference.PRIMARY) // Set the cursor readPreference
+ * collection.find({}).showRecordId(true) // Set the cursor showRecordId
+ * collection.find({}).sort([['a', 1]]) // Sets the sort order of the cursor query
+ * collection.find({}).hint('a_1') // Set the cursor hint
+ *
+ * All options are chainable, so one can do the following.
+ *
+ * collection.find({}).maxTimeMS(1000).maxScan(100).skip(1).toArray(..)
+ */
+class Cursor extends CoreCursor {
+ constructor(topology, ns, cmd, options) {
+ super(topology, ns, cmd, options);
+ if (this.operation) {
+ options = this.operation.options;
+ }
+
+ // Tailable cursor options
+ const numberOfRetries = options.numberOfRetries || 5;
+ const tailableRetryInterval = options.tailableRetryInterval || 500;
+ const currentNumberOfRetries = numberOfRetries;
+
+ // Get the promiseLibrary
+ const promiseLibrary = options.promiseLibrary || Promise;
+
+ // Internal cursor state
+ this.s = {
+ // Tailable cursor options
+ numberOfRetries: numberOfRetries,
+ tailableRetryInterval: tailableRetryInterval,
+ currentNumberOfRetries: currentNumberOfRetries,
+ // State
+ state: CursorState.INIT,
+ // Promise library
+ promiseLibrary,
+ // explicitlyIgnoreSession
+ explicitlyIgnoreSession: !!options.explicitlyIgnoreSession
+ };
+
+ // Optional ClientSession
+ if (!options.explicitlyIgnoreSession && options.session) {
+ this.cursorState.session = options.session;
+ }
+
+ // Translate correctly
+ if (this.options.noCursorTimeout === true) {
+ this.addCursorFlag('noCursorTimeout', true);
+ }
+
+ // Get the batchSize
+ let batchSize = 1000;
+ if (this.cmd.cursor && this.cmd.cursor.batchSize) {
+ batchSize = this.cmd.cursor.batchSize;
+ } else if (options.cursor && options.cursor.batchSize) {
+ batchSize = options.cursor.batchSize;
+ } else if (typeof options.batchSize === 'number') {
+ batchSize = options.batchSize;
+ }
+
+ // Set the batchSize
+ this.setCursorBatchSize(batchSize);
+ }
+
+ get readPreference() {
+ if (this.operation) {
+ return this.operation.readPreference;
+ }
+
+ return this.options.readPreference;
+ }
+
+ get sortValue() {
+ return this.cmd.sort;
+ }
+
+ _initializeCursor(callback) {
+ if (this.operation && this.operation.session != null) {
+ this.cursorState.session = this.operation.session;
+ } else {
+ // implicitly create a session if one has not been provided
+ if (
+ !this.s.explicitlyIgnoreSession &&
+ !this.cursorState.session &&
+ this.topology.hasSessionSupport()
+ ) {
+ this.cursorState.session = this.topology.startSession({ owner: this });
+
+ if (this.operation) {
+ this.operation.session = this.cursorState.session;
+ }
+ }
+ }
+
+ super._initializeCursor(callback);
+ }
+
+ /**
+ * Check if there is any document still available in the cursor
+ * @method
+ * @param {Cursor~resultCallback} [callback] The result callback.
+ * @throws {MongoError}
+ * @return {Promise} returns Promise if no callback passed
+ */
+ hasNext(callback) {
+ if (this.s.state === CursorState.CLOSED || (this.isDead && this.isDead())) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ return maybePromise(this, callback, cb => {
+ const cursor = this;
+ if (cursor.isNotified()) {
+ return cb(null, false);
+ }
+
+ cursor._next((err, doc) => {
+ if (err) return cb(err);
+ if (doc == null || cursor.s.state === Cursor.CLOSED || cursor.isDead()) {
+ return cb(null, false);
+ }
+
+ cursor.s.state = CursorState.OPEN;
+
+ // NODE-2482: merge this into the core cursor implementation
+ cursor.cursorState.cursorIndex--;
+ if (cursor.cursorState.limit > 0) {
+ cursor.cursorState.currentLimit--;
+ }
+
+ cb(null, true);
+ });
+ });
+ }
+
+ /**
+ * Get the next available document from the cursor, returns null if no more documents are available.
+ * @method
+ * @param {Cursor~resultCallback} [callback] The result callback.
+ * @throws {MongoError}
+ * @return {Promise} returns Promise if no callback passed
+ */
+ next(callback) {
+ return maybePromise(this, callback, cb => {
+ const cursor = this;
+ if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead())) {
+ cb(MongoError.create({ message: 'Cursor is closed', driver: true }));
+ return;
+ }
+
+ if (cursor.s.state === CursorState.INIT && cursor.cmd.sort) {
+ try {
+ cursor.cmd.sort = formattedOrderClause(cursor.cmd.sort);
+ } catch (err) {
+ return cb(err);
+ }
+ }
+
+ cursor._next((err, doc) => {
+ if (err) return cb(err);
+ cursor.s.state = CursorState.OPEN;
+ cb(null, doc);
+ });
+ });
+ }
+
+ /**
+ * Set the cursor query
+ * @method
+ * @param {object} filter The filter object used for the cursor.
+ * @return {Cursor}
+ */
+ filter(filter) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.query = filter;
+ return this;
+ }
+
+ /**
+ * Set the cursor maxScan
+ * @method
+ * @param {object} maxScan Constrains the query to only scan the specified number of documents when fulfilling the query
+ * @deprecated as of MongoDB 4.0
+ * @return {Cursor}
+ */
+ maxScan(maxScan) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.maxScan = maxScan;
+ return this;
+ }
+
+ /**
+ * Set the cursor hint
+ * @method
+ * @param {object} hint If specified, then the query system will only consider plans using the hinted index.
+ * @return {Cursor}
+ */
+ hint(hint) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.hint = hint;
+ return this;
+ }
+
+ /**
+ * Set the cursor min
+ * @method
+ * @param {object} min Specify a $min value to specify the inclusive lower bound for a specific index in order to constrain the results of find(). The $min specifies the lower bound for all keys of a specific index in order.
+ * @return {Cursor}
+ */
+ min(min) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.min = min;
+ return this;
+ }
+
+ /**
+ * Set the cursor max
+ * @method
+ * @param {object} max Specify a $max value to specify the exclusive upper bound for a specific index in order to constrain the results of find(). The $max specifies the upper bound for all keys of a specific index in order.
+ * @return {Cursor}
+ */
+ max(max) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.max = max;
+ return this;
+ }
+
+ /**
+ * Set the cursor returnKey. If set to true, modifies the cursor to only return the index field or fields for the results of the query, rather than documents. If set to true and the query does not use an index to perform the read operation, the returned documents will not contain any fields.
+ * @method
+ * @param {bool} returnKey the returnKey value.
+ * @return {Cursor}
+ */
+ returnKey(value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.returnKey = value;
+ return this;
+ }
+
+ /**
+ * Set the cursor showRecordId
+ * @method
+ * @param {object} showRecordId The $showDiskLoc option has now been deprecated and replaced with the showRecordId field. $showDiskLoc will still be accepted for OP_QUERY stye find.
+ * @return {Cursor}
+ */
+ showRecordId(value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.showDiskLoc = value;
+ return this;
+ }
+
+ /**
+ * Set the cursor snapshot
+ * @method
+ * @param {object} snapshot The $snapshot operator prevents the cursor from returning a document more than once because an intervening write operation results in a move of the document.
+ * @deprecated as of MongoDB 4.0
+ * @return {Cursor}
+ */
+ snapshot(value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.snapshot = value;
+ return this;
+ }
+
+ /**
+ * Set a node.js specific cursor option
+ * @method
+ * @param {string} field The cursor option to set ['numberOfRetries', 'tailableRetryInterval'].
+ * @param {object} value The field value.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ setCursorOption(field, value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (fields.indexOf(field) === -1) {
+ throw MongoError.create({
+ message: `option ${field} is not a supported option ${fields}`,
+ driver: true
+ });
+ }
+
+ this.s[field] = value;
+ if (field === 'numberOfRetries') this.s.currentNumberOfRetries = value;
+ return this;
+ }
+
+ /**
+ * Add a cursor flag to the cursor
+ * @method
+ * @param {string} flag The flag to set, must be one of following ['tailable', 'oplogReplay', 'noCursorTimeout', 'awaitData', 'partial'].
+ * @param {boolean} value The flag boolean value.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ addCursorFlag(flag, value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (flags.indexOf(flag) === -1) {
+ throw MongoError.create({
+ message: `flag ${flag} is not a supported flag ${flags}`,
+ driver: true
+ });
+ }
+
+ if (typeof value !== 'boolean') {
+ throw MongoError.create({ message: `flag ${flag} must be a boolean value`, driver: true });
+ }
+
+ this.cmd[flag] = value;
+ return this;
+ }
+
+ /**
+ * Add a query modifier to the cursor query
+ * @method
+ * @param {string} name The query modifier (must start with $, such as $orderby etc)
+ * @param {string|boolean|number} value The modifier value.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ addQueryModifier(name, value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (name[0] !== '$') {
+ throw MongoError.create({ message: `${name} is not a valid query modifier`, driver: true });
+ }
+
+ // Strip of the $
+ const field = name.substr(1);
+ // Set on the command
+ this.cmd[field] = value;
+ // Deal with the special case for sort
+ if (field === 'orderby') this.cmd.sort = this.cmd[field];
+ return this;
+ }
+
+ /**
+ * Add a comment to the cursor query allowing for tracking the comment in the log.
+ * @method
+ * @param {string} value The comment attached to this query.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ comment(value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.comment = value;
+ return this;
+ }
+
+ /**
+ * Set a maxAwaitTimeMS on a tailing cursor query to allow to customize the timeout value for the option awaitData (Only supported on MongoDB 3.2 or higher, ignored otherwise)
+ * @method
+ * @param {number} value Number of milliseconds to wait before aborting the tailed query.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ maxAwaitTimeMS(value) {
+ if (typeof value !== 'number') {
+ throw MongoError.create({ message: 'maxAwaitTimeMS must be a number', driver: true });
+ }
+
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.maxAwaitTimeMS = value;
+ return this;
+ }
+
+ /**
+ * Set a maxTimeMS on the cursor query, allowing for hard timeout limits on queries (Only supported on MongoDB 2.6 or higher)
+ * @method
+ * @param {number} value Number of milliseconds to wait before aborting the query.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ maxTimeMS(value) {
+ if (typeof value !== 'number') {
+ throw MongoError.create({ message: 'maxTimeMS must be a number', driver: true });
+ }
+
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.maxTimeMS = value;
+ return this;
+ }
+
+ /**
+ * Sets a field projection for the query.
+ * @method
+ * @param {object} value The field projection object.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ project(value) {
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ this.cmd.fields = value;
+ return this;
+ }
+
+ /**
+ * Sets the sort order of the cursor query.
+ * @method
+ * @param {(string|array|object)} keyOrList The key or keys set for the sort.
+ * @param {number} [direction] The direction of the sorting (1 or -1).
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ sort(keyOrList, direction) {
+ if (this.options.tailable) {
+ throw MongoError.create({ message: "Tailable cursor doesn't support sorting", driver: true });
+ }
+
+ if (this.s.state === CursorState.CLOSED || this.s.state === CursorState.OPEN || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ let order = keyOrList;
+
+ // We have an array of arrays, we need to preserve the order of the sort
+ // so we will us a Map
+ if (Array.isArray(order) && Array.isArray(order[0])) {
+ order = new Map(
+ order.map(x => {
+ const value = [x[0], null];
+ if (x[1] === 'asc') {
+ value[1] = 1;
+ } else if (x[1] === 'desc') {
+ value[1] = -1;
+ } else if (x[1] === 1 || x[1] === -1 || x[1].$meta) {
+ value[1] = x[1];
+ } else {
+ throw new MongoError(
+ "Illegal sort clause, must be of the form [['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
+ );
+ }
+
+ return value;
+ })
+ );
+ }
+
+ if (direction != null) {
+ order = [[keyOrList, direction]];
+ }
+
+ this.cmd.sort = order;
+ return this;
+ }
+
+ /**
+ * Set the batch size for the cursor.
+ * @method
+ * @param {number} value The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/find/|find command documentation}.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ batchSize(value) {
+ if (this.options.tailable) {
+ throw MongoError.create({
+ message: "Tailable cursor doesn't support batchSize",
+ driver: true
+ });
+ }
+
+ if (this.s.state === CursorState.CLOSED || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (typeof value !== 'number') {
+ throw MongoError.create({ message: 'batchSize requires an integer', driver: true });
+ }
+
+ this.cmd.batchSize = value;
+ this.setCursorBatchSize(value);
+ return this;
+ }
+
+ /**
+ * Set the collation options for the cursor.
+ * @method
+ * @param {object} value The cursor collation options (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ collation(value) {
+ this.cmd.collation = value;
+ return this;
+ }
+
+ /**
+ * Set the limit for the cursor.
+ * @method
+ * @param {number} value The limit for the cursor query.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ limit(value) {
+ if (this.options.tailable) {
+ throw MongoError.create({ message: "Tailable cursor doesn't support limit", driver: true });
+ }
+
+ if (this.s.state === CursorState.OPEN || this.s.state === CursorState.CLOSED || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (typeof value !== 'number') {
+ throw MongoError.create({ message: 'limit requires an integer', driver: true });
+ }
+
+ this.cmd.limit = value;
+ this.setCursorLimit(value);
+ return this;
+ }
+
+ /**
+ * Set the skip for the cursor.
+ * @method
+ * @param {number} value The skip for the cursor query.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ skip(value) {
+ if (this.options.tailable) {
+ throw MongoError.create({ message: "Tailable cursor doesn't support skip", driver: true });
+ }
+
+ if (this.s.state === CursorState.OPEN || this.s.state === CursorState.CLOSED || this.isDead()) {
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
+ }
+
+ if (typeof value !== 'number') {
+ throw MongoError.create({ message: 'skip requires an integer', driver: true });
+ }
+
+ this.cmd.skip = value;
+ this.setCursorSkip(value);
+ return this;
+ }
+
+ /**
+ * The callback format for results
+ * @callback Cursor~resultCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {(object|null|boolean)} result The result object if the command was executed successfully.
+ */
+
+ /**
+ * Clone the cursor
+ * @function external:CoreCursor#clone
+ * @return {Cursor}
+ */
+
+ /**
+ * Resets the cursor
+ * @function external:CoreCursor#rewind
+ * @return {null}
+ */
+
+ /**
+ * Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
+ * not all of the elements will be iterated if this cursor had been previously accessed.
+ * In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
+ * **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
+ * at any given time if batch size is specified. Otherwise, the caller is responsible
+ * for making sure that the entire result can fit the memory.
+ * @method
+ * @deprecated
+ * @param {Cursor~resultCallback} callback The result callback.
+ * @throws {MongoError}
+ * @return {null}
+ */
+ each(callback) {
+ // Rewind cursor state
+ this.rewind();
+ // Set current cursor to INIT
+ this.s.state = CursorState.INIT;
+ // Run the query
+ each(this, callback);
+ }
+
+ /**
+ * The callback format for the forEach iterator method
+ * @callback Cursor~iteratorCallback
+ * @param {Object} doc An emitted document for the iterator
+ */
+
+ /**
+ * The callback error format for the forEach iterator method
+ * @callback Cursor~endCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ */
+
+ /**
+ * Iterates over all the documents for this cursor using the iterator, callback pattern.
+ * @method
+ * @param {Cursor~iteratorCallback} iterator The iteration callback.
+ * @param {Cursor~endCallback} callback The end callback.
+ * @throws {MongoError}
+ * @return {Promise} if no callback supplied
+ */
+ forEach(iterator, callback) {
+ // Rewind cursor state
+ this.rewind();
+
+ // Set current cursor to INIT
+ this.s.state = CursorState.INIT;
+
+ if (typeof callback === 'function') {
+ each(this, (err, doc) => {
+ if (err) {
+ callback(err);
+ return false;
+ }
+ if (doc != null) {
+ iterator(doc);
+ return true;
+ }
+ if (doc == null && callback) {
+ const internalCallback = callback;
+ callback = null;
+ internalCallback(null);
+ return false;
+ }
+ });
+ } else {
+ return new this.s.promiseLibrary((fulfill, reject) => {
+ each(this, (err, doc) => {
+ if (err) {
+ reject(err);
+ return false;
+ } else if (doc == null) {
+ fulfill(null);
+ return false;
+ } else {
+ iterator(doc);
+ return true;
+ }
+ });
+ });
+ }
+ }
+
+ /**
+ * Set the ReadPreference for the cursor.
+ * @method
+ * @param {(string|ReadPreference)} readPreference The new read preference for the cursor.
+ * @throws {MongoError}
+ * @return {Cursor}
+ */
+ setReadPreference(readPreference) {
+ if (this.s.state !== CursorState.INIT) {
+ throw MongoError.create({
+ message: 'cannot change cursor readPreference after cursor has been accessed',
+ driver: true
+ });
+ }
+
+ if (readPreference instanceof ReadPreference) {
+ this.options.readPreference = readPreference;
+ } else if (typeof readPreference === 'string') {
+ this.options.readPreference = new ReadPreference(readPreference);
+ } else {
+ throw new TypeError('Invalid read preference: ' + readPreference);
+ }
+
+ return this;
+ }
+
+ /**
+ * The callback format for results
+ * @callback Cursor~toArrayResultCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {object[]} documents All the documents the satisfy the cursor.
+ */
+
+ /**
+ * Returns an array of documents. The caller is responsible for making sure that there
+ * is enough memory to store the results. Note that the array only contains partial
+ * results when this cursor had been previously accessed. In that case,
+ * cursor.rewind() can be used to reset the cursor.
+ * @method
+ * @param {Cursor~toArrayResultCallback} [callback] The result callback.
+ * @throws {MongoError}
+ * @return {Promise} returns Promise if no callback passed
+ */
+ toArray(callback) {
+ if (this.options.tailable) {
+ throw MongoError.create({
+ message: 'Tailable cursor cannot be converted to array',
+ driver: true
+ });
+ }
+ return maybePromise(this, callback, cb => {
+ const cursor = this;
+ const items = [];
+
+ // Reset cursor
+ cursor.rewind();
+ cursor.s.state = CursorState.INIT;
+
+ // Fetch all the documents
+ const fetchDocs = () => {
+ cursor._next((err, doc) => {
+ if (err) {
+ return cursor._endSession
+ ? cursor._endSession(() => handleCallback(cb, err))
+ : handleCallback(cb, err);
+ }
+
+ if (doc == null) {
+ return cursor.close({ skipKillCursors: true }, () => handleCallback(cb, null, items));
+ }
+
+ // Add doc to items
+ items.push(doc);
+
+ // Get all buffered objects
+ if (cursor.bufferedCount() > 0) {
+ let docs = cursor.readBufferedDocuments(cursor.bufferedCount());
+
+ // Transform the doc if transform method added
+ if (cursor.s.transforms && typeof cursor.s.transforms.doc === 'function') {
+ docs = docs.map(cursor.s.transforms.doc);
+ }
+
+ Array.prototype.push.apply(items, docs);
+ }
+
+ // Attempt a fetch
+ fetchDocs();
+ });
+ };
+
+ fetchDocs();
+ });
+ }
+
+ /**
+ * The callback format for results
+ * @callback Cursor~countResultCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {number} count The count of documents.
+ */
+
+ /**
+ * Get the count of documents for this cursor
+ * @method
+ * @param {boolean} [applySkipLimit=true] Should the count command apply limit and skip settings on the cursor or in the passed in options.
+ * @param {object} [options] Optional settings.
+ * @param {number} [options.skip] The number of documents to skip.
+ * @param {number} [options.limit] The maximum amounts to count before aborting.
+ * @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
+ * @param {string} [options.hint] An index name hint for the query.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {Cursor~countResultCallback} [callback] The result callback.
+ * @return {Promise} returns Promise if no callback passed
+ */
+ count(applySkipLimit, opts, callback) {
+ if (this.cmd.query == null)
+ throw MongoError.create({
+ message: 'count can only be used with find command',
+ driver: true
+ });
+ if (typeof opts === 'function') (callback = opts), (opts = {});
+ opts = opts || {};
+
+ if (typeof applySkipLimit === 'function') {
+ callback = applySkipLimit;
+ applySkipLimit = true;
+ }
+
+ if (this.cursorState.session) {
+ opts = Object.assign({}, opts, { session: this.cursorState.session });
+ }
+
+ const countOperation = new CountOperation(this, applySkipLimit, opts);
+
+ return executeOperation(this.topology, countOperation, callback);
+ }
+
+ /**
+ * Close the cursor, sending a KillCursor command and emitting close.
+ * @method
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.skipKillCursors] Bypass calling killCursors when closing the cursor.
+ * @param {Cursor~resultCallback} [callback] The result callback.
+ * @return {Promise} returns Promise if no callback passed
+ */
+ close(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = Object.assign({}, { skipKillCursors: false }, options);
+
+ this.s.state = CursorState.CLOSED;
+ if (!options.skipKillCursors) {
+ // Kill the cursor
+ this.kill();
+ }
+
+ const completeClose = () => {
+ // Emit the close event for the cursor
+ this.emit('close');
+
+ // Callback if provided
+ if (typeof callback === 'function') {
+ return handleCallback(callback, null, this);
+ }
+
+ // Return a Promise
+ return new this.s.promiseLibrary(resolve => {
+ resolve();
+ });
+ };
+
+ if (this.cursorState.session) {
+ if (typeof callback === 'function') {
+ return this._endSession(() => completeClose());
+ }
+
+ return new this.s.promiseLibrary(resolve => {
+ this._endSession(() => completeClose().then(resolve));
+ });
+ }
+
+ return completeClose();
+ }
+
+ /**
+ * Map all documents using the provided function
+ * @method
+ * @param {function} [transform] The mapping transformation method.
+ * @return {Cursor}
+ */
+ map(transform) {
+ if (this.cursorState.transforms && this.cursorState.transforms.doc) {
+ const oldTransform = this.cursorState.transforms.doc;
+ this.cursorState.transforms.doc = doc => {
+ return transform(oldTransform(doc));
+ };
+ } else {
+ this.cursorState.transforms = { doc: transform };
+ }
+
+ return this;
+ }
+
+ /**
+ * Is the cursor closed
+ * @method
+ * @return {boolean}
+ */
+ isClosed() {
+ return this.isDead();
+ }
+
+ destroy(err) {
+ if (err) this.emit('error', err);
+ this.pause();
+ this.close();
+ }
+
+ /**
+ * Return a modified Readable stream including a possible transform method.
+ * @method
+ * @param {object} [options] Optional settings.
+ * @param {function} [options.transform] A transformation method applied to each document emitted by the stream.
+ * @return {Cursor}
+ * TODO: replace this method with transformStream in next major release
+ */
+ stream(options) {
+ this.cursorState.streamOptions = options || {};
+ return this;
+ }
+
+ /**
+ * Return a modified Readable stream that applies a given transform function, if supplied. If none supplied,
+ * returns a stream of unmodified docs.
+ * @method
+ * @param {object} [options] Optional settings.
+ * @param {function} [options.transform] A transformation method applied to each document emitted by the stream.
+ * @return {stream}
+ */
+ transformStream(options) {
+ const streamOptions = options || {};
+ if (typeof streamOptions.transform === 'function') {
+ const stream = new Transform({
+ objectMode: true,
+ transform: function(chunk, encoding, callback) {
+ this.push(streamOptions.transform(chunk));
+ callback();
+ }
+ });
+
+ return this.pipe(stream);
+ }
+
+ return this.pipe(new PassThrough({ objectMode: true }));
+ }
+
+ /**
+ * Execute the explain for the cursor
+ * @method
+ * @param {Cursor~resultCallback} [callback] The result callback.
+ * @return {Promise} returns Promise if no callback passed
+ */
+ explain(callback) {
+ // NOTE: the next line includes a special case for operations which do not
+ // subclass `CommandOperationV2`. To be removed asap.
+ if (this.operation && this.operation.cmd == null) {
+ this.operation.options.explain = true;
+ this.operation.fullResponse = false;
+ return executeOperation(this.topology, this.operation, callback);
+ }
+
+ this.cmd.explain = true;
+
+ // Do we have a readConcern
+ if (this.cmd.readConcern) {
+ delete this.cmd['readConcern'];
+ }
+ return maybePromise(this, callback, cb => {
+ CoreCursor.prototype._next.apply(this, [cb]);
+ });
+ }
+
+ /**
+ * Return the cursor logger
+ * @method
+ * @return {Logger} return the cursor logger
+ * @ignore
+ */
+ getLogger() {
+ return this.logger;
+ }
+}
+
+/**
+ * Cursor stream data event, fired for each document in the cursor.
+ *
+ * @event Cursor#data
+ * @type {object}
+ */
+
+/**
+ * Cursor stream end event
+ *
+ * @event Cursor#end
+ * @type {null}
+ */
+
+/**
+ * Cursor stream close event
+ *
+ * @event Cursor#close
+ * @type {null}
+ */
+
+/**
+ * Cursor stream readable event
+ *
+ * @event Cursor#readable
+ * @type {null}
+ */
+
+// aliases
+Cursor.prototype.maxTimeMs = Cursor.prototype.maxTimeMS;
+
+// deprecated methods
+deprecate(Cursor.prototype.each, 'Cursor.each is deprecated. Use Cursor.forEach instead.');
+deprecate(
+ Cursor.prototype.maxScan,
+ 'Cursor.maxScan is deprecated, and will be removed in a later version'
+);
+
+deprecate(
+ Cursor.prototype.snapshot,
+ 'Cursor Snapshot is deprecated, and will be removed in a later version'
+);
+
+/**
+ * The read() method pulls some data out of the internal buffer and returns it. If there is no data available, then it will return null.
+ * @function external:Readable#read
+ * @param {number} size Optional argument to specify how much data to read.
+ * @return {(String | Buffer | null)}
+ */
+
+/**
+ * Call this function to cause the stream to return strings of the specified encoding instead of Buffer objects.
+ * @function external:Readable#setEncoding
+ * @param {string} encoding The encoding to use.
+ * @return {null}
+ */
+
+/**
+ * This method will cause the readable stream to resume emitting data events.
+ * @function external:Readable#resume
+ * @return {null}
+ */
+
+/**
+ * This method will cause a stream in flowing-mode to stop emitting data events. Any data that becomes available will remain in the internal buffer.
+ * @function external:Readable#pause
+ * @return {null}
+ */
+
+/**
+ * This method pulls all the data out of a readable stream, and writes it to the supplied destination, automatically managing the flow so that the destination is not overwhelmed by a fast readable stream.
+ * @function external:Readable#pipe
+ * @param {Writable} destination The destination for writing data
+ * @param {object} [options] Pipe options
+ * @return {null}
+ */
+
+/**
+ * This method will remove the hooks set up for a previous pipe() call.
+ * @function external:Readable#unpipe
+ * @param {Writable} [destination] The destination for writing data
+ * @return {null}
+ */
+
+/**
+ * This is useful in certain cases where a stream is being consumed by a parser, which needs to "un-consume" some data that it has optimistically pulled out of the source, so that the stream can be passed on to some other party.
+ * @function external:Readable#unshift
+ * @param {(Buffer|string)} chunk Chunk of data to unshift onto the read queue.
+ * @return {null}
+ */
+
+/**
+ * Versions of Node prior to v0.10 had streams that did not implement the entire Streams API as it is today. (See "Compatibility" below for more information.)
+ * @function external:Readable#wrap
+ * @param {Stream} stream An "old style" readable stream.
+ * @return {null}
+ */
+
+module.exports = Cursor;
diff --git a/node_modules/mongodb/lib/db.js b/node_modules/mongodb/lib/db.js
new file mode 100644
index 0000000..e28d25a
--- /dev/null
+++ b/node_modules/mongodb/lib/db.js
@@ -0,0 +1,1031 @@
+'use strict';
+
+const EventEmitter = require('events').EventEmitter;
+const inherits = require('util').inherits;
+const getSingleProperty = require('./utils').getSingleProperty;
+const CommandCursor = require('./command_cursor');
+const handleCallback = require('./utils').handleCallback;
+const filterOptions = require('./utils').filterOptions;
+const toError = require('./utils').toError;
+const ReadPreference = require('./core').ReadPreference;
+const MongoError = require('./core').MongoError;
+const ObjectID = require('./core').ObjectID;
+const Logger = require('./core').Logger;
+const Collection = require('./collection');
+const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
+const executeLegacyOperation = require('./utils').executeLegacyOperation;
+const resolveReadPreference = require('./utils').resolveReadPreference;
+const ChangeStream = require('./change_stream');
+const deprecate = require('util').deprecate;
+const deprecateOptions = require('./utils').deprecateOptions;
+const MongoDBNamespace = require('./utils').MongoDBNamespace;
+const CONSTANTS = require('./constants');
+const WriteConcern = require('./write_concern');
+const ReadConcern = require('./read_concern');
+const AggregationCursor = require('./aggregation_cursor');
+
+// Operations
+const createListener = require('./operations/db_ops').createListener;
+const ensureIndex = require('./operations/db_ops').ensureIndex;
+const evaluate = require('./operations/db_ops').evaluate;
+const profilingInfo = require('./operations/db_ops').profilingInfo;
+const validateDatabaseName = require('./operations/db_ops').validateDatabaseName;
+
+const AggregateOperation = require('./operations/aggregate');
+const AddUserOperation = require('./operations/add_user');
+const CollectionsOperation = require('./operations/collections');
+const CommandOperation = require('./operations/command');
+const CreateCollectionOperation = require('./operations/create_collection');
+const CreateIndexOperation = require('./operations/create_index');
+const DropCollectionOperation = require('./operations/drop').DropCollectionOperation;
+const DropDatabaseOperation = require('./operations/drop').DropDatabaseOperation;
+const ExecuteDbAdminCommandOperation = require('./operations/execute_db_admin_command');
+const IndexInformationOperation = require('./operations/index_information');
+const ListCollectionsOperation = require('./operations/list_collections');
+const ProfilingLevelOperation = require('./operations/profiling_level');
+const RemoveUserOperation = require('./operations/remove_user');
+const RenameOperation = require('./operations/rename');
+const SetProfilingLevelOperation = require('./operations/set_profiling_level');
+
+const executeOperation = require('./operations/execute_operation');
+
+/**
+ * @fileOverview The **Db** class is a class that represents a MongoDB Database.
+ *
+ * @example
+ * const MongoClient = require('mongodb').MongoClient;
+ * // Connection url
+ * const url = 'mongodb://localhost:27017';
+ * // Database Name
+ * const dbName = 'test';
+ * // Connect using MongoClient
+ * MongoClient.connect(url, function(err, client) {
+ * // Select the database by name
+ * const testDb = client.db(dbName);
+ * client.close();
+ * });
+ */
+
+// Allowed parameters
+const legalOptionNames = [
+ 'w',
+ 'wtimeout',
+ 'fsync',
+ 'j',
+ 'readPreference',
+ 'readPreferenceTags',
+ 'native_parser',
+ 'forceServerObjectId',
+ 'pkFactory',
+ 'serializeFunctions',
+ 'raw',
+ 'bufferMaxEntries',
+ 'authSource',
+ 'ignoreUndefined',
+ 'promoteLongs',
+ 'promiseLibrary',
+ 'readConcern',
+ 'retryMiliSeconds',
+ 'numberOfRetries',
+ 'parentDb',
+ 'noListener',
+ 'loggerLevel',
+ 'logger',
+ 'promoteBuffers',
+ 'promoteLongs',
+ 'promoteValues',
+ 'compression',
+ 'retryWrites'
+];
+
+/**
+ * Creates a new Db instance
+ * @class
+ * @param {string} databaseName The name of the database this instance represents.
+ * @param {(Server|ReplSet|Mongos)} topology The server topology for the database.
+ * @param {object} [options] Optional settings.
+ * @param {string} [options.authSource] If the database authentication is dependent on another databaseName.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
+ * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
+ * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
+ * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {object} [options.readConcern] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
+ * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
+ * @property {(Server|ReplSet|Mongos)} serverConfig Get the current db topology.
+ * @property {number} bufferMaxEntries Current bufferMaxEntries value for the database
+ * @property {string} databaseName The name of the database this instance represents.
+ * @property {object} options The options associated with the db instance.
+ * @property {boolean} native_parser The current value of the parameter native_parser.
+ * @property {boolean} slaveOk The current slaveOk value for the db instance.
+ * @property {object} writeConcern The current write concern values.
+ * @property {object} topology Access the topology object (single server, replicaset or mongos).
+ * @fires Db#close
+ * @fires Db#reconnect
+ * @fires Db#error
+ * @fires Db#timeout
+ * @fires Db#parseError
+ * @fires Db#fullsetup
+ * @return {Db} a Db instance.
+ */
+function Db(databaseName, topology, options) {
+ options = options || {};
+ if (!(this instanceof Db)) return new Db(databaseName, topology, options);
+ EventEmitter.call(this);
+
+ // Get the promiseLibrary
+ const promiseLibrary = options.promiseLibrary || Promise;
+
+ // Filter the options
+ options = filterOptions(options, legalOptionNames);
+
+ // Ensure we put the promiseLib in the options
+ options.promiseLibrary = promiseLibrary;
+
+ // Internal state of the db object
+ this.s = {
+ // DbCache
+ dbCache: {},
+ // Children db's
+ children: [],
+ // Topology
+ topology: topology,
+ // Options
+ options: options,
+ // Logger instance
+ logger: Logger('Db', options),
+ // Get the bson parser
+ bson: topology ? topology.bson : null,
+ // Unpack read preference
+ readPreference: ReadPreference.fromOptions(options),
+ // Set buffermaxEntries
+ bufferMaxEntries: typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : -1,
+ // Parent db (if chained)
+ parentDb: options.parentDb || null,
+ // Set up the primary key factory or fallback to ObjectID
+ pkFactory: options.pkFactory || ObjectID,
+ // Get native parser
+ nativeParser: options.nativeParser || options.native_parser,
+ // Promise library
+ promiseLibrary: promiseLibrary,
+ // No listener
+ noListener: typeof options.noListener === 'boolean' ? options.noListener : false,
+ // ReadConcern
+ readConcern: ReadConcern.fromOptions(options),
+ writeConcern: WriteConcern.fromOptions(options),
+ // Namespace
+ namespace: new MongoDBNamespace(databaseName)
+ };
+
+ // Ensure we have a valid db name
+ validateDatabaseName(databaseName);
+
+ // Add a read Only property
+ getSingleProperty(this, 'serverConfig', this.s.topology);
+ getSingleProperty(this, 'bufferMaxEntries', this.s.bufferMaxEntries);
+ getSingleProperty(this, 'databaseName', this.s.namespace.db);
+
+ // This is a child db, do not register any listeners
+ if (options.parentDb) return;
+ if (this.s.noListener) return;
+
+ // Add listeners
+ topology.on('error', createListener(this, 'error', this));
+ topology.on('timeout', createListener(this, 'timeout', this));
+ topology.on('close', createListener(this, 'close', this));
+ topology.on('parseError', createListener(this, 'parseError', this));
+ topology.once('open', createListener(this, 'open', this));
+ topology.once('fullsetup', createListener(this, 'fullsetup', this));
+ topology.once('all', createListener(this, 'all', this));
+ topology.on('reconnect', createListener(this, 'reconnect', this));
+}
+
+inherits(Db, EventEmitter);
+
+// Topology
+Object.defineProperty(Db.prototype, 'topology', {
+ enumerable: true,
+ get: function() {
+ return this.s.topology;
+ }
+});
+
+// Options
+Object.defineProperty(Db.prototype, 'options', {
+ enumerable: true,
+ get: function() {
+ return this.s.options;
+ }
+});
+
+// slaveOk specified
+Object.defineProperty(Db.prototype, 'slaveOk', {
+ enumerable: true,
+ get: function() {
+ if (
+ this.s.options.readPreference != null &&
+ (this.s.options.readPreference !== 'primary' ||
+ this.s.options.readPreference.mode !== 'primary')
+ ) {
+ return true;
+ }
+ return false;
+ }
+});
+
+Object.defineProperty(Db.prototype, 'readConcern', {
+ enumerable: true,
+ get: function() {
+ return this.s.readConcern;
+ }
+});
+
+Object.defineProperty(Db.prototype, 'readPreference', {
+ enumerable: true,
+ get: function() {
+ if (this.s.readPreference == null) {
+ // TODO: check client
+ return ReadPreference.primary;
+ }
+
+ return this.s.readPreference;
+ }
+});
+
+// get the write Concern
+Object.defineProperty(Db.prototype, 'writeConcern', {
+ enumerable: true,
+ get: function() {
+ return this.s.writeConcern;
+ }
+});
+
+Object.defineProperty(Db.prototype, 'namespace', {
+ enumerable: true,
+ get: function() {
+ return this.s.namespace.toString();
+ }
+});
+
+/**
+ * Execute a command
+ * @method
+ * @param {object} command The command hash
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.command = function(command, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = Object.assign({}, options);
+
+ const commandOperation = new CommandOperation(this, options, null, command);
+
+ return executeOperation(this.s.topology, commandOperation, callback);
+};
+
+/**
+ * Execute an aggregation framework pipeline against the database, needs MongoDB >= 3.6
+ * @method
+ * @param {object} [pipeline=[]] Array containing all the aggregation framework commands for the execution.
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
+ * @param {object} [options.cursor] Return the query as cursor, on 2.6 > it returns as a real cursor on pre 2.6 it returns as an emulated cursor.
+ * @param {number} [options.cursor.batchSize=1000] Deprecated. Use `options.batchSize`
+ * @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
+ * @param {boolean} [options.allowDiskUse=false] allowDiskUse lets the server know if it can use disk to store temporary results for the aggregation (requires mongodb 2.6 >).
+ * @param {number} [options.maxTimeMS] maxTimeMS specifies a cumulative time limit in milliseconds for processing operations on the cursor. MongoDB interrupts the operation at the earliest following interrupt point.
+ * @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query.
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
+ * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
+ * @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
+ * @param {string} [options.comment] Add a comment to an aggregation command
+ * @param {string|object} [options.hint] Add an index selection hint to an aggregation command
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Database~aggregationCallback} callback The command result callback
+ * @return {(null|AggregationCursor)}
+ */
+Db.prototype.aggregate = function(pipeline, options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ // If we have no options or callback we are doing
+ // a cursor based aggregation
+ if (options == null && callback == null) {
+ options = {};
+ }
+
+ const cursor = new AggregationCursor(
+ this.s.topology,
+ new AggregateOperation(this, pipeline, options),
+ options
+ );
+
+ // TODO: remove this when NODE-2074 is resolved
+ if (typeof callback === 'function') {
+ callback(null, cursor);
+ return;
+ }
+
+ return cursor;
+};
+
+/**
+ * Return the Admin db instance
+ * @method
+ * @return {Admin} return the new Admin db instance
+ */
+Db.prototype.admin = function() {
+ const Admin = require('./admin');
+
+ return new Admin(this, this.s.topology, this.s.promiseLibrary);
+};
+
+/**
+ * The callback format for the collection method, must be used if strict is specified
+ * @callback Db~collectionResultCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {Collection} collection The collection instance.
+ */
+
+/**
+ * The callback format for an aggregation call
+ * @callback Database~aggregationCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {AggregationCursor} cursor The cursor if the aggregation command was executed successfully.
+ */
+
+const collectionKeys = [
+ 'pkFactory',
+ 'readPreference',
+ 'serializeFunctions',
+ 'strict',
+ 'readConcern',
+ 'ignoreUndefined',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'promoteLongs'
+];
+
+/**
+ * Fetch a specific collection (containing the actual collection information). If the application does not use strict mode you
+ * can use it without a callback in the following way: `const collection = db.collection('mycollection');`
+ *
+ * @method
+ * @param {string} name the collection name we wish to access.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
+ * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
+ * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
+ * @param {object} [options.readConcern] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
+ * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
+ * @param {Db~collectionResultCallback} [callback] The collection result callback
+ * @return {Collection} return the new Collection instance if not in strict mode
+ */
+Db.prototype.collection = function(name, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ options = Object.assign({}, options);
+
+ // Set the promise library
+ options.promiseLibrary = this.s.promiseLibrary;
+
+ // If we have not set a collection level readConcern set the db level one
+ options.readConcern = options.readConcern
+ ? new ReadConcern(options.readConcern.level)
+ : this.readConcern;
+
+ // Do we have ignoreUndefined set
+ if (this.s.options.ignoreUndefined) {
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
+ }
+
+ // Merge in all needed options and ensure correct writeConcern merging from db level
+ options = mergeOptionsAndWriteConcern(options, this.s.options, collectionKeys, true);
+
+ // Execute
+ if (options == null || !options.strict) {
+ try {
+ const collection = new Collection(
+ this,
+ this.s.topology,
+ this.databaseName,
+ name,
+ this.s.pkFactory,
+ options
+ );
+ if (callback) callback(null, collection);
+ return collection;
+ } catch (err) {
+ if (err instanceof MongoError && callback) return callback(err);
+ throw err;
+ }
+ }
+
+ // Strict mode
+ if (typeof callback !== 'function') {
+ throw toError(`A callback is required in strict mode. While getting collection ${name}`);
+ }
+
+ // Did the user destroy the topology
+ if (this.serverConfig && this.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ const listCollectionOptions = Object.assign({}, options, { nameOnly: true });
+
+ // Strict mode
+ this.listCollections({ name: name }, listCollectionOptions).toArray((err, collections) => {
+ if (err != null) return handleCallback(callback, err, null);
+ if (collections.length === 0)
+ return handleCallback(
+ callback,
+ toError(`Collection ${name} does not exist. Currently in strict mode.`),
+ null
+ );
+
+ try {
+ return handleCallback(
+ callback,
+ null,
+ new Collection(this, this.s.topology, this.databaseName, name, this.s.pkFactory, options)
+ );
+ } catch (err) {
+ return handleCallback(callback, err, null);
+ }
+ });
+};
+
+/**
+ * Create a new collection on a server with the specified options. Use this to create capped collections.
+ * More information about command options available at https://docs.mongodb.com/manual/reference/command/create/
+ *
+ * @method
+ * @param {string} name the collection name we wish to access.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
+ * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
+ * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
+ * @param {boolean} [options.capped=false] Create a capped collection.
+ * @param {boolean} [options.autoIndexId=true] DEPRECATED: Create an index on the _id field of the document, True by default on MongoDB 2.6 - 3.0
+ * @param {number} [options.size] The size of the capped collection in bytes.
+ * @param {number} [options.max] The maximum number of documents in the capped collection.
+ * @param {number} [options.flags] Optional. Available for the MMAPv1 storage engine only to set the usePowerOf2Sizes and the noPadding flag.
+ * @param {object} [options.storageEngine] Allows users to specify configuration to the storage engine on a per-collection basis when creating a collection on MongoDB 3.0 or higher.
+ * @param {object} [options.validator] Allows users to specify validation rules or expressions for the collection. For more information, see Document Validation on MongoDB 3.2 or higher.
+ * @param {string} [options.validationLevel] Determines how strictly MongoDB applies the validation rules to existing documents during an update on MongoDB 3.2 or higher.
+ * @param {string} [options.validationAction] Determines whether to error on invalid documents or just warn about the violations but allow invalid documents to be inserted on MongoDB 3.2 or higher.
+ * @param {object} [options.indexOptionDefaults] Allows users to specify a default configuration for indexes when creating a collection on MongoDB 3.2 or higher.
+ * @param {string} [options.viewOn] The name of the source collection or view from which to create the view. The name is not the full namespace of the collection or view; i.e. does not include the database name and implies the same database as the view to create on MongoDB 3.4 or higher.
+ * @param {array} [options.pipeline] An array that consists of the aggregation pipeline stage. Creates the view by applying the specified pipeline to the viewOn collection or view on MongoDB 3.4 or higher.
+ * @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~collectionResultCallback} [callback] The results callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.createCollection = deprecateOptions(
+ {
+ name: 'Db.createCollection',
+ deprecatedOptions: ['autoIndexId'],
+ optionsIndex: 1
+ },
+ function(name, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ options.promiseLibrary = options.promiseLibrary || this.s.promiseLibrary;
+ options.readConcern = options.readConcern
+ ? new ReadConcern(options.readConcern.level)
+ : this.readConcern;
+ const createCollectionOperation = new CreateCollectionOperation(this, name, options);
+
+ return executeOperation(this.s.topology, createCollectionOperation, callback);
+ }
+);
+
+/**
+ * Get all the db statistics.
+ *
+ * @method
+ * @param {object} [options] Optional settings.
+ * @param {number} [options.scale] Divide the returned sizes by scale value.
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The collection result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.stats = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ // Build command object
+ const commandObject = { dbStats: true };
+ // Check if we have the scale value
+ if (options['scale'] != null) commandObject['scale'] = options['scale'];
+
+ // If we have a readPreference set
+ if (options.readPreference == null && this.s.readPreference) {
+ options.readPreference = this.s.readPreference;
+ }
+
+ const statsOperation = new CommandOperation(this, options, null, commandObject);
+
+ // Execute the command
+ return executeOperation(this.s.topology, statsOperation, callback);
+};
+
+/**
+ * Get the list of all collection information for the specified db.
+ *
+ * @method
+ * @param {object} [filter={}] Query to filter collections by
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.nameOnly=false] Since 4.0: If true, will only return the collection name in the response, and will omit additional info
+ * @param {number} [options.batchSize=1000] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @return {CommandCursor}
+ */
+Db.prototype.listCollections = function(filter, options) {
+ filter = filter || {};
+ options = options || {};
+
+ return new CommandCursor(
+ this.s.topology,
+ new ListCollectionsOperation(this, filter, options),
+ options
+ );
+};
+
+/**
+ * Evaluate JavaScript on the server
+ *
+ * @method
+ * @param {Code} code JavaScript to execute on server.
+ * @param {(object|array)} parameters The parameters for the call.
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.nolock=false] Tell MongoDB not to block on the evaluation of the javascript.
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The results callback
+ * @deprecated Eval is deprecated on MongoDB 3.2 and forward
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.eval = deprecate(function(code, parameters, options, callback) {
+ const args = Array.prototype.slice.call(arguments, 1);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ parameters = args.length ? args.shift() : parameters;
+ options = args.length ? args.shift() || {} : {};
+
+ return executeLegacyOperation(this.s.topology, evaluate, [
+ this,
+ code,
+ parameters,
+ options,
+ callback
+ ]);
+}, 'Db.eval is deprecated as of MongoDB version 3.2');
+
+/**
+ * Rename a collection.
+ *
+ * @method
+ * @param {string} fromCollection Name of current collection to rename.
+ * @param {string} toCollection New name of of the collection.
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~collectionResultCallback} [callback] The results callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY });
+
+ // Add return new collection
+ options.new_collection = true;
+
+ const renameOperation = new RenameOperation(
+ this.collection(fromCollection),
+ toCollection,
+ options
+ );
+
+ return executeOperation(this.s.topology, renameOperation, callback);
+};
+
+/**
+ * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
+ *
+ * @method
+ * @param {string} name Name of collection to drop
+ * @param {Object} [options] Optional settings
+ * @param {WriteConcern} [options.writeConcern] A full WriteConcern object
+ * @param {(number|string)} [options.w] The write concern
+ * @param {number} [options.wtimeout] The write concern timeout
+ * @param {boolean} [options.j] The journal write concern
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The results callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.dropCollection = function(name, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const dropCollectionOperation = new DropCollectionOperation(this, name, options);
+
+ return executeOperation(this.s.topology, dropCollectionOperation, callback);
+};
+
+/**
+ * Drop a database, removing it permanently from the server.
+ *
+ * @method
+ * @param {Object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The results callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.dropDatabase = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const dropDatabaseOperation = new DropDatabaseOperation(this, options);
+
+ return executeOperation(this.s.topology, dropDatabaseOperation, callback);
+};
+
+/**
+ * Fetch all collections for the current db.
+ *
+ * @method
+ * @param {Object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~collectionsResultCallback} [callback] The results callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.collections = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const collectionsOperation = new CollectionsOperation(this, options);
+
+ return executeOperation(this.s.topology, collectionsOperation, callback);
+};
+
+/**
+ * Runs a command on the database as admin.
+ * @method
+ * @param {object} command The command hash
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ options.readPreference = resolveReadPreference(this, options);
+
+ const executeDbAdminCommandOperation = new ExecuteDbAdminCommandOperation(
+ this,
+ selector,
+ options
+ );
+
+ return executeOperation(this.s.topology, executeDbAdminCommandOperation, callback);
+};
+
+/**
+ * Creates an index on the db and collection.
+ * @method
+ * @param {string} name Name of the collection to create the index on.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.unique=false] Creates an unique index.
+ * @param {boolean} [options.sparse=false] Creates a sparse index.
+ * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
+ * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * @param {number} [options.min] For geospatial indexes set the lower bound for the co-ordinates.
+ * @param {number} [options.max] For geospatial indexes set the high bound for the co-ordinates.
+ * @param {number} [options.v] Specify the format version of the indexes.
+ * @param {number} [options.expireAfterSeconds] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * @param {string} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ * @param {object} [options.partialFilterExpression] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options ? Object.assign({}, options) : {};
+
+ const createIndexOperation = new CreateIndexOperation(this, name, fieldOrSpec, options);
+
+ return executeOperation(this.s.topology, createIndexOperation, callback);
+};
+
+/**
+ * Ensures that an index exists, if it does not it creates it
+ * @method
+ * @deprecated since version 2.0
+ * @param {string} name The index name
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.unique=false] Creates an unique index.
+ * @param {boolean} [options.sparse=false] Creates a sparse index.
+ * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
+ * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * @param {number} [options.min] For geospatial indexes set the lower bound for the co-ordinates.
+ * @param {number} [options.max] For geospatial indexes set the high bound for the co-ordinates.
+ * @param {number} [options.v] Specify the format version of the indexes.
+ * @param {number} [options.expireAfterSeconds] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * @param {number} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.ensureIndex = deprecate(function(name, fieldOrSpec, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.s.topology, ensureIndex, [
+ this,
+ name,
+ fieldOrSpec,
+ options,
+ callback
+ ]);
+}, 'Db.ensureIndex is deprecated as of MongoDB version 3.0 / driver version 2.0');
+
+Db.prototype.addChild = function(db) {
+ if (this.s.parentDb) return this.s.parentDb.addChild(db);
+ this.s.children.push(db);
+};
+
+/**
+ * Add a user to the database.
+ * @method
+ * @param {string} username The username.
+ * @param {string} password The password.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {object} [options.customData] Custom data associated with the user (only Mongodb 2.6 or higher)
+ * @param {object[]} [options.roles] Roles associated with the created user (only Mongodb 2.6 or higher)
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.addUser = function(username, password, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // Special case where there is no password ($external users)
+ if (typeof username === 'string' && password != null && typeof password === 'object') {
+ options = password;
+ password = null;
+ }
+
+ const addUserOperation = new AddUserOperation(this, username, password, options);
+
+ return executeOperation(this.s.topology, addUserOperation, callback);
+};
+
+/**
+ * Remove a user from a database
+ * @method
+ * @param {string} username The username.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.removeUser = function(username, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const removeUserOperation = new RemoveUserOperation(this, username, options);
+
+ return executeOperation(this.s.topology, removeUserOperation, callback);
+};
+
+/**
+ * Set the current profiling level of MongoDB
+ *
+ * @param {string} level The new profiling level (off, slow_only, all).
+ * @param {Object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback.
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.setProfilingLevel = function(level, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const setProfilingLevelOperation = new SetProfilingLevelOperation(this, level, options);
+
+ return executeOperation(this.s.topology, setProfilingLevelOperation, callback);
+};
+
+/**
+ * Retrieve the current profiling information for MongoDB
+ *
+ * @param {Object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Query the system.profile collection directly.
+ */
+Db.prototype.profilingInfo = deprecate(function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.s.topology, profilingInfo, [this, options, callback]);
+}, 'Db.profilingInfo is deprecated. Query the system.profile collection directly.');
+
+/**
+ * Retrieve the current profiling Level for MongoDB
+ *
+ * @param {Object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.profilingLevel = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const profilingLevelOperation = new ProfilingLevelOperation(this, options);
+
+ return executeOperation(this.s.topology, profilingLevelOperation, callback);
+};
+
+/**
+ * Retrieves this collections index info.
+ * @method
+ * @param {string} name The name of the collection.
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.full=false] Returns the full raw index information.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {Db~resultCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+Db.prototype.indexInformation = function(name, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ const indexInformationOperation = new IndexInformationOperation(this, name, options);
+
+ return executeOperation(this.s.topology, indexInformationOperation, callback);
+};
+
+/**
+ * Unref all sockets
+ * @method
+ */
+Db.prototype.unref = function() {
+ this.s.topology.unref();
+};
+
+/**
+ * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this database. Will ignore all changes to system collections.
+ * @method
+ * @since 3.1.0
+ * @param {Array} [pipeline] An array of {@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents. This allows for filtering (using $match) and manipulating the change stream documents.
+ * @param {object} [options] Optional settings
+ * @param {string} [options.fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
+ * @param {object} [options.resumeAfter] Specifies the logical starting point for the new change stream. This should be the _id field from a previously returned change stream document.
+ * @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
+ * @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
+ * @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
+ * @param {ReadPreference} [options.readPreference] The read preference. Defaults to the read preference of the database. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
+ * @param {Timestamp} [options.startAtOperationTime] receive change events that occur after the specified timestamp
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @return {ChangeStream} a ChangeStream instance.
+ */
+Db.prototype.watch = function(pipeline, options) {
+ pipeline = pipeline || [];
+ options = options || {};
+
+ // Allow optionally not specifying a pipeline
+ if (!Array.isArray(pipeline)) {
+ options = pipeline;
+ pipeline = [];
+ }
+
+ return new ChangeStream(this, pipeline, options);
+};
+
+/**
+ * Return the db logger
+ * @method
+ * @return {Logger} return the db logger
+ * @ignore
+ */
+Db.prototype.getLogger = function() {
+ return this.s.logger;
+};
+
+/**
+ * Db close event
+ *
+ * Emitted after a socket closed against a single server or mongos proxy.
+ *
+ * @event Db#close
+ * @type {MongoError}
+ */
+
+/**
+ * Db reconnect event
+ *
+ * * Server: Emitted when the driver has reconnected and re-authenticated.
+ * * ReplicaSet: N/A
+ * * Mongos: Emitted when the driver reconnects and re-authenticates successfully against a Mongos.
+ *
+ * @event Db#reconnect
+ * @type {object}
+ */
+
+/**
+ * Db error event
+ *
+ * Emitted after an error occurred against a single server or mongos proxy.
+ *
+ * @event Db#error
+ * @type {MongoError}
+ */
+
+/**
+ * Db timeout event
+ *
+ * Emitted after a socket timeout occurred against a single server or mongos proxy.
+ *
+ * @event Db#timeout
+ * @type {MongoError}
+ */
+
+/**
+ * Db parseError event
+ *
+ * The parseError event is emitted if the driver detects illegal or corrupt BSON being received from the server.
+ *
+ * @event Db#parseError
+ * @type {MongoError}
+ */
+
+/**
+ * Db fullsetup event, emitted when all servers in the topology have been connected to at start up time.
+ *
+ * * Server: Emitted when the driver has connected to the single server and has authenticated.
+ * * ReplSet: Emitted after the driver has attempted to connect to all replicaset members.
+ * * Mongos: Emitted after the driver has attempted to connect to all mongos proxies.
+ *
+ * @event Db#fullsetup
+ * @type {Db}
+ */
+
+// Constants
+Db.SYSTEM_NAMESPACE_COLLECTION = CONSTANTS.SYSTEM_NAMESPACE_COLLECTION;
+Db.SYSTEM_INDEX_COLLECTION = CONSTANTS.SYSTEM_INDEX_COLLECTION;
+Db.SYSTEM_PROFILE_COLLECTION = CONSTANTS.SYSTEM_PROFILE_COLLECTION;
+Db.SYSTEM_USER_COLLECTION = CONSTANTS.SYSTEM_USER_COLLECTION;
+Db.SYSTEM_COMMAND_COLLECTION = CONSTANTS.SYSTEM_COMMAND_COLLECTION;
+Db.SYSTEM_JS_COLLECTION = CONSTANTS.SYSTEM_JS_COLLECTION;
+
+module.exports = Db;
diff --git a/node_modules/mongodb/lib/dynamic_loaders.js b/node_modules/mongodb/lib/dynamic_loaders.js
new file mode 100644
index 0000000..c461002
--- /dev/null
+++ b/node_modules/mongodb/lib/dynamic_loaders.js
@@ -0,0 +1,32 @@
+'use strict';
+
+let collection;
+let cursor;
+let db;
+
+function loadCollection() {
+ if (!collection) {
+ collection = require('./collection');
+ }
+ return collection;
+}
+
+function loadCursor() {
+ if (!cursor) {
+ cursor = require('./cursor');
+ }
+ return cursor;
+}
+
+function loadDb() {
+ if (!db) {
+ db = require('./db');
+ }
+ return db;
+}
+
+module.exports = {
+ loadCollection,
+ loadCursor,
+ loadDb
+};
diff --git a/node_modules/mongodb/lib/error.js b/node_modules/mongodb/lib/error.js
new file mode 100644
index 0000000..4d104e9
--- /dev/null
+++ b/node_modules/mongodb/lib/error.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const MongoNetworkError = require('./core').MongoNetworkError;
+const mongoErrorContextSymbol = require('./core').mongoErrorContextSymbol;
+
+const GET_MORE_NON_RESUMABLE_CODES = new Set([
+ 136, // CappedPositionLost
+ 237, // CursorKilled
+ 11601 // Interrupted
+]);
+
+// From spec@https://github.com/mongodb/specifications/blob/7a2e93d85935ee4b1046a8d2ad3514c657dc74fa/source/change-streams/change-streams.rst#resumable-error:
+//
+// An error is considered resumable if it meets any of the following criteria:
+// - any error encountered which is not a server error (e.g. a timeout error or network error)
+// - any server error response from a getMore command excluding those containing the error label
+// NonRetryableChangeStreamError and those containing the following error codes:
+// - Interrupted: 11601
+// - CappedPositionLost: 136
+// - CursorKilled: 237
+//
+// An error on an aggregate command is not a resumable error. Only errors on a getMore command may be considered resumable errors.
+
+function isGetMoreError(error) {
+ if (error[mongoErrorContextSymbol]) {
+ return error[mongoErrorContextSymbol].isGetMore;
+ }
+}
+
+function isResumableError(error) {
+ if (!isGetMoreError(error)) {
+ return false;
+ }
+
+ if (error instanceof MongoNetworkError) {
+ return true;
+ }
+
+ return !(
+ GET_MORE_NON_RESUMABLE_CODES.has(error.code) ||
+ error.hasErrorLabel('NonRetryableChangeStreamError')
+ );
+}
+
+module.exports = { GET_MORE_NON_RESUMABLE_CODES, isResumableError };
diff --git a/node_modules/mongodb/lib/gridfs-stream/download.js b/node_modules/mongodb/lib/gridfs-stream/download.js
new file mode 100644
index 0000000..2c060fd
--- /dev/null
+++ b/node_modules/mongodb/lib/gridfs-stream/download.js
@@ -0,0 +1,422 @@
+'use strict';
+
+var stream = require('stream'),
+ util = require('util');
+
+module.exports = GridFSBucketReadStream;
+
+/**
+ * A readable stream that enables you to read buffers from GridFS.
+ *
+ * Do not instantiate this class directly. Use `openDownloadStream()` instead.
+ *
+ * @class
+ * @extends external:Readable
+ * @param {Collection} chunks Handle for chunks collection
+ * @param {Collection} files Handle for files collection
+ * @param {Object} readPreference The read preference to use
+ * @param {Object} filter The query to use to find the file document
+ * @param {Object} [options] Optional settings.
+ * @param {Number} [options.sort] Optional sort for the file find query
+ * @param {Number} [options.skip] Optional skip for the file find query
+ * @param {Number} [options.start] Optional 0-based offset in bytes to start streaming from
+ * @param {Number} [options.end] Optional 0-based offset in bytes to stop streaming before
+ * @fires GridFSBucketReadStream#error
+ * @fires GridFSBucketReadStream#file
+ */
+function GridFSBucketReadStream(chunks, files, readPreference, filter, options) {
+ this.s = {
+ bytesRead: 0,
+ chunks: chunks,
+ cursor: null,
+ expected: 0,
+ files: files,
+ filter: filter,
+ init: false,
+ expectedEnd: 0,
+ file: null,
+ options: options,
+ readPreference: readPreference
+ };
+
+ stream.Readable.call(this);
+}
+
+util.inherits(GridFSBucketReadStream, stream.Readable);
+
+/**
+ * An error occurred
+ *
+ * @event GridFSBucketReadStream#error
+ * @type {Error}
+ */
+
+/**
+ * Fires when the stream loaded the file document corresponding to the
+ * provided id.
+ *
+ * @event GridFSBucketReadStream#file
+ * @type {object}
+ */
+
+/**
+ * Emitted when a chunk of data is available to be consumed.
+ *
+ * @event GridFSBucketReadStream#data
+ * @type {object}
+ */
+
+/**
+ * Fired when the stream is exhausted (no more data events).
+ *
+ * @event GridFSBucketReadStream#end
+ * @type {object}
+ */
+
+/**
+ * Fired when the stream is exhausted and the underlying cursor is killed
+ *
+ * @event GridFSBucketReadStream#close
+ * @type {object}
+ */
+
+/**
+ * Reads from the cursor and pushes to the stream.
+ * Private Impl, do not call directly
+ * @ignore
+ * @method
+ */
+
+GridFSBucketReadStream.prototype._read = function() {
+ var _this = this;
+ if (this.destroyed) {
+ return;
+ }
+
+ waitForFile(_this, function() {
+ doRead(_this);
+ });
+};
+
+/**
+ * Sets the 0-based offset in bytes to start streaming from. Throws
+ * an error if this stream has entered flowing mode
+ * (e.g. if you've already called `on('data')`)
+ * @method
+ * @param {Number} start Offset in bytes to start reading at
+ * @return {GridFSBucketReadStream} Reference to Self
+ */
+
+GridFSBucketReadStream.prototype.start = function(start) {
+ throwIfInitialized(this);
+ this.s.options.start = start;
+ return this;
+};
+
+/**
+ * Sets the 0-based offset in bytes to start streaming from. Throws
+ * an error if this stream has entered flowing mode
+ * (e.g. if you've already called `on('data')`)
+ * @method
+ * @param {Number} end Offset in bytes to stop reading at
+ * @return {GridFSBucketReadStream} Reference to self
+ */
+
+GridFSBucketReadStream.prototype.end = function(end) {
+ throwIfInitialized(this);
+ this.s.options.end = end;
+ return this;
+};
+
+/**
+ * Marks this stream as aborted (will never push another `data` event)
+ * and kills the underlying cursor. Will emit the 'end' event, and then
+ * the 'close' event once the cursor is successfully killed.
+ *
+ * @method
+ * @param {GridFSBucket~errorCallback} [callback] called when the cursor is successfully closed or an error occurred.
+ * @fires GridFSBucketWriteStream#close
+ * @fires GridFSBucketWriteStream#end
+ */
+
+GridFSBucketReadStream.prototype.abort = function(callback) {
+ var _this = this;
+ this.push(null);
+ this.destroyed = true;
+ if (this.s.cursor) {
+ this.s.cursor.close(function(error) {
+ _this.emit('close');
+ callback && callback(error);
+ });
+ } else {
+ if (!this.s.init) {
+ // If not initialized, fire close event because we will never
+ // get a cursor
+ _this.emit('close');
+ }
+ callback && callback();
+ }
+};
+
+/**
+ * @ignore
+ */
+
+function throwIfInitialized(self) {
+ if (self.s.init) {
+ throw new Error('You cannot change options after the stream has entered' + 'flowing mode!');
+ }
+}
+
+/**
+ * @ignore
+ */
+
+function doRead(_this) {
+ if (_this.destroyed) {
+ return;
+ }
+
+ _this.s.cursor.next(function(error, doc) {
+ if (_this.destroyed) {
+ return;
+ }
+ if (error) {
+ return __handleError(_this, error);
+ }
+ if (!doc) {
+ _this.push(null);
+
+ process.nextTick(() => {
+ _this.s.cursor.close(function(error) {
+ if (error) {
+ __handleError(_this, error);
+ return;
+ }
+
+ _this.emit('close');
+ });
+ });
+
+ return;
+ }
+
+ var bytesRemaining = _this.s.file.length - _this.s.bytesRead;
+ var expectedN = _this.s.expected++;
+ var expectedLength = Math.min(_this.s.file.chunkSize, bytesRemaining);
+
+ if (doc.n > expectedN) {
+ var errmsg = 'ChunkIsMissing: Got unexpected n: ' + doc.n + ', expected: ' + expectedN;
+ return __handleError(_this, new Error(errmsg));
+ }
+
+ if (doc.n < expectedN) {
+ errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n + ', expected: ' + expectedN;
+ return __handleError(_this, new Error(errmsg));
+ }
+
+ var buf = Buffer.isBuffer(doc.data) ? doc.data : doc.data.buffer;
+
+ if (buf.length !== expectedLength) {
+ if (bytesRemaining <= 0) {
+ errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n;
+ return __handleError(_this, new Error(errmsg));
+ }
+
+ errmsg =
+ 'ChunkIsWrongSize: Got unexpected length: ' + buf.length + ', expected: ' + expectedLength;
+ return __handleError(_this, new Error(errmsg));
+ }
+
+ _this.s.bytesRead += buf.length;
+
+ if (buf.length === 0) {
+ return _this.push(null);
+ }
+
+ var sliceStart = null;
+ var sliceEnd = null;
+
+ if (_this.s.bytesToSkip != null) {
+ sliceStart = _this.s.bytesToSkip;
+ _this.s.bytesToSkip = 0;
+ }
+
+ const atEndOfStream = expectedN === _this.s.expectedEnd - 1;
+ const bytesLeftToRead = _this.s.options.end - _this.s.bytesToSkip;
+ if (atEndOfStream && _this.s.bytesToTrim != null) {
+ sliceEnd = _this.s.file.chunkSize - _this.s.bytesToTrim;
+ } else if (_this.s.options.end && bytesLeftToRead < doc.data.length()) {
+ sliceEnd = bytesLeftToRead;
+ }
+
+ if (sliceStart != null || sliceEnd != null) {
+ buf = buf.slice(sliceStart || 0, sliceEnd || buf.length);
+ }
+
+ _this.push(buf);
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function init(self) {
+ var findOneOptions = {};
+ if (self.s.readPreference) {
+ findOneOptions.readPreference = self.s.readPreference;
+ }
+ if (self.s.options && self.s.options.sort) {
+ findOneOptions.sort = self.s.options.sort;
+ }
+ if (self.s.options && self.s.options.skip) {
+ findOneOptions.skip = self.s.options.skip;
+ }
+
+ self.s.files.findOne(self.s.filter, findOneOptions, function(error, doc) {
+ if (error) {
+ return __handleError(self, error);
+ }
+ if (!doc) {
+ var identifier = self.s.filter._id ? self.s.filter._id.toString() : self.s.filter.filename;
+ var errmsg = 'FileNotFound: file ' + identifier + ' was not found';
+ var err = new Error(errmsg);
+ err.code = 'ENOENT';
+ return __handleError(self, err);
+ }
+
+ // If document is empty, kill the stream immediately and don't
+ // execute any reads
+ if (doc.length <= 0) {
+ self.push(null);
+ return;
+ }
+
+ if (self.destroyed) {
+ // If user destroys the stream before we have a cursor, wait
+ // until the query is done to say we're 'closed' because we can't
+ // cancel a query.
+ self.emit('close');
+ return;
+ }
+
+ self.s.bytesToSkip = handleStartOption(self, doc, self.s.options);
+
+ var filter = { files_id: doc._id };
+
+ // Currently (MongoDB 3.4.4) skip function does not support the index,
+ // it needs to retrieve all the documents first and then skip them. (CS-25811)
+ // As work around we use $gte on the "n" field.
+ if (self.s.options && self.s.options.start != null) {
+ var skip = Math.floor(self.s.options.start / doc.chunkSize);
+ if (skip > 0) {
+ filter['n'] = { $gte: skip };
+ }
+ }
+ self.s.cursor = self.s.chunks.find(filter).sort({ n: 1 });
+
+ if (self.s.readPreference) {
+ self.s.cursor.setReadPreference(self.s.readPreference);
+ }
+
+ self.s.expectedEnd = Math.ceil(doc.length / doc.chunkSize);
+ self.s.file = doc;
+ self.s.bytesToTrim = handleEndOption(self, doc, self.s.cursor, self.s.options);
+ self.emit('file', doc);
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function waitForFile(_this, callback) {
+ if (_this.s.file) {
+ return callback();
+ }
+
+ if (!_this.s.init) {
+ init(_this);
+ _this.s.init = true;
+ }
+
+ _this.once('file', function() {
+ callback();
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function handleStartOption(stream, doc, options) {
+ if (options && options.start != null) {
+ if (options.start > doc.length) {
+ throw new Error(
+ 'Stream start (' +
+ options.start +
+ ') must not be ' +
+ 'more than the length of the file (' +
+ doc.length +
+ ')'
+ );
+ }
+ if (options.start < 0) {
+ throw new Error('Stream start (' + options.start + ') must not be ' + 'negative');
+ }
+ if (options.end != null && options.end < options.start) {
+ throw new Error(
+ 'Stream start (' +
+ options.start +
+ ') must not be ' +
+ 'greater than stream end (' +
+ options.end +
+ ')'
+ );
+ }
+
+ stream.s.bytesRead = Math.floor(options.start / doc.chunkSize) * doc.chunkSize;
+ stream.s.expected = Math.floor(options.start / doc.chunkSize);
+
+ return options.start - stream.s.bytesRead;
+ }
+}
+
+/**
+ * @ignore
+ */
+
+function handleEndOption(stream, doc, cursor, options) {
+ if (options && options.end != null) {
+ if (options.end > doc.length) {
+ throw new Error(
+ 'Stream end (' +
+ options.end +
+ ') must not be ' +
+ 'more than the length of the file (' +
+ doc.length +
+ ')'
+ );
+ }
+ if (options.start < 0) {
+ throw new Error('Stream end (' + options.end + ') must not be ' + 'negative');
+ }
+
+ var start = options.start != null ? Math.floor(options.start / doc.chunkSize) : 0;
+
+ cursor.limit(Math.ceil(options.end / doc.chunkSize) - start);
+
+ stream.s.expectedEnd = Math.ceil(options.end / doc.chunkSize);
+
+ return Math.ceil(options.end / doc.chunkSize) * doc.chunkSize - options.end;
+ }
+}
+
+/**
+ * @ignore
+ */
+
+function __handleError(_this, error) {
+ _this.emit('error', error);
+}
diff --git a/node_modules/mongodb/lib/gridfs-stream/index.js b/node_modules/mongodb/lib/gridfs-stream/index.js
new file mode 100644
index 0000000..6509839
--- /dev/null
+++ b/node_modules/mongodb/lib/gridfs-stream/index.js
@@ -0,0 +1,359 @@
+'use strict';
+
+var Emitter = require('events').EventEmitter;
+var GridFSBucketReadStream = require('./download');
+var GridFSBucketWriteStream = require('./upload');
+var shallowClone = require('../utils').shallowClone;
+var toError = require('../utils').toError;
+var util = require('util');
+var executeLegacyOperation = require('../utils').executeLegacyOperation;
+
+var DEFAULT_GRIDFS_BUCKET_OPTIONS = {
+ bucketName: 'fs',
+ chunkSizeBytes: 255 * 1024
+};
+
+module.exports = GridFSBucket;
+
+/**
+ * Constructor for a streaming GridFS interface
+ * @class
+ * @extends external:EventEmitter
+ * @param {Db} db A db handle
+ * @param {object} [options] Optional settings.
+ * @param {string} [options.bucketName="fs"] The 'files' and 'chunks' collections will be prefixed with the bucket name followed by a dot.
+ * @param {number} [options.chunkSizeBytes=255 * 1024] Number of bytes stored in each chunk. Defaults to 255KB
+ * @param {object} [options.writeConcern] Optional write concern to be passed to write operations, for instance `{ w: 1 }`
+ * @param {object} [options.readPreference] Optional read preference to be passed to read operations
+ * @fires GridFSBucketWriteStream#index
+ */
+
+function GridFSBucket(db, options) {
+ Emitter.apply(this);
+ this.setMaxListeners(0);
+
+ if (options && typeof options === 'object') {
+ options = shallowClone(options);
+ var keys = Object.keys(DEFAULT_GRIDFS_BUCKET_OPTIONS);
+ for (var i = 0; i < keys.length; ++i) {
+ if (!options[keys[i]]) {
+ options[keys[i]] = DEFAULT_GRIDFS_BUCKET_OPTIONS[keys[i]];
+ }
+ }
+ } else {
+ options = DEFAULT_GRIDFS_BUCKET_OPTIONS;
+ }
+
+ this.s = {
+ db: db,
+ options: options,
+ _chunksCollection: db.collection(options.bucketName + '.chunks'),
+ _filesCollection: db.collection(options.bucketName + '.files'),
+ checkedIndexes: false,
+ calledOpenUploadStream: false,
+ promiseLibrary: db.s.promiseLibrary || Promise
+ };
+}
+
+util.inherits(GridFSBucket, Emitter);
+
+/**
+ * When the first call to openUploadStream is made, the upload stream will
+ * check to see if it needs to create the proper indexes on the chunks and
+ * files collections. This event is fired either when 1) it determines that
+ * no index creation is necessary, 2) when it successfully creates the
+ * necessary indexes.
+ *
+ * @event GridFSBucket#index
+ * @type {Error}
+ */
+
+/**
+ * Returns a writable stream (GridFSBucketWriteStream) for writing
+ * buffers to GridFS. The stream's 'id' property contains the resulting
+ * file's id.
+ * @method
+ * @param {string} filename The value of the 'filename' key in the files doc
+ * @param {object} [options] Optional settings.
+ * @param {number} [options.chunkSizeBytes] Optional overwrite this bucket's chunkSizeBytes for this file
+ * @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
+ * @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
+ * @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
+ * @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
+ * @return {GridFSBucketWriteStream}
+ */
+
+GridFSBucket.prototype.openUploadStream = function(filename, options) {
+ if (options) {
+ options = shallowClone(options);
+ } else {
+ options = {};
+ }
+ if (!options.chunkSizeBytes) {
+ options.chunkSizeBytes = this.s.options.chunkSizeBytes;
+ }
+ return new GridFSBucketWriteStream(this, filename, options);
+};
+
+/**
+ * Returns a writable stream (GridFSBucketWriteStream) for writing
+ * buffers to GridFS for a custom file id. The stream's 'id' property contains the resulting
+ * file's id.
+ * @method
+ * @param {string|number|object} id A custom id used to identify the file
+ * @param {string} filename The value of the 'filename' key in the files doc
+ * @param {object} [options] Optional settings.
+ * @param {number} [options.chunkSizeBytes] Optional overwrite this bucket's chunkSizeBytes for this file
+ * @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
+ * @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
+ * @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
+ * @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
+ * @return {GridFSBucketWriteStream}
+ */
+
+GridFSBucket.prototype.openUploadStreamWithId = function(id, filename, options) {
+ if (options) {
+ options = shallowClone(options);
+ } else {
+ options = {};
+ }
+
+ if (!options.chunkSizeBytes) {
+ options.chunkSizeBytes = this.s.options.chunkSizeBytes;
+ }
+
+ options.id = id;
+
+ return new GridFSBucketWriteStream(this, filename, options);
+};
+
+/**
+ * Returns a readable stream (GridFSBucketReadStream) for streaming file
+ * data from GridFS.
+ * @method
+ * @param {ObjectId} id The id of the file doc
+ * @param {Object} [options] Optional settings.
+ * @param {Number} [options.start] Optional 0-based offset in bytes to start streaming from
+ * @param {Number} [options.end] Optional 0-based offset in bytes to stop streaming before
+ * @return {GridFSBucketReadStream}
+ */
+
+GridFSBucket.prototype.openDownloadStream = function(id, options) {
+ var filter = { _id: id };
+ options = {
+ start: options && options.start,
+ end: options && options.end
+ };
+
+ return new GridFSBucketReadStream(
+ this.s._chunksCollection,
+ this.s._filesCollection,
+ this.s.options.readPreference,
+ filter,
+ options
+ );
+};
+
+/**
+ * Deletes a file with the given id
+ * @method
+ * @param {ObjectId} id The id of the file doc
+ * @param {GridFSBucket~errorCallback} [callback]
+ */
+
+GridFSBucket.prototype.delete = function(id, callback) {
+ return executeLegacyOperation(this.s.db.s.topology, _delete, [this, id, callback], {
+ skipSessions: true
+ });
+};
+
+/**
+ * @ignore
+ */
+
+function _delete(_this, id, callback) {
+ _this.s._filesCollection.deleteOne({ _id: id }, function(error, res) {
+ if (error) {
+ return callback(error);
+ }
+
+ _this.s._chunksCollection.deleteMany({ files_id: id }, function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ // Delete orphaned chunks before returning FileNotFound
+ if (!res.result.n) {
+ var errmsg = 'FileNotFound: no file with id ' + id + ' found';
+ return callback(new Error(errmsg));
+ }
+
+ callback();
+ });
+ });
+}
+
+/**
+ * Convenience wrapper around find on the files collection
+ * @method
+ * @param {Object} filter
+ * @param {Object} [options] Optional settings for cursor
+ * @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/find|find command documentation}.
+ * @param {number} [options.limit] Optional limit for cursor
+ * @param {number} [options.maxTimeMS] Optional maxTimeMS for cursor
+ * @param {boolean} [options.noCursorTimeout] Optionally set cursor's `noCursorTimeout` flag
+ * @param {number} [options.skip] Optional skip for cursor
+ * @param {object} [options.sort] Optional sort for cursor
+ * @return {Cursor}
+ */
+
+GridFSBucket.prototype.find = function(filter, options) {
+ filter = filter || {};
+ options = options || {};
+
+ var cursor = this.s._filesCollection.find(filter);
+
+ if (options.batchSize != null) {
+ cursor.batchSize(options.batchSize);
+ }
+ if (options.limit != null) {
+ cursor.limit(options.limit);
+ }
+ if (options.maxTimeMS != null) {
+ cursor.maxTimeMS(options.maxTimeMS);
+ }
+ if (options.noCursorTimeout != null) {
+ cursor.addCursorFlag('noCursorTimeout', options.noCursorTimeout);
+ }
+ if (options.skip != null) {
+ cursor.skip(options.skip);
+ }
+ if (options.sort != null) {
+ cursor.sort(options.sort);
+ }
+
+ return cursor;
+};
+
+/**
+ * Returns a readable stream (GridFSBucketReadStream) for streaming the
+ * file with the given name from GridFS. If there are multiple files with
+ * the same name, this will stream the most recent file with the given name
+ * (as determined by the `uploadDate` field). You can set the `revision`
+ * option to change this behavior.
+ * @method
+ * @param {String} filename The name of the file to stream
+ * @param {Object} [options] Optional settings
+ * @param {number} [options.revision=-1] The revision number relative to the oldest file with the given filename. 0 gets you the oldest file, 1 gets you the 2nd oldest, -1 gets you the newest.
+ * @param {Number} [options.start] Optional 0-based offset in bytes to start streaming from
+ * @param {Number} [options.end] Optional 0-based offset in bytes to stop streaming before
+ * @return {GridFSBucketReadStream}
+ */
+
+GridFSBucket.prototype.openDownloadStreamByName = function(filename, options) {
+ var sort = { uploadDate: -1 };
+ var skip = null;
+ if (options && options.revision != null) {
+ if (options.revision >= 0) {
+ sort = { uploadDate: 1 };
+ skip = options.revision;
+ } else {
+ skip = -options.revision - 1;
+ }
+ }
+
+ var filter = { filename: filename };
+ options = {
+ sort: sort,
+ skip: skip,
+ start: options && options.start,
+ end: options && options.end
+ };
+ return new GridFSBucketReadStream(
+ this.s._chunksCollection,
+ this.s._filesCollection,
+ this.s.options.readPreference,
+ filter,
+ options
+ );
+};
+
+/**
+ * Renames the file with the given _id to the given string
+ * @method
+ * @param {ObjectId} id the id of the file to rename
+ * @param {String} filename new name for the file
+ * @param {GridFSBucket~errorCallback} [callback]
+ */
+
+GridFSBucket.prototype.rename = function(id, filename, callback) {
+ return executeLegacyOperation(this.s.db.s.topology, _rename, [this, id, filename, callback], {
+ skipSessions: true
+ });
+};
+
+/**
+ * @ignore
+ */
+
+function _rename(_this, id, filename, callback) {
+ var filter = { _id: id };
+ var update = { $set: { filename: filename } };
+ _this.s._filesCollection.updateOne(filter, update, function(error, res) {
+ if (error) {
+ return callback(error);
+ }
+ if (!res.result.n) {
+ return callback(toError('File with id ' + id + ' not found'));
+ }
+ callback();
+ });
+}
+
+/**
+ * Removes this bucket's files collection, followed by its chunks collection.
+ * @method
+ * @param {GridFSBucket~errorCallback} [callback]
+ */
+
+GridFSBucket.prototype.drop = function(callback) {
+ return executeLegacyOperation(this.s.db.s.topology, _drop, [this, callback], {
+ skipSessions: true
+ });
+};
+
+/**
+ * Return the db logger
+ * @method
+ * @return {Logger} return the db logger
+ * @ignore
+ */
+GridFSBucket.prototype.getLogger = function() {
+ return this.s.db.s.logger;
+};
+
+/**
+ * @ignore
+ */
+
+function _drop(_this, callback) {
+ _this.s._filesCollection.drop(function(error) {
+ if (error) {
+ return callback(error);
+ }
+ _this.s._chunksCollection.drop(function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ return callback();
+ });
+ });
+}
+
+/**
+ * Callback format for all GridFSBucket methods that can accept a callback.
+ * @callback GridFSBucket~errorCallback
+ * @param {MongoError|undefined} error If present, an error instance representing any errors that occurred
+ * @param {*} result If present, a returned result for the method
+ */
diff --git a/node_modules/mongodb/lib/gridfs-stream/upload.js b/node_modules/mongodb/lib/gridfs-stream/upload.js
new file mode 100644
index 0000000..578949a
--- /dev/null
+++ b/node_modules/mongodb/lib/gridfs-stream/upload.js
@@ -0,0 +1,538 @@
+'use strict';
+
+var core = require('../core');
+var crypto = require('crypto');
+var stream = require('stream');
+var util = require('util');
+var Buffer = require('safe-buffer').Buffer;
+
+var ERROR_NAMESPACE_NOT_FOUND = 26;
+
+module.exports = GridFSBucketWriteStream;
+
+/**
+ * A writable stream that enables you to write buffers to GridFS.
+ *
+ * Do not instantiate this class directly. Use `openUploadStream()` instead.
+ *
+ * @class
+ * @extends external:Writable
+ * @param {GridFSBucket} bucket Handle for this stream's corresponding bucket
+ * @param {string} filename The value of the 'filename' key in the files doc
+ * @param {object} [options] Optional settings.
+ * @param {string|number|object} [options.id] Custom file id for the GridFS file.
+ * @param {number} [options.chunkSizeBytes] The chunk size to use, in bytes
+ * @param {number} [options.w] The write concern
+ * @param {number} [options.wtimeout] The write concern timeout
+ * @param {number} [options.j] The journal write concern
+ * @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
+ * @fires GridFSBucketWriteStream#error
+ * @fires GridFSBucketWriteStream#finish
+ */
+
+function GridFSBucketWriteStream(bucket, filename, options) {
+ options = options || {};
+ this.bucket = bucket;
+ this.chunks = bucket.s._chunksCollection;
+ this.filename = filename;
+ this.files = bucket.s._filesCollection;
+ this.options = options;
+ // Signals the write is all done
+ this.done = false;
+
+ this.id = options.id ? options.id : core.BSON.ObjectId();
+ this.chunkSizeBytes = this.options.chunkSizeBytes;
+ this.bufToStore = Buffer.alloc(this.chunkSizeBytes);
+ this.length = 0;
+ this.md5 = !options.disableMD5 && crypto.createHash('md5');
+ this.n = 0;
+ this.pos = 0;
+ this.state = {
+ streamEnd: false,
+ outstandingRequests: 0,
+ errored: false,
+ aborted: false,
+ promiseLibrary: this.bucket.s.promiseLibrary
+ };
+
+ if (!this.bucket.s.calledOpenUploadStream) {
+ this.bucket.s.calledOpenUploadStream = true;
+
+ var _this = this;
+ checkIndexes(this, function() {
+ _this.bucket.s.checkedIndexes = true;
+ _this.bucket.emit('index');
+ });
+ }
+}
+
+util.inherits(GridFSBucketWriteStream, stream.Writable);
+
+/**
+ * An error occurred
+ *
+ * @event GridFSBucketWriteStream#error
+ * @type {Error}
+ */
+
+/**
+ * `end()` was called and the write stream successfully wrote the file
+ * metadata and all the chunks to MongoDB.
+ *
+ * @event GridFSBucketWriteStream#finish
+ * @type {object}
+ */
+
+/**
+ * Write a buffer to the stream.
+ *
+ * @method
+ * @param {Buffer} chunk Buffer to write
+ * @param {String} encoding Optional encoding for the buffer
+ * @param {GridFSBucket~errorCallback} callback Function to call when the chunk was added to the buffer, or if the entire chunk was persisted to MongoDB if this chunk caused a flush.
+ * @return {Boolean} False if this write required flushing a chunk to MongoDB. True otherwise.
+ */
+
+GridFSBucketWriteStream.prototype.write = function(chunk, encoding, callback) {
+ var _this = this;
+ return waitForIndexes(this, function() {
+ return doWrite(_this, chunk, encoding, callback);
+ });
+};
+
+/**
+ * Places this write stream into an aborted state (all future writes fail)
+ * and deletes all chunks that have already been written.
+ *
+ * @method
+ * @param {GridFSBucket~errorCallback} callback called when chunks are successfully removed or error occurred
+ * @return {Promise} if no callback specified
+ */
+
+GridFSBucketWriteStream.prototype.abort = function(callback) {
+ if (this.state.streamEnd) {
+ var error = new Error('Cannot abort a stream that has already completed');
+ if (typeof callback === 'function') {
+ return callback(error);
+ }
+ return this.state.promiseLibrary.reject(error);
+ }
+ if (this.state.aborted) {
+ error = new Error('Cannot call abort() on a stream twice');
+ if (typeof callback === 'function') {
+ return callback(error);
+ }
+ return this.state.promiseLibrary.reject(error);
+ }
+ this.state.aborted = true;
+ this.chunks.deleteMany({ files_id: this.id }, function(error) {
+ if (typeof callback === 'function') callback(error);
+ });
+};
+
+/**
+ * Tells the stream that no more data will be coming in. The stream will
+ * persist the remaining data to MongoDB, write the files document, and
+ * then emit a 'finish' event.
+ *
+ * @method
+ * @param {Buffer} chunk Buffer to write
+ * @param {String} encoding Optional encoding for the buffer
+ * @param {GridFSBucket~errorCallback} callback Function to call when all files and chunks have been persisted to MongoDB
+ */
+
+GridFSBucketWriteStream.prototype.end = function(chunk, encoding, callback) {
+ var _this = this;
+ if (typeof chunk === 'function') {
+ (callback = chunk), (chunk = null), (encoding = null);
+ } else if (typeof encoding === 'function') {
+ (callback = encoding), (encoding = null);
+ }
+
+ if (checkAborted(this, callback)) {
+ return;
+ }
+ this.state.streamEnd = true;
+
+ if (callback) {
+ this.once('finish', function(result) {
+ callback(null, result);
+ });
+ }
+
+ if (!chunk) {
+ waitForIndexes(this, function() {
+ writeRemnant(_this);
+ });
+ return;
+ }
+
+ this.write(chunk, encoding, function() {
+ writeRemnant(_this);
+ });
+};
+
+/**
+ * @ignore
+ */
+
+function __handleError(_this, error, callback) {
+ if (_this.state.errored) {
+ return;
+ }
+ _this.state.errored = true;
+ if (callback) {
+ return callback(error);
+ }
+ _this.emit('error', error);
+}
+
+/**
+ * @ignore
+ */
+
+function createChunkDoc(filesId, n, data) {
+ return {
+ _id: core.BSON.ObjectId(),
+ files_id: filesId,
+ n: n,
+ data: data
+ };
+}
+
+/**
+ * @ignore
+ */
+
+function checkChunksIndex(_this, callback) {
+ _this.chunks.listIndexes().toArray(function(error, indexes) {
+ if (error) {
+ // Collection doesn't exist so create index
+ if (error.code === ERROR_NAMESPACE_NOT_FOUND) {
+ var index = { files_id: 1, n: 1 };
+ _this.chunks.createIndex(index, { background: false, unique: true }, function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ callback();
+ });
+ return;
+ }
+ return callback(error);
+ }
+
+ var hasChunksIndex = false;
+ indexes.forEach(function(index) {
+ if (index.key) {
+ var keys = Object.keys(index.key);
+ if (keys.length === 2 && index.key.files_id === 1 && index.key.n === 1) {
+ hasChunksIndex = true;
+ }
+ }
+ });
+
+ if (hasChunksIndex) {
+ callback();
+ } else {
+ index = { files_id: 1, n: 1 };
+ var indexOptions = getWriteOptions(_this);
+
+ indexOptions.background = false;
+ indexOptions.unique = true;
+
+ _this.chunks.createIndex(index, indexOptions, function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ callback();
+ });
+ }
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function checkDone(_this, callback) {
+ if (_this.done) return true;
+ if (_this.state.streamEnd && _this.state.outstandingRequests === 0 && !_this.state.errored) {
+ // Set done so we dont' trigger duplicate createFilesDoc
+ _this.done = true;
+ // Create a new files doc
+ var filesDoc = createFilesDoc(
+ _this.id,
+ _this.length,
+ _this.chunkSizeBytes,
+ _this.md5 && _this.md5.digest('hex'),
+ _this.filename,
+ _this.options.contentType,
+ _this.options.aliases,
+ _this.options.metadata
+ );
+
+ if (checkAborted(_this, callback)) {
+ return false;
+ }
+
+ _this.files.insertOne(filesDoc, getWriteOptions(_this), function(error) {
+ if (error) {
+ return __handleError(_this, error, callback);
+ }
+ _this.emit('finish', filesDoc);
+ });
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @ignore
+ */
+
+function checkIndexes(_this, callback) {
+ _this.files.findOne({}, { _id: 1 }, function(error, doc) {
+ if (error) {
+ return callback(error);
+ }
+ if (doc) {
+ return callback();
+ }
+
+ _this.files.listIndexes().toArray(function(error, indexes) {
+ if (error) {
+ // Collection doesn't exist so create index
+ if (error.code === ERROR_NAMESPACE_NOT_FOUND) {
+ var index = { filename: 1, uploadDate: 1 };
+ _this.files.createIndex(index, { background: false }, function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ checkChunksIndex(_this, callback);
+ });
+ return;
+ }
+ return callback(error);
+ }
+
+ var hasFileIndex = false;
+ indexes.forEach(function(index) {
+ var keys = Object.keys(index.key);
+ if (keys.length === 2 && index.key.filename === 1 && index.key.uploadDate === 1) {
+ hasFileIndex = true;
+ }
+ });
+
+ if (hasFileIndex) {
+ checkChunksIndex(_this, callback);
+ } else {
+ index = { filename: 1, uploadDate: 1 };
+
+ var indexOptions = getWriteOptions(_this);
+
+ indexOptions.background = false;
+
+ _this.files.createIndex(index, indexOptions, function(error) {
+ if (error) {
+ return callback(error);
+ }
+
+ checkChunksIndex(_this, callback);
+ });
+ }
+ });
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function createFilesDoc(_id, length, chunkSize, md5, filename, contentType, aliases, metadata) {
+ var ret = {
+ _id: _id,
+ length: length,
+ chunkSize: chunkSize,
+ uploadDate: new Date(),
+ filename: filename
+ };
+
+ if (md5) {
+ ret.md5 = md5;
+ }
+
+ if (contentType) {
+ ret.contentType = contentType;
+ }
+
+ if (aliases) {
+ ret.aliases = aliases;
+ }
+
+ if (metadata) {
+ ret.metadata = metadata;
+ }
+
+ return ret;
+}
+
+/**
+ * @ignore
+ */
+
+function doWrite(_this, chunk, encoding, callback) {
+ if (checkAborted(_this, callback)) {
+ return false;
+ }
+
+ var inputBuf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
+
+ _this.length += inputBuf.length;
+
+ // Input is small enough to fit in our buffer
+ if (_this.pos + inputBuf.length < _this.chunkSizeBytes) {
+ inputBuf.copy(_this.bufToStore, _this.pos);
+ _this.pos += inputBuf.length;
+
+ callback && callback();
+
+ // Note that we reverse the typical semantics of write's return value
+ // to be compatible with node's `.pipe()` function.
+ // True means client can keep writing.
+ return true;
+ }
+
+ // Otherwise, buffer is too big for current chunk, so we need to flush
+ // to MongoDB.
+ var inputBufRemaining = inputBuf.length;
+ var spaceRemaining = _this.chunkSizeBytes - _this.pos;
+ var numToCopy = Math.min(spaceRemaining, inputBuf.length);
+ var outstandingRequests = 0;
+ while (inputBufRemaining > 0) {
+ var inputBufPos = inputBuf.length - inputBufRemaining;
+ inputBuf.copy(_this.bufToStore, _this.pos, inputBufPos, inputBufPos + numToCopy);
+ _this.pos += numToCopy;
+ spaceRemaining -= numToCopy;
+ if (spaceRemaining === 0) {
+ if (_this.md5) {
+ _this.md5.update(_this.bufToStore);
+ }
+ var doc = createChunkDoc(_this.id, _this.n, Buffer.from(_this.bufToStore));
+ ++_this.state.outstandingRequests;
+ ++outstandingRequests;
+
+ if (checkAborted(_this, callback)) {
+ return false;
+ }
+
+ _this.chunks.insertOne(doc, getWriteOptions(_this), function(error) {
+ if (error) {
+ return __handleError(_this, error);
+ }
+ --_this.state.outstandingRequests;
+ --outstandingRequests;
+
+ if (!outstandingRequests) {
+ _this.emit('drain', doc);
+ callback && callback();
+ checkDone(_this);
+ }
+ });
+
+ spaceRemaining = _this.chunkSizeBytes;
+ _this.pos = 0;
+ ++_this.n;
+ }
+ inputBufRemaining -= numToCopy;
+ numToCopy = Math.min(spaceRemaining, inputBufRemaining);
+ }
+
+ // Note that we reverse the typical semantics of write's return value
+ // to be compatible with node's `.pipe()` function.
+ // False means the client should wait for the 'drain' event.
+ return false;
+}
+
+/**
+ * @ignore
+ */
+
+function getWriteOptions(_this) {
+ var obj = {};
+ if (_this.options.writeConcern) {
+ obj.w = _this.options.writeConcern.w;
+ obj.wtimeout = _this.options.writeConcern.wtimeout;
+ obj.j = _this.options.writeConcern.j;
+ }
+ return obj;
+}
+
+/**
+ * @ignore
+ */
+
+function waitForIndexes(_this, callback) {
+ if (_this.bucket.s.checkedIndexes) {
+ return callback(false);
+ }
+
+ _this.bucket.once('index', function() {
+ callback(true);
+ });
+
+ return true;
+}
+
+/**
+ * @ignore
+ */
+
+function writeRemnant(_this, callback) {
+ // Buffer is empty, so don't bother to insert
+ if (_this.pos === 0) {
+ return checkDone(_this, callback);
+ }
+
+ ++_this.state.outstandingRequests;
+
+ // Create a new buffer to make sure the buffer isn't bigger than it needs
+ // to be.
+ var remnant = Buffer.alloc(_this.pos);
+ _this.bufToStore.copy(remnant, 0, 0, _this.pos);
+ if (_this.md5) {
+ _this.md5.update(remnant);
+ }
+ var doc = createChunkDoc(_this.id, _this.n, remnant);
+
+ // If the stream was aborted, do not write remnant
+ if (checkAborted(_this, callback)) {
+ return false;
+ }
+
+ _this.chunks.insertOne(doc, getWriteOptions(_this), function(error) {
+ if (error) {
+ return __handleError(_this, error);
+ }
+ --_this.state.outstandingRequests;
+ checkDone(_this);
+ });
+}
+
+/**
+ * @ignore
+ */
+
+function checkAborted(_this, callback) {
+ if (_this.state.aborted) {
+ if (typeof callback === 'function') {
+ callback(new Error('this stream has been aborted'));
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/node_modules/mongodb/lib/gridfs/chunk.js b/node_modules/mongodb/lib/gridfs/chunk.js
new file mode 100644
index 0000000..d276d72
--- /dev/null
+++ b/node_modules/mongodb/lib/gridfs/chunk.js
@@ -0,0 +1,236 @@
+'use strict';
+
+var Binary = require('../core').BSON.Binary,
+ ObjectID = require('../core').BSON.ObjectID;
+
+var Buffer = require('safe-buffer').Buffer;
+
+/**
+ * Class for representing a single chunk in GridFS.
+ *
+ * @class
+ *
+ * @param file {GridStore} The {@link GridStore} object holding this chunk.
+ * @param mongoObject {object} The mongo object representation of this chunk.
+ *
+ * @throws Error when the type of data field for {@link mongoObject} is not
+ * supported. Currently supported types for data field are instances of
+ * {@link String}, {@link Array}, {@link Binary} and {@link Binary}
+ * from the bson module
+ *
+ * @see Chunk#buildMongoObject
+ */
+var Chunk = function(file, mongoObject, writeConcern) {
+ if (!(this instanceof Chunk)) return new Chunk(file, mongoObject);
+
+ this.file = file;
+ var mongoObjectFinal = mongoObject == null ? {} : mongoObject;
+ this.writeConcern = writeConcern || { w: 1 };
+ this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
+ this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
+ this.data = new Binary();
+
+ if (typeof mongoObjectFinal.data === 'string') {
+ var buffer = Buffer.alloc(mongoObjectFinal.data.length);
+ buffer.write(mongoObjectFinal.data, 0, mongoObjectFinal.data.length, 'binary');
+ this.data = new Binary(buffer);
+ } else if (Array.isArray(mongoObjectFinal.data)) {
+ buffer = Buffer.alloc(mongoObjectFinal.data.length);
+ var data = mongoObjectFinal.data.join('');
+ buffer.write(data, 0, data.length, 'binary');
+ this.data = new Binary(buffer);
+ } else if (mongoObjectFinal.data && mongoObjectFinal.data._bsontype === 'Binary') {
+ this.data = mongoObjectFinal.data;
+ } else if (!Buffer.isBuffer(mongoObjectFinal.data) && !(mongoObjectFinal.data == null)) {
+ throw Error('Illegal chunk format');
+ }
+
+ // Update position
+ this.internalPosition = 0;
+};
+
+/**
+ * Writes a data to this object and advance the read/write head.
+ *
+ * @param data {string} the data to write
+ * @param callback {function(*, GridStore)} This will be called after executing
+ * this method. The first parameter will contain null and the second one
+ * will contain a reference to this object.
+ */
+Chunk.prototype.write = function(data, callback) {
+ this.data.write(data, this.internalPosition, data.length, 'binary');
+ this.internalPosition = this.data.length();
+ if (callback != null) return callback(null, this);
+ return this;
+};
+
+/**
+ * Reads data and advances the read/write head.
+ *
+ * @param length {number} The length of data to read.
+ *
+ * @return {string} The data read if the given length will not exceed the end of
+ * the chunk. Returns an empty String otherwise.
+ */
+Chunk.prototype.read = function(length) {
+ // Default to full read if no index defined
+ length = length == null || length === 0 ? this.length() : length;
+
+ if (this.length() - this.internalPosition + 1 >= length) {
+ var data = this.data.read(this.internalPosition, length);
+ this.internalPosition = this.internalPosition + length;
+ return data;
+ } else {
+ return '';
+ }
+};
+
+Chunk.prototype.readSlice = function(length) {
+ if (this.length() - this.internalPosition >= length) {
+ var data = null;
+ if (this.data.buffer != null) {
+ //Pure BSON
+ data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length);
+ } else {
+ //Native BSON
+ data = Buffer.alloc(length);
+ length = this.data.readInto(data, this.internalPosition);
+ }
+ this.internalPosition = this.internalPosition + length;
+ return data;
+ } else {
+ return null;
+ }
+};
+
+/**
+ * Checks if the read/write head is at the end.
+ *
+ * @return {boolean} Whether the read/write head has reached the end of this
+ * chunk.
+ */
+Chunk.prototype.eof = function() {
+ return this.internalPosition === this.length() ? true : false;
+};
+
+/**
+ * Reads one character from the data of this chunk and advances the read/write
+ * head.
+ *
+ * @return {string} a single character data read if the the read/write head is
+ * not at the end of the chunk. Returns an empty String otherwise.
+ */
+Chunk.prototype.getc = function() {
+ return this.read(1);
+};
+
+/**
+ * Clears the contents of the data in this chunk and resets the read/write head
+ * to the initial position.
+ */
+Chunk.prototype.rewind = function() {
+ this.internalPosition = 0;
+ this.data = new Binary();
+};
+
+/**
+ * Saves this chunk to the database. Also overwrites existing entries having the
+ * same id as this chunk.
+ *
+ * @param callback {function(*, GridStore)} This will be called after executing
+ * this method. The first parameter will contain null and the second one
+ * will contain a reference to this object.
+ */
+Chunk.prototype.save = function(options, callback) {
+ var self = this;
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ self.file.chunkCollection(function(err, collection) {
+ if (err) return callback(err);
+
+ // Merge the options
+ var writeOptions = { upsert: true };
+ for (var name in options) writeOptions[name] = options[name];
+ for (name in self.writeConcern) writeOptions[name] = self.writeConcern[name];
+
+ if (self.data.length() > 0) {
+ self.buildMongoObject(function(mongoObject) {
+ var options = { forceServerObjectId: true };
+ for (var name in self.writeConcern) {
+ options[name] = self.writeConcern[name];
+ }
+
+ collection.replaceOne({ _id: self.objectId }, mongoObject, writeOptions, function(err) {
+ callback(err, self);
+ });
+ });
+ } else {
+ callback(null, self);
+ }
+ // });
+ });
+};
+
+/**
+ * Creates a mongoDB object representation of this chunk.
+ *
+ * @param callback {function(Object)} This will be called after executing this
+ * method. The object will be passed to the first parameter and will have
+ * the structure:
+ *
+ *
+ * {
+ * '_id' : , // {number} id for this chunk
+ * 'files_id' : , // {number} foreign key to the file collection
+ * 'n' : , // {number} chunk number
+ * 'data' : , // {bson#Binary} the chunk data itself
+ * }
+ *
+ *
+ * @see MongoDB GridFS Chunk Object Structure
+ */
+Chunk.prototype.buildMongoObject = function(callback) {
+ var mongoObject = {
+ files_id: this.file.fileId,
+ n: this.chunkNumber,
+ data: this.data
+ };
+ // If we are saving using a specific ObjectId
+ if (this.objectId != null) mongoObject._id = this.objectId;
+
+ callback(mongoObject);
+};
+
+/**
+ * @return {number} the length of the data
+ */
+Chunk.prototype.length = function() {
+ return this.data.length();
+};
+
+/**
+ * The position of the read/write head
+ * @name position
+ * @lends Chunk#
+ * @field
+ */
+Object.defineProperty(Chunk.prototype, 'position', {
+ enumerable: true,
+ get: function() {
+ return this.internalPosition;
+ },
+ set: function(value) {
+ this.internalPosition = value;
+ }
+});
+
+/**
+ * The default chunk size
+ * @constant
+ */
+Chunk.DEFAULT_CHUNK_SIZE = 1024 * 255;
+
+module.exports = Chunk;
diff --git a/node_modules/mongodb/lib/gridfs/grid_store.js b/node_modules/mongodb/lib/gridfs/grid_store.js
new file mode 100644
index 0000000..9d9ff25
--- /dev/null
+++ b/node_modules/mongodb/lib/gridfs/grid_store.js
@@ -0,0 +1,1920 @@
+'use strict';
+
+/**
+ * @fileOverview GridFS is a tool for MongoDB to store files to the database.
+ * Because of the restrictions of the object size the database can hold, a
+ * facility to split a file into several chunks is needed. The {@link GridStore}
+ * class offers a simplified api to interact with files while managing the
+ * chunks of split files behind the scenes. More information about GridFS can be
+ * found here.
+ *
+ * @example
+ * const MongoClient = require('mongodb').MongoClient;
+ * const GridStore = require('mongodb').GridStore;
+ * const ObjectID = require('mongodb').ObjectID;
+ * const test = require('assert');
+ * // Connection url
+ * const url = 'mongodb://localhost:27017';
+ * // Database Name
+ * const dbName = 'test';
+ * // Connect using MongoClient
+ * MongoClient.connect(url, function(err, client) {
+ * const db = client.db(dbName);
+ * const gridStore = new GridStore(db, null, "w");
+ * gridStore.open(function(err, gridStore) {
+ * gridStore.write("hello world!", function(err, gridStore) {
+ * gridStore.close(function(err, result) {
+ * // Let's read the file using object Id
+ * GridStore.read(db, result._id, function(err, data) {
+ * test.equal('hello world!', data);
+ * client.close();
+ * test.done();
+ * });
+ * });
+ * });
+ * });
+ * });
+ */
+const Chunk = require('./chunk');
+const ObjectID = require('../core').BSON.ObjectID;
+const ReadPreference = require('../core').ReadPreference;
+const Buffer = require('safe-buffer').Buffer;
+const fs = require('fs');
+const f = require('util').format;
+const util = require('util');
+const MongoError = require('../core').MongoError;
+const inherits = util.inherits;
+const Duplex = require('stream').Duplex;
+const shallowClone = require('../utils').shallowClone;
+const executeLegacyOperation = require('../utils').executeLegacyOperation;
+const deprecate = require('util').deprecate;
+
+var REFERENCE_BY_FILENAME = 0,
+ REFERENCE_BY_ID = 1;
+
+const deprecationFn = deprecate(() => {},
+'GridStore is deprecated, and will be removed in a future version. Please use GridFSBucket instead');
+
+/**
+ * Namespace provided by the core module
+ * @external Duplex
+ */
+
+/**
+ * Create a new GridStore instance
+ *
+ * Modes
+ * - **"r"** - read only. This is the default mode.
+ * - **"w"** - write in truncate mode. Existing data will be overwritten.
+ *
+ * @class
+ * @param {Db} db A database instance to interact with.
+ * @param {object} [id] optional unique id for this file
+ * @param {string} [filename] optional filename for this file, no unique constrain on the field
+ * @param {string} mode set the mode for this file.
+ * @param {object} [options] Optional settings.
+ * @param {(number|string)} [options.w] The write concern.
+ * @param {number} [options.wtimeout] The write concern timeout.
+ * @param {boolean} [options.j=false] Specify a journal write concern.
+ * @param {boolean} [options.fsync=false] Specify a file sync write concern.
+ * @param {string} [options.root] Root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * @param {string} [options.content_type] MIME type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**.
+ * @param {number} [options.chunk_size=261120] Size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**.
+ * @param {object} [options.metadata] Arbitrary data the user wants to store.
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @property {number} chunkSize Get the gridstore chunk size.
+ * @property {number} md5 The md5 checksum for this file.
+ * @property {number} chunkNumber The current chunk number the gridstore has materialized into memory
+ * @return {GridStore} a GridStore instance.
+ * @deprecated Use GridFSBucket API instead
+ */
+var GridStore = function GridStore(db, id, filename, mode, options) {
+ deprecationFn();
+ if (!(this instanceof GridStore)) return new GridStore(db, id, filename, mode, options);
+ this.db = db;
+
+ // Handle options
+ if (typeof options === 'undefined') options = {};
+ // Handle mode
+ if (typeof mode === 'undefined') {
+ mode = filename;
+ filename = undefined;
+ } else if (typeof mode === 'object') {
+ options = mode;
+ mode = filename;
+ filename = undefined;
+ }
+
+ if (id && id._bsontype === 'ObjectID') {
+ this.referenceBy = REFERENCE_BY_ID;
+ this.fileId = id;
+ this.filename = filename;
+ } else if (typeof filename === 'undefined') {
+ this.referenceBy = REFERENCE_BY_FILENAME;
+ this.filename = id;
+ if (mode.indexOf('w') != null) {
+ this.fileId = new ObjectID();
+ }
+ } else {
+ this.referenceBy = REFERENCE_BY_ID;
+ this.fileId = id;
+ this.filename = filename;
+ }
+
+ // Set up the rest
+ this.mode = mode == null ? 'r' : mode;
+ this.options = options || {};
+
+ // Opened
+ this.isOpen = false;
+
+ // Set the root if overridden
+ this.root =
+ this.options['root'] == null ? GridStore.DEFAULT_ROOT_COLLECTION : this.options['root'];
+ this.position = 0;
+ this.readPreference =
+ this.options.readPreference || db.options.readPreference || ReadPreference.primary;
+ this.writeConcern = _getWriteConcern(db, this.options);
+ // Set default chunk size
+ this.internalChunkSize =
+ this.options['chunkSize'] == null ? Chunk.DEFAULT_CHUNK_SIZE : this.options['chunkSize'];
+
+ // Get the promiseLibrary
+ var promiseLibrary = this.options.promiseLibrary || Promise;
+
+ // Set the promiseLibrary
+ this.promiseLibrary = promiseLibrary;
+
+ Object.defineProperty(this, 'chunkSize', {
+ enumerable: true,
+ get: function() {
+ return this.internalChunkSize;
+ },
+ set: function(value) {
+ if (!(this.mode[0] === 'w' && this.position === 0 && this.uploadDate == null)) {
+ this.internalChunkSize = this.internalChunkSize;
+ } else {
+ this.internalChunkSize = value;
+ }
+ }
+ });
+
+ Object.defineProperty(this, 'md5', {
+ enumerable: true,
+ get: function() {
+ return this.internalMd5;
+ }
+ });
+
+ Object.defineProperty(this, 'chunkNumber', {
+ enumerable: true,
+ get: function() {
+ return this.currentChunk && this.currentChunk.chunkNumber
+ ? this.currentChunk.chunkNumber
+ : null;
+ }
+ });
+};
+
+/**
+ * The callback format for the Gridstore.open method
+ * @callback GridStore~openCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {GridStore} gridStore The GridStore instance if the open method was successful.
+ */
+
+/**
+ * Opens the file from the database and initialize this object. Also creates a
+ * new one if file does not exist.
+ *
+ * @method
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~openCallback} [callback] this will be called after executing this method
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.open = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ if (this.mode !== 'w' && this.mode !== 'w+' && this.mode !== 'r') {
+ throw MongoError.create({ message: 'Illegal mode ' + this.mode, driver: true });
+ }
+
+ return executeLegacyOperation(this.db.s.topology, open, [this, options, callback], {
+ skipSessions: true
+ });
+};
+
+var open = function(self, options, callback) {
+ // Get the write concern
+ var writeConcern = _getWriteConcern(self.db, self.options);
+
+ // If we are writing we need to ensure we have the right indexes for md5's
+ if (self.mode === 'w' || self.mode === 'w+') {
+ // Get files collection
+ var collection = self.collection();
+ // Put index on filename
+ collection.ensureIndex([['filename', 1]], writeConcern, function() {
+ // Get chunk collection
+ var chunkCollection = self.chunkCollection();
+ // Make an unique index for compatibility with mongo-cxx-driver:legacy
+ var chunkIndexOptions = shallowClone(writeConcern);
+ chunkIndexOptions.unique = true;
+ // Ensure index on chunk collection
+ chunkCollection.ensureIndex(
+ [
+ ['files_id', 1],
+ ['n', 1]
+ ],
+ chunkIndexOptions,
+ function() {
+ // Open the connection
+ _open(self, writeConcern, function(err, r) {
+ if (err) return callback(err);
+ self.isOpen = true;
+ callback(err, r);
+ });
+ }
+ );
+ });
+ } else {
+ // Open the gridstore
+ _open(self, writeConcern, function(err, r) {
+ if (err) return callback(err);
+ self.isOpen = true;
+ callback(err, r);
+ });
+ }
+};
+
+/**
+ * Verify if the file is at EOF.
+ *
+ * @method
+ * @return {boolean} true if the read/write head is at the end of this file.
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.eof = function() {
+ return this.position === this.length ? true : false;
+};
+
+/**
+ * The callback result format.
+ * @callback GridStore~resultCallback
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {object} result The result from the callback.
+ */
+
+/**
+ * Retrieves a single character from this file.
+ *
+ * @method
+ * @param {GridStore~resultCallback} [callback] this gets called after this method is executed. Passes null to the first parameter and the character read to the second or null to the second if the read/write head is at the end of the file.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.getc = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.db.s.topology, getc, [this, options, callback], {
+ skipSessions: true
+ });
+};
+
+var getc = function(self, options, callback) {
+ if (self.eof()) {
+ callback(null, null);
+ } else if (self.currentChunk.eof()) {
+ nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) {
+ self.currentChunk = chunk;
+ self.position = self.position + 1;
+ callback(err, self.currentChunk.getc());
+ });
+ } else {
+ self.position = self.position + 1;
+ callback(null, self.currentChunk.getc());
+ }
+};
+
+/**
+ * Writes a string to the file with a newline character appended at the end if
+ * the given string does not have one.
+ *
+ * @method
+ * @param {string} string the string to write.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.puts = function(string, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ var finalString = string.match(/\n$/) == null ? string + '\n' : string;
+ return executeLegacyOperation(
+ this.db.s.topology,
+ this.write.bind(this),
+ [finalString, options, callback],
+ { skipSessions: true }
+ );
+};
+
+/**
+ * Return a modified Readable stream including a possible transform method.
+ *
+ * @method
+ * @return {GridStoreStream}
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.stream = function() {
+ return new GridStoreStream(this);
+};
+
+/**
+ * Writes some data. This method will work properly only if initialized with mode "w" or "w+".
+ *
+ * @method
+ * @param {(string|Buffer)} data the data to write.
+ * @param {boolean} [close] closes this file after writing if set to true.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.write = function write(data, close, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(
+ this.db.s.topology,
+ _writeNormal,
+ [this, data, close, options, callback],
+ { skipSessions: true }
+ );
+};
+
+/**
+ * Handles the destroy part of a stream
+ *
+ * @method
+ * @result {null}
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.destroy = function destroy() {
+ // close and do not emit any more events. queued data is not sent.
+ if (!this.writable) return;
+ this.readable = false;
+ if (this.writable) {
+ this.writable = false;
+ this._q.length = 0;
+ this.emit('close');
+ }
+};
+
+/**
+ * Stores a file from the file system to the GridFS database.
+ *
+ * @method
+ * @param {(string|Buffer|FileHandle)} file the file to store.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.writeFile = function(file, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.db.s.topology, writeFile, [this, file, options, callback], {
+ skipSessions: true
+ });
+};
+
+var writeFile = function(self, file, options, callback) {
+ if (typeof file === 'string') {
+ fs.open(file, 'r', function(err, fd) {
+ if (err) return callback(err);
+ self.writeFile(fd, callback);
+ });
+ return;
+ }
+
+ self.open(function(err, self) {
+ if (err) return callback(err, self);
+
+ fs.fstat(file, function(err, stats) {
+ if (err) return callback(err, self);
+
+ var offset = 0;
+ var index = 0;
+
+ // Write a chunk
+ var writeChunk = function() {
+ // Allocate the buffer
+ var _buffer = Buffer.alloc(self.chunkSize);
+ // Read the file
+ fs.read(file, _buffer, 0, _buffer.length, offset, function(err, bytesRead, data) {
+ if (err) return callback(err, self);
+
+ offset = offset + bytesRead;
+
+ // Create a new chunk for the data
+ var chunk = new Chunk(self, { n: index++ }, self.writeConcern);
+ chunk.write(data.slice(0, bytesRead), function(err, chunk) {
+ if (err) return callback(err, self);
+
+ chunk.save({}, function(err) {
+ if (err) return callback(err, self);
+
+ self.position = self.position + bytesRead;
+
+ // Point to current chunk
+ self.currentChunk = chunk;
+
+ if (offset >= stats.size) {
+ fs.close(file, function(err) {
+ if (err) return callback(err);
+
+ self.close(function(err) {
+ if (err) return callback(err, self);
+ return callback(null, self);
+ });
+ });
+ } else {
+ return process.nextTick(writeChunk);
+ }
+ });
+ });
+ });
+ };
+
+ // Process the first write
+ process.nextTick(writeChunk);
+ });
+ });
+};
+
+/**
+ * Saves this file to the database. This will overwrite the old entry if it
+ * already exists. This will work properly only if mode was initialized to
+ * "w" or "w+".
+ *
+ * @method
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.close = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.db.s.topology, close, [this, options, callback], {
+ skipSessions: true
+ });
+};
+
+var close = function(self, options, callback) {
+ if (self.mode[0] === 'w') {
+ // Set up options
+ options = Object.assign({}, self.writeConcern, options);
+
+ if (self.currentChunk != null && self.currentChunk.position > 0) {
+ self.currentChunk.save({}, function(err) {
+ if (err && typeof callback === 'function') return callback(err);
+
+ self.collection(function(err, files) {
+ if (err && typeof callback === 'function') return callback(err);
+
+ // Build the mongo object
+ if (self.uploadDate != null) {
+ buildMongoObject(self, function(err, mongoObject) {
+ if (err) {
+ if (typeof callback === 'function') return callback(err);
+ else throw err;
+ }
+
+ files.save(mongoObject, options, function(err) {
+ if (typeof callback === 'function') callback(err, mongoObject);
+ });
+ });
+ } else {
+ self.uploadDate = new Date();
+ buildMongoObject(self, function(err, mongoObject) {
+ if (err) {
+ if (typeof callback === 'function') return callback(err);
+ else throw err;
+ }
+
+ files.save(mongoObject, options, function(err) {
+ if (typeof callback === 'function') callback(err, mongoObject);
+ });
+ });
+ }
+ });
+ });
+ } else {
+ self.collection(function(err, files) {
+ if (err && typeof callback === 'function') return callback(err);
+
+ self.uploadDate = new Date();
+ buildMongoObject(self, function(err, mongoObject) {
+ if (err) {
+ if (typeof callback === 'function') return callback(err);
+ else throw err;
+ }
+
+ files.save(mongoObject, options, function(err) {
+ if (typeof callback === 'function') callback(err, mongoObject);
+ });
+ });
+ });
+ }
+ } else if (self.mode[0] === 'r') {
+ if (typeof callback === 'function') callback(null, null);
+ } else {
+ if (typeof callback === 'function')
+ callback(MongoError.create({ message: f('Illegal mode %s', self.mode), driver: true }));
+ }
+};
+
+/**
+ * The collection callback format.
+ * @callback GridStore~collectionCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {Collection} collection The collection from the command execution.
+ */
+
+/**
+ * Retrieve this file's chunks collection.
+ *
+ * @method
+ * @param {GridStore~collectionCallback} callback the command callback.
+ * @return {Collection}
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.chunkCollection = function(callback) {
+ if (typeof callback === 'function') return this.db.collection(this.root + '.chunks', callback);
+ return this.db.collection(this.root + '.chunks');
+};
+
+/**
+ * Deletes all the chunks of this file in the database.
+ *
+ * @method
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.unlink = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.db.s.topology, unlink, [this, options, callback], {
+ skipSessions: true
+ });
+};
+
+var unlink = function(self, options, callback) {
+ deleteChunks(self, function(err) {
+ if (err !== null) {
+ err.message = 'at deleteChunks: ' + err.message;
+ return callback(err);
+ }
+
+ self.collection(function(err, collection) {
+ if (err !== null) {
+ err.message = 'at collection: ' + err.message;
+ return callback(err);
+ }
+
+ collection.remove({ _id: self.fileId }, self.writeConcern, function(err) {
+ callback(err, self);
+ });
+ });
+ });
+};
+
+/**
+ * Retrieves the file collection associated with this object.
+ *
+ * @method
+ * @param {GridStore~collectionCallback} callback the command callback.
+ * @return {Collection}
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.collection = function(callback) {
+ if (typeof callback === 'function') this.db.collection(this.root + '.files', callback);
+ return this.db.collection(this.root + '.files');
+};
+
+/**
+ * The readlines callback format.
+ * @callback GridStore~readlinesCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {string[]} strings The array of strings returned.
+ */
+
+/**
+ * Read the entire file as a list of strings splitting by the provided separator.
+ *
+ * @method
+ * @param {string} [separator] The character to be recognized as the newline separator.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~readlinesCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.readlines = function(separator, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ separator = args.length ? args.shift() : '\n';
+ separator = separator || '\n';
+ options = args.length ? args.shift() : {};
+
+ return executeLegacyOperation(
+ this.db.s.topology,
+ readlines,
+ [this, separator, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var readlines = function(self, separator, options, callback) {
+ self.read(function(err, data) {
+ if (err) return callback(err);
+
+ var items = data.toString().split(separator);
+ items = items.length > 0 ? items.splice(0, items.length - 1) : [];
+ for (var i = 0; i < items.length; i++) {
+ items[i] = items[i] + separator;
+ }
+
+ callback(null, items);
+ });
+};
+
+/**
+ * Deletes all the chunks of this file in the database if mode was set to "w" or
+ * "w+" and resets the read/write head to the initial position.
+ *
+ * @method
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.rewind = function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ return executeLegacyOperation(this.db.s.topology, rewind, [this, options, callback], {
+ skipSessions: true
+ });
+};
+
+var rewind = function(self, options, callback) {
+ if (self.currentChunk.chunkNumber !== 0) {
+ if (self.mode[0] === 'w') {
+ deleteChunks(self, function(err) {
+ if (err) return callback(err);
+ self.currentChunk = new Chunk(self, { n: 0 }, self.writeConcern);
+ self.position = 0;
+ callback(null, self);
+ });
+ } else {
+ self.currentChunk(0, function(err, chunk) {
+ if (err) return callback(err);
+ self.currentChunk = chunk;
+ self.currentChunk.rewind();
+ self.position = 0;
+ callback(null, self);
+ });
+ }
+ } else {
+ self.currentChunk.rewind();
+ self.position = 0;
+ callback(null, self);
+ }
+};
+
+/**
+ * The read callback format.
+ * @callback GridStore~readCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {Buffer} data The data read from the GridStore object
+ */
+
+/**
+ * Retrieves the contents of this file and advances the read/write head. Works with Buffers only.
+ *
+ * There are 3 signatures for this method:
+ *
+ * (callback)
+ * (length, callback)
+ * (length, buffer, callback)
+ *
+ * @method
+ * @param {number} [length] the number of characters to read. Reads all the characters from the read/write head to the EOF if not specified.
+ * @param {(string|Buffer)} [buffer] a string to hold temporary data. This is used for storing the string data read so far when recursively calling this method.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~readCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.read = function(length, buffer, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ length = args.length ? args.shift() : null;
+ buffer = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+
+ return executeLegacyOperation(
+ this.db.s.topology,
+ read,
+ [this, length, buffer, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var read = function(self, length, buffer, options, callback) {
+ // The data is a c-terminated string and thus the length - 1
+ var finalLength = length == null ? self.length - self.position : length;
+ var finalBuffer = buffer == null ? Buffer.alloc(finalLength) : buffer;
+ // Add a index to buffer to keep track of writing position or apply current index
+ finalBuffer._index = buffer != null && buffer._index != null ? buffer._index : 0;
+
+ if (self.currentChunk.length() - self.currentChunk.position + finalBuffer._index >= finalLength) {
+ var slice = self.currentChunk.readSlice(finalLength - finalBuffer._index);
+ // Copy content to final buffer
+ slice.copy(finalBuffer, finalBuffer._index);
+ // Update internal position
+ self.position = self.position + finalBuffer.length;
+ // Check if we don't have a file at all
+ if (finalLength === 0 && finalBuffer.length === 0)
+ return callback(MongoError.create({ message: 'File does not exist', driver: true }), null);
+ // Else return data
+ return callback(null, finalBuffer);
+ }
+
+ // Read the next chunk
+ slice = self.currentChunk.readSlice(self.currentChunk.length() - self.currentChunk.position);
+ // Copy content to final buffer
+ slice.copy(finalBuffer, finalBuffer._index);
+ // Update index position
+ finalBuffer._index += slice.length;
+
+ // Load next chunk and read more
+ nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) {
+ if (err) return callback(err);
+
+ if (chunk.length() > 0) {
+ self.currentChunk = chunk;
+ self.read(length, finalBuffer, callback);
+ } else {
+ if (finalBuffer._index > 0) {
+ callback(null, finalBuffer);
+ } else {
+ callback(
+ MongoError.create({
+ message: 'no chunks found for file, possibly corrupt',
+ driver: true
+ }),
+ null
+ );
+ }
+ }
+ });
+};
+
+/**
+ * The tell callback format.
+ * @callback GridStore~tellCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {number} position The current read position in the GridStore.
+ */
+
+/**
+ * Retrieves the position of the read/write head of this file.
+ *
+ * @method
+ * @param {number} [length] the number of characters to read. Reads all the characters from the read/write head to the EOF if not specified.
+ * @param {(string|Buffer)} [buffer] a string to hold temporary data. This is used for storing the string data read so far when recursively calling this method.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~tellCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.tell = function(callback) {
+ var self = this;
+ // We provided a callback leg
+ if (typeof callback === 'function') return callback(null, this.position);
+ // Return promise
+ return new self.promiseLibrary(function(resolve) {
+ resolve(self.position);
+ });
+};
+
+/**
+ * The tell callback format.
+ * @callback GridStore~gridStoreCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {GridStore} gridStore The gridStore.
+ */
+
+/**
+ * Moves the read/write head to a new location.
+ *
+ * There are 3 signatures for this method
+ *
+ * Seek Location Modes
+ * - **GridStore.IO_SEEK_SET**, **(default)** set the position from the start of the file.
+ * - **GridStore.IO_SEEK_CUR**, set the position from the current position in the file.
+ * - **GridStore.IO_SEEK_END**, set the position from the end of the file.
+ *
+ * @method
+ * @param {number} [position] the position to seek to
+ * @param {number} [seekLocation] seek mode. Use one of the Seek Location modes.
+ * @param {object} [options] Optional settings
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~gridStoreCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.prototype.seek = function(position, seekLocation, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ seekLocation = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+
+ return executeLegacyOperation(
+ this.db.s.topology,
+ seek,
+ [this, position, seekLocation, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var seek = function(self, position, seekLocation, options, callback) {
+ // Seek only supports read mode
+ if (self.mode !== 'r') {
+ return callback(
+ MongoError.create({ message: 'seek is only supported for mode r', driver: true })
+ );
+ }
+
+ var seekLocationFinal = seekLocation == null ? GridStore.IO_SEEK_SET : seekLocation;
+ var finalPosition = position;
+ var targetPosition = 0;
+
+ // Calculate the position
+ if (seekLocationFinal === GridStore.IO_SEEK_CUR) {
+ targetPosition = self.position + finalPosition;
+ } else if (seekLocationFinal === GridStore.IO_SEEK_END) {
+ targetPosition = self.length + finalPosition;
+ } else {
+ targetPosition = finalPosition;
+ }
+
+ // Get the chunk
+ var newChunkNumber = Math.floor(targetPosition / self.chunkSize);
+ var seekChunk = function() {
+ nthChunk(self, newChunkNumber, function(err, chunk) {
+ if (err) return callback(err, null);
+ if (chunk == null) return callback(new Error('no chunk found'));
+
+ // Set the current chunk
+ self.currentChunk = chunk;
+ self.position = targetPosition;
+ self.currentChunk.position = self.position % self.chunkSize;
+ callback(err, self);
+ });
+ };
+
+ seekChunk();
+};
+
+/**
+ * @ignore
+ */
+var _open = function(self, options, callback) {
+ var collection = self.collection();
+ // Create the query
+ var query =
+ self.referenceBy === REFERENCE_BY_ID ? { _id: self.fileId } : { filename: self.filename };
+ query = null == self.fileId && self.filename == null ? null : query;
+ options.readPreference = self.readPreference;
+
+ // Fetch the chunks
+ if (query != null) {
+ collection.findOne(query, options, function(err, doc) {
+ if (err) {
+ return error(err);
+ }
+
+ // Check if the collection for the files exists otherwise prepare the new one
+ if (doc != null) {
+ self.fileId = doc._id;
+ // Prefer a new filename over the existing one if this is a write
+ self.filename =
+ self.mode === 'r' || self.filename === undefined ? doc.filename : self.filename;
+ self.contentType = doc.contentType;
+ self.internalChunkSize = doc.chunkSize;
+ self.uploadDate = doc.uploadDate;
+ self.aliases = doc.aliases;
+ self.length = doc.length;
+ self.metadata = doc.metadata;
+ self.internalMd5 = doc.md5;
+ } else if (self.mode !== 'r') {
+ self.fileId = self.fileId == null ? new ObjectID() : self.fileId;
+ self.contentType = GridStore.DEFAULT_CONTENT_TYPE;
+ self.internalChunkSize =
+ self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize;
+ self.length = 0;
+ } else {
+ self.length = 0;
+ var txtId = self.fileId._bsontype === 'ObjectID' ? self.fileId.toHexString() : self.fileId;
+ return error(
+ MongoError.create({
+ message: f(
+ 'file with id %s not opened for writing',
+ self.referenceBy === REFERENCE_BY_ID ? txtId : self.filename
+ ),
+ driver: true
+ }),
+ self
+ );
+ }
+
+ // Process the mode of the object
+ if (self.mode === 'r') {
+ nthChunk(self, 0, options, function(err, chunk) {
+ if (err) return error(err);
+ self.currentChunk = chunk;
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if (self.mode === 'w' && doc) {
+ // Delete any existing chunks
+ deleteChunks(self, options, function(err) {
+ if (err) return error(err);
+ self.currentChunk = new Chunk(self, { n: 0 }, self.writeConcern);
+ self.contentType =
+ self.options['content_type'] == null ? self.contentType : self.options['content_type'];
+ self.internalChunkSize =
+ self.options['chunk_size'] == null
+ ? self.internalChunkSize
+ : self.options['chunk_size'];
+ self.metadata =
+ self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.aliases = self.options['aliases'] == null ? self.aliases : self.options['aliases'];
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if (self.mode === 'w') {
+ self.currentChunk = new Chunk(self, { n: 0 }, self.writeConcern);
+ self.contentType =
+ self.options['content_type'] == null ? self.contentType : self.options['content_type'];
+ self.internalChunkSize =
+ self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.aliases = self.options['aliases'] == null ? self.aliases : self.options['aliases'];
+ self.position = 0;
+ callback(null, self);
+ } else if (self.mode === 'w+') {
+ nthChunk(self, lastChunkNumber(self), options, function(err, chunk) {
+ if (err) return error(err);
+ // Set the current chunk
+ self.currentChunk = chunk == null ? new Chunk(self, { n: 0 }, self.writeConcern) : chunk;
+ self.currentChunk.position = self.currentChunk.data.length();
+ self.metadata =
+ self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.aliases = self.options['aliases'] == null ? self.aliases : self.options['aliases'];
+ self.position = self.length;
+ callback(null, self);
+ });
+ }
+ });
+ } else {
+ // Write only mode
+ self.fileId = null == self.fileId ? new ObjectID() : self.fileId;
+ self.contentType = GridStore.DEFAULT_CONTENT_TYPE;
+ self.internalChunkSize =
+ self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize;
+ self.length = 0;
+
+ // No file exists set up write mode
+ if (self.mode === 'w') {
+ // Delete any existing chunks
+ deleteChunks(self, options, function(err) {
+ if (err) return error(err);
+ self.currentChunk = new Chunk(self, { n: 0 }, self.writeConcern);
+ self.contentType =
+ self.options['content_type'] == null ? self.contentType : self.options['content_type'];
+ self.internalChunkSize =
+ self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.aliases = self.options['aliases'] == null ? self.aliases : self.options['aliases'];
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if (self.mode === 'w+') {
+ nthChunk(self, lastChunkNumber(self), options, function(err, chunk) {
+ if (err) return error(err);
+ // Set the current chunk
+ self.currentChunk = chunk == null ? new Chunk(self, { n: 0 }, self.writeConcern) : chunk;
+ self.currentChunk.position = self.currentChunk.data.length();
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.aliases = self.options['aliases'] == null ? self.aliases : self.options['aliases'];
+ self.position = self.length;
+ callback(null, self);
+ });
+ }
+ }
+
+ // only pass error to callback once
+ function error(err) {
+ if (error.err) return;
+ callback((error.err = err));
+ }
+};
+
+/**
+ * @ignore
+ */
+var writeBuffer = function(self, buffer, close, callback) {
+ if (typeof close === 'function') {
+ callback = close;
+ close = null;
+ }
+ var finalClose = typeof close === 'boolean' ? close : false;
+
+ if (self.mode !== 'w') {
+ callback(
+ MongoError.create({
+ message: f(
+ 'file with id %s not opened for writing',
+ self.referenceBy === REFERENCE_BY_ID ? self.referenceBy : self.filename
+ ),
+ driver: true
+ }),
+ null
+ );
+ } else {
+ if (self.currentChunk.position + buffer.length >= self.chunkSize) {
+ // Write out the current Chunk and then keep writing until we have less data left than a chunkSize left
+ // to a new chunk (recursively)
+ var previousChunkNumber = self.currentChunk.chunkNumber;
+ var leftOverDataSize = self.chunkSize - self.currentChunk.position;
+ var firstChunkData = buffer.slice(0, leftOverDataSize);
+ var leftOverData = buffer.slice(leftOverDataSize);
+ // A list of chunks to write out
+ var chunksToWrite = [self.currentChunk.write(firstChunkData)];
+ // If we have more data left than the chunk size let's keep writing new chunks
+ while (leftOverData.length >= self.chunkSize) {
+ // Create a new chunk and write to it
+ var newChunk = new Chunk(self, { n: previousChunkNumber + 1 }, self.writeConcern);
+ firstChunkData = leftOverData.slice(0, self.chunkSize);
+ leftOverData = leftOverData.slice(self.chunkSize);
+ // Update chunk number
+ previousChunkNumber = previousChunkNumber + 1;
+ // Write data
+ newChunk.write(firstChunkData);
+ // Push chunk to save list
+ chunksToWrite.push(newChunk);
+ }
+
+ // Set current chunk with remaining data
+ self.currentChunk = new Chunk(self, { n: previousChunkNumber + 1 }, self.writeConcern);
+ // If we have left over data write it
+ if (leftOverData.length > 0) self.currentChunk.write(leftOverData);
+
+ // Update the position for the gridstore
+ self.position = self.position + buffer.length;
+ // Total number of chunks to write
+ var numberOfChunksToWrite = chunksToWrite.length;
+
+ for (var i = 0; i < chunksToWrite.length; i++) {
+ chunksToWrite[i].save({}, function(err) {
+ if (err) return callback(err);
+
+ numberOfChunksToWrite = numberOfChunksToWrite - 1;
+
+ if (numberOfChunksToWrite <= 0) {
+ // We care closing the file before returning
+ if (finalClose) {
+ return self.close(function(err) {
+ callback(err, self);
+ });
+ }
+
+ // Return normally
+ return callback(null, self);
+ }
+ });
+ }
+ } else {
+ // Update the position for the gridstore
+ self.position = self.position + buffer.length;
+ // We have less data than the chunk size just write it and callback
+ self.currentChunk.write(buffer);
+ // We care closing the file before returning
+ if (finalClose) {
+ return self.close(function(err) {
+ callback(err, self);
+ });
+ }
+ // Return normally
+ return callback(null, self);
+ }
+ }
+};
+
+/**
+ * Creates a mongoDB object representation of this object.
+ *
+ *
+ * {
+ * '_id' : , // {number} id for this file
+ * 'filename' : , // {string} name for this file
+ * 'contentType' : , // {string} mime type for this file
+ * 'length' : , // {number} size of this file?
+ * 'chunksize' : , // {number} chunk size used by this file
+ * 'uploadDate' : , // {Date}
+ * 'aliases' : , // {array of string}
+ * 'metadata' : , // {string}
+ * }
+ *
+ *
+ * @ignore
+ */
+var buildMongoObject = function(self, callback) {
+ // Calcuate the length
+ var mongoObject = {
+ _id: self.fileId,
+ filename: self.filename,
+ contentType: self.contentType,
+ length: self.position ? self.position : 0,
+ chunkSize: self.chunkSize,
+ uploadDate: self.uploadDate,
+ aliases: self.aliases,
+ metadata: self.metadata
+ };
+
+ var md5Command = { filemd5: self.fileId, root: self.root };
+ self.db.command(md5Command, function(err, results) {
+ if (err) return callback(err);
+
+ mongoObject.md5 = results.md5;
+ callback(null, mongoObject);
+ });
+};
+
+/**
+ * Gets the nth chunk of this file.
+ * @ignore
+ */
+var nthChunk = function(self, chunkNumber, options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || self.writeConcern;
+ options.readPreference = self.readPreference;
+ // Get the nth chunk
+ self
+ .chunkCollection()
+ .findOne({ files_id: self.fileId, n: chunkNumber }, options, function(err, chunk) {
+ if (err) return callback(err);
+
+ var finalChunk = chunk == null ? {} : chunk;
+ callback(null, new Chunk(self, finalChunk, self.writeConcern));
+ });
+};
+
+/**
+ * @ignore
+ */
+var lastChunkNumber = function(self) {
+ return Math.floor((self.length ? self.length - 1 : 0) / self.chunkSize);
+};
+
+/**
+ * Deletes all the chunks of this file in the database.
+ *
+ * @ignore
+ */
+var deleteChunks = function(self, options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ options = options || self.writeConcern;
+
+ if (self.fileId != null) {
+ self.chunkCollection().remove({ files_id: self.fileId }, options, function(err) {
+ if (err) return callback(err, false);
+ callback(null, true);
+ });
+ } else {
+ callback(null, true);
+ }
+};
+
+/**
+ * The collection to be used for holding the files and chunks collection.
+ *
+ * @classconstant DEFAULT_ROOT_COLLECTION
+ */
+GridStore.DEFAULT_ROOT_COLLECTION = 'fs';
+
+/**
+ * Default file mime type
+ *
+ * @classconstant DEFAULT_CONTENT_TYPE
+ */
+GridStore.DEFAULT_CONTENT_TYPE = 'binary/octet-stream';
+
+/**
+ * Seek mode where the given length is absolute.
+ *
+ * @classconstant IO_SEEK_SET
+ */
+GridStore.IO_SEEK_SET = 0;
+
+/**
+ * Seek mode where the given length is an offset to the current read/write head.
+ *
+ * @classconstant IO_SEEK_CUR
+ */
+GridStore.IO_SEEK_CUR = 1;
+
+/**
+ * Seek mode where the given length is an offset to the end of the file.
+ *
+ * @classconstant IO_SEEK_END
+ */
+GridStore.IO_SEEK_END = 2;
+
+/**
+ * Checks if a file exists in the database.
+ *
+ * @method
+ * @static
+ * @param {Db} db the database to query.
+ * @param {string} name The name of the file to look for.
+ * @param {string} [rootCollection] The root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] result from exists.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.exist = function(db, fileIdObject, rootCollection, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ rootCollection = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+ options = options || {};
+
+ return executeLegacyOperation(
+ db.s.topology,
+ exists,
+ [db, fileIdObject, rootCollection, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var exists = function(db, fileIdObject, rootCollection, options, callback) {
+ // Establish read preference
+ var readPreference = options.readPreference || ReadPreference.PRIMARY;
+ // Fetch collection
+ var rootCollectionFinal =
+ rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
+ db.collection(rootCollectionFinal + '.files', function(err, collection) {
+ if (err) return callback(err);
+
+ // Build query
+ var query =
+ typeof fileIdObject === 'string' ||
+ Object.prototype.toString.call(fileIdObject) === '[object RegExp]'
+ ? { filename: fileIdObject }
+ : { _id: fileIdObject }; // Attempt to locate file
+
+ // We have a specific query
+ if (
+ fileIdObject != null &&
+ typeof fileIdObject === 'object' &&
+ Object.prototype.toString.call(fileIdObject) !== '[object RegExp]'
+ ) {
+ query = fileIdObject;
+ }
+
+ // Check if the entry exists
+ collection.findOne(query, { readPreference: readPreference }, function(err, item) {
+ if (err) return callback(err);
+ callback(null, item == null ? false : true);
+ });
+ });
+};
+
+/**
+ * Gets the list of files stored in the GridFS.
+ *
+ * @method
+ * @static
+ * @param {Db} db the database to query.
+ * @param {string} [rootCollection] The root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] result from exists.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.list = function(db, rootCollection, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ rootCollection = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+ options = options || {};
+
+ return executeLegacyOperation(db.s.topology, list, [db, rootCollection, options, callback], {
+ skipSessions: true
+ });
+};
+
+var list = function(db, rootCollection, options, callback) {
+ // Ensure we have correct values
+ if (rootCollection != null && typeof rootCollection === 'object') {
+ options = rootCollection;
+ rootCollection = null;
+ }
+
+ // Establish read preference
+ var readPreference = options.readPreference || ReadPreference.primary;
+ // Check if we are returning by id not filename
+ var byId = options['id'] != null ? options['id'] : false;
+ // Fetch item
+ var rootCollectionFinal =
+ rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
+ var items = [];
+ db.collection(rootCollectionFinal + '.files', function(err, collection) {
+ if (err) return callback(err);
+
+ collection.find({}, { readPreference: readPreference }, function(err, cursor) {
+ if (err) return callback(err);
+
+ cursor.each(function(err, item) {
+ if (item != null) {
+ items.push(byId ? item._id : item.filename);
+ } else {
+ callback(err, items);
+ }
+ });
+ });
+ });
+};
+
+/**
+ * Reads the contents of a file.
+ *
+ * This method has the following signatures
+ *
+ * (db, name, callback)
+ * (db, name, length, callback)
+ * (db, name, length, offset, callback)
+ * (db, name, length, offset, options, callback)
+ *
+ * @method
+ * @static
+ * @param {Db} db the database to query.
+ * @param {string} name The name of the file.
+ * @param {number} [length] The size of data to read.
+ * @param {number} [offset] The offset from the head of the file of which to start reading from.
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~readCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.read = function(db, name, length, offset, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ length = args.length ? args.shift() : null;
+ offset = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : null;
+ options = options || {};
+
+ return executeLegacyOperation(
+ db.s.topology,
+ readStatic,
+ [db, name, length, offset, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var readStatic = function(db, name, length, offset, options, callback) {
+ new GridStore(db, name, 'r', options).open(function(err, gridStore) {
+ if (err) return callback(err);
+ // Make sure we are not reading out of bounds
+ if (offset && offset >= gridStore.length)
+ return callback('offset larger than size of file', null);
+ if (length && length > gridStore.length)
+ return callback('length is larger than the size of the file', null);
+ if (offset && length && offset + length > gridStore.length)
+ return callback('offset and length is larger than the size of the file', null);
+
+ if (offset != null) {
+ gridStore.seek(offset, function(err, gridStore) {
+ if (err) return callback(err);
+ gridStore.read(length, callback);
+ });
+ } else {
+ gridStore.read(length, callback);
+ }
+ });
+};
+
+/**
+ * Read the entire file as a list of strings splitting by the provided separator.
+ *
+ * @method
+ * @static
+ * @param {Db} db the database to query.
+ * @param {(String|object)} name the name of the file.
+ * @param {string} [separator] The character to be recognized as the newline separator.
+ * @param {object} [options] Optional settings.
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~readlinesCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.readlines = function(db, name, separator, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ separator = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : null;
+ options = options || {};
+
+ return executeLegacyOperation(
+ db.s.topology,
+ readlinesStatic,
+ [db, name, separator, options, callback],
+ { skipSessions: true }
+ );
+};
+
+var readlinesStatic = function(db, name, separator, options, callback) {
+ var finalSeperator = separator == null ? '\n' : separator;
+ new GridStore(db, name, 'r', options).open(function(err, gridStore) {
+ if (err) return callback(err);
+ gridStore.readlines(finalSeperator, callback);
+ });
+};
+
+/**
+ * Deletes the chunks and metadata information of a file from GridFS.
+ *
+ * @method
+ * @static
+ * @param {Db} db The database to query.
+ * @param {(string|array)} names The name/names of the files to delete.
+ * @param {object} [options] Optional settings.
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @param {GridStore~resultCallback} [callback] the command callback.
+ * @return {Promise} returns Promise if no callback passed
+ * @deprecated Use GridFSBucket API instead
+ */
+GridStore.unlink = function(db, names, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ options = args.length ? args.shift() : {};
+ options = options || {};
+
+ return executeLegacyOperation(db.s.topology, unlinkStatic, [this, db, names, options, callback], {
+ skipSessions: true
+ });
+};
+
+var unlinkStatic = function(self, db, names, options, callback) {
+ // Get the write concern
+ var writeConcern = _getWriteConcern(db, options);
+
+ // List of names
+ if (names.constructor === Array) {
+ var tc = 0;
+ for (var i = 0; i < names.length; i++) {
+ ++tc;
+ GridStore.unlink(db, names[i], options, function() {
+ if (--tc === 0) {
+ callback(null, self);
+ }
+ });
+ }
+ } else {
+ new GridStore(db, names, 'w', options).open(function(err, gridStore) {
+ if (err) return callback(err);
+ deleteChunks(gridStore, function(err) {
+ if (err) return callback(err);
+ gridStore.collection(function(err, collection) {
+ if (err) return callback(err);
+ collection.remove({ _id: gridStore.fileId }, writeConcern, function(err) {
+ callback(err, self);
+ });
+ });
+ });
+ });
+ }
+};
+
+/**
+ * @ignore
+ */
+var _writeNormal = function(self, data, close, options, callback) {
+ // If we have a buffer write it using the writeBuffer method
+ if (Buffer.isBuffer(data)) {
+ return writeBuffer(self, data, close, callback);
+ } else {
+ return writeBuffer(self, Buffer.from(data, 'binary'), close, callback);
+ }
+};
+
+/**
+ * @ignore
+ */
+var _setWriteConcernHash = function(options) {
+ var finalOptions = {};
+ if (options.w != null) finalOptions.w = options.w;
+ if (options.journal === true) finalOptions.j = options.journal;
+ if (options.j === true) finalOptions.j = options.j;
+ if (options.fsync === true) finalOptions.fsync = options.fsync;
+ if (options.wtimeout != null) finalOptions.wtimeout = options.wtimeout;
+ return finalOptions;
+};
+
+/**
+ * @ignore
+ */
+var _getWriteConcern = function(self, options) {
+ // Final options
+ var finalOptions = { w: 1 };
+ options = options || {};
+
+ // Local options verification
+ if (
+ options.w != null ||
+ typeof options.j === 'boolean' ||
+ typeof options.journal === 'boolean' ||
+ typeof options.fsync === 'boolean'
+ ) {
+ finalOptions = _setWriteConcernHash(options);
+ } else if (options.safe != null && typeof options.safe === 'object') {
+ finalOptions = _setWriteConcernHash(options.safe);
+ } else if (typeof options.safe === 'boolean') {
+ finalOptions = { w: options.safe ? 1 : 0 };
+ } else if (
+ self.options.w != null ||
+ typeof self.options.j === 'boolean' ||
+ typeof self.options.journal === 'boolean' ||
+ typeof self.options.fsync === 'boolean'
+ ) {
+ finalOptions = _setWriteConcernHash(self.options);
+ } else if (
+ self.safe &&
+ (self.safe.w != null ||
+ typeof self.safe.j === 'boolean' ||
+ typeof self.safe.journal === 'boolean' ||
+ typeof self.safe.fsync === 'boolean')
+ ) {
+ finalOptions = _setWriteConcernHash(self.safe);
+ } else if (typeof self.safe === 'boolean') {
+ finalOptions = { w: self.safe ? 1 : 0 };
+ }
+
+ // Ensure we don't have an invalid combination of write concerns
+ if (
+ finalOptions.w < 1 &&
+ (finalOptions.journal === true || finalOptions.j === true || finalOptions.fsync === true)
+ )
+ throw MongoError.create({
+ message: 'No acknowledgement using w < 1 cannot be combined with journal:true or fsync:true',
+ driver: true
+ });
+
+ // Return the options
+ return finalOptions;
+};
+
+/**
+ * Create a new GridStoreStream instance (INTERNAL TYPE, do not instantiate directly)
+ *
+ * @class
+ * @extends external:Duplex
+ * @return {GridStoreStream} a GridStoreStream instance.
+ * @deprecated Use GridFSBucket API instead
+ */
+var GridStoreStream = function(gs) {
+ // Initialize the duplex stream
+ Duplex.call(this);
+
+ // Get the gridstore
+ this.gs = gs;
+
+ // End called
+ this.endCalled = false;
+
+ // If we have a seek
+ this.totalBytesToRead = this.gs.length - this.gs.position;
+ this.seekPosition = this.gs.position;
+};
+
+//
+// Inherit duplex
+inherits(GridStoreStream, Duplex);
+
+GridStoreStream.prototype._pipe = GridStoreStream.prototype.pipe;
+
+// Set up override
+GridStoreStream.prototype.pipe = function(destination) {
+ var self = this;
+
+ // Only open gridstore if not already open
+ if (!self.gs.isOpen) {
+ self.gs.open(function(err) {
+ if (err) return self.emit('error', err);
+ self.totalBytesToRead = self.gs.length - self.gs.position;
+ self._pipe.apply(self, [destination]);
+ });
+ } else {
+ self.totalBytesToRead = self.gs.length - self.gs.position;
+ self._pipe.apply(self, [destination]);
+ }
+
+ return destination;
+};
+
+// Called by stream
+GridStoreStream.prototype._read = function() {
+ var self = this;
+
+ var read = function() {
+ // Read data
+ self.gs.read(length, function(err, buffer) {
+ if (err && !self.endCalled) return self.emit('error', err);
+
+ // Stream is closed
+ if (self.endCalled || buffer == null) return self.push(null);
+ // Remove bytes read
+ if (buffer.length <= self.totalBytesToRead) {
+ self.totalBytesToRead = self.totalBytesToRead - buffer.length;
+ self.push(buffer);
+ } else if (buffer.length > self.totalBytesToRead) {
+ self.totalBytesToRead = self.totalBytesToRead - buffer._index;
+ self.push(buffer.slice(0, buffer._index));
+ }
+
+ // Finished reading
+ if (self.totalBytesToRead <= 0) {
+ self.endCalled = true;
+ }
+ });
+ };
+
+ // Set read length
+ var length =
+ self.gs.length < self.gs.chunkSize ? self.gs.length - self.seekPosition : self.gs.chunkSize;
+ if (!self.gs.isOpen) {
+ self.gs.open(function(err) {
+ self.totalBytesToRead = self.gs.length - self.gs.position;
+ if (err) return self.emit('error', err);
+ read();
+ });
+ } else {
+ read();
+ }
+};
+
+GridStoreStream.prototype.destroy = function() {
+ this.pause();
+ this.endCalled = true;
+ this.gs.close();
+ this.emit('end');
+};
+
+GridStoreStream.prototype.write = function(chunk) {
+ var self = this;
+ if (self.endCalled)
+ return self.emit(
+ 'error',
+ MongoError.create({ message: 'attempting to write to stream after end called', driver: true })
+ );
+ // Do we have to open the gridstore
+ if (!self.gs.isOpen) {
+ self.gs.open(function() {
+ self.gs.isOpen = true;
+ self.gs.write(chunk, function() {
+ process.nextTick(function() {
+ self.emit('drain');
+ });
+ });
+ });
+ return false;
+ } else {
+ self.gs.write(chunk, function() {
+ self.emit('drain');
+ });
+ return true;
+ }
+};
+
+GridStoreStream.prototype.end = function(chunk, encoding, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ chunk = args.length ? args.shift() : null;
+ encoding = args.length ? args.shift() : null;
+ self.endCalled = true;
+
+ if (chunk) {
+ self.gs.write(chunk, function() {
+ self.gs.close(function() {
+ if (typeof callback === 'function') callback();
+ self.emit('end');
+ });
+ });
+ }
+
+ self.gs.close(function() {
+ if (typeof callback === 'function') callback();
+ self.emit('end');
+ });
+};
+
+/**
+ * The read() method pulls some data out of the internal buffer and returns it. If there is no data available, then it will return null.
+ * @function external:Duplex#read
+ * @param {number} size Optional argument to specify how much data to read.
+ * @return {(String | Buffer | null)}
+ */
+
+/**
+ * Call this function to cause the stream to return strings of the specified encoding instead of Buffer objects.
+ * @function external:Duplex#setEncoding
+ * @param {string} encoding The encoding to use.
+ * @return {null}
+ */
+
+/**
+ * This method will cause the readable stream to resume emitting data events.
+ * @function external:Duplex#resume
+ * @return {null}
+ */
+
+/**
+ * This method will cause a stream in flowing-mode to stop emitting data events. Any data that becomes available will remain in the internal buffer.
+ * @function external:Duplex#pause
+ * @return {null}
+ */
+
+/**
+ * This method pulls all the data out of a readable stream, and writes it to the supplied destination, automatically managing the flow so that the destination is not overwhelmed by a fast readable stream.
+ * @function external:Duplex#pipe
+ * @param {Writable} destination The destination for writing data
+ * @param {object} [options] Pipe options
+ * @return {null}
+ */
+
+/**
+ * This method will remove the hooks set up for a previous pipe() call.
+ * @function external:Duplex#unpipe
+ * @param {Writable} [destination] The destination for writing data
+ * @return {null}
+ */
+
+/**
+ * This is useful in certain cases where a stream is being consumed by a parser, which needs to "un-consume" some data that it has optimistically pulled out of the source, so that the stream can be passed on to some other party.
+ * @function external:Duplex#unshift
+ * @param {(Buffer|string)} chunk Chunk of data to unshift onto the read queue.
+ * @return {null}
+ */
+
+/**
+ * Versions of Node prior to v0.10 had streams that did not implement the entire Streams API as it is today. (See "Compatibility" below for more information.)
+ * @function external:Duplex#wrap
+ * @param {Stream} stream An "old style" readable stream.
+ * @return {null}
+ */
+
+/**
+ * This method writes some data to the underlying system, and calls the supplied callback once the data has been fully handled.
+ * @function external:Duplex#write
+ * @param {(string|Buffer)} chunk The data to write
+ * @param {string} encoding The encoding, if chunk is a String
+ * @param {function} callback Callback for when this chunk of data is flushed
+ * @return {boolean}
+ */
+
+/**
+ * Call this method when no more data will be written to the stream. If supplied, the callback is attached as a listener on the finish event.
+ * @function external:Duplex#end
+ * @param {(string|Buffer)} chunk The data to write
+ * @param {string} encoding The encoding, if chunk is a String
+ * @param {function} callback Callback for when this chunk of data is flushed
+ * @return {null}
+ */
+
+/**
+ * GridStoreStream stream data event, fired for each document in the cursor.
+ *
+ * @event GridStoreStream#data
+ * @type {object}
+ */
+
+/**
+ * GridStoreStream stream end event
+ *
+ * @event GridStoreStream#end
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream close event
+ *
+ * @event GridStoreStream#close
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream readable event
+ *
+ * @event GridStoreStream#readable
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream drain event
+ *
+ * @event GridStoreStream#drain
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream finish event
+ *
+ * @event GridStoreStream#finish
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream pipe event
+ *
+ * @event GridStoreStream#pipe
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream unpipe event
+ *
+ * @event GridStoreStream#unpipe
+ * @type {null}
+ */
+
+/**
+ * GridStoreStream stream error event
+ *
+ * @event GridStoreStream#error
+ * @type {null}
+ */
+
+/**
+ * @ignore
+ */
+module.exports = GridStore;
diff --git a/node_modules/mongodb/lib/mongo_client.js b/node_modules/mongodb/lib/mongo_client.js
new file mode 100644
index 0000000..eea5c45
--- /dev/null
+++ b/node_modules/mongodb/lib/mongo_client.js
@@ -0,0 +1,521 @@
+'use strict';
+
+const ChangeStream = require('./change_stream');
+const Db = require('./db');
+const EventEmitter = require('events').EventEmitter;
+const inherits = require('util').inherits;
+const MongoError = require('./core').MongoError;
+const deprecate = require('util').deprecate;
+const WriteConcern = require('./write_concern');
+const MongoDBNamespace = require('./utils').MongoDBNamespace;
+const ReadPreference = require('./core/topologies/read_preference');
+const maybePromise = require('./utils').maybePromise;
+const NativeTopology = require('./topologies/native_topology');
+const connect = require('./operations/connect').connect;
+const validOptions = require('./operations/connect').validOptions;
+
+/**
+ * @fileOverview The **MongoClient** class is a class that allows for making Connections to MongoDB.
+ *
+ * @example
+ * // Connect using a MongoClient instance
+ * const MongoClient = require('mongodb').MongoClient;
+ * const test = require('assert');
+ * // Connection url
+ * const url = 'mongodb://localhost:27017';
+ * // Database Name
+ * const dbName = 'test';
+ * // Connect using MongoClient
+ * const mongoClient = new MongoClient(url);
+ * mongoClient.connect(function(err, client) {
+ * const db = client.db(dbName);
+ * client.close();
+ * });
+ *
+ * @example
+ * // Connect using the MongoClient.connect static method
+ * const MongoClient = require('mongodb').MongoClient;
+ * const test = require('assert');
+ * // Connection url
+ * const url = 'mongodb://localhost:27017';
+ * // Database Name
+ * const dbName = 'test';
+ * // Connect using MongoClient
+ * MongoClient.connect(url, function(err, client) {
+ * const db = client.db(dbName);
+ * client.close();
+ * });
+ */
+
+/**
+ * A string specifying the level of a ReadConcern
+ * @typedef {'local'|'available'|'majority'|'linearizable'|'snapshot'} ReadConcernLevel
+ * @see https://docs.mongodb.com/manual/reference/read-concern/index.html#read-concern-levels
+ */
+
+/**
+ * Configuration options for drivers wrapping the node driver.
+ *
+ * @typedef {Object} DriverInfoOptions
+ * @property {string} [name] The name of the driver
+ * @property {string} [version] The version of the driver
+ * @property {string} [platform] Optional platform information
+ */
+
+/**
+ * Configuration options for drivers wrapping the node driver.
+ *
+ * @typedef {Object} DriverInfoOptions
+ * @property {string} [name] The name of the driver
+ * @property {string} [version] The version of the driver
+ * @property {string} [platform] Optional platform information
+ */
+
+/**
+ * Creates a new MongoClient instance
+ * @class
+ * @param {string} url The connection URI string
+ * @param {object} [options] Optional settings
+ * @param {number} [options.poolSize=5] The maximum size of the individual server pool
+ * @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
+ * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
+ * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
+ * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
+ * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
+ * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function. *deprecated* use `tls` variants
+ * @param {boolean} [options.tls=false] Enable TLS connections
+ * @param {boolean} [options.tlsInsecure=false] Relax TLS constraints, disabling validation
+ * @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
+ * @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
+ * @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
+ * @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
+ * @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
+ * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
+ * @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
+ * @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
+ * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
+ * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
+ * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
+ * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
+ * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
+ * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
+ * @param {string} [options.replicaSet=undefined] The Replicaset set name
+ * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
+ * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
+ * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
+ * @param {string} [options.authSource=undefined] Define the database to authenticate against
+ * @param {(number|string)} [options.w] The write concern
+ * @param {number} [options.wtimeout] The write concern timeout
+ * @param {boolean} [options.j=false] Specify a journal write concern
+ * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
+ * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
+ * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
+ * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
+ * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
+ * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
+ * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
+ * @param {object} [options.logger=undefined] Custom logger object
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
+ * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
+ * @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
+ * @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
+ * @param {string} [options.auth.user=undefined] The username for auth
+ * @param {string} [options.auth.password=undefined] The password for auth
+ * @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
+ * @param {object} [options.compression] Type of compression to use: snappy or zlib
+ * @param {boolean} [options.fsync=false] Specify a file sync write concern
+ * @param {array} [options.readPreferenceTags] Read preference tags
+ * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
+ * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
+ * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
+ * @param {boolean} [options.useNewUrlParser=true] Determines whether or not to use the new url parser. Enables the new, spec-compliant, url parser shipped in the core driver. This url parser fixes a number of problems with the original parser, and aims to outright replace that parser in the near future. Defaults to true, and must be explicitly set to false to use the legacy url parser.
+ * @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
+ * @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
+ * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
+ * @param {MongoClient~connectCallback} [callback] The command result callback
+ * @return {MongoClient} a MongoClient instance
+ */
+function MongoClient(url, options) {
+ if (!(this instanceof MongoClient)) return new MongoClient(url, options);
+ // Set up event emitter
+ EventEmitter.call(this);
+
+ // The internal state
+ this.s = {
+ url: url,
+ options: options || {},
+ promiseLibrary: (options && options.promiseLibrary) || Promise,
+ dbCache: new Map(),
+ sessions: new Set(),
+ writeConcern: WriteConcern.fromOptions(options),
+ namespace: new MongoDBNamespace('admin')
+ };
+}
+
+/**
+ * @ignore
+ */
+inherits(MongoClient, EventEmitter);
+
+Object.defineProperty(MongoClient.prototype, 'writeConcern', {
+ enumerable: true,
+ get: function() {
+ return this.s.writeConcern;
+ }
+});
+
+Object.defineProperty(MongoClient.prototype, 'readPreference', {
+ enumerable: true,
+ get: function() {
+ return ReadPreference.primary;
+ }
+});
+
+/**
+ * The callback format for results
+ * @callback MongoClient~connectCallback
+ * @param {MongoError} error An error instance representing the error during the execution.
+ * @param {MongoClient} client The connected client.
+ */
+
+/**
+ * Connect to MongoDB using a url as documented at
+ *
+ * docs.mongodb.org/manual/reference/connection-string/
+ *
+ * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
+ *
+ * @method
+ * @param {MongoClient~connectCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+MongoClient.prototype.connect = function(callback) {
+ if (typeof callback === 'string') {
+ throw new TypeError('`connect` only accepts a callback');
+ }
+
+ const client = this;
+ return maybePromise(this, callback, cb => {
+ const err = validOptions(client.s.options);
+ if (err) return cb(err);
+
+ connect(client, client.s.url, client.s.options, err => {
+ if (err) return cb(err);
+ cb(null, client);
+ });
+ });
+};
+
+MongoClient.prototype.logout = deprecate(function(options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ if (typeof callback === 'function') callback(null, true);
+}, 'Multiple authentication is prohibited on a connected client, please only authenticate once per MongoClient');
+
+/**
+ * Close the db and its underlying connections
+ * @method
+ * @param {boolean} [force=false] Force close, emitting no events
+ * @param {Db~noResultCallback} [callback] The result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+MongoClient.prototype.close = function(force, callback) {
+ if (typeof force === 'function') {
+ callback = force;
+ force = false;
+ }
+
+ const client = this;
+ return maybePromise(this, callback, cb => {
+ const completeClose = err => {
+ client.emit('close', client);
+
+ if (!(client.topology instanceof NativeTopology)) {
+ for (const item of client.s.dbCache) {
+ item[1].emit('close', client);
+ }
+ }
+
+ client.removeAllListeners('close');
+ cb(err);
+ };
+
+ if (client.topology == null) {
+ completeClose();
+ return;
+ }
+
+ client.topology.close(force, err => {
+ const autoEncrypter = client.topology.s.options.autoEncrypter;
+ if (!autoEncrypter) {
+ completeClose(err);
+ return;
+ }
+
+ autoEncrypter.teardown(force, err2 => completeClose(err || err2));
+ });
+ });
+};
+
+/**
+ * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
+ * related in a parent-child relationship to the original instance so that events are correctly emitted on child
+ * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
+ * You can control these behaviors with the options noListener and returnNonCachedInstance.
+ *
+ * @method
+ * @param {string} [dbName] The name of the database we want to use. If not provided, use database name from connection string.
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
+ * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
+ * @return {Db}
+ */
+MongoClient.prototype.db = function(dbName, options) {
+ options = options || {};
+
+ // Default to db from connection string if not provided
+ if (!dbName) {
+ dbName = this.s.options.dbName;
+ }
+
+ // Copy the options and add out internal override of the not shared flag
+ const finalOptions = Object.assign({}, this.s.options, options);
+
+ // Do we have the db in the cache already
+ if (this.s.dbCache.has(dbName) && finalOptions.returnNonCachedInstance !== true) {
+ return this.s.dbCache.get(dbName);
+ }
+
+ // Add promiseLibrary
+ finalOptions.promiseLibrary = this.s.promiseLibrary;
+
+ // If no topology throw an error message
+ if (!this.topology) {
+ throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db');
+ }
+
+ // Return the db object
+ const db = new Db(dbName, this.topology, finalOptions);
+
+ // Add the db to the cache
+ this.s.dbCache.set(dbName, db);
+ // Return the database
+ return db;
+};
+
+/**
+ * Check if MongoClient is connected
+ *
+ * @method
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
+ * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
+ * @return {boolean}
+ */
+MongoClient.prototype.isConnected = function(options) {
+ options = options || {};
+
+ if (!this.topology) return false;
+ return this.topology.isConnected(options);
+};
+
+/**
+ * Connect to MongoDB using a url as documented at
+ *
+ * docs.mongodb.org/manual/reference/connection-string/
+ *
+ * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
+ *
+ * @method
+ * @static
+ * @param {string} url The connection URI string
+ * @param {object} [options] Optional settings
+ * @param {number} [options.poolSize=5] The maximum size of the individual server pool
+ * @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority *deprecated* use `tls` variants
+ * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
+ * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
+ * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
+ * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
+ * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function. *deprecated* use `tls` variants
+ * @param {boolean} [options.tls=false] Enable TLS connections
+ * @param {boolean} [options.tlsInsecure=false] Relax TLS constraints, disabling validation
+ * @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
+ * @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
+ * @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
+ * @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
+ * @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
+ * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {boolean} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
+ * @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
+ * @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
+ * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
+ * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
+ * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
+ * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
+ * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
+ * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
+ * @param {string} [options.replicaSet=undefined] The Replicaset set name
+ * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
+ * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
+ * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
+ * @param {string} [options.authSource=undefined] Define the database to authenticate against
+ * @param {(number|string)} [options.w] The write concern
+ * @param {number} [options.wtimeout] The write concern timeout
+ * @param {boolean} [options.j=false] Specify a journal write concern
+ * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
+ * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
+ * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
+ * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
+ * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
+ * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
+ * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
+ * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
+ * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
+ * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
+ * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
+ * @param {object} [options.logger=undefined] Custom logger object
+ * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
+ * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
+ * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
+ * @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
+ * @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
+ * @param {string} [options.auth.user=undefined] The username for auth
+ * @param {string} [options.auth.password=undefined] The password for auth
+ * @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
+ * @param {object} [options.compression] Type of compression to use: snappy or zlib
+ * @param {boolean} [options.fsync=false] Specify a file sync write concern
+ * @param {array} [options.readPreferenceTags] Read preference tags
+ * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
+ * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
+ * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
+ * @param {MongoClient~connectCallback} [callback] The command result callback
+ * @return {Promise} returns Promise if no callback passed
+ */
+MongoClient.connect = function(url, options, callback) {
+ const args = Array.prototype.slice.call(arguments, 1);
+ callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
+ options = args.length ? args.shift() : null;
+ options = options || {};
+
+ // Create client
+ const mongoClient = new MongoClient(url, options);
+ // Execute the connect method
+ return mongoClient.connect(callback);
+};
+
+/**
+ * Starts a new session on the server
+ *
+ * @param {SessionOptions} [options] optional settings for a driver session
+ * @return {ClientSession} the newly established session
+ */
+MongoClient.prototype.startSession = function(options) {
+ options = Object.assign({ explicit: true }, options);
+ if (!this.topology) {
+ throw new MongoError('Must connect to a server before calling this method');
+ }
+
+ if (!this.topology.hasSessionSupport()) {
+ throw new MongoError('Current topology does not support sessions');
+ }
+
+ return this.topology.startSession(options, this.s.options);
+};
+
+/**
+ * Runs a given operation with an implicitly created session. The lifetime of the session
+ * will be handled without the need for user interaction.
+ *
+ * NOTE: presently the operation MUST return a Promise (either explicit or implicity as an async function)
+ *
+ * @param {Object} [options] Optional settings to be appled to implicitly created session
+ * @param {Function} operation An operation to execute with an implicitly created session. The signature of this MUST be `(session) => {}`
+ * @return {Promise}
+ */
+MongoClient.prototype.withSession = function(options, operation) {
+ if (typeof options === 'function') (operation = options), (options = undefined);
+ const session = this.startSession(options);
+
+ let cleanupHandler = (err, result, opts) => {
+ // prevent multiple calls to cleanupHandler
+ cleanupHandler = () => {
+ throw new ReferenceError('cleanupHandler was called too many times');
+ };
+
+ opts = Object.assign({ throw: true }, opts);
+ session.endSession();
+
+ if (err) {
+ if (opts.throw) throw err;
+ return Promise.reject(err);
+ }
+ };
+
+ try {
+ const result = operation(session);
+ return Promise.resolve(result)
+ .then(result => cleanupHandler(null, result))
+ .catch(err => cleanupHandler(err, null, { throw: true }));
+ } catch (err) {
+ return cleanupHandler(err, null, { throw: false });
+ }
+};
+/**
+ * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this cluster. Will ignore all changes to system collections, as well as the local, admin,
+ * and config databases.
+ * @method
+ * @since 3.1.0
+ * @param {Array} [pipeline] An array of {@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents. This allows for filtering (using $match) and manipulating the change stream documents.
+ * @param {object} [options] Optional settings
+ * @param {string} [options.fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
+ * @param {object} [options.resumeAfter] Specifies the logical starting point for the new change stream. This should be the _id field from a previously returned change stream document.
+ * @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
+ * @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
+ * @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
+ * @param {ReadPreference} [options.readPreference] The read preference. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
+ * @param {Timestamp} [options.startAtOperationTime] receive change events that occur after the specified timestamp
+ * @param {ClientSession} [options.session] optional session to use for this operation
+ * @return {ChangeStream} a ChangeStream instance.
+ */
+MongoClient.prototype.watch = function(pipeline, options) {
+ pipeline = pipeline || [];
+ options = options || {};
+
+ // Allow optionally not specifying a pipeline
+ if (!Array.isArray(pipeline)) {
+ options = pipeline;
+ pipeline = [];
+ }
+
+ return new ChangeStream(this, pipeline, options);
+};
+
+/**
+ * Return the mongo client logger
+ * @method
+ * @return {Logger} return the mongo client logger
+ * @ignore
+ */
+MongoClient.prototype.getLogger = function() {
+ return this.s.options.logger;
+};
+
+module.exports = MongoClient;
diff --git a/node_modules/mongodb/lib/operations/add_user.js b/node_modules/mongodb/lib/operations/add_user.js
new file mode 100644
index 0000000..1f3f3a6
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/add_user.js
@@ -0,0 +1,96 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const CommandOperation = require('./command');
+const defineAspects = require('./operation').defineAspects;
+const crypto = require('crypto');
+const handleCallback = require('../utils').handleCallback;
+const toError = require('../utils').toError;
+
+class AddUserOperation extends CommandOperation {
+ constructor(db, username, password, options) {
+ super(db, options);
+
+ this.username = username;
+ this.password = password;
+ }
+
+ _buildCommand() {
+ const db = this.db;
+ const username = this.username;
+ const password = this.password;
+ const options = this.options;
+
+ // Get additional values
+ let roles = Array.isArray(options.roles) ? options.roles : [];
+
+ // If not roles defined print deprecated message
+ // TODO: handle deprecation properly
+ if (roles.length === 0) {
+ console.log('Creating a user without roles is deprecated in MongoDB >= 2.6');
+ }
+
+ // Check the db name and add roles if needed
+ if (
+ (db.databaseName.toLowerCase() === 'admin' || options.dbName === 'admin') &&
+ !Array.isArray(options.roles)
+ ) {
+ roles = ['root'];
+ } else if (!Array.isArray(options.roles)) {
+ roles = ['dbOwner'];
+ }
+
+ const digestPassword = db.s.topology.lastIsMaster().maxWireVersion >= 7;
+
+ let userPassword = password;
+
+ if (!digestPassword) {
+ // Use node md5 generator
+ const md5 = crypto.createHash('md5');
+ // Generate keys used for authentication
+ md5.update(username + ':mongo:' + password);
+ userPassword = md5.digest('hex');
+ }
+
+ // Build the command to execute
+ const command = {
+ createUser: username,
+ customData: options.customData || {},
+ roles: roles,
+ digestPassword
+ };
+
+ // No password
+ if (typeof password === 'string') {
+ command.pwd = userPassword;
+ }
+
+ return command;
+ }
+
+ execute(callback) {
+ const options = this.options;
+
+ // Error out if digestPassword set
+ if (options.digestPassword != null) {
+ return callback(
+ toError(
+ "The digestPassword option is not supported via add_user. Please use db.command('createUser', ...) instead for this option."
+ )
+ );
+ }
+
+ // Attempt to execute auth command
+ super.execute((err, r) => {
+ if (!err) {
+ return handleCallback(callback, err, r);
+ }
+
+ return handleCallback(callback, err, null);
+ });
+ }
+}
+
+defineAspects(AddUserOperation, Aspect.WRITE_OPERATION);
+
+module.exports = AddUserOperation;
diff --git a/node_modules/mongodb/lib/operations/admin_ops.js b/node_modules/mongodb/lib/operations/admin_ops.js
new file mode 100644
index 0000000..b08071c
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/admin_ops.js
@@ -0,0 +1,62 @@
+'use strict';
+
+const executeCommand = require('./db_ops').executeCommand;
+const executeDbAdminCommand = require('./db_ops').executeDbAdminCommand;
+
+/**
+ * Get ReplicaSet status
+ *
+ * @param {Admin} a collection instance.
+ * @param {Object} [options] Optional settings. See Admin.prototype.replSetGetStatus for a list of options.
+ * @param {Admin~resultCallback} [callback] The command result callback.
+ */
+function replSetGetStatus(admin, options, callback) {
+ executeDbAdminCommand(admin.s.db, { replSetGetStatus: 1 }, options, callback);
+}
+
+/**
+ * Retrieve this db's server status.
+ *
+ * @param {Admin} a collection instance.
+ * @param {Object} [options] Optional settings. See Admin.prototype.serverStatus for a list of options.
+ * @param {Admin~resultCallback} [callback] The command result callback
+ */
+function serverStatus(admin, options, callback) {
+ executeDbAdminCommand(admin.s.db, { serverStatus: 1 }, options, callback);
+}
+
+/**
+ * Validate an existing collection
+ *
+ * @param {Admin} a collection instance.
+ * @param {string} collectionName The name of the collection to validate.
+ * @param {Object} [options] Optional settings. See Admin.prototype.validateCollection for a list of options.
+ * @param {Admin~resultCallback} [callback] The command result callback.
+ */
+function validateCollection(admin, collectionName, options, callback) {
+ const command = { validate: collectionName };
+ const keys = Object.keys(options);
+
+ // Decorate command with extra options
+ for (let i = 0; i < keys.length; i++) {
+ if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
+ command[keys[i]] = options[keys[i]];
+ }
+ }
+
+ executeCommand(admin.s.db, command, options, (err, doc) => {
+ if (err != null) return callback(err, null);
+
+ if (doc.ok === 0) return callback(new Error('Error with validate command'), null);
+ if (doc.result != null && doc.result.constructor !== String)
+ return callback(new Error('Error with validation data'), null);
+ if (doc.result != null && doc.result.match(/exception|corrupt/) != null)
+ return callback(new Error('Error: invalid collection ' + collectionName), null);
+ if (doc.valid != null && !doc.valid)
+ return callback(new Error('Error: invalid collection ' + collectionName), null);
+
+ return callback(null, doc);
+ });
+}
+
+module.exports = { replSetGetStatus, serverStatus, validateCollection };
diff --git a/node_modules/mongodb/lib/operations/aggregate.js b/node_modules/mongodb/lib/operations/aggregate.js
new file mode 100644
index 0000000..e0f2da8
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/aggregate.js
@@ -0,0 +1,106 @@
+'use strict';
+
+const CommandOperationV2 = require('./command_v2');
+const MongoError = require('../core').MongoError;
+const maxWireVersion = require('../core/utils').maxWireVersion;
+const ReadPreference = require('../core').ReadPreference;
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+
+const DB_AGGREGATE_COLLECTION = 1;
+const MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT = 8;
+
+class AggregateOperation extends CommandOperationV2 {
+ constructor(parent, pipeline, options) {
+ super(parent, options, { fullResponse: true });
+
+ this.target =
+ parent.s.namespace && parent.s.namespace.collection
+ ? parent.s.namespace.collection
+ : DB_AGGREGATE_COLLECTION;
+
+ this.pipeline = pipeline;
+
+ // determine if we have a write stage, override read preference if so
+ this.hasWriteStage = false;
+ if (typeof options.out === 'string') {
+ this.pipeline = this.pipeline.concat({ $out: options.out });
+ this.hasWriteStage = true;
+ } else if (pipeline.length > 0) {
+ const finalStage = pipeline[pipeline.length - 1];
+ if (finalStage.$out || finalStage.$merge) {
+ this.hasWriteStage = true;
+ }
+ }
+
+ if (this.hasWriteStage) {
+ this.readPreference = ReadPreference.primary;
+ }
+
+ if (options.explain && (this.readConcern || this.writeConcern)) {
+ throw new MongoError(
+ '"explain" cannot be used on an aggregate call with readConcern/writeConcern'
+ );
+ }
+
+ if (options.cursor != null && typeof options.cursor !== 'object') {
+ throw new MongoError('cursor options must be an object');
+ }
+ }
+
+ get canRetryRead() {
+ return !this.hasWriteStage;
+ }
+
+ addToPipeline(stage) {
+ this.pipeline.push(stage);
+ }
+
+ execute(server, callback) {
+ const options = this.options;
+ const serverWireVersion = maxWireVersion(server);
+ const command = { aggregate: this.target, pipeline: this.pipeline };
+
+ if (this.hasWriteStage && serverWireVersion < MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) {
+ this.readConcern = null;
+ }
+
+ if (serverWireVersion >= 5) {
+ if (this.hasWriteStage && this.writeConcern) {
+ Object.assign(command, { writeConcern: this.writeConcern });
+ }
+ }
+
+ if (options.bypassDocumentValidation === true) {
+ command.bypassDocumentValidation = options.bypassDocumentValidation;
+ }
+
+ if (typeof options.allowDiskUse === 'boolean') {
+ command.allowDiskUse = options.allowDiskUse;
+ }
+
+ if (options.hint) {
+ command.hint = options.hint;
+ }
+
+ if (options.explain) {
+ options.full = false;
+ command.explain = options.explain;
+ }
+
+ command.cursor = options.cursor || {};
+ if (options.batchSize && !this.hasWriteStage) {
+ command.cursor.batchSize = options.batchSize;
+ }
+
+ super.executeCommand(server, command, callback);
+ }
+}
+
+defineAspects(AggregateOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = AggregateOperation;
diff --git a/node_modules/mongodb/lib/operations/bulk_write.js b/node_modules/mongodb/lib/operations/bulk_write.js
new file mode 100644
index 0000000..8f14f02
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/bulk_write.js
@@ -0,0 +1,104 @@
+'use strict';
+
+const applyRetryableWrites = require('../utils').applyRetryableWrites;
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const MongoError = require('../core').MongoError;
+const OperationBase = require('./operation').OperationBase;
+
+class BulkWriteOperation extends OperationBase {
+ constructor(collection, operations, options) {
+ super(options);
+
+ this.collection = collection;
+ this.operations = operations;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const operations = this.operations;
+ let options = this.options;
+
+ // Add ignoreUndfined
+ if (coll.s.options.ignoreUndefined) {
+ options = Object.assign({}, options);
+ options.ignoreUndefined = coll.s.options.ignoreUndefined;
+ }
+
+ // Create the bulk operation
+ const bulk =
+ options.ordered === true || options.ordered == null
+ ? coll.initializeOrderedBulkOp(options)
+ : coll.initializeUnorderedBulkOp(options);
+
+ // Do we have a collation
+ let collation = false;
+
+ // for each op go through and add to the bulk
+ try {
+ for (let i = 0; i < operations.length; i++) {
+ // Get the operation type
+ const key = Object.keys(operations[i])[0];
+ // Check if we have a collation
+ if (operations[i][key].collation) {
+ collation = true;
+ }
+
+ // Pass to the raw bulk
+ bulk.raw(operations[i]);
+ }
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Final options for retryable writes and write concern
+ let finalOptions = Object.assign({}, options);
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
+
+ const writeCon = finalOptions.writeConcern ? finalOptions.writeConcern : {};
+ const capabilities = coll.s.topology.capabilities();
+
+ // Did the user pass in a collation, check if our write server supports it
+ if (collation && capabilities && !capabilities.commandsTakeCollation) {
+ return callback(new MongoError('server/primary/mongos does not support collation'));
+ }
+
+ // Execute the bulk
+ bulk.execute(writeCon, finalOptions, (err, r) => {
+ // We have connection level error
+ if (!r && err) {
+ return callback(err, null);
+ }
+
+ r.insertedCount = r.nInserted;
+ r.matchedCount = r.nMatched;
+ r.modifiedCount = r.nModified || 0;
+ r.deletedCount = r.nRemoved;
+ r.upsertedCount = r.getUpsertedIds().length;
+ r.upsertedIds = {};
+ r.insertedIds = {};
+
+ // Update the n
+ r.n = r.insertedCount;
+
+ // Inserted documents
+ const inserted = r.getInsertedIds();
+ // Map inserted ids
+ for (let i = 0; i < inserted.length; i++) {
+ r.insertedIds[inserted[i].index] = inserted[i]._id;
+ }
+
+ // Upserted documents
+ const upserted = r.getUpsertedIds();
+ // Map upserted ids
+ for (let i = 0; i < upserted.length; i++) {
+ r.upsertedIds[upserted[i].index] = upserted[i]._id;
+ }
+
+ // Return the results
+ callback(null, r);
+ });
+ }
+}
+
+module.exports = BulkWriteOperation;
diff --git a/node_modules/mongodb/lib/operations/collection_ops.js b/node_modules/mongodb/lib/operations/collection_ops.js
new file mode 100644
index 0000000..df5995d
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/collection_ops.js
@@ -0,0 +1,374 @@
+'use strict';
+
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const Code = require('../core').BSON.Code;
+const createIndexDb = require('./db_ops').createIndex;
+const decorateWithCollation = require('../utils').decorateWithCollation;
+const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
+const ensureIndexDb = require('./db_ops').ensureIndex;
+const evaluate = require('./db_ops').evaluate;
+const executeCommand = require('./db_ops').executeCommand;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const handleCallback = require('../utils').handleCallback;
+const indexInformationDb = require('./db_ops').indexInformation;
+const Long = require('../core').BSON.Long;
+const MongoError = require('../core').MongoError;
+const ReadPreference = require('../core').ReadPreference;
+const toError = require('../utils').toError;
+const insertDocuments = require('./common_functions').insertDocuments;
+const updateDocuments = require('./common_functions').updateDocuments;
+
+/**
+ * Group function helper
+ * @ignore
+ */
+// var groupFunction = function () {
+// var c = db[ns].find(condition);
+// var map = new Map();
+// var reduce_function = reduce;
+//
+// while (c.hasNext()) {
+// var obj = c.next();
+// var key = {};
+//
+// for (var i = 0, len = keys.length; i < len; ++i) {
+// var k = keys[i];
+// key[k] = obj[k];
+// }
+//
+// var aggObj = map.get(key);
+//
+// if (aggObj == null) {
+// var newObj = Object.extend({}, key);
+// aggObj = Object.extend(newObj, initial);
+// map.put(key, aggObj);
+// }
+//
+// reduce_function(obj, aggObj);
+// }
+//
+// return { "result": map.values() };
+// }.toString();
+const groupFunction =
+ 'function () {\nvar c = db[ns].find(condition);\nvar map = new Map();\nvar reduce_function = reduce;\n\nwhile (c.hasNext()) {\nvar obj = c.next();\nvar key = {};\n\nfor (var i = 0, len = keys.length; i < len; ++i) {\nvar k = keys[i];\nkey[k] = obj[k];\n}\n\nvar aggObj = map.get(key);\n\nif (aggObj == null) {\nvar newObj = Object.extend({}, key);\naggObj = Object.extend(newObj, initial);\nmap.put(key, aggObj);\n}\n\nreduce_function(obj, aggObj);\n}\n\nreturn { "result": map.values() };\n}';
+
+// Check the update operation to ensure it has atomic operators.
+function checkForAtomicOperators(update) {
+ if (Array.isArray(update)) {
+ return update.reduce((err, u) => err || checkForAtomicOperators(u), null);
+ }
+
+ const keys = Object.keys(update);
+
+ // same errors as the server would give for update doc lacking atomic operators
+ if (keys.length === 0) {
+ return toError('The update operation document must contain at least one atomic operator.');
+ }
+
+ if (keys[0][0] !== '$') {
+ return toError('the update operation document must contain atomic operators.');
+ }
+}
+
+/**
+ * Create an index on the db and collection.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings. See Collection.prototype.createIndex for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function createIndex(coll, fieldOrSpec, options, callback) {
+ createIndexDb(coll.s.db, coll.collectionName, fieldOrSpec, options, callback);
+}
+
+/**
+ * Create multiple indexes in the collection. This method is only supported for
+ * MongoDB 2.6 or higher. Earlier version of MongoDB will throw a command not supported
+ * error. Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {array} indexSpecs An array of index specifications to be created
+ * @param {Object} [options] Optional settings. See Collection.prototype.createIndexes for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function createIndexes(coll, indexSpecs, options, callback) {
+ const capabilities = coll.s.topology.capabilities();
+
+ // Ensure we generate the correct name if the parameter is not set
+ for (let i = 0; i < indexSpecs.length; i++) {
+ if (indexSpecs[i].name == null) {
+ const keys = [];
+
+ // Did the user pass in a collation, check if our write server supports it
+ if (indexSpecs[i].collation && capabilities && !capabilities.commandsTakeCollation) {
+ return callback(new MongoError('server/primary/mongos does not support collation'));
+ }
+
+ for (let name in indexSpecs[i].key) {
+ keys.push(`${name}_${indexSpecs[i].key[name]}`);
+ }
+
+ // Set the name
+ indexSpecs[i].name = keys.join('_');
+ }
+ }
+
+ options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY });
+
+ // Execute the index
+ executeCommand(
+ coll.s.db,
+ {
+ createIndexes: coll.collectionName,
+ indexes: indexSpecs
+ },
+ options,
+ callback
+ );
+}
+
+/**
+ * Ensure that an index exists. If the index does not exist, this function creates it.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings. See Collection.prototype.ensureIndex for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function ensureIndex(coll, fieldOrSpec, options, callback) {
+ ensureIndexDb(coll.s.db, coll.collectionName, fieldOrSpec, options, callback);
+}
+
+/**
+ * Run a group command across a collection.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {(object|array|function|code)} keys An object, array or function expressing the keys to group by.
+ * @param {object} condition An optional condition that must be true for a row to be considered.
+ * @param {object} initial Initial value of the aggregation counter object.
+ * @param {(function|Code)} reduce The reduce function aggregates (reduces) the objects iterated
+ * @param {(function|Code)} finalize An optional function to be run on each item in the result set just before the item is returned.
+ * @param {boolean} command Specify if you wish to run using the internal group command or using eval, default is true.
+ * @param {object} [options] Optional settings. See Collection.prototype.group for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ * @deprecated MongoDB 3.6 or higher will no longer support the group command. We recommend rewriting using the aggregation framework.
+ */
+function group(coll, keys, condition, initial, reduce, finalize, command, options, callback) {
+ // Execute using the command
+ if (command) {
+ const reduceFunction = reduce && reduce._bsontype === 'Code' ? reduce : new Code(reduce);
+
+ const selector = {
+ group: {
+ ns: coll.collectionName,
+ $reduce: reduceFunction,
+ cond: condition,
+ initial: initial,
+ out: 'inline'
+ }
+ };
+
+ // if finalize is defined
+ if (finalize != null) selector.group['finalize'] = finalize;
+ // Set up group selector
+ if ('function' === typeof keys || (keys && keys._bsontype === 'Code')) {
+ selector.group.$keyf = keys && keys._bsontype === 'Code' ? keys : new Code(keys);
+ } else {
+ const hash = {};
+ keys.forEach(key => {
+ hash[key] = 1;
+ });
+ selector.group.key = hash;
+ }
+
+ options = Object.assign({}, options);
+ // Ensure we have the right read preference inheritance
+ options.readPreference = resolveReadPreference(coll, options);
+
+ // Do we have a readConcern specified
+ decorateWithReadConcern(selector, coll, options);
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(selector, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Execute command
+ executeCommand(coll.s.db, selector, options, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result.retval);
+ });
+ } else {
+ // Create execution scope
+ const scope = reduce != null && reduce._bsontype === 'Code' ? reduce.scope : {};
+
+ scope.ns = coll.collectionName;
+ scope.keys = keys;
+ scope.condition = condition;
+ scope.initial = initial;
+
+ // Pass in the function text to execute within mongodb.
+ const groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';');
+
+ evaluate(coll.s.db, new Code(groupfn, scope), null, options, (err, results) => {
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, results.result || results);
+ });
+ }
+}
+
+/**
+ * Retrieve all the indexes on the collection.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {Object} [options] Optional settings. See Collection.prototype.indexes for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function indexes(coll, options, callback) {
+ options = Object.assign({}, { full: true }, options);
+ indexInformationDb(coll.s.db, coll.collectionName, options, callback);
+}
+
+/**
+ * Check if one or more indexes exist on the collection. This fails on the first index that doesn't exist.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {(string|array)} indexes One or more index names to check.
+ * @param {Object} [options] Optional settings. See Collection.prototype.indexExists for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function indexExists(coll, indexes, options, callback) {
+ indexInformation(coll, options, (err, indexInformation) => {
+ // If we have an error return
+ if (err != null) return handleCallback(callback, err, null);
+ // Let's check for the index names
+ if (!Array.isArray(indexes))
+ return handleCallback(callback, null, indexInformation[indexes] != null);
+ // Check in list of indexes
+ for (let i = 0; i < indexes.length; i++) {
+ if (indexInformation[indexes[i]] == null) {
+ return handleCallback(callback, null, false);
+ }
+ }
+
+ // All keys found return true
+ return handleCallback(callback, null, true);
+ });
+}
+
+/**
+ * Retrieve this collection's index info.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {object} [options] Optional settings. See Collection.prototype.indexInformation for a list of options.
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+function indexInformation(coll, options, callback) {
+ indexInformationDb(coll.s.db, coll.collectionName, options, callback);
+}
+
+/**
+ * Return N parallel cursors for a collection to allow parallel reading of the entire collection. There are
+ * no ordering guarantees for returned results.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {object} [options] Optional settings. See Collection.prototype.parallelCollectionScan for a list of options.
+ * @param {Collection~parallelCollectionScanCallback} [callback] The command result callback
+ */
+function parallelCollectionScan(coll, options, callback) {
+ // Create command object
+ const commandObject = {
+ parallelCollectionScan: coll.collectionName,
+ numCursors: options.numCursors
+ };
+
+ // Do we have a readConcern specified
+ decorateWithReadConcern(commandObject, coll, options);
+
+ // Store the raw value
+ const raw = options.raw;
+ delete options['raw'];
+
+ // Execute the command
+ executeCommand(coll.s.db, commandObject, options, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+ if (result == null)
+ return handleCallback(
+ callback,
+ new Error('no result returned for parallelCollectionScan'),
+ null
+ );
+
+ options = Object.assign({ explicitlyIgnoreSession: true }, options);
+
+ const cursors = [];
+ // Add the raw back to the option
+ if (raw) options.raw = raw;
+ // Create command cursors for each item
+ for (let i = 0; i < result.cursors.length; i++) {
+ const rawId = result.cursors[i].cursor.id;
+ // Convert cursorId to Long if needed
+ const cursorId = typeof rawId === 'number' ? Long.fromNumber(rawId) : rawId;
+ // Add a command cursor
+ cursors.push(coll.s.topology.cursor(coll.namespace, cursorId, options));
+ }
+
+ handleCallback(callback, null, cursors);
+ });
+}
+
+/**
+ * Save a document.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {object} doc Document to save
+ * @param {object} [options] Optional settings. See Collection.prototype.save for a list of options.
+ * @param {Collection~writeOpCallback} [callback] The command result callback
+ * @deprecated use insertOne, insertMany, updateOne or updateMany
+ */
+function save(coll, doc, options, callback) {
+ // Get the write concern options
+ const finalOptions = applyWriteConcern(
+ Object.assign({}, options),
+ { db: coll.s.db, collection: coll },
+ options
+ );
+ // Establish if we need to perform an insert or update
+ if (doc._id != null) {
+ finalOptions.upsert = true;
+ return updateDocuments(coll, { _id: doc._id }, doc, finalOptions, callback);
+ }
+
+ // Insert the document
+ insertDocuments(coll, [doc], finalOptions, (err, result) => {
+ if (callback == null) return;
+ if (doc == null) return handleCallback(callback, null, null);
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result);
+ });
+}
+
+module.exports = {
+ checkForAtomicOperators,
+ createIndex,
+ createIndexes,
+ ensureIndex,
+ group,
+ indexes,
+ indexExists,
+ indexInformation,
+ parallelCollectionScan,
+ save
+};
diff --git a/node_modules/mongodb/lib/operations/collections.js b/node_modules/mongodb/lib/operations/collections.js
new file mode 100644
index 0000000..eac690a
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/collections.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const handleCallback = require('../utils').handleCallback;
+
+let collection;
+function loadCollection() {
+ if (!collection) {
+ collection = require('../collection');
+ }
+ return collection;
+}
+
+class CollectionsOperation extends OperationBase {
+ constructor(db, options) {
+ super(options);
+
+ this.db = db;
+ }
+
+ execute(callback) {
+ const db = this.db;
+ let options = this.options;
+
+ let Collection = loadCollection();
+
+ options = Object.assign({}, options, { nameOnly: true });
+ // Let's get the collection names
+ db.listCollections({}, options).toArray((err, documents) => {
+ if (err != null) return handleCallback(callback, err, null);
+ // Filter collections removing any illegal ones
+ documents = documents.filter(doc => {
+ return doc.name.indexOf('$') === -1;
+ });
+
+ // Return the collection objects
+ handleCallback(
+ callback,
+ null,
+ documents.map(d => {
+ return new Collection(
+ db,
+ db.s.topology,
+ db.databaseName,
+ d.name,
+ db.s.pkFactory,
+ db.s.options
+ );
+ })
+ );
+ });
+ }
+}
+
+module.exports = CollectionsOperation;
diff --git a/node_modules/mongodb/lib/operations/command.js b/node_modules/mongodb/lib/operations/command.js
new file mode 100644
index 0000000..3c795be
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/command.js
@@ -0,0 +1,120 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const OperationBase = require('./operation').OperationBase;
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const debugOptions = require('../utils').debugOptions;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const ReadPreference = require('../core').ReadPreference;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const MongoDBNamespace = require('../utils').MongoDBNamespace;
+
+const debugFields = [
+ 'authSource',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'native_parser',
+ 'forceServerObjectId',
+ 'serializeFunctions',
+ 'raw',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'bufferMaxEntries',
+ 'numberOfRetries',
+ 'retryMiliSeconds',
+ 'readPreference',
+ 'pkFactory',
+ 'parentDb',
+ 'promiseLibrary',
+ 'noListener'
+];
+
+class CommandOperation extends OperationBase {
+ constructor(db, options, collection, command) {
+ super(options);
+
+ if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
+ if (collection != null) {
+ this.options.readPreference = resolveReadPreference(collection, options);
+ } else {
+ this.options.readPreference = resolveReadPreference(db, options);
+ }
+ } else {
+ if (collection != null) {
+ applyWriteConcern(this.options, { db, coll: collection }, this.options);
+ } else {
+ applyWriteConcern(this.options, { db }, this.options);
+ }
+ this.options.readPreference = ReadPreference.primary;
+ }
+
+ this.db = db;
+
+ if (command != null) {
+ this.command = command;
+ }
+
+ if (collection != null) {
+ this.collection = collection;
+ }
+ }
+
+ _buildCommand() {
+ if (this.command != null) {
+ return this.command;
+ }
+ }
+
+ execute(callback) {
+ const db = this.db;
+ const options = Object.assign({}, this.options);
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ let command;
+ try {
+ command = this._buildCommand();
+ } catch (e) {
+ return callback(e);
+ }
+
+ // Get the db name we are executing against
+ const dbName = options.dbName || options.authdb || db.databaseName;
+
+ // Convert the readPreference if its not a write
+ if (this.hasAspect(Aspect.WRITE_OPERATION)) {
+ if (options.writeConcern && (!options.session || !options.session.inTransaction())) {
+ command.writeConcern = options.writeConcern;
+ }
+ }
+
+ // Debug information
+ if (db.s.logger.isDebug()) {
+ db.s.logger.debug(
+ `executing command ${JSON.stringify(
+ command
+ )} against ${dbName}.$cmd with options [${JSON.stringify(
+ debugOptions(debugFields, options)
+ )}]`
+ );
+ }
+
+ const namespace =
+ this.namespace != null ? this.namespace : new MongoDBNamespace(dbName, '$cmd');
+
+ // Execute command
+ db.s.topology.command(namespace, command, options, (err, result) => {
+ if (err) return handleCallback(callback, err);
+ if (options.full) return handleCallback(callback, null, result);
+ handleCallback(callback, null, result.result);
+ });
+ }
+}
+
+module.exports = CommandOperation;
diff --git a/node_modules/mongodb/lib/operations/command_v2.js b/node_modules/mongodb/lib/operations/command_v2.js
new file mode 100644
index 0000000..8081d90
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/command_v2.js
@@ -0,0 +1,107 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const OperationBase = require('./operation').OperationBase;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const ReadConcern = require('../read_concern');
+const WriteConcern = require('../write_concern');
+const maxWireVersion = require('../core/utils').maxWireVersion;
+const commandSupportsReadConcern = require('../core/sessions').commandSupportsReadConcern;
+const MongoError = require('../error').MongoError;
+
+const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5;
+
+class CommandOperationV2 extends OperationBase {
+ constructor(parent, options, operationOptions) {
+ super(options);
+
+ this.ns = parent.s.namespace.withCollection('$cmd');
+ this.readPreference = resolveReadPreference(parent, this.options);
+ this.readConcern = resolveReadConcern(parent, this.options);
+ this.writeConcern = resolveWriteConcern(parent, this.options);
+ this.explain = false;
+
+ if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
+ this.fullResponse = true;
+ }
+
+ // TODO: A lot of our code depends on having the read preference in the options. This should
+ // go away, but also requires massive test rewrites.
+ this.options.readPreference = this.readPreference;
+
+ // TODO(NODE-2056): make logger another "inheritable" property
+ if (parent.s.logger) {
+ this.logger = parent.s.logger;
+ } else if (parent.s.db && parent.s.db.logger) {
+ this.logger = parent.s.db.logger;
+ }
+ }
+
+ executeCommand(server, cmd, callback) {
+ // TODO: consider making this a non-enumerable property
+ this.server = server;
+
+ const options = this.options;
+ const serverWireVersion = maxWireVersion(server);
+ const inTransaction = this.session && this.session.inTransaction();
+
+ if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) {
+ Object.assign(cmd, { readConcern: this.readConcern });
+ }
+
+ if (options.collation && serverWireVersion < SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
+ callback(
+ new MongoError(
+ `Server ${server.name}, which reports wire version ${serverWireVersion}, does not support collation`
+ )
+ );
+ return;
+ }
+
+ if (serverWireVersion >= SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
+ if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION)) {
+ Object.assign(cmd, { writeConcern: this.writeConcern });
+ }
+
+ if (options.collation && typeof options.collation === 'object') {
+ Object.assign(cmd, { collation: options.collation });
+ }
+ }
+
+ if (typeof options.maxTimeMS === 'number') {
+ cmd.maxTimeMS = options.maxTimeMS;
+ }
+
+ if (typeof options.comment === 'string') {
+ cmd.comment = options.comment;
+ }
+
+ if (this.logger && this.logger.isDebug()) {
+ this.logger.debug(`executing command ${JSON.stringify(cmd)} against ${this.ns}`);
+ }
+
+ server.command(this.ns.toString(), cmd, this.options, (err, result) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ if (this.fullResponse) {
+ callback(null, result);
+ return;
+ }
+
+ callback(null, result.result);
+ });
+ }
+}
+
+function resolveWriteConcern(parent, options) {
+ return WriteConcern.fromOptions(options) || parent.writeConcern;
+}
+
+function resolveReadConcern(parent, options) {
+ return ReadConcern.fromOptions(options) || parent.readConcern;
+}
+
+module.exports = CommandOperationV2;
diff --git a/node_modules/mongodb/lib/operations/common_functions.js b/node_modules/mongodb/lib/operations/common_functions.js
new file mode 100644
index 0000000..c027697
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/common_functions.js
@@ -0,0 +1,409 @@
+'use strict';
+
+const applyRetryableWrites = require('../utils').applyRetryableWrites;
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const decorateWithCollation = require('../utils').decorateWithCollation;
+const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
+const executeCommand = require('./db_ops').executeCommand;
+const formattedOrderClause = require('../utils').formattedOrderClause;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const ReadPreference = require('../core').ReadPreference;
+const toError = require('../utils').toError;
+const CursorState = require('../core/cursor').CursorState;
+
+/**
+ * Build the count command.
+ *
+ * @method
+ * @param {collectionOrCursor} an instance of a collection or cursor
+ * @param {object} query The query for the count.
+ * @param {object} [options] Optional settings. See Collection.prototype.count and Cursor.prototype.count for a list of options.
+ */
+function buildCountCommand(collectionOrCursor, query, options) {
+ const skip = options.skip;
+ const limit = options.limit;
+ let hint = options.hint;
+ const maxTimeMS = options.maxTimeMS;
+ query = query || {};
+
+ // Final query
+ const cmd = {
+ count: options.collectionName,
+ query: query
+ };
+
+ if (collectionOrCursor.s.numberOfRetries) {
+ // collectionOrCursor is a cursor
+ if (collectionOrCursor.options.hint) {
+ hint = collectionOrCursor.options.hint;
+ } else if (collectionOrCursor.cmd.hint) {
+ hint = collectionOrCursor.cmd.hint;
+ }
+ decorateWithCollation(cmd, collectionOrCursor, collectionOrCursor.cmd);
+ } else {
+ decorateWithCollation(cmd, collectionOrCursor, options);
+ }
+
+ // Add limit, skip and maxTimeMS if defined
+ if (typeof skip === 'number') cmd.skip = skip;
+ if (typeof limit === 'number') cmd.limit = limit;
+ if (typeof maxTimeMS === 'number') cmd.maxTimeMS = maxTimeMS;
+ if (hint) cmd.hint = hint;
+
+ // Do we have a readConcern specified
+ decorateWithReadConcern(cmd, collectionOrCursor);
+
+ return cmd;
+}
+
+function deleteCallback(err, r, callback) {
+ if (callback == null) return;
+ if (err && callback) return callback(err);
+ if (r == null) return callback(null, { result: { ok: 1 } });
+ r.deletedCount = r.result.n;
+ if (callback) callback(null, r);
+}
+
+/**
+ * Find and update a document.
+ *
+ * @method
+ * @param {Collection} a Collection instance.
+ * @param {object} query Query object to locate the object to modify.
+ * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
+ * @param {object} doc The fields/vals to be updated.
+ * @param {object} [options] Optional settings. See Collection.prototype.findAndModify for a list of options.
+ * @param {Collection~findAndModifyCallback} [callback] The command result callback
+ * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
+ */
+function findAndModify(coll, query, sort, doc, options, callback) {
+ // Create findAndModify command object
+ const queryObject = {
+ findAndModify: coll.collectionName,
+ query: query
+ };
+
+ sort = formattedOrderClause(sort);
+ if (sort) {
+ queryObject.sort = sort;
+ }
+
+ queryObject.new = options.new ? true : false;
+ queryObject.remove = options.remove ? true : false;
+ queryObject.upsert = options.upsert ? true : false;
+
+ const projection = options.projection || options.fields;
+
+ if (projection) {
+ queryObject.fields = projection;
+ }
+
+ if (options.arrayFilters) {
+ queryObject.arrayFilters = options.arrayFilters;
+ delete options.arrayFilters;
+ }
+
+ if (doc && !options.remove) {
+ queryObject.update = doc;
+ }
+
+ if (options.maxTimeMS) queryObject.maxTimeMS = options.maxTimeMS;
+
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ options.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
+
+ // No check on the documents
+ options.checkKeys = false;
+
+ // Final options for retryable writes and write concern
+ let finalOptions = Object.assign({}, options);
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
+
+ // Decorate the findAndModify command with the write Concern
+ if (finalOptions.writeConcern) {
+ queryObject.writeConcern = finalOptions.writeConcern;
+ }
+
+ // Have we specified bypassDocumentValidation
+ if (finalOptions.bypassDocumentValidation === true) {
+ queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
+ }
+
+ finalOptions.readPreference = ReadPreference.primary;
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(queryObject, coll, finalOptions);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Execute the command
+ executeCommand(coll.s.db, queryObject, finalOptions, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+
+ return handleCallback(callback, null, result);
+ });
+}
+
+/**
+ * Retrieves this collections index info.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to retrieve the index info.
+ * @param {string} name The name of the collection.
+ * @param {object} [options] Optional settings. See Db.prototype.indexInformation for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function indexInformation(db, name, options, callback) {
+ // If we specified full information
+ const full = options['full'] == null ? false : options['full'];
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+ // Process all the results from the index command and collection
+ function processResults(indexes) {
+ // Contains all the information
+ let info = {};
+ // Process all the indexes
+ for (let i = 0; i < indexes.length; i++) {
+ const index = indexes[i];
+ // Let's unpack the object
+ info[index.name] = [];
+ for (let name in index.key) {
+ info[index.name].push([name, index.key[name]]);
+ }
+ }
+
+ return info;
+ }
+
+ // Get the list of indexes of the specified collection
+ db.collection(name)
+ .listIndexes(options)
+ .toArray((err, indexes) => {
+ if (err) return callback(toError(err));
+ if (!Array.isArray(indexes)) return handleCallback(callback, null, []);
+ if (full) return handleCallback(callback, null, indexes);
+ handleCallback(callback, null, processResults(indexes));
+ });
+}
+
+function prepareDocs(coll, docs, options) {
+ const forceServerObjectId =
+ typeof options.forceServerObjectId === 'boolean'
+ ? options.forceServerObjectId
+ : coll.s.db.options.forceServerObjectId;
+
+ // no need to modify the docs if server sets the ObjectId
+ if (forceServerObjectId === true) {
+ return docs;
+ }
+
+ return docs.map(doc => {
+ if (forceServerObjectId !== true && doc._id == null) {
+ doc._id = coll.s.pkFactory.createPk();
+ }
+
+ return doc;
+ });
+}
+
+// Get the next available document from the cursor, returns null if no more documents are available.
+function nextObject(cursor, callback) {
+ if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead())) {
+ return handleCallback(
+ callback,
+ MongoError.create({ message: 'Cursor is closed', driver: true })
+ );
+ }
+
+ if (cursor.s.state === CursorState.INIT && cursor.cmd && cursor.cmd.sort) {
+ try {
+ cursor.cmd.sort = formattedOrderClause(cursor.cmd.sort);
+ } catch (err) {
+ return handleCallback(callback, err);
+ }
+ }
+
+ // Get the next object
+ cursor._next((err, doc) => {
+ cursor.s.state = CursorState.OPEN;
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, null, doc);
+ });
+}
+
+function insertDocuments(coll, docs, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+ // Ensure we are operating on an array op docs
+ docs = Array.isArray(docs) ? docs : [docs];
+
+ // Final options for retryable writes and write concern
+ let finalOptions = Object.assign({}, options);
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
+
+ // If keep going set unordered
+ if (finalOptions.keepGoing === true) finalOptions.ordered = false;
+ finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
+
+ docs = prepareDocs(coll, docs, options);
+
+ // File inserts
+ coll.s.topology.insert(coll.s.namespace, docs, finalOptions, (err, result) => {
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err);
+ if (result == null) return handleCallback(callback, null, null);
+ if (result.result.code) return handleCallback(callback, toError(result.result));
+ if (result.result.writeErrors)
+ return handleCallback(callback, toError(result.result.writeErrors[0]));
+ // Add docs to the list
+ result.ops = docs;
+ // Return the results
+ handleCallback(callback, null, result);
+ });
+}
+
+function removeDocuments(coll, selector, options, callback) {
+ if (typeof options === 'function') {
+ (callback = options), (options = {});
+ } else if (typeof selector === 'function') {
+ callback = selector;
+ options = {};
+ selector = {};
+ }
+
+ // Create an empty options object if the provided one is null
+ options = options || {};
+
+ // Final options for retryable writes and write concern
+ let finalOptions = Object.assign({}, options);
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
+
+ // If selector is null set empty
+ if (selector == null) selector = {};
+
+ // Build the op
+ const op = { q: selector, limit: 0 };
+ if (options.single) {
+ op.limit = 1;
+ } else if (finalOptions.retryWrites) {
+ finalOptions.retryWrites = false;
+ }
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(finalOptions, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Execute the remove
+ coll.s.topology.remove(coll.s.namespace, [op], finalOptions, (err, result) => {
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err, null);
+ if (result == null) return handleCallback(callback, null, null);
+ if (result.result.code) return handleCallback(callback, toError(result.result));
+ if (result.result.writeErrors) {
+ return handleCallback(callback, toError(result.result.writeErrors[0]));
+ }
+
+ // Return the results
+ handleCallback(callback, null, result);
+ });
+}
+
+function updateDocuments(coll, selector, document, options, callback) {
+ if ('function' === typeof options) (callback = options), (options = null);
+ if (options == null) options = {};
+ if (!('function' === typeof callback)) callback = null;
+
+ // If we are not providing a selector or document throw
+ if (selector == null || typeof selector !== 'object')
+ return callback(toError('selector must be a valid JavaScript object'));
+ if (document == null || typeof document !== 'object')
+ return callback(toError('document must be a valid JavaScript object'));
+
+ // Final options for retryable writes and write concern
+ let finalOptions = Object.assign({}, options);
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
+
+ // Do we return the actual result document
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
+
+ // Execute the operation
+ const op = { q: selector, u: document };
+ op.upsert = options.upsert !== void 0 ? !!options.upsert : false;
+ op.multi = options.multi !== void 0 ? !!options.multi : false;
+
+ if (options.hint) {
+ op.hint = options.hint;
+ }
+
+ if (finalOptions.arrayFilters) {
+ op.arrayFilters = finalOptions.arrayFilters;
+ delete finalOptions.arrayFilters;
+ }
+
+ if (finalOptions.retryWrites && op.multi) {
+ finalOptions.retryWrites = false;
+ }
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(finalOptions, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Update options
+ coll.s.topology.update(coll.s.namespace, [op], finalOptions, (err, result) => {
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err, null);
+ if (result == null) return handleCallback(callback, null, null);
+ if (result.result.code) return handleCallback(callback, toError(result.result));
+ if (result.result.writeErrors)
+ return handleCallback(callback, toError(result.result.writeErrors[0]));
+ // Return the results
+ handleCallback(callback, null, result);
+ });
+}
+
+function updateCallback(err, r, callback) {
+ if (callback == null) return;
+ if (err) return callback(err);
+ if (r == null) return callback(null, { result: { ok: 1 } });
+ r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
+ r.upsertedId =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0
+ ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
+ : null;
+ r.upsertedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
+ r.matchedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
+ callback(null, r);
+}
+
+module.exports = {
+ buildCountCommand,
+ deleteCallback,
+ findAndModify,
+ indexInformation,
+ nextObject,
+ prepareDocs,
+ insertDocuments,
+ removeDocuments,
+ updateDocuments,
+ updateCallback
+};
diff --git a/node_modules/mongodb/lib/operations/connect.js b/node_modules/mongodb/lib/operations/connect.js
new file mode 100644
index 0000000..bcdd3eb
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/connect.js
@@ -0,0 +1,798 @@
+'use strict';
+
+const deprecate = require('util').deprecate;
+const Logger = require('../core').Logger;
+const MongoCredentials = require('../core').MongoCredentials;
+const MongoError = require('../core').MongoError;
+const Mongos = require('../topologies/mongos');
+const NativeTopology = require('../topologies/native_topology');
+const parse = require('../core').parseConnectionString;
+const ReadConcern = require('../read_concern');
+const ReadPreference = require('../core').ReadPreference;
+const ReplSet = require('../topologies/replset');
+const Server = require('../topologies/server');
+const ServerSessionPool = require('../core').Sessions.ServerSessionPool;
+const emitDeprecationWarning = require('../utils').emitDeprecationWarning;
+const fs = require('fs');
+const BSON = require('../core/connection/utils').retrieveBSON();
+const CMAP_EVENT_NAMES = require('../cmap/events').CMAP_EVENT_NAMES;
+
+let client;
+function loadClient() {
+ if (!client) {
+ client = require('../mongo_client');
+ }
+ return client;
+}
+
+const legacyParse = deprecate(
+ require('../url_parser'),
+ 'current URL string parser is deprecated, and will be removed in a future version. ' +
+ 'To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.'
+);
+
+const AUTH_MECHANISM_INTERNAL_MAP = {
+ DEFAULT: 'default',
+ 'MONGODB-CR': 'mongocr',
+ PLAIN: 'plain',
+ 'MONGODB-X509': 'x509',
+ 'SCRAM-SHA-1': 'scram-sha-1',
+ 'SCRAM-SHA-256': 'scram-sha-256'
+};
+
+const monitoringEvents = [
+ 'timeout',
+ 'close',
+ 'serverOpening',
+ 'serverDescriptionChanged',
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'serverClosed',
+ 'topologyOpening',
+ 'topologyClosed',
+ 'topologyDescriptionChanged',
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed',
+ 'joined',
+ 'left',
+ 'ping',
+ 'ha',
+ 'all',
+ 'fullsetup',
+ 'open'
+];
+
+const VALID_AUTH_MECHANISMS = new Set([
+ 'DEFAULT',
+ 'MONGODB-CR',
+ 'PLAIN',
+ 'MONGODB-X509',
+ 'SCRAM-SHA-1',
+ 'SCRAM-SHA-256',
+ 'GSSAPI'
+]);
+
+const validOptionNames = [
+ 'poolSize',
+ 'ssl',
+ 'sslValidate',
+ 'sslCA',
+ 'sslCert',
+ 'sslKey',
+ 'sslPass',
+ 'sslCRL',
+ 'autoReconnect',
+ 'noDelay',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'connectTimeoutMS',
+ 'family',
+ 'socketTimeoutMS',
+ 'reconnectTries',
+ 'reconnectInterval',
+ 'ha',
+ 'haInterval',
+ 'replicaSet',
+ 'secondaryAcceptableLatencyMS',
+ 'acceptableLatencyMS',
+ 'connectWithNoPrimary',
+ 'authSource',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'forceServerObjectId',
+ 'serializeFunctions',
+ 'ignoreUndefined',
+ 'raw',
+ 'bufferMaxEntries',
+ 'readPreference',
+ 'pkFactory',
+ 'promiseLibrary',
+ 'readConcern',
+ 'maxStalenessSeconds',
+ 'loggerLevel',
+ 'logger',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'promoteLongs',
+ 'domainsEnabled',
+ 'checkServerIdentity',
+ 'validateOptions',
+ 'appname',
+ 'auth',
+ 'user',
+ 'password',
+ 'authMechanism',
+ 'compression',
+ 'fsync',
+ 'readPreferenceTags',
+ 'numberOfRetries',
+ 'auto_reconnect',
+ 'minSize',
+ 'monitorCommands',
+ 'retryWrites',
+ 'retryReads',
+ 'useNewUrlParser',
+ 'useUnifiedTopology',
+ 'serverSelectionTimeoutMS',
+ 'useRecoveryToken',
+ 'autoEncryption',
+ 'driverInfo',
+ 'tls',
+ 'tlsInsecure',
+ 'tlsinsecure',
+ 'tlsAllowInvalidCertificates',
+ 'tlsAllowInvalidHostnames',
+ 'tlsCAFile',
+ 'tlsCertificateFile',
+ 'tlsCertificateKeyFile',
+ 'tlsCertificateKeyFilePassword',
+ 'minHeartbeatFrequencyMS',
+ 'heartbeatFrequencyMS',
+ 'waitQueueTimeoutMS'
+];
+
+const ignoreOptionNames = ['native_parser'];
+const legacyOptionNames = ['server', 'replset', 'replSet', 'mongos', 'db'];
+
+// Validate options object
+function validOptions(options) {
+ const _validOptions = validOptionNames.concat(legacyOptionNames);
+
+ for (const name in options) {
+ if (ignoreOptionNames.indexOf(name) !== -1) {
+ continue;
+ }
+
+ if (_validOptions.indexOf(name) === -1) {
+ if (options.validateOptions) {
+ return new MongoError(`option ${name} is not supported`);
+ } else {
+ console.warn(`the options [${name}] is not supported`);
+ }
+ }
+
+ if (legacyOptionNames.indexOf(name) !== -1) {
+ console.warn(
+ `the server/replset/mongos/db options are deprecated, ` +
+ `all their options are supported at the top level of the options object [${validOptionNames}]`
+ );
+ }
+ }
+}
+
+const LEGACY_OPTIONS_MAP = validOptionNames.reduce((obj, name) => {
+ obj[name.toLowerCase()] = name;
+ return obj;
+}, {});
+
+function addListeners(mongoClient, topology) {
+ topology.on('authenticated', createListener(mongoClient, 'authenticated'));
+ topology.on('error', createListener(mongoClient, 'error'));
+ topology.on('timeout', createListener(mongoClient, 'timeout'));
+ topology.on('close', createListener(mongoClient, 'close'));
+ topology.on('parseError', createListener(mongoClient, 'parseError'));
+ topology.once('open', createListener(mongoClient, 'open'));
+ topology.once('fullsetup', createListener(mongoClient, 'fullsetup'));
+ topology.once('all', createListener(mongoClient, 'all'));
+ topology.on('reconnect', createListener(mongoClient, 'reconnect'));
+}
+
+function assignTopology(client, topology) {
+ client.topology = topology;
+
+ if (!(topology instanceof NativeTopology)) {
+ topology.s.sessionPool = new ServerSessionPool(topology.s.coreTopology);
+ }
+}
+
+// Clear out all events
+function clearAllEvents(topology) {
+ monitoringEvents.forEach(event => topology.removeAllListeners(event));
+}
+
+// Collect all events in order from SDAM
+function collectEvents(mongoClient, topology) {
+ let MongoClient = loadClient();
+ const collectedEvents = [];
+
+ if (mongoClient instanceof MongoClient) {
+ monitoringEvents.forEach(event => {
+ topology.on(event, (object1, object2) => {
+ if (event === 'open') {
+ collectedEvents.push({ event: event, object1: mongoClient });
+ } else {
+ collectedEvents.push({ event: event, object1: object1, object2: object2 });
+ }
+ });
+ });
+ }
+
+ return collectedEvents;
+}
+
+function resolveTLSOptions(options) {
+ if (options.tls == null) {
+ return;
+ }
+
+ ['sslCA', 'sslKey', 'sslCert'].forEach(optionName => {
+ if (options[optionName]) {
+ options[optionName] = fs.readFileSync(options[optionName]);
+ }
+ });
+}
+
+const emitDeprecationForNonUnifiedTopology = deprecate(() => {},
+'current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. ' + 'To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.');
+
+function connect(mongoClient, url, options, callback) {
+ options = Object.assign({}, options);
+
+ // If callback is null throw an exception
+ if (callback == null) {
+ throw new Error('no callback function provided');
+ }
+
+ let didRequestAuthentication = false;
+ const logger = Logger('MongoClient', options);
+
+ // Did we pass in a Server/ReplSet/Mongos
+ if (url instanceof Server || url instanceof ReplSet || url instanceof Mongos) {
+ return connectWithUrl(mongoClient, url, options, connectCallback);
+ }
+
+ const useNewUrlParser = options.useNewUrlParser !== false;
+
+ const parseFn = useNewUrlParser ? parse : legacyParse;
+ const transform = useNewUrlParser ? transformUrlOptions : legacyTransformUrlOptions;
+
+ parseFn(url, options, (err, _object) => {
+ // Do not attempt to connect if parsing error
+ if (err) return callback(err);
+
+ // Flatten
+ const object = transform(_object);
+
+ // Parse the string
+ const _finalOptions = createUnifiedOptions(object, options);
+
+ // Check if we have connection and socket timeout set
+ if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
+ if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 10000;
+ if (_finalOptions.retryWrites == null) _finalOptions.retryWrites = true;
+ if (_finalOptions.useRecoveryToken == null) _finalOptions.useRecoveryToken = true;
+ if (_finalOptions.readPreference == null) _finalOptions.readPreference = 'primary';
+
+ if (_finalOptions.db_options && _finalOptions.db_options.auth) {
+ delete _finalOptions.db_options.auth;
+ }
+
+ // resolve tls options if needed
+ resolveTLSOptions(_finalOptions);
+
+ // Store the merged options object
+ mongoClient.s.options = _finalOptions;
+
+ // Failure modes
+ if (object.servers.length === 0) {
+ return callback(new Error('connection string must contain at least one seed host'));
+ }
+
+ if (_finalOptions.auth && !_finalOptions.credentials) {
+ try {
+ didRequestAuthentication = true;
+ _finalOptions.credentials = generateCredentials(
+ mongoClient,
+ _finalOptions.auth.user,
+ _finalOptions.auth.password,
+ _finalOptions
+ );
+ } catch (err) {
+ return callback(err);
+ }
+ }
+
+ if (_finalOptions.useUnifiedTopology) {
+ return createTopology(mongoClient, 'unified', _finalOptions, connectCallback);
+ }
+
+ emitDeprecationForNonUnifiedTopology();
+
+ // Do we have a replicaset then skip discovery and go straight to connectivity
+ if (_finalOptions.replicaSet || _finalOptions.rs_name) {
+ return createTopology(mongoClient, 'replicaset', _finalOptions, connectCallback);
+ } else if (object.servers.length > 1) {
+ return createTopology(mongoClient, 'mongos', _finalOptions, connectCallback);
+ } else {
+ return createServer(mongoClient, _finalOptions, connectCallback);
+ }
+ });
+
+ function connectCallback(err, topology) {
+ const warningMessage = `seed list contains no mongos proxies, replicaset connections requires the parameter replicaSet to be supplied in the URI or options object, mongodb://server:port/db?replicaSet=name`;
+ if (err && err.message === 'no mongos proxies found in seed list') {
+ if (logger.isWarn()) {
+ logger.warn(warningMessage);
+ }
+
+ // Return a more specific error message for MongoClient.connect
+ return callback(new MongoError(warningMessage));
+ }
+
+ if (didRequestAuthentication) {
+ mongoClient.emit('authenticated', null, true);
+ }
+
+ // Return the error and db instance
+ callback(err, topology);
+ }
+}
+
+function connectWithUrl(mongoClient, url, options, connectCallback) {
+ // Set the topology
+ assignTopology(mongoClient, url);
+
+ // Add listeners
+ addListeners(mongoClient, url);
+
+ // Propagate the events to the client
+ relayEvents(mongoClient, url);
+
+ let finalOptions = Object.assign({}, options);
+
+ // If we have a readPreference passed in by the db options, convert it from a string
+ if (typeof options.readPreference === 'string' || typeof options.read_preference === 'string') {
+ finalOptions.readPreference = new ReadPreference(
+ options.readPreference || options.read_preference
+ );
+ }
+
+ const isDoingAuth = finalOptions.user || finalOptions.password || finalOptions.authMechanism;
+ if (isDoingAuth && !finalOptions.credentials) {
+ try {
+ finalOptions.credentials = generateCredentials(
+ mongoClient,
+ finalOptions.user,
+ finalOptions.password,
+ finalOptions
+ );
+ } catch (err) {
+ return connectCallback(err, url);
+ }
+ }
+
+ return url.connect(finalOptions, connectCallback);
+}
+
+function createListener(mongoClient, event) {
+ const eventSet = new Set(['all', 'fullsetup', 'open', 'reconnect']);
+ return (v1, v2) => {
+ if (eventSet.has(event)) {
+ return mongoClient.emit(event, mongoClient);
+ }
+
+ mongoClient.emit(event, v1, v2);
+ };
+}
+
+function createServer(mongoClient, options, callback) {
+ // Pass in the promise library
+ options.promiseLibrary = mongoClient.s.promiseLibrary;
+
+ // Set default options
+ const servers = translateOptions(options);
+
+ const server = servers[0];
+
+ // Propagate the events to the client
+ const collectedEvents = collectEvents(mongoClient, server);
+
+ // Connect to topology
+ server.connect(options, (err, topology) => {
+ if (err) {
+ server.close(true);
+ return callback(err);
+ }
+ // Clear out all the collected event listeners
+ clearAllEvents(server);
+
+ // Relay all the events
+ relayEvents(mongoClient, server);
+ // Add listeners
+ addListeners(mongoClient, server);
+ // Check if we are really speaking to a mongos
+ const ismaster = topology.lastIsMaster();
+
+ // Set the topology
+ assignTopology(mongoClient, topology);
+
+ // Do we actually have a mongos
+ if (ismaster && ismaster.msg === 'isdbgrid') {
+ // Destroy the current connection
+ topology.close();
+ // Create mongos connection instead
+ return createTopology(mongoClient, 'mongos', options, callback);
+ }
+
+ // Fire all the events
+ replayEvents(mongoClient, collectedEvents);
+ // Otherwise callback
+ callback(err, topology);
+ });
+}
+
+const DEPRECATED_UNIFIED_EVENTS = new Set([
+ 'reconnect',
+ 'reconnectFailed',
+ 'attemptReconnect',
+ 'joined',
+ 'left',
+ 'ping',
+ 'ha',
+ 'all',
+ 'fullsetup',
+ 'open'
+]);
+
+function registerDeprecatedEventNotifiers(client) {
+ client.on('newListener', eventName => {
+ if (DEPRECATED_UNIFIED_EVENTS.has(eventName)) {
+ emitDeprecationWarning(
+ `The \`${eventName}\` event is no longer supported by the unified topology, please read more by visiting http://bit.ly/2D8WfT6`,
+ 'DeprecationWarning'
+ );
+ }
+ });
+}
+
+function createTopology(mongoClient, topologyType, options, callback) {
+ // Pass in the promise library
+ options.promiseLibrary = mongoClient.s.promiseLibrary;
+
+ const translationOptions = {};
+ if (topologyType === 'unified') translationOptions.createServers = false;
+
+ // Set default options
+ const servers = translateOptions(options, translationOptions);
+
+ // determine CSFLE support
+ if (options.autoEncryption != null) {
+ let AutoEncrypter;
+ try {
+ require.resolve('mongodb-client-encryption');
+ } catch (err) {
+ callback(
+ new MongoError(
+ 'Auto-encryption requested, but the module is not installed. Please add `mongodb-client-encryption` as a dependency of your project'
+ )
+ );
+ return;
+ }
+
+ try {
+ let mongodbClientEncryption = require('mongodb-client-encryption');
+ if (typeof mongodbClientEncryption.extension !== 'function') {
+ callback(
+ new MongoError(
+ 'loaded version of `mongodb-client-encryption` does not have property `extension`. Please make sure you are loading the correct version of `mongodb-client-encryption`'
+ )
+ );
+ }
+ AutoEncrypter = mongodbClientEncryption.extension(require('../../index')).AutoEncrypter;
+ } catch (err) {
+ callback(err);
+ return;
+ }
+
+ const mongoCryptOptions = Object.assign(
+ {
+ bson:
+ options.bson ||
+ new BSON([
+ BSON.Binary,
+ BSON.Code,
+ BSON.DBRef,
+ BSON.Decimal128,
+ BSON.Double,
+ BSON.Int32,
+ BSON.Long,
+ BSON.Map,
+ BSON.MaxKey,
+ BSON.MinKey,
+ BSON.ObjectId,
+ BSON.BSONRegExp,
+ BSON.Symbol,
+ BSON.Timestamp
+ ])
+ },
+ options.autoEncryption
+ );
+
+ options.autoEncrypter = new AutoEncrypter(mongoClient, mongoCryptOptions);
+ }
+
+ // Create the topology
+ let topology;
+ if (topologyType === 'mongos') {
+ topology = new Mongos(servers, options);
+ } else if (topologyType === 'replicaset') {
+ topology = new ReplSet(servers, options);
+ } else if (topologyType === 'unified') {
+ topology = new NativeTopology(options.servers, options);
+ registerDeprecatedEventNotifiers(mongoClient);
+ }
+
+ // Add listeners
+ addListeners(mongoClient, topology);
+
+ // Propagate the events to the client
+ relayEvents(mongoClient, topology);
+
+ // Open the connection
+ assignTopology(mongoClient, topology);
+
+ // initialize CSFLE if requested
+ if (options.autoEncrypter) {
+ options.autoEncrypter.init(err => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ topology.connect(options, err => {
+ if (err) {
+ topology.close(true);
+ callback(err);
+ return;
+ }
+
+ callback(undefined, topology);
+ });
+ });
+
+ return;
+ }
+
+ // otherwise connect normally
+ topology.connect(options, err => {
+ if (err) {
+ topology.close(true);
+ return callback(err);
+ }
+
+ callback(undefined, topology);
+ return;
+ });
+}
+
+function createUnifiedOptions(finalOptions, options) {
+ const childOptions = [
+ 'mongos',
+ 'server',
+ 'db',
+ 'replset',
+ 'db_options',
+ 'server_options',
+ 'rs_options',
+ 'mongos_options'
+ ];
+ const noMerge = ['readconcern', 'compression', 'autoencryption'];
+
+ for (const name in options) {
+ if (noMerge.indexOf(name.toLowerCase()) !== -1) {
+ finalOptions[name] = options[name];
+ } else if (childOptions.indexOf(name.toLowerCase()) !== -1) {
+ finalOptions = mergeOptions(finalOptions, options[name], false);
+ } else {
+ if (
+ options[name] &&
+ typeof options[name] === 'object' &&
+ !Buffer.isBuffer(options[name]) &&
+ !Array.isArray(options[name])
+ ) {
+ finalOptions = mergeOptions(finalOptions, options[name], true);
+ } else {
+ finalOptions[name] = options[name];
+ }
+ }
+ }
+
+ return finalOptions;
+}
+
+function generateCredentials(client, username, password, options) {
+ options = Object.assign({}, options);
+
+ // the default db to authenticate against is 'self'
+ // if authententicate is called from a retry context, it may be another one, like admin
+ const source = options.authSource || options.authdb || options.dbName;
+
+ // authMechanism
+ const authMechanismRaw = options.authMechanism || 'DEFAULT';
+ const authMechanism = authMechanismRaw.toUpperCase();
+
+ if (!VALID_AUTH_MECHANISMS.has(authMechanism)) {
+ throw MongoError.create({
+ message: `authentication mechanism ${authMechanismRaw} not supported', options.authMechanism`,
+ driver: true
+ });
+ }
+
+ if (authMechanism === 'GSSAPI') {
+ return new MongoCredentials({
+ mechanism: process.platform === 'win32' ? 'sspi' : 'gssapi',
+ mechanismProperties: options,
+ source,
+ username,
+ password
+ });
+ }
+
+ return new MongoCredentials({
+ mechanism: AUTH_MECHANISM_INTERNAL_MAP[authMechanism],
+ source,
+ username,
+ password
+ });
+}
+
+function legacyTransformUrlOptions(object) {
+ return mergeOptions(createUnifiedOptions({}, object), object, false);
+}
+
+function mergeOptions(target, source, flatten) {
+ for (const name in source) {
+ if (source[name] && typeof source[name] === 'object' && flatten) {
+ target = mergeOptions(target, source[name], flatten);
+ } else {
+ target[name] = source[name];
+ }
+ }
+
+ return target;
+}
+
+function relayEvents(mongoClient, topology) {
+ const serverOrCommandEvents = [
+ // APM
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed',
+
+ // SDAM
+ 'serverOpening',
+ 'serverClosed',
+ 'serverDescriptionChanged',
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'topologyOpening',
+ 'topologyClosed',
+ 'topologyDescriptionChanged',
+
+ // Legacy
+ 'joined',
+ 'left',
+ 'ping',
+ 'ha'
+ ].concat(CMAP_EVENT_NAMES);
+
+ serverOrCommandEvents.forEach(event => {
+ topology.on(event, (object1, object2) => {
+ mongoClient.emit(event, object1, object2);
+ });
+ });
+}
+
+//
+// Replay any events due to single server connection switching to Mongos
+//
+function replayEvents(mongoClient, events) {
+ for (let i = 0; i < events.length; i++) {
+ mongoClient.emit(events[i].event, events[i].object1, events[i].object2);
+ }
+}
+
+function transformUrlOptions(_object) {
+ let object = Object.assign({ servers: _object.hosts }, _object.options);
+ for (let name in object) {
+ const camelCaseName = LEGACY_OPTIONS_MAP[name];
+ if (camelCaseName) {
+ object[camelCaseName] = object[name];
+ }
+ }
+
+ const hasUsername = _object.auth && _object.auth.username;
+ const hasAuthMechanism = _object.options && _object.options.authMechanism;
+ if (hasUsername || hasAuthMechanism) {
+ object.auth = Object.assign({}, _object.auth);
+ if (object.auth.db) {
+ object.authSource = object.authSource || object.auth.db;
+ }
+
+ if (object.auth.username) {
+ object.auth.user = object.auth.username;
+ }
+ }
+
+ if (_object.defaultDatabase) {
+ object.dbName = _object.defaultDatabase;
+ }
+
+ if (object.maxPoolSize) {
+ object.poolSize = object.maxPoolSize;
+ }
+
+ if (object.readConcernLevel) {
+ object.readConcern = new ReadConcern(object.readConcernLevel);
+ }
+
+ if (object.wTimeoutMS) {
+ object.wtimeout = object.wTimeoutMS;
+ }
+
+ if (_object.srvHost) {
+ object.srvHost = _object.srvHost;
+ }
+
+ return object;
+}
+
+function translateOptions(options, translationOptions) {
+ translationOptions = Object.assign({}, { createServers: true }, translationOptions);
+
+ // If we have a readPreference passed in by the db options
+ if (typeof options.readPreference === 'string' || typeof options.read_preference === 'string') {
+ options.readPreference = new ReadPreference(options.readPreference || options.read_preference);
+ }
+
+ // Do we have readPreference tags, add them
+ if (options.readPreference && (options.readPreferenceTags || options.read_preference_tags)) {
+ options.readPreference.tags = options.readPreferenceTags || options.read_preference_tags;
+ }
+
+ // Do we have maxStalenessSeconds
+ if (options.maxStalenessSeconds) {
+ options.readPreference.maxStalenessSeconds = options.maxStalenessSeconds;
+ }
+
+ // Set the socket and connection timeouts
+ if (options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
+ if (options.connectTimeoutMS == null) options.connectTimeoutMS = 10000;
+
+ if (!translationOptions.createServers) {
+ return;
+ }
+
+ // Create server instances
+ return options.servers.map(serverObj => {
+ return serverObj.domain_socket
+ ? new Server(serverObj.domain_socket, 27017, options)
+ : new Server(serverObj.host, serverObj.port, options);
+ });
+}
+
+module.exports = { validOptions, connect };
diff --git a/node_modules/mongodb/lib/operations/count.js b/node_modules/mongodb/lib/operations/count.js
new file mode 100644
index 0000000..a7216d6
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/count.js
@@ -0,0 +1,68 @@
+'use strict';
+
+const buildCountCommand = require('./common_functions').buildCountCommand;
+const OperationBase = require('./operation').OperationBase;
+
+class CountOperation extends OperationBase {
+ constructor(cursor, applySkipLimit, options) {
+ super(options);
+
+ this.cursor = cursor;
+ this.applySkipLimit = applySkipLimit;
+ }
+
+ execute(callback) {
+ const cursor = this.cursor;
+ const applySkipLimit = this.applySkipLimit;
+ const options = this.options;
+
+ if (applySkipLimit) {
+ if (typeof cursor.cursorSkip() === 'number') options.skip = cursor.cursorSkip();
+ if (typeof cursor.cursorLimit() === 'number') options.limit = cursor.cursorLimit();
+ }
+
+ // Ensure we have the right read preference inheritance
+ if (options.readPreference) {
+ cursor.setReadPreference(options.readPreference);
+ }
+
+ if (
+ typeof options.maxTimeMS !== 'number' &&
+ cursor.cmd &&
+ typeof cursor.cmd.maxTimeMS === 'number'
+ ) {
+ options.maxTimeMS = cursor.cmd.maxTimeMS;
+ }
+
+ let finalOptions = {};
+ finalOptions.skip = options.skip;
+ finalOptions.limit = options.limit;
+ finalOptions.hint = options.hint;
+ finalOptions.maxTimeMS = options.maxTimeMS;
+
+ // Command
+ finalOptions.collectionName = cursor.namespace.collection;
+
+ let command;
+ try {
+ command = buildCountCommand(cursor, cursor.cmd.query, finalOptions);
+ } catch (err) {
+ return callback(err);
+ }
+
+ // Set cursor server to the same as the topology
+ cursor.server = cursor.topology.s.coreTopology;
+
+ // Execute the command
+ cursor.topology.command(
+ cursor.namespace.withCollection('$cmd'),
+ command,
+ cursor.options,
+ (err, result) => {
+ callback(err, result ? result.result.n : null);
+ }
+ );
+ }
+}
+
+module.exports = CountOperation;
diff --git a/node_modules/mongodb/lib/operations/count_documents.js b/node_modules/mongodb/lib/operations/count_documents.js
new file mode 100644
index 0000000..d043abf
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/count_documents.js
@@ -0,0 +1,41 @@
+'use strict';
+
+const AggregateOperation = require('./aggregate');
+
+class CountDocumentsOperation extends AggregateOperation {
+ constructor(collection, query, options) {
+ const pipeline = [{ $match: query }];
+ if (typeof options.skip === 'number') {
+ pipeline.push({ $skip: options.skip });
+ }
+
+ if (typeof options.limit === 'number') {
+ pipeline.push({ $limit: options.limit });
+ }
+
+ pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });
+
+ super(collection, pipeline, options);
+ }
+
+ execute(server, callback) {
+ super.execute(server, (err, result) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ // NOTE: We're avoiding creating a cursor here to reduce the callstack.
+ const response = result.result;
+ if (response.cursor == null || response.cursor.firstBatch == null) {
+ callback(null, 0);
+ return;
+ }
+
+ const docs = response.cursor.firstBatch;
+ callback(null, docs.length ? docs[0].n : 0);
+ });
+ }
+}
+
+module.exports = CountDocumentsOperation;
diff --git a/node_modules/mongodb/lib/operations/create_collection.js b/node_modules/mongodb/lib/operations/create_collection.js
new file mode 100644
index 0000000..d8ab4ae
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/create_collection.js
@@ -0,0 +1,117 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const CommandOperation = require('./command');
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const handleCallback = require('../utils').handleCallback;
+const loadCollection = require('../dynamic_loaders').loadCollection;
+const MongoError = require('../core').MongoError;
+const ReadPreference = require('../core').ReadPreference;
+
+// Filter out any write concern options
+const illegalCommandFields = [
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'fsync',
+ 'autoIndexId',
+ 'strict',
+ 'serializeFunctions',
+ 'pkFactory',
+ 'raw',
+ 'readPreference',
+ 'session',
+ 'readConcern',
+ 'writeConcern'
+];
+
+class CreateCollectionOperation extends CommandOperation {
+ constructor(db, name, options) {
+ super(db, options);
+
+ this.name = name;
+ }
+
+ _buildCommand() {
+ const name = this.name;
+ const options = this.options;
+
+ // Create collection command
+ const cmd = { create: name };
+ // Add all optional parameters
+ for (let n in options) {
+ if (
+ options[n] != null &&
+ typeof options[n] !== 'function' &&
+ illegalCommandFields.indexOf(n) === -1
+ ) {
+ cmd[n] = options[n];
+ }
+ }
+
+ return cmd;
+ }
+
+ execute(callback) {
+ const db = this.db;
+ const name = this.name;
+ const options = this.options;
+
+ let Collection = loadCollection();
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ let listCollectionOptions = Object.assign({}, options, { nameOnly: true });
+ listCollectionOptions = applyWriteConcern(listCollectionOptions, { db }, listCollectionOptions);
+
+ // Check if we have the name
+ db.listCollections({ name }, listCollectionOptions)
+ .setReadPreference(ReadPreference.PRIMARY)
+ .toArray((err, collections) => {
+ if (err != null) return handleCallback(callback, err, null);
+ if (collections.length > 0 && listCollectionOptions.strict) {
+ return handleCallback(
+ callback,
+ MongoError.create({
+ message: `Collection ${name} already exists. Currently in strict mode.`,
+ driver: true
+ }),
+ null
+ );
+ } else if (collections.length > 0) {
+ try {
+ return handleCallback(
+ callback,
+ null,
+ new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
+ );
+ } catch (err) {
+ return handleCallback(callback, err);
+ }
+ }
+
+ // Execute command
+ super.execute(err => {
+ if (err) return handleCallback(callback, err);
+
+ try {
+ return handleCallback(
+ callback,
+ null,
+ new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
+ );
+ } catch (err) {
+ return handleCallback(callback, err);
+ }
+ });
+ });
+ }
+}
+
+defineAspects(CreateCollectionOperation, Aspect.WRITE_OPERATION);
+
+module.exports = CreateCollectionOperation;
diff --git a/node_modules/mongodb/lib/operations/create_index.js b/node_modules/mongodb/lib/operations/create_index.js
new file mode 100644
index 0000000..98bba71
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/create_index.js
@@ -0,0 +1,92 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const CommandOperation = require('./command');
+const defineAspects = require('./operation').defineAspects;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const parseIndexOptions = require('../utils').parseIndexOptions;
+
+const keysToOmit = new Set([
+ 'name',
+ 'key',
+ 'writeConcern',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'fsync',
+ 'readPreference',
+ 'session'
+]);
+
+class CreateIndexOperation extends CommandOperation {
+ constructor(db, name, fieldOrSpec, options) {
+ super(db, options);
+
+ // Build the index
+ const indexParameters = parseIndexOptions(fieldOrSpec);
+ // Generate the index name
+ const indexName = typeof options.name === 'string' ? options.name : indexParameters.name;
+ // Set up the index
+ const indexesObject = { name: indexName, key: indexParameters.fieldHash };
+
+ this.name = name;
+ this.fieldOrSpec = fieldOrSpec;
+ this.indexes = indexesObject;
+ }
+
+ _buildCommand() {
+ const options = this.options;
+ const name = this.name;
+ const indexes = this.indexes;
+
+ // merge all the options
+ for (let optionName in options) {
+ if (!keysToOmit.has(optionName)) {
+ indexes[optionName] = options[optionName];
+ }
+ }
+
+ // Create command, apply write concern to command
+ const cmd = { createIndexes: name, indexes: [indexes] };
+
+ return cmd;
+ }
+
+ execute(callback) {
+ const db = this.db;
+ const options = this.options;
+ const indexes = this.indexes;
+
+ // Get capabilities
+ const capabilities = db.s.topology.capabilities();
+
+ // Did the user pass in a collation, check if our write server supports it
+ if (options.collation && capabilities && !capabilities.commandsTakeCollation) {
+ // Create a new error
+ const error = new MongoError('server/primary/mongos does not support collation');
+ error.code = 67;
+ // Return the error
+ return callback(error);
+ }
+
+ // Ensure we have a callback
+ if (options.writeConcern && typeof callback !== 'function') {
+ throw MongoError.create({
+ message: 'Cannot use a writeConcern without a provided callback',
+ driver: true
+ });
+ }
+
+ // Attempt to run using createIndexes command
+ super.execute((err, result) => {
+ if (err == null) return handleCallback(callback, err, indexes.name);
+
+ return handleCallback(callback, err, result);
+ });
+ }
+}
+
+defineAspects(CreateIndexOperation, Aspect.WRITE_OPERATION);
+
+module.exports = CreateIndexOperation;
diff --git a/node_modules/mongodb/lib/operations/create_indexes.js b/node_modules/mongodb/lib/operations/create_indexes.js
new file mode 100644
index 0000000..46228e8
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/create_indexes.js
@@ -0,0 +1,61 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const OperationBase = require('./operation').OperationBase;
+const executeCommand = require('./db_ops').executeCommand;
+const MongoError = require('../core').MongoError;
+const ReadPreference = require('../core').ReadPreference;
+
+class CreateIndexesOperation extends OperationBase {
+ constructor(collection, indexSpecs, options) {
+ super(options);
+
+ this.collection = collection;
+ this.indexSpecs = indexSpecs;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const indexSpecs = this.indexSpecs;
+ let options = this.options;
+
+ const capabilities = coll.s.topology.capabilities();
+
+ // Ensure we generate the correct name if the parameter is not set
+ for (let i = 0; i < indexSpecs.length; i++) {
+ if (indexSpecs[i].name == null) {
+ const keys = [];
+
+ // Did the user pass in a collation, check if our write server supports it
+ if (indexSpecs[i].collation && capabilities && !capabilities.commandsTakeCollation) {
+ return callback(new MongoError('server/primary/mongos does not support collation'));
+ }
+
+ for (let name in indexSpecs[i].key) {
+ keys.push(`${name}_${indexSpecs[i].key[name]}`);
+ }
+
+ // Set the name
+ indexSpecs[i].name = keys.join('_');
+ }
+ }
+
+ options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY });
+
+ // Execute the index
+ executeCommand(
+ coll.s.db,
+ {
+ createIndexes: coll.collectionName,
+ indexes: indexSpecs
+ },
+ options,
+ callback
+ );
+ }
+}
+
+defineAspects(CreateIndexesOperation, Aspect.WRITE_OPERATION);
+
+module.exports = CreateIndexesOperation;
diff --git a/node_modules/mongodb/lib/operations/cursor_ops.js b/node_modules/mongodb/lib/operations/cursor_ops.js
new file mode 100644
index 0000000..98df606
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/cursor_ops.js
@@ -0,0 +1,168 @@
+'use strict';
+
+const buildCountCommand = require('./collection_ops').buildCountCommand;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const push = Array.prototype.push;
+const CursorState = require('../core/cursor').CursorState;
+
+/**
+ * Get the count of documents for this cursor.
+ *
+ * @method
+ * @param {Cursor} cursor The Cursor instance on which to count.
+ * @param {boolean} [applySkipLimit=true] Specifies whether the count command apply limit and skip settings should be applied on the cursor or in the provided options.
+ * @param {object} [options] Optional settings. See Cursor.prototype.count for a list of options.
+ * @param {Cursor~countResultCallback} [callback] The result callback.
+ */
+function count(cursor, applySkipLimit, opts, callback) {
+ if (applySkipLimit) {
+ if (typeof cursor.cursorSkip() === 'number') opts.skip = cursor.cursorSkip();
+ if (typeof cursor.cursorLimit() === 'number') opts.limit = cursor.cursorLimit();
+ }
+
+ // Ensure we have the right read preference inheritance
+ if (opts.readPreference) {
+ cursor.setReadPreference(opts.readPreference);
+ }
+
+ if (
+ typeof opts.maxTimeMS !== 'number' &&
+ cursor.cmd &&
+ typeof cursor.cmd.maxTimeMS === 'number'
+ ) {
+ opts.maxTimeMS = cursor.cmd.maxTimeMS;
+ }
+
+ let options = {};
+ options.skip = opts.skip;
+ options.limit = opts.limit;
+ options.hint = opts.hint;
+ options.maxTimeMS = opts.maxTimeMS;
+
+ // Command
+ options.collectionName = cursor.namespace.collection;
+
+ let command;
+ try {
+ command = buildCountCommand(cursor, cursor.cmd.query, options);
+ } catch (err) {
+ return callback(err);
+ }
+
+ // Set cursor server to the same as the topology
+ cursor.server = cursor.topology.s.coreTopology;
+
+ // Execute the command
+ cursor.topology.command(
+ cursor.namespace.withCollection('$cmd'),
+ command,
+ cursor.options,
+ (err, result) => {
+ callback(err, result ? result.result.n : null);
+ }
+ );
+}
+
+/**
+ * Iterates over all the documents for this cursor. See Cursor.prototype.each for more information.
+ *
+ * @method
+ * @deprecated
+ * @param {Cursor} cursor The Cursor instance on which to run.
+ * @param {Cursor~resultCallback} callback The result callback.
+ */
+function each(cursor, callback) {
+ if (!callback) throw MongoError.create({ message: 'callback is mandatory', driver: true });
+ if (cursor.isNotified()) return;
+ if (cursor.s.state === CursorState.CLOSED || cursor.isDead()) {
+ return handleCallback(
+ callback,
+ MongoError.create({ message: 'Cursor is closed', driver: true })
+ );
+ }
+
+ if (cursor.s.state === CursorState.INIT) {
+ cursor.s.state = CursorState.OPEN;
+ }
+
+ // Define function to avoid global scope escape
+ let fn = null;
+ // Trampoline all the entries
+ if (cursor.bufferedCount() > 0) {
+ while ((fn = loop(cursor, callback))) fn(cursor, callback);
+ each(cursor, callback);
+ } else {
+ cursor.next((err, item) => {
+ if (err) return handleCallback(callback, err);
+ if (item == null) {
+ return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, null));
+ }
+
+ if (handleCallback(callback, null, item) === false) return;
+ each(cursor, callback);
+ });
+ }
+}
+
+// Trampoline emptying the number of retrieved items
+// without incurring a nextTick operation
+function loop(cursor, callback) {
+ // No more items we are done
+ if (cursor.bufferedCount() === 0) return;
+ // Get the next document
+ cursor._next(callback);
+ // Loop
+ return loop;
+}
+
+/**
+ * Returns an array of documents. See Cursor.prototype.toArray for more information.
+ *
+ * @method
+ * @param {Cursor} cursor The Cursor instance from which to get the next document.
+ * @param {Cursor~toArrayResultCallback} [callback] The result callback.
+ */
+function toArray(cursor, callback) {
+ const items = [];
+
+ // Reset cursor
+ cursor.rewind();
+ cursor.s.state = CursorState.INIT;
+
+ // Fetch all the documents
+ const fetchDocs = () => {
+ cursor._next((err, doc) => {
+ if (err) {
+ return cursor._endSession
+ ? cursor._endSession(() => handleCallback(callback, err))
+ : handleCallback(callback, err);
+ }
+ if (doc == null) {
+ return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, items));
+ }
+
+ // Add doc to items
+ items.push(doc);
+
+ // Get all buffered objects
+ if (cursor.bufferedCount() > 0) {
+ let docs = cursor.readBufferedDocuments(cursor.bufferedCount());
+
+ // Transform the doc if transform method added
+ if (cursor.s.transforms && typeof cursor.s.transforms.doc === 'function') {
+ docs = docs.map(cursor.s.transforms.doc);
+ }
+
+ push.apply(items, docs);
+ }
+
+ // Attempt a fetch
+ fetchDocs();
+ });
+ };
+
+ fetchDocs();
+}
+
+module.exports = { count, each, toArray };
diff --git a/node_modules/mongodb/lib/operations/db_ops.js b/node_modules/mongodb/lib/operations/db_ops.js
new file mode 100644
index 0000000..ada6c9a
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/db_ops.js
@@ -0,0 +1,829 @@
+'use strict';
+
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const Code = require('../core').BSON.Code;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const crypto = require('crypto');
+const debugOptions = require('../utils').debugOptions;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const parseIndexOptions = require('../utils').parseIndexOptions;
+const ReadPreference = require('../core').ReadPreference;
+const toError = require('../utils').toError;
+const CONSTANTS = require('../constants');
+const MongoDBNamespace = require('../utils').MongoDBNamespace;
+
+const count = require('./collection_ops').count;
+const findOne = require('./collection_ops').findOne;
+const remove = require('./collection_ops').remove;
+const updateOne = require('./collection_ops').updateOne;
+
+let collection;
+function loadCollection() {
+ if (!collection) {
+ collection = require('../collection');
+ }
+ return collection;
+}
+let db;
+function loadDb() {
+ if (!db) {
+ db = require('../db');
+ }
+ return db;
+}
+
+const debugFields = [
+ 'authSource',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'native_parser',
+ 'forceServerObjectId',
+ 'serializeFunctions',
+ 'raw',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'bufferMaxEntries',
+ 'numberOfRetries',
+ 'retryMiliSeconds',
+ 'readPreference',
+ 'pkFactory',
+ 'parentDb',
+ 'promiseLibrary',
+ 'noListener'
+];
+
+/**
+ * Add a user to the database.
+ * @method
+ * @param {Db} db The Db instance on which to add a user.
+ * @param {string} username The username.
+ * @param {string} password The password.
+ * @param {object} [options] Optional settings. See Db.prototype.addUser for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function addUser(db, username, password, options, callback) {
+ let Db = loadDb();
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+ // Attempt to execute auth command
+ executeAuthCreateUserCommand(db, username, password, options, (err, r) => {
+ // We need to perform the backward compatible insert operation
+ if (err && err.code === -5000) {
+ const finalOptions = applyWriteConcern(Object.assign({}, options), { db }, options);
+
+ // Use node md5 generator
+ const md5 = crypto.createHash('md5');
+ // Generate keys used for authentication
+ md5.update(username + ':mongo:' + password);
+ const userPassword = md5.digest('hex');
+
+ // If we have another db set
+ const dbToUse = options.dbName ? new Db(options.dbName, db.s.topology, db.s.options) : db;
+
+ // Fetch a user collection
+ const collection = dbToUse.collection(CONSTANTS.SYSTEM_USER_COLLECTION);
+
+ // Check if we are inserting the first user
+ count(collection, {}, finalOptions, (err, count) => {
+ // We got an error (f.ex not authorized)
+ if (err != null) return handleCallback(callback, err, null);
+ // Check if the user exists and update i
+ const findOptions = Object.assign({ projection: { dbName: 1 } }, finalOptions);
+ collection.find({ user: username }, findOptions).toArray(err => {
+ // We got an error (f.ex not authorized)
+ if (err != null) return handleCallback(callback, err, null);
+ // Add command keys
+ finalOptions.upsert = true;
+
+ // We have a user, let's update the password or upsert if not
+ updateOne(
+ collection,
+ { user: username },
+ { $set: { user: username, pwd: userPassword } },
+ finalOptions,
+ err => {
+ if (count === 0 && err)
+ return handleCallback(callback, null, [{ user: username, pwd: userPassword }]);
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, [{ user: username, pwd: userPassword }]);
+ }
+ );
+ });
+ });
+
+ return;
+ }
+
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, err, r);
+ });
+}
+
+/**
+ * Fetch all collections for the current db.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to fetch collections.
+ * @param {object} [options] Optional settings. See Db.prototype.collections for a list of options.
+ * @param {Db~collectionsResultCallback} [callback] The results callback
+ */
+function collections(db, options, callback) {
+ let Collection = loadCollection();
+
+ options = Object.assign({}, options, { nameOnly: true });
+ // Let's get the collection names
+ db.listCollections({}, options).toArray((err, documents) => {
+ if (err != null) return handleCallback(callback, err, null);
+ // Filter collections removing any illegal ones
+ documents = documents.filter(doc => {
+ return doc.name.indexOf('$') === -1;
+ });
+
+ // Return the collection objects
+ handleCallback(
+ callback,
+ null,
+ documents.map(d => {
+ return new Collection(
+ db,
+ db.s.topology,
+ db.databaseName,
+ d.name,
+ db.s.pkFactory,
+ db.s.options
+ );
+ })
+ );
+ });
+}
+
+/**
+ * Creates an index on the db and collection.
+ * @method
+ * @param {Db} db The Db instance on which to create an index.
+ * @param {string} name Name of the collection to create the index on.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings. See Db.prototype.createIndex for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function createIndex(db, name, fieldOrSpec, options, callback) {
+ // Get the write concern options
+ let finalOptions = Object.assign({}, { readPreference: ReadPreference.PRIMARY }, options);
+ finalOptions = applyWriteConcern(finalOptions, { db }, options);
+
+ // Ensure we have a callback
+ if (finalOptions.writeConcern && typeof callback !== 'function') {
+ throw MongoError.create({
+ message: 'Cannot use a writeConcern without a provided callback',
+ driver: true
+ });
+ }
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+
+ // Attempt to run using createIndexes command
+ createIndexUsingCreateIndexes(db, name, fieldOrSpec, finalOptions, (err, result) => {
+ if (err == null) return handleCallback(callback, err, result);
+
+ /**
+ * The following errors mean that the server recognized `createIndex` as a command so we don't need to fallback to an insert:
+ * 67 = 'CannotCreateIndex' (malformed index options)
+ * 85 = 'IndexOptionsConflict' (index already exists with different options)
+ * 86 = 'IndexKeySpecsConflict' (index already exists with the same name)
+ * 11000 = 'DuplicateKey' (couldn't build unique index because of dupes)
+ * 11600 = 'InterruptedAtShutdown' (interrupted at shutdown)
+ * 197 = 'InvalidIndexSpecificationOption' (`_id` with `background: true`)
+ */
+ if (
+ err.code === 67 ||
+ err.code === 11000 ||
+ err.code === 85 ||
+ err.code === 86 ||
+ err.code === 11600 ||
+ err.code === 197
+ ) {
+ return handleCallback(callback, err, result);
+ }
+
+ // Create command
+ const doc = createCreateIndexCommand(db, name, fieldOrSpec, options);
+ // Set no key checking
+ finalOptions.checkKeys = false;
+ // Insert document
+ db.s.topology.insert(
+ db.s.namespace.withCollection(CONSTANTS.SYSTEM_INDEX_COLLECTION),
+ doc,
+ finalOptions,
+ (err, result) => {
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err);
+ if (result == null) return handleCallback(callback, null, null);
+ if (result.result.writeErrors)
+ return handleCallback(callback, MongoError.create(result.result.writeErrors[0]), null);
+ handleCallback(callback, null, doc.name);
+ }
+ );
+ });
+}
+
+// Add listeners to topology
+function createListener(db, e, object) {
+ function listener(err) {
+ if (object.listeners(e).length > 0) {
+ object.emit(e, err, db);
+
+ // Emit on all associated db's if available
+ for (let i = 0; i < db.s.children.length; i++) {
+ db.s.children[i].emit(e, err, db.s.children[i]);
+ }
+ }
+ }
+ return listener;
+}
+
+/**
+ * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to drop the collection.
+ * @param {string} name Name of collection to drop
+ * @param {Object} [options] Optional settings. See Db.prototype.dropCollection for a list of options.
+ * @param {Db~resultCallback} [callback] The results callback
+ */
+function dropCollection(db, name, options, callback) {
+ executeCommand(db, name, options, (err, result) => {
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ if (err) return handleCallback(callback, err);
+ if (result.ok) return handleCallback(callback, null, true);
+ handleCallback(callback, null, false);
+ });
+}
+
+/**
+ * Drop a database, removing it permanently from the server.
+ *
+ * @method
+ * @param {Db} db The Db instance to drop.
+ * @param {Object} cmd The command document.
+ * @param {Object} [options] Optional settings. See Db.prototype.dropDatabase for a list of options.
+ * @param {Db~resultCallback} [callback] The results callback
+ */
+function dropDatabase(db, cmd, options, callback) {
+ executeCommand(db, cmd, options, (err, result) => {
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result.ok ? true : false);
+ });
+}
+
+/**
+ * Ensures that an index exists. If it does not, creates it.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to ensure the index.
+ * @param {string} name The index name
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {object} [options] Optional settings. See Db.prototype.ensureIndex for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function ensureIndex(db, name, fieldOrSpec, options, callback) {
+ // Get the write concern options
+ const finalOptions = applyWriteConcern({}, { db }, options);
+ // Create command
+ const selector = createCreateIndexCommand(db, name, fieldOrSpec, options);
+ const index_name = selector.name;
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+
+ // Merge primary readPreference
+ finalOptions.readPreference = ReadPreference.PRIMARY;
+
+ // Check if the index already exists
+ indexInformation(db, name, finalOptions, (err, indexInformation) => {
+ if (err != null && err.code !== 26) return handleCallback(callback, err, null);
+ // If the index does not exist, create it
+ if (indexInformation == null || !indexInformation[index_name]) {
+ createIndex(db, name, fieldOrSpec, options, callback);
+ } else {
+ if (typeof callback === 'function') return handleCallback(callback, null, index_name);
+ }
+ });
+}
+
+/**
+ * Evaluate JavaScript on the server
+ *
+ * @method
+ * @param {Db} db The Db instance.
+ * @param {Code} code JavaScript to execute on server.
+ * @param {(object|array)} parameters The parameters for the call.
+ * @param {object} [options] Optional settings. See Db.prototype.eval for a list of options.
+ * @param {Db~resultCallback} [callback] The results callback
+ * @deprecated Eval is deprecated on MongoDB 3.2 and forward
+ */
+function evaluate(db, code, parameters, options, callback) {
+ let finalCode = code;
+ let finalParameters = [];
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+
+ // If not a code object translate to one
+ if (!(finalCode && finalCode._bsontype === 'Code')) finalCode = new Code(finalCode);
+ // Ensure the parameters are correct
+ if (parameters != null && !Array.isArray(parameters) && typeof parameters !== 'function') {
+ finalParameters = [parameters];
+ } else if (parameters != null && Array.isArray(parameters) && typeof parameters !== 'function') {
+ finalParameters = parameters;
+ }
+
+ // Create execution selector
+ let cmd = { $eval: finalCode, args: finalParameters };
+ // Check if the nolock parameter is passed in
+ if (options['nolock']) {
+ cmd['nolock'] = options['nolock'];
+ }
+
+ // Set primary read preference
+ options.readPreference = new ReadPreference(ReadPreference.PRIMARY);
+
+ // Execute the command
+ executeCommand(db, cmd, options, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+ if (result && result.ok === 1) return handleCallback(callback, null, result.retval);
+ if (result)
+ return handleCallback(
+ callback,
+ MongoError.create({ message: `eval failed: ${result.errmsg}`, driver: true }),
+ null
+ );
+ handleCallback(callback, err, result);
+ });
+}
+
+/**
+ * Execute a command
+ *
+ * @method
+ * @param {Db} db The Db instance on which to execute the command.
+ * @param {object} command The command hash
+ * @param {object} [options] Optional settings. See Db.prototype.command for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function executeCommand(db, command, options, callback) {
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+ // Get the db name we are executing against
+ const dbName = options.dbName || options.authdb || db.databaseName;
+
+ // Convert the readPreference if its not a write
+ options.readPreference = resolveReadPreference(db, options);
+
+ // Debug information
+ if (db.s.logger.isDebug())
+ db.s.logger.debug(
+ `executing command ${JSON.stringify(
+ command
+ )} against ${dbName}.$cmd with options [${JSON.stringify(
+ debugOptions(debugFields, options)
+ )}]`
+ );
+
+ // Execute command
+ db.s.topology.command(db.s.namespace.withCollection('$cmd'), command, options, (err, result) => {
+ if (err) return handleCallback(callback, err);
+ if (options.full) return handleCallback(callback, null, result);
+ handleCallback(callback, null, result.result);
+ });
+}
+
+/**
+ * Runs a command on the database as admin.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to execute the command.
+ * @param {object} command The command hash
+ * @param {object} [options] Optional settings. See Db.prototype.executeDbAdminCommand for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function executeDbAdminCommand(db, command, options, callback) {
+ const namespace = new MongoDBNamespace('admin', '$cmd');
+
+ db.s.topology.command(namespace, command, options, (err, result) => {
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, null, result.result);
+ });
+}
+
+/**
+ * Retrieves this collections index info.
+ *
+ * @method
+ * @param {Db} db The Db instance on which to retrieve the index info.
+ * @param {string} name The name of the collection.
+ * @param {object} [options] Optional settings. See Db.prototype.indexInformation for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function indexInformation(db, name, options, callback) {
+ // If we specified full information
+ const full = options['full'] == null ? false : options['full'];
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+ // Process all the results from the index command and collection
+ function processResults(indexes) {
+ // Contains all the information
+ let info = {};
+ // Process all the indexes
+ for (let i = 0; i < indexes.length; i++) {
+ const index = indexes[i];
+ // Let's unpack the object
+ info[index.name] = [];
+ for (let name in index.key) {
+ info[index.name].push([name, index.key[name]]);
+ }
+ }
+
+ return info;
+ }
+
+ // Get the list of indexes of the specified collection
+ db.collection(name)
+ .listIndexes(options)
+ .toArray((err, indexes) => {
+ if (err) return callback(toError(err));
+ if (!Array.isArray(indexes)) return handleCallback(callback, null, []);
+ if (full) return handleCallback(callback, null, indexes);
+ handleCallback(callback, null, processResults(indexes));
+ });
+}
+
+/**
+ * Retrieve the current profiling information for MongoDB
+ *
+ * @method
+ * @param {Db} db The Db instance on which to retrieve the profiling info.
+ * @param {Object} [options] Optional settings. See Db.protoype.profilingInfo for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback.
+ * @deprecated Query the system.profile collection directly.
+ */
+function profilingInfo(db, options, callback) {
+ try {
+ db.collection('system.profile')
+ .find({}, options)
+ .toArray(callback);
+ } catch (err) {
+ return callback(err, null);
+ }
+}
+
+/**
+ * Remove a user from a database
+ *
+ * @method
+ * @param {Db} db The Db instance on which to remove the user.
+ * @param {string} username The username.
+ * @param {object} [options] Optional settings. See Db.prototype.removeUser for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function removeUser(db, username, options, callback) {
+ let Db = loadDb();
+
+ // Attempt to execute command
+ executeAuthRemoveUserCommand(db, username, options, (err, result) => {
+ if (err && err.code === -5000) {
+ const finalOptions = applyWriteConcern(Object.assign({}, options), { db }, options);
+ // If we have another db set
+ const db = options.dbName ? new Db(options.dbName, db.s.topology, db.s.options) : db;
+
+ // Fetch a user collection
+ const collection = db.collection(CONSTANTS.SYSTEM_USER_COLLECTION);
+
+ // Locate the user
+ findOne(collection, { user: username }, finalOptions, (err, user) => {
+ if (user == null) return handleCallback(callback, err, false);
+ remove(collection, { user: username }, finalOptions, err => {
+ handleCallback(callback, err, true);
+ });
+ });
+
+ return;
+ }
+
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, err, result);
+ });
+}
+
+// Validate the database name
+function validateDatabaseName(databaseName) {
+ if (typeof databaseName !== 'string')
+ throw MongoError.create({ message: 'database name must be a string', driver: true });
+ if (databaseName.length === 0)
+ throw MongoError.create({ message: 'database name cannot be the empty string', driver: true });
+ if (databaseName === '$external') return;
+
+ const invalidChars = [' ', '.', '$', '/', '\\'];
+ for (let i = 0; i < invalidChars.length; i++) {
+ if (databaseName.indexOf(invalidChars[i]) !== -1)
+ throw MongoError.create({
+ message: "database names cannot contain the character '" + invalidChars[i] + "'",
+ driver: true
+ });
+ }
+}
+
+/**
+ * Create the command object for Db.prototype.createIndex.
+ *
+ * @param {Db} db The Db instance on which to create the command.
+ * @param {string} name Name of the collection to create the index on.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {Object} [options] Optional settings. See Db.prototype.createIndex for a list of options.
+ * @return {Object} The insert command object.
+ */
+function createCreateIndexCommand(db, name, fieldOrSpec, options) {
+ const indexParameters = parseIndexOptions(fieldOrSpec);
+ const fieldHash = indexParameters.fieldHash;
+
+ // Generate the index name
+ const indexName = typeof options.name === 'string' ? options.name : indexParameters.name;
+ const selector = {
+ ns: db.s.namespace.withCollection(name).toString(),
+ key: fieldHash,
+ name: indexName
+ };
+
+ // Ensure we have a correct finalUnique
+ const finalUnique = options == null || 'object' === typeof options ? false : options;
+ // Set up options
+ options = options == null || typeof options === 'boolean' ? {} : options;
+
+ // Add all the options
+ const keysToOmit = Object.keys(selector);
+ for (let optionName in options) {
+ if (keysToOmit.indexOf(optionName) === -1) {
+ selector[optionName] = options[optionName];
+ }
+ }
+
+ if (selector['unique'] == null) selector['unique'] = finalUnique;
+
+ // Remove any write concern operations
+ const removeKeys = ['w', 'wtimeout', 'j', 'fsync', 'readPreference', 'session'];
+ for (let i = 0; i < removeKeys.length; i++) {
+ delete selector[removeKeys[i]];
+ }
+
+ // Return the command creation selector
+ return selector;
+}
+
+/**
+ * Create index using the createIndexes command.
+ *
+ * @param {Db} db The Db instance on which to execute the command.
+ * @param {string} name Name of the collection to create the index on.
+ * @param {(string|object)} fieldOrSpec Defines the index.
+ * @param {Object} [options] Optional settings. See Db.prototype.createIndex for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback.
+ */
+function createIndexUsingCreateIndexes(db, name, fieldOrSpec, options, callback) {
+ // Build the index
+ const indexParameters = parseIndexOptions(fieldOrSpec);
+ // Generate the index name
+ const indexName = typeof options.name === 'string' ? options.name : indexParameters.name;
+ // Set up the index
+ const indexes = [{ name: indexName, key: indexParameters.fieldHash }];
+ // merge all the options
+ const keysToOmit = Object.keys(indexes[0]).concat([
+ 'writeConcern',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'fsync',
+ 'readPreference',
+ 'session'
+ ]);
+
+ for (let optionName in options) {
+ if (keysToOmit.indexOf(optionName) === -1) {
+ indexes[0][optionName] = options[optionName];
+ }
+ }
+
+ // Get capabilities
+ const capabilities = db.s.topology.capabilities();
+
+ // Did the user pass in a collation, check if our write server supports it
+ if (indexes[0].collation && capabilities && !capabilities.commandsTakeCollation) {
+ // Create a new error
+ const error = new MongoError('server/primary/mongos does not support collation');
+ error.code = 67;
+ // Return the error
+ return callback(error);
+ }
+
+ // Create command, apply write concern to command
+ const cmd = applyWriteConcern({ createIndexes: name, indexes }, { db }, options);
+
+ // ReadPreference primary
+ options.readPreference = ReadPreference.PRIMARY;
+
+ // Build the command
+ executeCommand(db, cmd, options, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+ if (result.ok === 0) return handleCallback(callback, toError(result), null);
+ // Return the indexName for backward compatibility
+ handleCallback(callback, null, indexName);
+ });
+}
+
+/**
+ * Run the createUser command.
+ *
+ * @param {Db} db The Db instance on which to execute the command.
+ * @param {string} username The username of the user to add.
+ * @param {string} password The password of the user to add.
+ * @param {object} [options] Optional settings. See Db.prototype.addUser for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function executeAuthCreateUserCommand(db, username, password, options, callback) {
+ // Special case where there is no password ($external users)
+ if (typeof username === 'string' && password != null && typeof password === 'object') {
+ options = password;
+ password = null;
+ }
+
+ // Unpack all options
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ // Error out if we digestPassword set
+ if (options.digestPassword != null) {
+ return callback(
+ toError(
+ "The digestPassword option is not supported via add_user. Please use db.command('createUser', ...) instead for this option."
+ )
+ );
+ }
+
+ // Get additional values
+ const customData = options.customData != null ? options.customData : {};
+ let roles = Array.isArray(options.roles) ? options.roles : [];
+ const maxTimeMS = typeof options.maxTimeMS === 'number' ? options.maxTimeMS : null;
+
+ // If not roles defined print deprecated message
+ if (roles.length === 0) {
+ console.log('Creating a user without roles is deprecated in MongoDB >= 2.6');
+ }
+
+ // Get the error options
+ const commandOptions = { writeCommand: true };
+ if (options['dbName']) commandOptions.dbName = options['dbName'];
+
+ // Add maxTimeMS to options if set
+ if (maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
+
+ // Check the db name and add roles if needed
+ if (
+ (db.databaseName.toLowerCase() === 'admin' || options.dbName === 'admin') &&
+ !Array.isArray(options.roles)
+ ) {
+ roles = ['root'];
+ } else if (!Array.isArray(options.roles)) {
+ roles = ['dbOwner'];
+ }
+
+ const digestPassword = db.s.topology.lastIsMaster().maxWireVersion >= 7;
+
+ // Build the command to execute
+ let command = {
+ createUser: username,
+ customData: customData,
+ roles: roles,
+ digestPassword
+ };
+
+ // Apply write concern to command
+ command = applyWriteConcern(command, { db }, options);
+
+ let userPassword = password;
+
+ if (!digestPassword) {
+ // Use node md5 generator
+ const md5 = crypto.createHash('md5');
+ // Generate keys used for authentication
+ md5.update(username + ':mongo:' + password);
+ userPassword = md5.digest('hex');
+ }
+
+ // No password
+ if (typeof password === 'string') {
+ command.pwd = userPassword;
+ }
+
+ // Force write using primary
+ commandOptions.readPreference = ReadPreference.primary;
+
+ // Execute the command
+ executeCommand(db, command, commandOptions, (err, result) => {
+ if (err && err.ok === 0 && err.code === undefined)
+ return handleCallback(callback, { code: -5000 }, null);
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(
+ callback,
+ !result.ok ? toError(result) : null,
+ result.ok ? [{ user: username, pwd: '' }] : null
+ );
+ });
+}
+
+/**
+ * Run the dropUser command.
+ *
+ * @param {Db} db The Db instance on which to execute the command.
+ * @param {string} username The username of the user to remove.
+ * @param {object} [options] Optional settings. See Db.prototype.removeUser for a list of options.
+ * @param {Db~resultCallback} [callback] The command result callback
+ */
+function executeAuthRemoveUserCommand(db, username, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed())
+ return callback(new MongoError('topology was destroyed'));
+ // Get the error options
+ const commandOptions = { writeCommand: true };
+ if (options['dbName']) commandOptions.dbName = options['dbName'];
+
+ // Get additional values
+ const maxTimeMS = typeof options.maxTimeMS === 'number' ? options.maxTimeMS : null;
+
+ // Add maxTimeMS to options if set
+ if (maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
+
+ // Build the command to execute
+ let command = {
+ dropUser: username
+ };
+
+ // Apply write concern to command
+ command = applyWriteConcern(command, { db }, options);
+
+ // Force write using primary
+ commandOptions.readPreference = ReadPreference.primary;
+
+ // Execute the command
+ executeCommand(db, command, commandOptions, (err, result) => {
+ if (err && !err.ok && err.code === undefined) return handleCallback(callback, { code: -5000 });
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result.ok ? true : false);
+ });
+}
+
+module.exports = {
+ addUser,
+ collections,
+ createListener,
+ createIndex,
+ dropCollection,
+ dropDatabase,
+ ensureIndex,
+ evaluate,
+ executeCommand,
+ executeDbAdminCommand,
+ indexInformation,
+ profilingInfo,
+ removeUser,
+ validateDatabaseName
+};
diff --git a/node_modules/mongodb/lib/operations/delete_many.js b/node_modules/mongodb/lib/operations/delete_many.js
new file mode 100644
index 0000000..d881f67
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/delete_many.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const deleteCallback = require('./common_functions').deleteCallback;
+const removeDocuments = require('./common_functions').removeDocuments;
+
+class DeleteManyOperation extends OperationBase {
+ constructor(collection, filter, options) {
+ super(options);
+
+ this.collection = collection;
+ this.filter = filter;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const filter = this.filter;
+ const options = this.options;
+
+ options.single = false;
+ removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
+ }
+}
+
+module.exports = DeleteManyOperation;
diff --git a/node_modules/mongodb/lib/operations/delete_one.js b/node_modules/mongodb/lib/operations/delete_one.js
new file mode 100644
index 0000000..b05597f
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/delete_one.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const deleteCallback = require('./common_functions').deleteCallback;
+const removeDocuments = require('./common_functions').removeDocuments;
+
+class DeleteOneOperation extends OperationBase {
+ constructor(collection, filter, options) {
+ super(options);
+
+ this.collection = collection;
+ this.filter = filter;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const filter = this.filter;
+ const options = this.options;
+
+ options.single = true;
+ removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
+ }
+}
+
+module.exports = DeleteOneOperation;
diff --git a/node_modules/mongodb/lib/operations/distinct.js b/node_modules/mongodb/lib/operations/distinct.js
new file mode 100644
index 0000000..dcf4f7e
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/distinct.js
@@ -0,0 +1,85 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const CommandOperationV2 = require('./command_v2');
+const decorateWithCollation = require('../utils').decorateWithCollation;
+const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
+
+/**
+ * Return a list of distinct values for the given key across a collection.
+ *
+ * @class
+ * @property {Collection} a Collection instance.
+ * @property {string} key Field of the document to find distinct values for.
+ * @property {object} query The query for filtering the set of documents to which we apply the distinct filter.
+ * @property {object} [options] Optional settings. See Collection.prototype.distinct for a list of options.
+ */
+class DistinctOperation extends CommandOperationV2 {
+ /**
+ * Construct a Distinct operation.
+ *
+ * @param {Collection} a Collection instance.
+ * @param {string} key Field of the document to find distinct values for.
+ * @param {object} query The query for filtering the set of documents to which we apply the distinct filter.
+ * @param {object} [options] Optional settings. See Collection.prototype.distinct for a list of options.
+ */
+ constructor(collection, key, query, options) {
+ super(collection, options);
+
+ this.collection = collection;
+ this.key = key;
+ this.query = query;
+ }
+
+ /**
+ * Execute the operation.
+ *
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+ execute(server, callback) {
+ const coll = this.collection;
+ const key = this.key;
+ const query = this.query;
+ const options = this.options;
+
+ // Distinct command
+ const cmd = {
+ distinct: coll.collectionName,
+ key: key,
+ query: query
+ };
+
+ // Add maxTimeMS if defined
+ if (typeof options.maxTimeMS === 'number') {
+ cmd.maxTimeMS = options.maxTimeMS;
+ }
+
+ // Do we have a readConcern specified
+ decorateWithReadConcern(cmd, coll, options);
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(cmd, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ super.executeCommand(server, cmd, (err, result) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ callback(null, this.options.full ? result : result.values);
+ });
+ }
+}
+
+defineAspects(DistinctOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = DistinctOperation;
diff --git a/node_modules/mongodb/lib/operations/drop.js b/node_modules/mongodb/lib/operations/drop.js
new file mode 100644
index 0000000..be03716
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/drop.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const CommandOperation = require('./command');
+const defineAspects = require('./operation').defineAspects;
+const handleCallback = require('../utils').handleCallback;
+
+class DropOperation extends CommandOperation {
+ constructor(db, options) {
+ const finalOptions = Object.assign({}, options, db.s.options);
+
+ if (options.session) {
+ finalOptions.session = options.session;
+ }
+
+ super(db, finalOptions);
+ }
+
+ execute(callback) {
+ super.execute((err, result) => {
+ if (err) return handleCallback(callback, err);
+ if (result.ok) return handleCallback(callback, null, true);
+ handleCallback(callback, null, false);
+ });
+ }
+}
+
+defineAspects(DropOperation, Aspect.WRITE_OPERATION);
+
+class DropCollectionOperation extends DropOperation {
+ constructor(db, name, options) {
+ super(db, options);
+
+ this.name = name;
+ this.namespace = `${db.namespace}.${name}`;
+ }
+
+ _buildCommand() {
+ return { drop: this.name };
+ }
+}
+
+class DropDatabaseOperation extends DropOperation {
+ _buildCommand() {
+ return { dropDatabase: 1 };
+ }
+}
+
+module.exports = {
+ DropOperation,
+ DropCollectionOperation,
+ DropDatabaseOperation
+};
diff --git a/node_modules/mongodb/lib/operations/drop_index.js b/node_modules/mongodb/lib/operations/drop_index.js
new file mode 100644
index 0000000..a6ca783
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/drop_index.js
@@ -0,0 +1,42 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const CommandOperation = require('./command');
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const handleCallback = require('../utils').handleCallback;
+
+class DropIndexOperation extends CommandOperation {
+ constructor(collection, indexName, options) {
+ super(collection.s.db, options, collection);
+
+ this.collection = collection;
+ this.indexName = indexName;
+ }
+
+ _buildCommand() {
+ const collection = this.collection;
+ const indexName = this.indexName;
+ const options = this.options;
+
+ let cmd = { dropIndexes: collection.collectionName, index: indexName };
+
+ // Decorate command with writeConcern if supported
+ cmd = applyWriteConcern(cmd, { db: collection.s.db, collection }, options);
+
+ return cmd;
+ }
+
+ execute(callback) {
+ // Execute command
+ super.execute((err, result) => {
+ if (typeof callback !== 'function') return;
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result);
+ });
+ }
+}
+
+defineAspects(DropIndexOperation, Aspect.WRITE_OPERATION);
+
+module.exports = DropIndexOperation;
diff --git a/node_modules/mongodb/lib/operations/drop_indexes.js b/node_modules/mongodb/lib/operations/drop_indexes.js
new file mode 100644
index 0000000..ed404ee
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/drop_indexes.js
@@ -0,0 +1,23 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const DropIndexOperation = require('./drop_index');
+const handleCallback = require('../utils').handleCallback;
+
+class DropIndexesOperation extends DropIndexOperation {
+ constructor(collection, options) {
+ super(collection, '*', options);
+ }
+
+ execute(callback) {
+ super.execute(err => {
+ if (err) return handleCallback(callback, err, false);
+ handleCallback(callback, null, true);
+ });
+ }
+}
+
+defineAspects(DropIndexesOperation, Aspect.WRITE_OPERATION);
+
+module.exports = DropIndexesOperation;
diff --git a/node_modules/mongodb/lib/operations/estimated_document_count.js b/node_modules/mongodb/lib/operations/estimated_document_count.js
new file mode 100644
index 0000000..e2d6556
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/estimated_document_count.js
@@ -0,0 +1,58 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const CommandOperationV2 = require('./command_v2');
+
+class EstimatedDocumentCountOperation extends CommandOperationV2 {
+ constructor(collection, query, options) {
+ if (typeof options === 'undefined') {
+ options = query;
+ query = undefined;
+ }
+
+ super(collection, options);
+ this.collectionName = collection.s.namespace.collection;
+ if (query) {
+ this.query = query;
+ }
+ }
+
+ execute(server, callback) {
+ const options = this.options;
+ const cmd = { count: this.collectionName };
+
+ if (this.query) {
+ cmd.query = this.query;
+ }
+
+ if (typeof options.skip === 'number') {
+ cmd.skip = options.skip;
+ }
+
+ if (typeof options.limit === 'number') {
+ cmd.limit = options.limit;
+ }
+
+ if (options.hint) {
+ cmd.hint = options.hint;
+ }
+
+ super.executeCommand(server, cmd, (err, response) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ callback(null, response.n);
+ });
+ }
+}
+
+defineAspects(EstimatedDocumentCountOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = EstimatedDocumentCountOperation;
diff --git a/node_modules/mongodb/lib/operations/execute_db_admin_command.js b/node_modules/mongodb/lib/operations/execute_db_admin_command.js
new file mode 100644
index 0000000..d15fc8e
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/execute_db_admin_command.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+const MongoDBNamespace = require('../utils').MongoDBNamespace;
+
+class ExecuteDbAdminCommandOperation extends OperationBase {
+ constructor(db, selector, options) {
+ super(options);
+
+ this.db = db;
+ this.selector = selector;
+ }
+
+ execute(callback) {
+ const db = this.db;
+ const selector = this.selector;
+ const options = this.options;
+
+ const namespace = new MongoDBNamespace('admin', '$cmd');
+ db.s.topology.command(namespace, selector, options, (err, result) => {
+ // Did the user destroy the topology
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
+ return callback(new MongoError('topology was destroyed'));
+ }
+
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, null, result.result);
+ });
+ }
+}
+
+module.exports = ExecuteDbAdminCommandOperation;
diff --git a/node_modules/mongodb/lib/operations/execute_operation.js b/node_modules/mongodb/lib/operations/execute_operation.js
new file mode 100644
index 0000000..80d5785
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/execute_operation.js
@@ -0,0 +1,186 @@
+'use strict';
+
+const MongoError = require('../core/error').MongoError;
+const Aspect = require('./operation').Aspect;
+const OperationBase = require('./operation').OperationBase;
+const ReadPreference = require('../core/topologies/read_preference');
+const isRetryableError = require('../core/error').isRetryableError;
+const maxWireVersion = require('../core/utils').maxWireVersion;
+const isUnifiedTopology = require('../core/utils').isUnifiedTopology;
+
+/**
+ * Executes the given operation with provided arguments.
+ *
+ * This method reduces large amounts of duplication in the entire codebase by providing
+ * a single point for determining whether callbacks or promises should be used. Additionally
+ * it allows for a single point of entry to provide features such as implicit sessions, which
+ * are required by the Driver Sessions specification in the event that a ClientSession is
+ * not provided
+ *
+ * @param {object} topology The topology to execute this operation on
+ * @param {Operation} operation The operation to execute
+ * @param {function} callback The command result callback
+ */
+function executeOperation(topology, operation, callback) {
+ if (topology == null) {
+ throw new TypeError('This method requires a valid topology instance');
+ }
+
+ if (!(operation instanceof OperationBase)) {
+ throw new TypeError('This method requires a valid operation instance');
+ }
+
+ if (isUnifiedTopology(topology) && topology.shouldCheckForSessionSupport()) {
+ return selectServerForSessionSupport(topology, operation, callback);
+ }
+
+ const Promise = topology.s.promiseLibrary;
+
+ // The driver sessions spec mandates that we implicitly create sessions for operations
+ // that are not explicitly provided with a session.
+ let session, owner;
+ if (topology.hasSessionSupport()) {
+ if (operation.session == null) {
+ owner = Symbol();
+ session = topology.startSession({ owner });
+ operation.session = session;
+ } else if (operation.session.hasEnded) {
+ throw new MongoError('Use of expired sessions is not permitted');
+ }
+ }
+
+ let result;
+ if (typeof callback !== 'function') {
+ result = new Promise((resolve, reject) => {
+ callback = (err, res) => {
+ if (err) return reject(err);
+ resolve(res);
+ };
+ });
+ }
+
+ function executeCallback(err, result) {
+ if (session && session.owner === owner) {
+ session.endSession();
+ if (operation.session === session) {
+ operation.clearSession();
+ }
+ }
+
+ callback(err, result);
+ }
+
+ try {
+ if (operation.hasAspect(Aspect.EXECUTE_WITH_SELECTION)) {
+ executeWithServerSelection(topology, operation, executeCallback);
+ } else {
+ operation.execute(executeCallback);
+ }
+ } catch (e) {
+ if (session && session.owner === owner) {
+ session.endSession();
+ if (operation.session === session) {
+ operation.clearSession();
+ }
+ }
+
+ throw e;
+ }
+
+ return result;
+}
+
+function supportsRetryableReads(server) {
+ return maxWireVersion(server) >= 6;
+}
+
+function executeWithServerSelection(topology, operation, callback) {
+ const readPreference = operation.readPreference || ReadPreference.primary;
+ const inTransaction = operation.session && operation.session.inTransaction();
+
+ if (inTransaction && !readPreference.equals(ReadPreference.primary)) {
+ callback(
+ new MongoError(
+ `Read preference in a transaction must be primary, not: ${readPreference.mode}`
+ )
+ );
+
+ return;
+ }
+
+ const serverSelectionOptions = {
+ readPreference,
+ session: operation.session
+ };
+
+ function callbackWithRetry(err, result) {
+ if (err == null) {
+ return callback(null, result);
+ }
+
+ if (!isRetryableError(err)) {
+ return callback(err);
+ }
+
+ // select a new server, and attempt to retry the operation
+ topology.selectServer(serverSelectionOptions, (err, server) => {
+ if (err || !supportsRetryableReads(server)) {
+ callback(err, null);
+ return;
+ }
+
+ operation.execute(server, callback);
+ });
+ }
+
+ // select a server, and execute the operation against it
+ topology.selectServer(serverSelectionOptions, (err, server) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+
+ const shouldRetryReads =
+ topology.s.options.retryReads !== false &&
+ operation.session &&
+ !inTransaction &&
+ supportsRetryableReads(server) &&
+ operation.canRetryRead;
+
+ if (operation.hasAspect(Aspect.RETRYABLE) && shouldRetryReads) {
+ operation.execute(server, callbackWithRetry);
+ return;
+ }
+
+ operation.execute(server, callback);
+ });
+}
+
+// TODO: This is only supported for unified topology, it should go away once
+// we remove support for legacy topology types.
+function selectServerForSessionSupport(topology, operation, callback) {
+ const Promise = topology.s.promiseLibrary;
+
+ let result;
+ if (typeof callback !== 'function') {
+ result = new Promise((resolve, reject) => {
+ callback = (err, result) => {
+ if (err) return reject(err);
+ resolve(result);
+ };
+ });
+ }
+
+ topology.selectServer(ReadPreference.primaryPreferred, err => {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ executeOperation(topology, operation, callback);
+ });
+
+ return result;
+}
+
+module.exports = executeOperation;
diff --git a/node_modules/mongodb/lib/operations/find.js b/node_modules/mongodb/lib/operations/find.js
new file mode 100644
index 0000000..5d47db6
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+
+class FindOperation extends OperationBase {
+ constructor(collection, ns, command, options) {
+ super(options);
+
+ this.ns = ns;
+ this.cmd = command;
+ this.readPreference = resolveReadPreference(collection, this.options);
+ }
+
+ execute(server, callback) {
+ // copied from `CommandOperationV2`, to be subclassed in the future
+ this.server = server;
+
+ const cursorState = this.cursorState || {};
+
+ // TOOD: use `MongoDBNamespace` through and through
+ server.query(this.ns.toString(), this.cmd, cursorState, this.options, callback);
+ }
+}
+
+defineAspects(FindOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = FindOperation;
diff --git a/node_modules/mongodb/lib/operations/find_and_modify.js b/node_modules/mongodb/lib/operations/find_and_modify.js
new file mode 100644
index 0000000..8965eb4
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find_and_modify.js
@@ -0,0 +1,98 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const applyRetryableWrites = require('../utils').applyRetryableWrites;
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const decorateWithCollation = require('../utils').decorateWithCollation;
+const executeCommand = require('./db_ops').executeCommand;
+const formattedOrderClause = require('../utils').formattedOrderClause;
+const handleCallback = require('../utils').handleCallback;
+const ReadPreference = require('../core').ReadPreference;
+
+class FindAndModifyOperation extends OperationBase {
+ constructor(collection, query, sort, doc, options) {
+ super(options);
+
+ this.collection = collection;
+ this.query = query;
+ this.sort = sort;
+ this.doc = doc;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const query = this.query;
+ const sort = formattedOrderClause(this.sort);
+ const doc = this.doc;
+ let options = this.options;
+
+ // Create findAndModify command object
+ const queryObject = {
+ findAndModify: coll.collectionName,
+ query: query
+ };
+
+ if (sort) {
+ queryObject.sort = sort;
+ }
+
+ queryObject.new = options.new ? true : false;
+ queryObject.remove = options.remove ? true : false;
+ queryObject.upsert = options.upsert ? true : false;
+
+ const projection = options.projection || options.fields;
+
+ if (projection) {
+ queryObject.fields = projection;
+ }
+
+ if (options.arrayFilters) {
+ queryObject.arrayFilters = options.arrayFilters;
+ }
+
+ if (doc && !options.remove) {
+ queryObject.update = doc;
+ }
+
+ if (options.maxTimeMS) queryObject.maxTimeMS = options.maxTimeMS;
+
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ options.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
+
+ // No check on the documents
+ options.checkKeys = false;
+
+ // Final options for retryable writes and write concern
+ options = applyRetryableWrites(options, coll.s.db);
+ options = applyWriteConcern(options, { db: coll.s.db, collection: coll }, options);
+
+ // Decorate the findAndModify command with the write Concern
+ if (options.writeConcern) {
+ queryObject.writeConcern = options.writeConcern;
+ }
+
+ // Have we specified bypassDocumentValidation
+ if (options.bypassDocumentValidation === true) {
+ queryObject.bypassDocumentValidation = options.bypassDocumentValidation;
+ }
+
+ options.readPreference = ReadPreference.primary;
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(queryObject, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Execute the command
+ executeCommand(coll.s.db, queryObject, options, (err, result) => {
+ if (err) return handleCallback(callback, err, null);
+
+ return handleCallback(callback, null, result);
+ });
+ }
+}
+
+module.exports = FindAndModifyOperation;
diff --git a/node_modules/mongodb/lib/operations/find_one.js b/node_modules/mongodb/lib/operations/find_one.js
new file mode 100644
index 0000000..b584db6
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find_one.js
@@ -0,0 +1,37 @@
+'use strict';
+
+const handleCallback = require('../utils').handleCallback;
+const OperationBase = require('./operation').OperationBase;
+const toError = require('../utils').toError;
+
+class FindOneOperation extends OperationBase {
+ constructor(collection, query, options) {
+ super(options);
+
+ this.collection = collection;
+ this.query = query;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const query = this.query;
+ const options = this.options;
+
+ try {
+ const cursor = coll
+ .find(query, options)
+ .limit(-1)
+ .batchSize(1);
+
+ // Return the item
+ cursor.next((err, item) => {
+ if (err != null) return handleCallback(callback, toError(err), null);
+ handleCallback(callback, null, item);
+ });
+ } catch (e) {
+ callback(e);
+ }
+ }
+}
+
+module.exports = FindOneOperation;
diff --git a/node_modules/mongodb/lib/operations/find_one_and_delete.js b/node_modules/mongodb/lib/operations/find_one_and_delete.js
new file mode 100644
index 0000000..1c7527d
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find_one_and_delete.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const FindAndModifyOperation = require('./find_and_modify');
+
+class FindOneAndDeleteOperation extends FindAndModifyOperation {
+ constructor(collection, filter, options) {
+ // Final options
+ const finalOptions = Object.assign({}, options);
+ finalOptions.fields = options.projection;
+ finalOptions.remove = true;
+
+ super(collection, filter, finalOptions.sort, null, finalOptions);
+ }
+}
+
+module.exports = FindOneAndDeleteOperation;
diff --git a/node_modules/mongodb/lib/operations/find_one_and_replace.js b/node_modules/mongodb/lib/operations/find_one_and_replace.js
new file mode 100644
index 0000000..ae37df5
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find_one_and_replace.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const FindAndModifyOperation = require('./find_and_modify');
+
+class FindOneAndReplaceOperation extends FindAndModifyOperation {
+ constructor(collection, filter, replacement, options) {
+ // Final options
+ const finalOptions = Object.assign({}, options);
+ finalOptions.fields = options.projection;
+ finalOptions.update = true;
+ finalOptions.new = options.returnOriginal !== void 0 ? !options.returnOriginal : false;
+ finalOptions.upsert = options.upsert !== void 0 ? !!options.upsert : false;
+
+ super(collection, filter, finalOptions.sort, replacement, finalOptions);
+ }
+}
+
+module.exports = FindOneAndReplaceOperation;
diff --git a/node_modules/mongodb/lib/operations/find_one_and_update.js b/node_modules/mongodb/lib/operations/find_one_and_update.js
new file mode 100644
index 0000000..6a19965
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/find_one_and_update.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const FindAndModifyOperation = require('./find_and_modify');
+
+class FindOneAndUpdateOperation extends FindAndModifyOperation {
+ constructor(collection, filter, update, options) {
+ // Final options
+ const finalOptions = Object.assign({}, options);
+ finalOptions.fields = options.projection;
+ finalOptions.update = true;
+ finalOptions.new =
+ typeof options.returnOriginal === 'boolean' ? !options.returnOriginal : false;
+ finalOptions.upsert = typeof options.upsert === 'boolean' ? options.upsert : false;
+
+ super(collection, filter, finalOptions.sort, update, finalOptions);
+ }
+}
+
+module.exports = FindOneAndUpdateOperation;
diff --git a/node_modules/mongodb/lib/operations/geo_haystack_search.js b/node_modules/mongodb/lib/operations/geo_haystack_search.js
new file mode 100644
index 0000000..edd1fb1
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/geo_haystack_search.js
@@ -0,0 +1,79 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const OperationBase = require('./operation').OperationBase;
+const decorateCommand = require('../utils').decorateCommand;
+const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
+const executeCommand = require('./db_ops').executeCommand;
+const handleCallback = require('../utils').handleCallback;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const toError = require('../utils').toError;
+
+/**
+ * Execute a geo search using a geo haystack index on a collection.
+ *
+ * @class
+ * @property {Collection} a Collection instance.
+ * @property {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
+ * @property {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
+ * @property {object} [options] Optional settings. See Collection.prototype.geoHaystackSearch for a list of options.
+ */
+class GeoHaystackSearchOperation extends OperationBase {
+ /**
+ * Construct a GeoHaystackSearch operation.
+ *
+ * @param {Collection} a Collection instance.
+ * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
+ * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
+ * @param {object} [options] Optional settings. See Collection.prototype.geoHaystackSearch for a list of options.
+ */
+ constructor(collection, x, y, options) {
+ super(options);
+
+ this.collection = collection;
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Execute the operation.
+ *
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+ execute(callback) {
+ const coll = this.collection;
+ const x = this.x;
+ const y = this.y;
+ let options = this.options;
+
+ // Build command object
+ let commandObject = {
+ geoSearch: coll.collectionName,
+ near: [x, y]
+ };
+
+ // Remove read preference from hash if it exists
+ commandObject = decorateCommand(commandObject, options, ['readPreference', 'session']);
+
+ options = Object.assign({}, options);
+ // Ensure we have the right read preference inheritance
+ options.readPreference = resolveReadPreference(coll, options);
+
+ // Do we have a readConcern specified
+ decorateWithReadConcern(commandObject, coll, options);
+
+ // Execute the command
+ executeCommand(coll.s.db, commandObject, options, (err, res) => {
+ if (err) return handleCallback(callback, err);
+ if (res.err || res.errmsg) handleCallback(callback, toError(res));
+ // should we only be returning res.results here? Not sure if the user
+ // should see the other return information
+ handleCallback(callback, null, res);
+ });
+ }
+}
+
+defineAspects(GeoHaystackSearchOperation, Aspect.READ_OPERATION);
+
+module.exports = GeoHaystackSearchOperation;
diff --git a/node_modules/mongodb/lib/operations/index_exists.js b/node_modules/mongodb/lib/operations/index_exists.js
new file mode 100644
index 0000000..bd9dc0e
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/index_exists.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const handleCallback = require('../utils').handleCallback;
+const indexInformationDb = require('./db_ops').indexInformation;
+
+class IndexExistsOperation extends OperationBase {
+ constructor(collection, indexes, options) {
+ super(options);
+
+ this.collection = collection;
+ this.indexes = indexes;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const indexes = this.indexes;
+ const options = this.options;
+
+ indexInformationDb(coll.s.db, coll.collectionName, options, (err, indexInformation) => {
+ // If we have an error return
+ if (err != null) return handleCallback(callback, err, null);
+ // Let's check for the index names
+ if (!Array.isArray(indexes))
+ return handleCallback(callback, null, indexInformation[indexes] != null);
+ // Check in list of indexes
+ for (let i = 0; i < indexes.length; i++) {
+ if (indexInformation[indexes[i]] == null) {
+ return handleCallback(callback, null, false);
+ }
+ }
+
+ // All keys found return true
+ return handleCallback(callback, null, true);
+ });
+ }
+}
+
+module.exports = IndexExistsOperation;
diff --git a/node_modules/mongodb/lib/operations/index_information.js b/node_modules/mongodb/lib/operations/index_information.js
new file mode 100644
index 0000000..b18a603
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/index_information.js
@@ -0,0 +1,23 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const indexInformation = require('./common_functions').indexInformation;
+
+class IndexInformationOperation extends OperationBase {
+ constructor(db, name, options) {
+ super(options);
+
+ this.db = db;
+ this.name = name;
+ }
+
+ execute(callback) {
+ const db = this.db;
+ const name = this.name;
+ const options = this.options;
+
+ indexInformation(db, name, options, callback);
+ }
+}
+
+module.exports = IndexInformationOperation;
diff --git a/node_modules/mongodb/lib/operations/indexes.js b/node_modules/mongodb/lib/operations/indexes.js
new file mode 100644
index 0000000..e29a88a
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/indexes.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const indexInformation = require('./common_functions').indexInformation;
+
+class IndexesOperation extends OperationBase {
+ constructor(collection, options) {
+ super(options);
+
+ this.collection = collection;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ let options = this.options;
+
+ options = Object.assign({}, { full: true }, options);
+ indexInformation(coll.s.db, coll.collectionName, options, callback);
+ }
+}
+
+module.exports = IndexesOperation;
diff --git a/node_modules/mongodb/lib/operations/insert_many.js b/node_modules/mongodb/lib/operations/insert_many.js
new file mode 100644
index 0000000..460a535
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/insert_many.js
@@ -0,0 +1,63 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const BulkWriteOperation = require('./bulk_write');
+const MongoError = require('../core').MongoError;
+const prepareDocs = require('./common_functions').prepareDocs;
+
+class InsertManyOperation extends OperationBase {
+ constructor(collection, docs, options) {
+ super(options);
+
+ this.collection = collection;
+ this.docs = docs;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ let docs = this.docs;
+ const options = this.options;
+
+ if (!Array.isArray(docs)) {
+ return callback(
+ MongoError.create({ message: 'docs parameter must be an array of documents', driver: true })
+ );
+ }
+
+ // If keep going set unordered
+ options['serializeFunctions'] = options['serializeFunctions'] || coll.s.serializeFunctions;
+
+ docs = prepareDocs(coll, docs, options);
+
+ // Generate the bulk write operations
+ const operations = [
+ {
+ insertMany: docs
+ }
+ ];
+
+ const bulkWriteOperation = new BulkWriteOperation(coll, operations, options);
+
+ bulkWriteOperation.execute((err, result) => {
+ if (err) return callback(err, null);
+ callback(null, mapInsertManyResults(docs, result));
+ });
+ }
+}
+
+function mapInsertManyResults(docs, r) {
+ const finalResult = {
+ result: { ok: 1, n: r.insertedCount },
+ ops: docs,
+ insertedCount: r.insertedCount,
+ insertedIds: r.insertedIds
+ };
+
+ if (r.getLastOp()) {
+ finalResult.result.opTime = r.getLastOp();
+ }
+
+ return finalResult;
+}
+
+module.exports = InsertManyOperation;
diff --git a/node_modules/mongodb/lib/operations/insert_one.js b/node_modules/mongodb/lib/operations/insert_one.js
new file mode 100644
index 0000000..5e70880
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/insert_one.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const MongoError = require('../core').MongoError;
+const OperationBase = require('./operation').OperationBase;
+const insertDocuments = require('./common_functions').insertDocuments;
+
+class InsertOneOperation extends OperationBase {
+ constructor(collection, doc, options) {
+ super(options);
+
+ this.collection = collection;
+ this.doc = doc;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const doc = this.doc;
+ const options = this.options;
+
+ if (Array.isArray(doc)) {
+ return callback(
+ MongoError.create({ message: 'doc parameter must be an object', driver: true })
+ );
+ }
+
+ insertDocuments(coll, [doc], options, (err, r) => {
+ if (callback == null) return;
+ if (err && callback) return callback(err);
+ // Workaround for pre 2.6 servers
+ if (r == null) return callback(null, { result: { ok: 1 } });
+ // Add values to top level to ensure crud spec compatibility
+ r.insertedCount = r.result.n;
+ r.insertedId = doc._id;
+ if (callback) callback(null, r);
+ });
+ }
+}
+
+module.exports = InsertOneOperation;
diff --git a/node_modules/mongodb/lib/operations/is_capped.js b/node_modules/mongodb/lib/operations/is_capped.js
new file mode 100644
index 0000000..3bfd9ff
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/is_capped.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const OptionsOperation = require('./options_operation');
+const handleCallback = require('../utils').handleCallback;
+
+class IsCappedOperation extends OptionsOperation {
+ constructor(collection, options) {
+ super(collection, options);
+ }
+
+ execute(callback) {
+ super.execute((err, document) => {
+ if (err) return handleCallback(callback, err);
+ handleCallback(callback, null, !!(document && document.capped));
+ });
+ }
+}
+
+module.exports = IsCappedOperation;
diff --git a/node_modules/mongodb/lib/operations/list_collections.js b/node_modules/mongodb/lib/operations/list_collections.js
new file mode 100644
index 0000000..ee01d31
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/list_collections.js
@@ -0,0 +1,106 @@
+'use strict';
+
+const CommandOperationV2 = require('./command_v2');
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const maxWireVersion = require('../core/utils').maxWireVersion;
+const CONSTANTS = require('../constants');
+
+const LIST_COLLECTIONS_WIRE_VERSION = 3;
+
+function listCollectionsTransforms(databaseName) {
+ const matching = `${databaseName}.`;
+
+ return {
+ doc: doc => {
+ const index = doc.name.indexOf(matching);
+ // Remove database name if available
+ if (doc.name && index === 0) {
+ doc.name = doc.name.substr(index + matching.length);
+ }
+
+ return doc;
+ }
+ };
+}
+
+class ListCollectionsOperation extends CommandOperationV2 {
+ constructor(db, filter, options) {
+ super(db, options, { fullResponse: true });
+
+ this.db = db;
+ this.filter = filter;
+ this.nameOnly = !!this.options.nameOnly;
+
+ if (typeof this.options.batchSize === 'number') {
+ this.batchSize = this.options.batchSize;
+ }
+ }
+
+ execute(server, callback) {
+ if (maxWireVersion(server) < LIST_COLLECTIONS_WIRE_VERSION) {
+ let filter = this.filter;
+ const databaseName = this.db.s.namespace.db;
+
+ // If we have legacy mode and have not provided a full db name filter it
+ if (
+ typeof filter.name === 'string' &&
+ !new RegExp('^' + databaseName + '\\.').test(filter.name)
+ ) {
+ filter = Object.assign({}, filter);
+ filter.name = this.db.s.namespace.withCollection(filter.name).toString();
+ }
+
+ // No filter, filter by current database
+ if (filter == null) {
+ filter.name = `/${databaseName}/`;
+ }
+
+ // Rewrite the filter to use $and to filter out indexes
+ if (filter.name) {
+ filter = { $and: [{ name: filter.name }, { name: /^((?!\$).)*$/ }] };
+ } else {
+ filter = { name: /^((?!\$).)*$/ };
+ }
+
+ const transforms = listCollectionsTransforms(databaseName);
+ server.query(
+ `${databaseName}.${CONSTANTS.SYSTEM_NAMESPACE_COLLECTION}`,
+ { query: filter },
+ { batchSize: this.batchSize || 1000 },
+ {},
+ (err, result) => {
+ if (
+ result &&
+ result.message &&
+ result.message.documents &&
+ Array.isArray(result.message.documents)
+ ) {
+ result.message.documents = result.message.documents.map(transforms.doc);
+ }
+
+ callback(err, result);
+ }
+ );
+
+ return;
+ }
+
+ const command = {
+ listCollections: 1,
+ filter: this.filter,
+ cursor: this.batchSize ? { batchSize: this.batchSize } : {},
+ nameOnly: this.nameOnly
+ };
+
+ return super.executeCommand(server, command, callback);
+ }
+}
+
+defineAspects(ListCollectionsOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = ListCollectionsOperation;
diff --git a/node_modules/mongodb/lib/operations/list_databases.js b/node_modules/mongodb/lib/operations/list_databases.js
new file mode 100644
index 0000000..62b2606
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/list_databases.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const CommandOperationV2 = require('./command_v2');
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const MongoDBNamespace = require('../utils').MongoDBNamespace;
+
+class ListDatabasesOperation extends CommandOperationV2 {
+ constructor(db, options) {
+ super(db, options);
+ this.ns = new MongoDBNamespace('admin', '$cmd');
+ }
+
+ execute(server, callback) {
+ const cmd = { listDatabases: 1 };
+ if (this.options.nameOnly) {
+ cmd.nameOnly = Number(cmd.nameOnly);
+ }
+
+ if (this.options.filter) {
+ cmd.filter = this.options.filter;
+ }
+
+ if (typeof this.options.authorizedDatabases === 'boolean') {
+ cmd.authorizedDatabases = this.options.authorizedDatabases;
+ }
+
+ super.executeCommand(server, cmd, callback);
+ }
+}
+
+defineAspects(ListDatabasesOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = ListDatabasesOperation;
diff --git a/node_modules/mongodb/lib/operations/list_indexes.js b/node_modules/mongodb/lib/operations/list_indexes.js
new file mode 100644
index 0000000..302a31b
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/list_indexes.js
@@ -0,0 +1,42 @@
+'use strict';
+
+const CommandOperationV2 = require('./command_v2');
+const Aspect = require('./operation').Aspect;
+const defineAspects = require('./operation').defineAspects;
+const maxWireVersion = require('../core/utils').maxWireVersion;
+
+const LIST_INDEXES_WIRE_VERSION = 3;
+
+class ListIndexesOperation extends CommandOperationV2 {
+ constructor(collection, options) {
+ super(collection, options, { fullResponse: true });
+
+ this.collectionNamespace = collection.s.namespace;
+ }
+
+ execute(server, callback) {
+ const serverWireVersion = maxWireVersion(server);
+ if (serverWireVersion < LIST_INDEXES_WIRE_VERSION) {
+ const systemIndexesNS = this.collectionNamespace.withCollection('system.indexes').toString();
+ const collectionNS = this.collectionNamespace.toString();
+
+ server.query(systemIndexesNS, { query: { ns: collectionNS } }, {}, this.options, callback);
+ return;
+ }
+
+ const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};
+ super.executeCommand(
+ server,
+ { listIndexes: this.collectionNamespace.collection, cursor },
+ callback
+ );
+ }
+}
+
+defineAspects(ListIndexesOperation, [
+ Aspect.READ_OPERATION,
+ Aspect.RETRYABLE,
+ Aspect.EXECUTE_WITH_SELECTION
+]);
+
+module.exports = ListIndexesOperation;
diff --git a/node_modules/mongodb/lib/operations/map_reduce.js b/node_modules/mongodb/lib/operations/map_reduce.js
new file mode 100644
index 0000000..4ea2ac7
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/map_reduce.js
@@ -0,0 +1,190 @@
+'use strict';
+
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const Code = require('../core').BSON.Code;
+const decorateWithCollation = require('../utils').decorateWithCollation;
+const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
+const executeCommand = require('./db_ops').executeCommand;
+const handleCallback = require('../utils').handleCallback;
+const isObject = require('../utils').isObject;
+const loadDb = require('../dynamic_loaders').loadDb;
+const OperationBase = require('./operation').OperationBase;
+const resolveReadPreference = require('../utils').resolveReadPreference;
+const toError = require('../utils').toError;
+
+const exclusionList = [
+ 'readPreference',
+ 'session',
+ 'bypassDocumentValidation',
+ 'w',
+ 'wtimeout',
+ 'j',
+ 'writeConcern'
+];
+
+/**
+ * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
+ *
+ * @class
+ * @property {Collection} a Collection instance.
+ * @property {(function|string)} map The mapping function.
+ * @property {(function|string)} reduce The reduce function.
+ * @property {object} [options] Optional settings. See Collection.prototype.mapReduce for a list of options.
+ */
+class MapReduceOperation extends OperationBase {
+ /**
+ * Constructs a MapReduce operation.
+ *
+ * @param {Collection} a Collection instance.
+ * @param {(function|string)} map The mapping function.
+ * @param {(function|string)} reduce The reduce function.
+ * @param {object} [options] Optional settings. See Collection.prototype.mapReduce for a list of options.
+ */
+ constructor(collection, map, reduce, options) {
+ super(options);
+
+ this.collection = collection;
+ this.map = map;
+ this.reduce = reduce;
+ }
+
+ /**
+ * Execute the operation.
+ *
+ * @param {Collection~resultCallback} [callback] The command result callback
+ */
+ execute(callback) {
+ const coll = this.collection;
+ const map = this.map;
+ const reduce = this.reduce;
+ let options = this.options;
+
+ const mapCommandHash = {
+ mapreduce: coll.collectionName,
+ map: map,
+ reduce: reduce
+ };
+
+ // Add any other options passed in
+ for (let n in options) {
+ if ('scope' === n) {
+ mapCommandHash[n] = processScope(options[n]);
+ } else {
+ // Only include if not in exclusion list
+ if (exclusionList.indexOf(n) === -1) {
+ mapCommandHash[n] = options[n];
+ }
+ }
+ }
+
+ options = Object.assign({}, options);
+
+ // Ensure we have the right read preference inheritance
+ options.readPreference = resolveReadPreference(coll, options);
+
+ // If we have a read preference and inline is not set as output fail hard
+ if (
+ options.readPreference !== false &&
+ options.readPreference !== 'primary' &&
+ options['out'] &&
+ options['out'].inline !== 1 &&
+ options['out'] !== 'inline'
+ ) {
+ // Force readPreference to primary
+ options.readPreference = 'primary';
+ // Decorate command with writeConcern if supported
+ applyWriteConcern(mapCommandHash, { db: coll.s.db, collection: coll }, options);
+ } else {
+ decorateWithReadConcern(mapCommandHash, coll, options);
+ }
+
+ // Is bypassDocumentValidation specified
+ if (options.bypassDocumentValidation === true) {
+ mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
+ }
+
+ // Have we specified collation
+ try {
+ decorateWithCollation(mapCommandHash, coll, options);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ // Execute command
+ executeCommand(coll.s.db, mapCommandHash, options, (err, result) => {
+ if (err) return handleCallback(callback, err);
+ // Check if we have an error
+ if (1 !== result.ok || result.err || result.errmsg) {
+ return handleCallback(callback, toError(result));
+ }
+
+ // Create statistics value
+ const stats = {};
+ if (result.timeMillis) stats['processtime'] = result.timeMillis;
+ if (result.counts) stats['counts'] = result.counts;
+ if (result.timing) stats['timing'] = result.timing;
+
+ // invoked with inline?
+ if (result.results) {
+ // If we wish for no verbosity
+ if (options['verbose'] == null || !options['verbose']) {
+ return handleCallback(callback, null, result.results);
+ }
+
+ return handleCallback(callback, null, { results: result.results, stats: stats });
+ }
+
+ // The returned collection
+ let collection = null;
+
+ // If we have an object it's a different db
+ if (result.result != null && typeof result.result === 'object') {
+ const doc = result.result;
+ // Return a collection from another db
+ let Db = loadDb();
+ collection = new Db(doc.db, coll.s.db.s.topology, coll.s.db.s.options).collection(
+ doc.collection
+ );
+ } else {
+ // Create a collection object that wraps the result collection
+ collection = coll.s.db.collection(result.result);
+ }
+
+ // If we wish for no verbosity
+ if (options['verbose'] == null || !options['verbose']) {
+ return handleCallback(callback, err, collection);
+ }
+
+ // Return stats as third set of values
+ handleCallback(callback, err, { collection: collection, stats: stats });
+ });
+ }
+}
+
+/**
+ * Functions that are passed as scope args must
+ * be converted to Code instances.
+ * @ignore
+ */
+function processScope(scope) {
+ if (!isObject(scope) || scope._bsontype === 'ObjectID') {
+ return scope;
+ }
+
+ const keys = Object.keys(scope);
+ let key;
+ const new_scope = {};
+
+ for (let i = keys.length - 1; i >= 0; i--) {
+ key = keys[i];
+ if ('function' === typeof scope[key]) {
+ new_scope[key] = new Code(String(scope[key]));
+ } else {
+ new_scope[key] = processScope(scope[key]);
+ }
+ }
+
+ return new_scope;
+}
+
+module.exports = MapReduceOperation;
diff --git a/node_modules/mongodb/lib/operations/operation.js b/node_modules/mongodb/lib/operations/operation.js
new file mode 100644
index 0000000..fd82e66
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/operation.js
@@ -0,0 +1,65 @@
+'use strict';
+
+const Aspect = {
+ READ_OPERATION: Symbol('READ_OPERATION'),
+ WRITE_OPERATION: Symbol('WRITE_OPERATION'),
+ RETRYABLE: Symbol('RETRYABLE'),
+ EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION')
+};
+
+/**
+ * This class acts as a parent class for any operation and is responsible for setting this.options,
+ * as well as setting and getting a session.
+ * Additionally, this class implements `hasAspect`, which determines whether an operation has
+ * a specific aspect.
+ */
+class OperationBase {
+ constructor(options) {
+ this.options = Object.assign({}, options);
+ }
+
+ hasAspect(aspect) {
+ if (this.constructor.aspects == null) {
+ return false;
+ }
+ return this.constructor.aspects.has(aspect);
+ }
+
+ set session(session) {
+ Object.assign(this.options, { session });
+ }
+
+ get session() {
+ return this.options.session;
+ }
+
+ clearSession() {
+ delete this.options.session;
+ }
+
+ get canRetryRead() {
+ return true;
+ }
+
+ execute() {
+ throw new TypeError('`execute` must be implemented for OperationBase subclasses');
+ }
+}
+
+function defineAspects(operation, aspects) {
+ if (!Array.isArray(aspects) && !(aspects instanceof Set)) {
+ aspects = [aspects];
+ }
+ aspects = new Set(aspects);
+ Object.defineProperty(operation, 'aspects', {
+ value: aspects,
+ writable: false
+ });
+ return aspects;
+}
+
+module.exports = {
+ Aspect,
+ defineAspects,
+ OperationBase
+};
diff --git a/node_modules/mongodb/lib/operations/options_operation.js b/node_modules/mongodb/lib/operations/options_operation.js
new file mode 100644
index 0000000..9a739a5
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/options_operation.js
@@ -0,0 +1,32 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const handleCallback = require('../utils').handleCallback;
+const MongoError = require('../core').MongoError;
+
+class OptionsOperation extends OperationBase {
+ constructor(collection, options) {
+ super(options);
+
+ this.collection = collection;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const opts = this.options;
+
+ coll.s.db.listCollections({ name: coll.collectionName }, opts).toArray((err, collections) => {
+ if (err) return handleCallback(callback, err);
+ if (collections.length === 0) {
+ return handleCallback(
+ callback,
+ MongoError.create({ message: `collection ${coll.namespace} not found`, driver: true })
+ );
+ }
+
+ handleCallback(callback, err, collections[0].options || null);
+ });
+ }
+}
+
+module.exports = OptionsOperation;
diff --git a/node_modules/mongodb/lib/operations/profiling_level.js b/node_modules/mongodb/lib/operations/profiling_level.js
new file mode 100644
index 0000000..3f7639b
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/profiling_level.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const CommandOperation = require('./command');
+
+class ProfilingLevelOperation extends CommandOperation {
+ constructor(db, command, options) {
+ super(db, options);
+ }
+
+ _buildCommand() {
+ const command = { profile: -1 };
+
+ return command;
+ }
+
+ execute(callback) {
+ super.execute((err, doc) => {
+ if (err == null && doc.ok === 1) {
+ const was = doc.was;
+ if (was === 0) return callback(null, 'off');
+ if (was === 1) return callback(null, 'slow_only');
+ if (was === 2) return callback(null, 'all');
+ return callback(new Error('Error: illegal profiling level value ' + was), null);
+ } else {
+ err != null ? callback(err, null) : callback(new Error('Error with profile command'), null);
+ }
+ });
+ }
+}
+
+module.exports = ProfilingLevelOperation;
diff --git a/node_modules/mongodb/lib/operations/re_index.js b/node_modules/mongodb/lib/operations/re_index.js
new file mode 100644
index 0000000..89437fe
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/re_index.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const CommandOperation = require('./command');
+const handleCallback = require('../utils').handleCallback;
+
+class ReIndexOperation extends CommandOperation {
+ constructor(collection, options) {
+ super(collection.s.db, options, collection);
+ }
+
+ _buildCommand() {
+ const collection = this.collection;
+
+ const cmd = { reIndex: collection.collectionName };
+
+ return cmd;
+ }
+
+ execute(callback) {
+ super.execute((err, result) => {
+ if (callback == null) return;
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, null, result.ok ? true : false);
+ });
+ }
+}
+
+module.exports = ReIndexOperation;
diff --git a/node_modules/mongodb/lib/operations/remove_user.js b/node_modules/mongodb/lib/operations/remove_user.js
new file mode 100644
index 0000000..9e8376b
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/remove_user.js
@@ -0,0 +1,52 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const CommandOperation = require('./command');
+const defineAspects = require('./operation').defineAspects;
+const handleCallback = require('../utils').handleCallback;
+const WriteConcern = require('../write_concern');
+
+class RemoveUserOperation extends CommandOperation {
+ constructor(db, username, options) {
+ const commandOptions = {};
+
+ const writeConcern = WriteConcern.fromOptions(options);
+ if (writeConcern != null) {
+ commandOptions.writeConcern = writeConcern;
+ }
+
+ if (options.dbName) {
+ commandOptions.dbName = options.dbName;
+ }
+
+ // Add maxTimeMS to options if set
+ if (typeof options.maxTimeMS === 'number') {
+ commandOptions.maxTimeMS = options.maxTimeMS;
+ }
+
+ super(db, commandOptions);
+
+ this.username = username;
+ }
+
+ _buildCommand() {
+ const username = this.username;
+
+ // Build the command to execute
+ const command = { dropUser: username };
+
+ return command;
+ }
+
+ execute(callback) {
+ // Attempt to execute command
+ super.execute((err, result) => {
+ if (err) return handleCallback(callback, err, null);
+ handleCallback(callback, err, result.ok ? true : false);
+ });
+ }
+}
+
+defineAspects(RemoveUserOperation, Aspect.WRITE_OPERATION);
+
+module.exports = RemoveUserOperation;
diff --git a/node_modules/mongodb/lib/operations/rename.js b/node_modules/mongodb/lib/operations/rename.js
new file mode 100644
index 0000000..8098fe6
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/rename.js
@@ -0,0 +1,61 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const applyWriteConcern = require('../utils').applyWriteConcern;
+const checkCollectionName = require('../utils').checkCollectionName;
+const executeDbAdminCommand = require('./db_ops').executeDbAdminCommand;
+const handleCallback = require('../utils').handleCallback;
+const loadCollection = require('../dynamic_loaders').loadCollection;
+const toError = require('../utils').toError;
+
+class RenameOperation extends OperationBase {
+ constructor(collection, newName, options) {
+ super(options);
+
+ this.collection = collection;
+ this.newName = newName;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const newName = this.newName;
+ const options = this.options;
+
+ let Collection = loadCollection();
+ // Check the collection name
+ checkCollectionName(newName);
+ // Build the command
+ const renameCollection = coll.namespace;
+ const toCollection = coll.s.namespace.withCollection(newName).toString();
+ const dropTarget = typeof options.dropTarget === 'boolean' ? options.dropTarget : false;
+ const cmd = { renameCollection: renameCollection, to: toCollection, dropTarget: dropTarget };
+
+ // Decorate command with writeConcern if supported
+ applyWriteConcern(cmd, { db: coll.s.db, collection: coll }, options);
+
+ // Execute against admin
+ executeDbAdminCommand(coll.s.db.admin().s.db, cmd, options, (err, doc) => {
+ if (err) return handleCallback(callback, err, null);
+ // We have an error
+ if (doc.errmsg) return handleCallback(callback, toError(doc), null);
+ try {
+ return handleCallback(
+ callback,
+ null,
+ new Collection(
+ coll.s.db,
+ coll.s.topology,
+ coll.s.namespace.db,
+ newName,
+ coll.s.pkFactory,
+ coll.s.options
+ )
+ );
+ } catch (err) {
+ return handleCallback(callback, toError(err), null);
+ }
+ });
+ }
+}
+
+module.exports = RenameOperation;
diff --git a/node_modules/mongodb/lib/operations/replace_one.js b/node_modules/mongodb/lib/operations/replace_one.js
new file mode 100644
index 0000000..a5aa760
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/replace_one.js
@@ -0,0 +1,47 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const updateDocuments = require('./common_functions').updateDocuments;
+
+class ReplaceOneOperation extends OperationBase {
+ constructor(collection, filter, doc, options) {
+ super(options);
+
+ this.collection = collection;
+ this.filter = filter;
+ this.doc = doc;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const filter = this.filter;
+ const doc = this.doc;
+ const options = this.options;
+
+ // Set single document update
+ options.multi = false;
+
+ // Execute update
+ updateDocuments(coll, filter, doc, options, (err, r) => replaceCallback(err, r, doc, callback));
+ }
+}
+
+function replaceCallback(err, r, doc, callback) {
+ if (callback == null) return;
+ if (err && callback) return callback(err);
+ if (r == null) return callback(null, { result: { ok: 1 } });
+
+ r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
+ r.upsertedId =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0
+ ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
+ : null;
+ r.upsertedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
+ r.matchedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
+ r.ops = [doc]; // TODO: Should we still have this?
+ if (callback) callback(null, r);
+}
+
+module.exports = ReplaceOneOperation;
diff --git a/node_modules/mongodb/lib/operations/set_profiling_level.js b/node_modules/mongodb/lib/operations/set_profiling_level.js
new file mode 100644
index 0000000..b31cc13
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/set_profiling_level.js
@@ -0,0 +1,48 @@
+'use strict';
+
+const CommandOperation = require('./command');
+const levelValues = new Set(['off', 'slow_only', 'all']);
+
+class SetProfilingLevelOperation extends CommandOperation {
+ constructor(db, level, options) {
+ let profile = 0;
+
+ if (level === 'off') {
+ profile = 0;
+ } else if (level === 'slow_only') {
+ profile = 1;
+ } else if (level === 'all') {
+ profile = 2;
+ }
+
+ super(db, options);
+ this.level = level;
+ this.profile = profile;
+ }
+
+ _buildCommand() {
+ const profile = this.profile;
+
+ // Set up the profile number
+ const command = { profile };
+
+ return command;
+ }
+
+ execute(callback) {
+ const level = this.level;
+
+ if (!levelValues.has(level)) {
+ return callback(new Error('Error: illegal profiling level value ' + level));
+ }
+
+ super.execute((err, doc) => {
+ if (err == null && doc.ok === 1) return callback(null, level);
+ return err != null
+ ? callback(err, null)
+ : callback(new Error('Error with profile command'), null);
+ });
+ }
+}
+
+module.exports = SetProfilingLevelOperation;
diff --git a/node_modules/mongodb/lib/operations/stats.js b/node_modules/mongodb/lib/operations/stats.js
new file mode 100644
index 0000000..ff79126
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/stats.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const Aspect = require('./operation').Aspect;
+const CommandOperation = require('./command');
+const defineAspects = require('./operation').defineAspects;
+
+/**
+ * Get all the collection statistics.
+ *
+ * @class
+ * @property {Collection} a Collection instance.
+ * @property {object} [options] Optional settings. See Collection.prototype.stats for a list of options.
+ */
+class StatsOperation extends CommandOperation {
+ /**
+ * Construct a Stats operation.
+ *
+ * @param {Collection} a Collection instance.
+ * @param {object} [options] Optional settings. See Collection.prototype.stats for a list of options.
+ */
+ constructor(collection, options) {
+ super(collection.s.db, options, collection);
+ }
+
+ _buildCommand() {
+ const collection = this.collection;
+ const options = this.options;
+
+ // Build command object
+ const command = {
+ collStats: collection.collectionName
+ };
+
+ // Check if we have the scale value
+ if (options['scale'] != null) {
+ command['scale'] = options['scale'];
+ }
+
+ return command;
+ }
+}
+
+defineAspects(StatsOperation, Aspect.READ_OPERATION);
+
+module.exports = StatsOperation;
diff --git a/node_modules/mongodb/lib/operations/update_many.js b/node_modules/mongodb/lib/operations/update_many.js
new file mode 100644
index 0000000..9a18d25
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/update_many.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const updateCallback = require('./common_functions').updateCallback;
+const updateDocuments = require('./common_functions').updateDocuments;
+
+class UpdateManyOperation extends OperationBase {
+ constructor(collection, filter, update, options) {
+ super(options);
+
+ this.collection = collection;
+ this.filter = filter;
+ this.update = update;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const filter = this.filter;
+ const update = this.update;
+ const options = this.options;
+
+ // Set single document update
+ options.multi = true;
+ // Execute update
+ updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
+ }
+}
+
+module.exports = UpdateManyOperation;
diff --git a/node_modules/mongodb/lib/operations/update_one.js b/node_modules/mongodb/lib/operations/update_one.js
new file mode 100644
index 0000000..b1c1bc1
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/update_one.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const OperationBase = require('./operation').OperationBase;
+const updateDocuments = require('./common_functions').updateDocuments;
+
+class UpdateOneOperation extends OperationBase {
+ constructor(collection, filter, update, options) {
+ super(options);
+
+ this.collection = collection;
+ this.filter = filter;
+ this.update = update;
+ }
+
+ execute(callback) {
+ const coll = this.collection;
+ const filter = this.filter;
+ const update = this.update;
+ const options = this.options;
+
+ // Set single document update
+ options.multi = false;
+ // Execute update
+ updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
+ }
+}
+
+function updateCallback(err, r, callback) {
+ if (callback == null) return;
+ if (err) return callback(err);
+ if (r == null) return callback(null, { result: { ok: 1 } });
+ r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
+ r.upsertedId =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0
+ ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
+ : null;
+ r.upsertedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
+ r.matchedCount =
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
+ callback(null, r);
+}
+
+module.exports = UpdateOneOperation;
diff --git a/node_modules/mongodb/lib/operations/validate_collection.js b/node_modules/mongodb/lib/operations/validate_collection.js
new file mode 100644
index 0000000..133c6c4
--- /dev/null
+++ b/node_modules/mongodb/lib/operations/validate_collection.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const CommandOperation = require('./command');
+
+class ValidateCollectionOperation extends CommandOperation {
+ constructor(admin, collectionName, options) {
+ // Decorate command with extra options
+ let command = { validate: collectionName };
+ const keys = Object.keys(options);
+ for (let i = 0; i < keys.length; i++) {
+ if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
+ command[keys[i]] = options[keys[i]];
+ }
+ }
+
+ super(admin.s.db, options, null, command);
+
+ this.collectionName;
+ }
+
+ execute(callback) {
+ const collectionName = this.collectionName;
+
+ super.execute((err, doc) => {
+ if (err != null) return callback(err, null);
+
+ if (doc.ok === 0) return callback(new Error('Error with validate command'), null);
+ if (doc.result != null && doc.result.constructor !== String)
+ return callback(new Error('Error with validation data'), null);
+ if (doc.result != null && doc.result.match(/exception|corrupt/) != null)
+ return callback(new Error('Error: invalid collection ' + collectionName), null);
+ if (doc.valid != null && !doc.valid)
+ return callback(new Error('Error: invalid collection ' + collectionName), null);
+
+ return callback(null, doc);
+ });
+ }
+}
+
+module.exports = ValidateCollectionOperation;
diff --git a/node_modules/mongodb/lib/read_concern.js b/node_modules/mongodb/lib/read_concern.js
new file mode 100644
index 0000000..b48b8e0
--- /dev/null
+++ b/node_modules/mongodb/lib/read_concern.js
@@ -0,0 +1,61 @@
+'use strict';
+
+/**
+ * The **ReadConcern** class is a class that represents a MongoDB ReadConcern.
+ * @class
+ * @property {string} level The read concern level
+ * @see https://docs.mongodb.com/manual/reference/read-concern/index.html
+ */
+class ReadConcern {
+ /**
+ * Constructs a ReadConcern from the read concern properties.
+ * @param {string} [level] The read concern level ({'local'|'available'|'majority'|'linearizable'|'snapshot'})
+ */
+ constructor(level) {
+ if (level != null) {
+ this.level = level;
+ }
+ }
+
+ /**
+ * Construct a ReadConcern given an options object.
+ *
+ * @param {object} options The options object from which to extract the write concern.
+ * @return {ReadConcern}
+ */
+ static fromOptions(options) {
+ if (options == null) {
+ return;
+ }
+
+ if (options.readConcern) {
+ if (options.readConcern instanceof ReadConcern) {
+ return options.readConcern;
+ }
+
+ return new ReadConcern(options.readConcern.level);
+ }
+
+ if (options.level) {
+ return new ReadConcern(options.level);
+ }
+ }
+
+ static get MAJORITY() {
+ return 'majority';
+ }
+
+ static get AVAILABLE() {
+ return 'available';
+ }
+
+ static get LINEARIZABLE() {
+ return 'linearizable';
+ }
+
+ static get SNAPSHOT() {
+ return 'snapshot';
+ }
+}
+
+module.exports = ReadConcern;
diff --git a/node_modules/mongodb/lib/topologies/mongos.js b/node_modules/mongodb/lib/topologies/mongos.js
new file mode 100644
index 0000000..10e66d2
--- /dev/null
+++ b/node_modules/mongodb/lib/topologies/mongos.js
@@ -0,0 +1,445 @@
+'use strict';
+
+const TopologyBase = require('./topology_base').TopologyBase;
+const MongoError = require('../core').MongoError;
+const CMongos = require('../core').Mongos;
+const Cursor = require('../cursor');
+const Server = require('./server');
+const Store = require('./topology_base').Store;
+const MAX_JS_INT = require('../utils').MAX_JS_INT;
+const translateOptions = require('../utils').translateOptions;
+const filterOptions = require('../utils').filterOptions;
+const mergeOptions = require('../utils').mergeOptions;
+
+/**
+ * @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
+ * used to construct connections.
+ *
+ * **Mongos Should not be used, use MongoClient.connect**
+ */
+
+// Allowed parameters
+var legalOptionNames = [
+ 'ha',
+ 'haInterval',
+ 'acceptableLatencyMS',
+ 'poolSize',
+ 'ssl',
+ 'checkServerIdentity',
+ 'sslValidate',
+ 'sslCA',
+ 'sslCRL',
+ 'sslCert',
+ 'ciphers',
+ 'ecdhCurve',
+ 'sslKey',
+ 'sslPass',
+ 'socketOptions',
+ 'bufferMaxEntries',
+ 'store',
+ 'auto_reconnect',
+ 'autoReconnect',
+ 'emitError',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'noDelay',
+ 'connectTimeoutMS',
+ 'socketTimeoutMS',
+ 'loggerLevel',
+ 'logger',
+ 'reconnectTries',
+ 'appname',
+ 'domainsEnabled',
+ 'servername',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'promiseLibrary',
+ 'monitorCommands'
+];
+
+/**
+ * Creates a new Mongos instance
+ * @class
+ * @deprecated
+ * @param {Server[]} servers A seedlist of servers participating in the replicaset.
+ * @param {object} [options] Optional settings.
+ * @param {booelan} [options.ha=true] Turn on high availability monitoring.
+ * @param {number} [options.haInterval=5000] Time between each replicaset status check.
+ * @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
+ * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for MongoS proxy selection
+ * @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {array} [options.sslCA] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {array} [options.sslCRL] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {string} [options.ciphers] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {string} [options.ecdhCurve] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {(Buffer|string)} [options.sslCert] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslKey] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslPass] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {string} [options.servername] String containing the server name requested via TLS SNI.
+ * @param {object} [options.socketOptions] Socket options
+ * @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
+ * @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
+ * @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
+ * @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @fires Mongos#connect
+ * @fires Mongos#ha
+ * @fires Mongos#joined
+ * @fires Mongos#left
+ * @fires Mongos#fullsetup
+ * @fires Mongos#open
+ * @fires Mongos#close
+ * @fires Mongos#error
+ * @fires Mongos#timeout
+ * @fires Mongos#parseError
+ * @fires Mongos#commandStarted
+ * @fires Mongos#commandSucceeded
+ * @fires Mongos#commandFailed
+ * @property {string} parserType the parser type used (c++ or js).
+ * @return {Mongos} a Mongos instance.
+ */
+class Mongos extends TopologyBase {
+ constructor(servers, options) {
+ super();
+
+ options = options || {};
+ var self = this;
+
+ // Filter the options
+ options = filterOptions(options, legalOptionNames);
+
+ // Ensure all the instances are Server
+ for (var i = 0; i < servers.length; i++) {
+ if (!(servers[i] instanceof Server)) {
+ throw MongoError.create({
+ message: 'all seed list instances must be of the Server type',
+ driver: true
+ });
+ }
+ }
+
+ // Stored options
+ var storeOptions = {
+ force: false,
+ bufferMaxEntries:
+ typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
+ };
+
+ // Shared global store
+ var store = options.store || new Store(self, storeOptions);
+
+ // Build seed list
+ var seedlist = servers.map(function(x) {
+ return { host: x.host, port: x.port };
+ });
+
+ // Get the reconnect option
+ var reconnect = typeof options.auto_reconnect === 'boolean' ? options.auto_reconnect : true;
+ reconnect = typeof options.autoReconnect === 'boolean' ? options.autoReconnect : reconnect;
+
+ // Clone options
+ var clonedOptions = mergeOptions(
+ {},
+ {
+ disconnectHandler: store,
+ cursorFactory: Cursor,
+ reconnect: reconnect,
+ emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
+ size: typeof options.poolSize === 'number' ? options.poolSize : 5,
+ monitorCommands:
+ typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
+ }
+ );
+
+ // Translate any SSL options and other connectivity options
+ clonedOptions = translateOptions(clonedOptions, options);
+
+ // Socket options
+ var socketOptions =
+ options.socketOptions && Object.keys(options.socketOptions).length > 0
+ ? options.socketOptions
+ : options;
+
+ // Translate all the options to the core types
+ clonedOptions = translateOptions(clonedOptions, socketOptions);
+
+ // Internal state
+ this.s = {
+ // Create the Mongos
+ coreTopology: new CMongos(seedlist, clonedOptions),
+ // Server capabilities
+ sCapabilities: null,
+ // Debug turned on
+ debug: clonedOptions.debug,
+ // Store option defaults
+ storeOptions: storeOptions,
+ // Cloned options
+ clonedOptions: clonedOptions,
+ // Actual store of callbacks
+ store: store,
+ // Options
+ options: options,
+ // Server Session Pool
+ sessionPool: null,
+ // Active client sessions
+ sessions: new Set(),
+ // Promise library
+ promiseLibrary: options.promiseLibrary || Promise
+ };
+ }
+
+ // Connect
+ connect(_options, callback) {
+ var self = this;
+ if ('function' === typeof _options) (callback = _options), (_options = {});
+ if (_options == null) _options = {};
+ if (!('function' === typeof callback)) callback = null;
+ _options = Object.assign({}, this.s.clonedOptions, _options);
+ self.s.options = _options;
+
+ // Update bufferMaxEntries
+ self.s.storeOptions.bufferMaxEntries =
+ typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
+
+ // Error handler
+ var connectErrorHandler = function() {
+ return function(err) {
+ // Remove all event handlers
+ var events = ['timeout', 'error', 'close'];
+ events.forEach(function(e) {
+ self.removeListener(e, connectErrorHandler);
+ });
+
+ self.s.coreTopology.removeListener('connect', connectErrorHandler);
+ // Force close the topology
+ self.close(true);
+
+ // Try to callback
+ try {
+ callback(err);
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+ };
+
+ // Actual handler
+ var errorHandler = function(event) {
+ return function(err) {
+ if (event !== 'error') {
+ self.emit(event, err);
+ }
+ };
+ };
+
+ // Error handler
+ var reconnectHandler = function() {
+ self.emit('reconnect');
+ self.s.store.execute();
+ };
+
+ // relay the event
+ var relay = function(event) {
+ return function(t, server) {
+ self.emit(event, t, server);
+ };
+ };
+
+ // Connect handler
+ var connectHandler = function() {
+ // Clear out all the current handlers left over
+ var events = ['timeout', 'error', 'close', 'fullsetup'];
+ events.forEach(function(e) {
+ self.s.coreTopology.removeAllListeners(e);
+ });
+
+ // Set up listeners
+ self.s.coreTopology.on('timeout', errorHandler('timeout'));
+ self.s.coreTopology.on('error', errorHandler('error'));
+ self.s.coreTopology.on('close', errorHandler('close'));
+
+ // Set up serverConfig listeners
+ self.s.coreTopology.on('fullsetup', function() {
+ self.emit('fullsetup', self);
+ });
+
+ // Emit open event
+ self.emit('open', null, self);
+
+ // Return correctly
+ try {
+ callback(null, self);
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+
+ // Clear out all the current handlers left over
+ var events = [
+ 'timeout',
+ 'error',
+ 'close',
+ 'serverOpening',
+ 'serverDescriptionChanged',
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'serverClosed',
+ 'topologyOpening',
+ 'topologyClosed',
+ 'topologyDescriptionChanged',
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed'
+ ];
+ events.forEach(function(e) {
+ self.s.coreTopology.removeAllListeners(e);
+ });
+
+ // Set up SDAM listeners
+ self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
+ self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
+ self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
+ self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
+ self.s.coreTopology.on('serverOpening', relay('serverOpening'));
+ self.s.coreTopology.on('serverClosed', relay('serverClosed'));
+ self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
+ self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
+ self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
+ self.s.coreTopology.on('commandStarted', relay('commandStarted'));
+ self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
+ self.s.coreTopology.on('commandFailed', relay('commandFailed'));
+
+ // Set up listeners
+ self.s.coreTopology.once('timeout', connectErrorHandler('timeout'));
+ self.s.coreTopology.once('error', connectErrorHandler('error'));
+ self.s.coreTopology.once('close', connectErrorHandler('close'));
+ self.s.coreTopology.once('connect', connectHandler);
+ // Join and leave events
+ self.s.coreTopology.on('joined', relay('joined'));
+ self.s.coreTopology.on('left', relay('left'));
+
+ // Reconnect server
+ self.s.coreTopology.on('reconnect', reconnectHandler);
+
+ // Start connection
+ self.s.coreTopology.connect(_options);
+ }
+}
+
+Object.defineProperty(Mongos.prototype, 'haInterval', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.s.haInterval;
+ }
+});
+
+/**
+ * A mongos connect event, used to verify that the connection is up and running
+ *
+ * @event Mongos#connect
+ * @type {Mongos}
+ */
+
+/**
+ * The mongos high availability event
+ *
+ * @event Mongos#ha
+ * @type {function}
+ * @param {string} type The stage in the high availability event (start|end)
+ * @param {boolean} data.norepeat This is a repeating high availability process or a single execution only
+ * @param {number} data.id The id for this high availability request
+ * @param {object} data.state An object containing the information about the current replicaset
+ */
+
+/**
+ * A server member left the mongos set
+ *
+ * @event Mongos#left
+ * @type {function}
+ * @param {string} type The type of member that left (primary|secondary|arbiter)
+ * @param {Server} server The server object that left
+ */
+
+/**
+ * A server member joined the mongos set
+ *
+ * @event Mongos#joined
+ * @type {function}
+ * @param {string} type The type of member that joined (primary|secondary|arbiter)
+ * @param {Server} server The server object that joined
+ */
+
+/**
+ * Mongos fullsetup event, emitted when all proxies in the topology have been connected to.
+ *
+ * @event Mongos#fullsetup
+ * @type {Mongos}
+ */
+
+/**
+ * Mongos open event, emitted when mongos can start processing commands.
+ *
+ * @event Mongos#open
+ * @type {Mongos}
+ */
+
+/**
+ * Mongos close event
+ *
+ * @event Mongos#close
+ * @type {object}
+ */
+
+/**
+ * Mongos error event, emitted if there is an error listener.
+ *
+ * @event Mongos#error
+ * @type {MongoError}
+ */
+
+/**
+ * Mongos timeout event
+ *
+ * @event Mongos#timeout
+ * @type {object}
+ */
+
+/**
+ * Mongos parseError event
+ *
+ * @event Mongos#parseError
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event Mongos#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event Mongos#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event Mongos#commandFailed
+ * @type {object}
+ */
+
+module.exports = Mongos;
diff --git a/node_modules/mongodb/lib/topologies/native_topology.js b/node_modules/mongodb/lib/topologies/native_topology.js
new file mode 100644
index 0000000..778ddc9
--- /dev/null
+++ b/node_modules/mongodb/lib/topologies/native_topology.js
@@ -0,0 +1,68 @@
+'use strict';
+
+const Topology = require('../core').Topology;
+const ServerCapabilities = require('./topology_base').ServerCapabilities;
+const Cursor = require('../cursor');
+const translateOptions = require('../utils').translateOptions;
+
+class NativeTopology extends Topology {
+ constructor(servers, options) {
+ options = options || {};
+
+ let clonedOptions = Object.assign(
+ {},
+ {
+ cursorFactory: Cursor,
+ reconnect: false,
+ emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
+ maxPoolSize: typeof options.poolSize === 'number' ? options.poolSize : 5,
+ minPoolSize: typeof options.minSize === 'number' ? options.minSize : 0,
+ monitorCommands:
+ typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
+ }
+ );
+
+ // Translate any SSL options and other connectivity options
+ clonedOptions = translateOptions(clonedOptions, options);
+
+ // Socket options
+ var socketOptions =
+ options.socketOptions && Object.keys(options.socketOptions).length > 0
+ ? options.socketOptions
+ : options;
+
+ // Translate all the options to the core types
+ clonedOptions = translateOptions(clonedOptions, socketOptions);
+
+ super(servers, clonedOptions);
+ }
+
+ capabilities() {
+ if (this.s.sCapabilities) return this.s.sCapabilities;
+ if (this.lastIsMaster() == null) return null;
+ this.s.sCapabilities = new ServerCapabilities(this.lastIsMaster());
+ return this.s.sCapabilities;
+ }
+
+ // Command
+ command(ns, cmd, options, callback) {
+ super.command(ns.toString(), cmd, options, callback);
+ }
+
+ // Insert
+ insert(ns, ops, options, callback) {
+ super.insert(ns.toString(), ops, options, callback);
+ }
+
+ // Update
+ update(ns, ops, options, callback) {
+ super.update(ns.toString(), ops, options, callback);
+ }
+
+ // Remove
+ remove(ns, ops, options, callback) {
+ super.remove(ns.toString(), ops, options, callback);
+ }
+}
+
+module.exports = NativeTopology;
diff --git a/node_modules/mongodb/lib/topologies/replset.js b/node_modules/mongodb/lib/topologies/replset.js
new file mode 100644
index 0000000..69df26d
--- /dev/null
+++ b/node_modules/mongodb/lib/topologies/replset.js
@@ -0,0 +1,489 @@
+'use strict';
+
+const Server = require('./server');
+const Cursor = require('../cursor');
+const MongoError = require('../core').MongoError;
+const TopologyBase = require('./topology_base').TopologyBase;
+const Store = require('./topology_base').Store;
+const CReplSet = require('../core').ReplSet;
+const MAX_JS_INT = require('../utils').MAX_JS_INT;
+const translateOptions = require('../utils').translateOptions;
+const filterOptions = require('../utils').filterOptions;
+const mergeOptions = require('../utils').mergeOptions;
+
+/**
+ * @fileOverview The **ReplSet** class is a class that represents a Replicaset topology and is
+ * used to construct connections.
+ *
+ * **ReplSet Should not be used, use MongoClient.connect**
+ */
+
+// Allowed parameters
+var legalOptionNames = [
+ 'ha',
+ 'haInterval',
+ 'replicaSet',
+ 'rs_name',
+ 'secondaryAcceptableLatencyMS',
+ 'connectWithNoPrimary',
+ 'poolSize',
+ 'ssl',
+ 'checkServerIdentity',
+ 'sslValidate',
+ 'sslCA',
+ 'sslCert',
+ 'ciphers',
+ 'ecdhCurve',
+ 'sslCRL',
+ 'sslKey',
+ 'sslPass',
+ 'socketOptions',
+ 'bufferMaxEntries',
+ 'store',
+ 'auto_reconnect',
+ 'autoReconnect',
+ 'emitError',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'noDelay',
+ 'connectTimeoutMS',
+ 'socketTimeoutMS',
+ 'strategy',
+ 'debug',
+ 'family',
+ 'loggerLevel',
+ 'logger',
+ 'reconnectTries',
+ 'appname',
+ 'domainsEnabled',
+ 'servername',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'maxStalenessSeconds',
+ 'promiseLibrary',
+ 'minSize',
+ 'monitorCommands'
+];
+
+/**
+ * Creates a new ReplSet instance
+ * @class
+ * @deprecated
+ * @param {Server[]} servers A seedlist of servers participating in the replicaset.
+ * @param {object} [options] Optional settings.
+ * @param {boolean} [options.ha=true] Turn on high availability monitoring.
+ * @param {number} [options.haInterval=10000] Time between each replicaset status check.
+ * @param {string} [options.replicaSet] The name of the replicaset to connect to.
+ * @param {number} [options.secondaryAcceptableLatencyMS=15] Sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
+ * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
+ * @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
+ * @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {array} [options.sslCA] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {array} [options.sslCRL] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslCert] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher.
+ * @param {string} [options.ciphers] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {string} [options.ecdhCurve] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {(Buffer|string)} [options.sslKey] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslPass] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {string} [options.servername] String containing the server name requested via TLS SNI.
+ * @param {object} [options.socketOptions] Socket options
+ * @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
+ * @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
+ * @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
+ * @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @fires ReplSet#connect
+ * @fires ReplSet#ha
+ * @fires ReplSet#joined
+ * @fires ReplSet#left
+ * @fires ReplSet#fullsetup
+ * @fires ReplSet#open
+ * @fires ReplSet#close
+ * @fires ReplSet#error
+ * @fires ReplSet#timeout
+ * @fires ReplSet#parseError
+ * @fires ReplSet#commandStarted
+ * @fires ReplSet#commandSucceeded
+ * @fires ReplSet#commandFailed
+ * @property {string} parserType the parser type used (c++ or js).
+ * @return {ReplSet} a ReplSet instance.
+ */
+class ReplSet extends TopologyBase {
+ constructor(servers, options) {
+ super();
+
+ options = options || {};
+ var self = this;
+
+ // Filter the options
+ options = filterOptions(options, legalOptionNames);
+
+ // Ensure all the instances are Server
+ for (var i = 0; i < servers.length; i++) {
+ if (!(servers[i] instanceof Server)) {
+ throw MongoError.create({
+ message: 'all seed list instances must be of the Server type',
+ driver: true
+ });
+ }
+ }
+
+ // Stored options
+ var storeOptions = {
+ force: false,
+ bufferMaxEntries:
+ typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
+ };
+
+ // Shared global store
+ var store = options.store || new Store(self, storeOptions);
+
+ // Build seed list
+ var seedlist = servers.map(function(x) {
+ return { host: x.host, port: x.port };
+ });
+
+ // Clone options
+ var clonedOptions = mergeOptions(
+ {},
+ {
+ disconnectHandler: store,
+ cursorFactory: Cursor,
+ reconnect: false,
+ emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
+ size: typeof options.poolSize === 'number' ? options.poolSize : 5,
+ monitorCommands:
+ typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
+ }
+ );
+
+ // Translate any SSL options and other connectivity options
+ clonedOptions = translateOptions(clonedOptions, options);
+
+ // Socket options
+ var socketOptions =
+ options.socketOptions && Object.keys(options.socketOptions).length > 0
+ ? options.socketOptions
+ : options;
+
+ // Translate all the options to the core types
+ clonedOptions = translateOptions(clonedOptions, socketOptions);
+
+ // Create the ReplSet
+ var coreTopology = new CReplSet(seedlist, clonedOptions);
+
+ // Listen to reconnect event
+ coreTopology.on('reconnect', function() {
+ self.emit('reconnect');
+ store.execute();
+ });
+
+ // Internal state
+ this.s = {
+ // Replicaset
+ coreTopology: coreTopology,
+ // Server capabilities
+ sCapabilities: null,
+ // Debug tag
+ tag: options.tag,
+ // Store options
+ storeOptions: storeOptions,
+ // Cloned options
+ clonedOptions: clonedOptions,
+ // Store
+ store: store,
+ // Options
+ options: options,
+ // Server Session Pool
+ sessionPool: null,
+ // Active client sessions
+ sessions: new Set(),
+ // Promise library
+ promiseLibrary: options.promiseLibrary || Promise
+ };
+
+ // Debug
+ if (clonedOptions.debug) {
+ // Last ismaster
+ Object.defineProperty(this, 'replset', {
+ enumerable: true,
+ get: function() {
+ return coreTopology;
+ }
+ });
+ }
+ }
+
+ // Connect method
+ connect(_options, callback) {
+ var self = this;
+ if ('function' === typeof _options) (callback = _options), (_options = {});
+ if (_options == null) _options = {};
+ if (!('function' === typeof callback)) callback = null;
+ _options = Object.assign({}, this.s.clonedOptions, _options);
+ self.s.options = _options;
+
+ // Update bufferMaxEntries
+ self.s.storeOptions.bufferMaxEntries =
+ typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
+
+ // Actual handler
+ var errorHandler = function(event) {
+ return function(err) {
+ if (event !== 'error') {
+ self.emit(event, err);
+ }
+ };
+ };
+
+ // Clear out all the current handlers left over
+ var events = [
+ 'timeout',
+ 'error',
+ 'close',
+ 'serverOpening',
+ 'serverDescriptionChanged',
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'serverClosed',
+ 'topologyOpening',
+ 'topologyClosed',
+ 'topologyDescriptionChanged',
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed',
+ 'joined',
+ 'left',
+ 'ping',
+ 'ha'
+ ];
+ events.forEach(function(e) {
+ self.s.coreTopology.removeAllListeners(e);
+ });
+
+ // relay the event
+ var relay = function(event) {
+ return function(t, server) {
+ self.emit(event, t, server);
+ };
+ };
+
+ // Replset events relay
+ var replsetRelay = function(event) {
+ return function(t, server) {
+ self.emit(event, t, server.lastIsMaster(), server);
+ };
+ };
+
+ // Relay ha
+ var relayHa = function(t, state) {
+ self.emit('ha', t, state);
+
+ if (t === 'start') {
+ self.emit('ha_connect', t, state);
+ } else if (t === 'end') {
+ self.emit('ha_ismaster', t, state);
+ }
+ };
+
+ // Set up serverConfig listeners
+ self.s.coreTopology.on('joined', replsetRelay('joined'));
+ self.s.coreTopology.on('left', relay('left'));
+ self.s.coreTopology.on('ping', relay('ping'));
+ self.s.coreTopology.on('ha', relayHa);
+
+ // Set up SDAM listeners
+ self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
+ self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
+ self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
+ self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
+ self.s.coreTopology.on('serverOpening', relay('serverOpening'));
+ self.s.coreTopology.on('serverClosed', relay('serverClosed'));
+ self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
+ self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
+ self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
+ self.s.coreTopology.on('commandStarted', relay('commandStarted'));
+ self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
+ self.s.coreTopology.on('commandFailed', relay('commandFailed'));
+
+ self.s.coreTopology.on('fullsetup', function() {
+ self.emit('fullsetup', self, self);
+ });
+
+ self.s.coreTopology.on('all', function() {
+ self.emit('all', null, self);
+ });
+
+ // Connect handler
+ var connectHandler = function() {
+ // Set up listeners
+ self.s.coreTopology.once('timeout', errorHandler('timeout'));
+ self.s.coreTopology.once('error', errorHandler('error'));
+ self.s.coreTopology.once('close', errorHandler('close'));
+
+ // Emit open event
+ self.emit('open', null, self);
+
+ // Return correctly
+ try {
+ callback(null, self);
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+
+ // Error handler
+ var connectErrorHandler = function() {
+ return function(err) {
+ ['timeout', 'error', 'close'].forEach(function(e) {
+ self.s.coreTopology.removeListener(e, connectErrorHandler);
+ });
+
+ self.s.coreTopology.removeListener('connect', connectErrorHandler);
+ // Destroy the replset
+ self.s.coreTopology.destroy();
+
+ // Try to callback
+ try {
+ callback(err);
+ } catch (err) {
+ if (!self.s.coreTopology.isConnected())
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+ };
+
+ // Set up listeners
+ self.s.coreTopology.once('timeout', connectErrorHandler('timeout'));
+ self.s.coreTopology.once('error', connectErrorHandler('error'));
+ self.s.coreTopology.once('close', connectErrorHandler('close'));
+ self.s.coreTopology.once('connect', connectHandler);
+
+ // Start connection
+ self.s.coreTopology.connect(_options);
+ }
+
+ close(forceClosed, callback) {
+ ['timeout', 'error', 'close', 'joined', 'left'].forEach(e => this.removeAllListeners(e));
+ super.close(forceClosed, callback);
+ }
+}
+
+Object.defineProperty(ReplSet.prototype, 'haInterval', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.s.haInterval;
+ }
+});
+
+/**
+ * A replset connect event, used to verify that the connection is up and running
+ *
+ * @event ReplSet#connect
+ * @type {ReplSet}
+ */
+
+/**
+ * The replset high availability event
+ *
+ * @event ReplSet#ha
+ * @type {function}
+ * @param {string} type The stage in the high availability event (start|end)
+ * @param {boolean} data.norepeat This is a repeating high availability process or a single execution only
+ * @param {number} data.id The id for this high availability request
+ * @param {object} data.state An object containing the information about the current replicaset
+ */
+
+/**
+ * A server member left the replicaset
+ *
+ * @event ReplSet#left
+ * @type {function}
+ * @param {string} type The type of member that left (primary|secondary|arbiter)
+ * @param {Server} server The server object that left
+ */
+
+/**
+ * A server member joined the replicaset
+ *
+ * @event ReplSet#joined
+ * @type {function}
+ * @param {string} type The type of member that joined (primary|secondary|arbiter)
+ * @param {Server} server The server object that joined
+ */
+
+/**
+ * ReplSet open event, emitted when replicaset can start processing commands.
+ *
+ * @event ReplSet#open
+ * @type {Replset}
+ */
+
+/**
+ * ReplSet fullsetup event, emitted when all servers in the topology have been connected to.
+ *
+ * @event ReplSet#fullsetup
+ * @type {Replset}
+ */
+
+/**
+ * ReplSet close event
+ *
+ * @event ReplSet#close
+ * @type {object}
+ */
+
+/**
+ * ReplSet error event, emitted if there is an error listener.
+ *
+ * @event ReplSet#error
+ * @type {MongoError}
+ */
+
+/**
+ * ReplSet timeout event
+ *
+ * @event ReplSet#timeout
+ * @type {object}
+ */
+
+/**
+ * ReplSet parseError event
+ *
+ * @event ReplSet#parseError
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event ReplSet#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event ReplSet#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event ReplSet#commandFailed
+ * @type {object}
+ */
+
+module.exports = ReplSet;
diff --git a/node_modules/mongodb/lib/topologies/server.js b/node_modules/mongodb/lib/topologies/server.js
new file mode 100644
index 0000000..3079cb9
--- /dev/null
+++ b/node_modules/mongodb/lib/topologies/server.js
@@ -0,0 +1,448 @@
+'use strict';
+
+const CServer = require('../core').Server;
+const Cursor = require('../cursor');
+const TopologyBase = require('./topology_base').TopologyBase;
+const Store = require('./topology_base').Store;
+const MongoError = require('../core').MongoError;
+const MAX_JS_INT = require('../utils').MAX_JS_INT;
+const translateOptions = require('../utils').translateOptions;
+const filterOptions = require('../utils').filterOptions;
+const mergeOptions = require('../utils').mergeOptions;
+
+/**
+ * @fileOverview The **Server** class is a class that represents a single server topology and is
+ * used to construct connections.
+ *
+ * **Server Should not be used, use MongoClient.connect**
+ */
+
+// Allowed parameters
+var legalOptionNames = [
+ 'ha',
+ 'haInterval',
+ 'acceptableLatencyMS',
+ 'poolSize',
+ 'ssl',
+ 'checkServerIdentity',
+ 'sslValidate',
+ 'sslCA',
+ 'sslCRL',
+ 'sslCert',
+ 'ciphers',
+ 'ecdhCurve',
+ 'sslKey',
+ 'sslPass',
+ 'socketOptions',
+ 'bufferMaxEntries',
+ 'store',
+ 'auto_reconnect',
+ 'autoReconnect',
+ 'emitError',
+ 'keepAlive',
+ 'keepAliveInitialDelay',
+ 'noDelay',
+ 'connectTimeoutMS',
+ 'socketTimeoutMS',
+ 'family',
+ 'loggerLevel',
+ 'logger',
+ 'reconnectTries',
+ 'reconnectInterval',
+ 'monitoring',
+ 'appname',
+ 'domainsEnabled',
+ 'servername',
+ 'promoteLongs',
+ 'promoteValues',
+ 'promoteBuffers',
+ 'compression',
+ 'promiseLibrary',
+ 'monitorCommands'
+];
+
+/**
+ * Creates a new Server instance
+ * @class
+ * @deprecated
+ * @param {string} host The host for the server, can be either an IP4, IP6 or domain socket style host.
+ * @param {number} [port] The server port if IP4.
+ * @param {object} [options] Optional settings.
+ * @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
+ * @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
+ * @param {array} [options.sslCA] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {array} [options.sslCRL] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslCert] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {string} [options.ciphers] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {string} [options.ecdhCurve] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
+ * @param {(Buffer|string)} [options.sslKey] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {(Buffer|string)} [options.sslPass] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
+ * @param {string} [options.servername] String containing the server name requested via TLS SNI.
+ * @param {object} [options.socketOptions] Socket options
+ * @param {boolean} [options.socketOptions.autoReconnect=true] Reconnect on error.
+ * @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
+ * @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
+ * @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
+ * @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
+ * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
+ * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
+ * @param {boolean} [options.monitoring=true] Triggers the server instance to call ismaster
+ * @param {number} [options.haInterval=10000] The interval of calling ismaster when monitoring is enabled.
+ * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
+ * @fires Server#connect
+ * @fires Server#close
+ * @fires Server#error
+ * @fires Server#timeout
+ * @fires Server#parseError
+ * @fires Server#reconnect
+ * @fires Server#commandStarted
+ * @fires Server#commandSucceeded
+ * @fires Server#commandFailed
+ * @property {string} parserType the parser type used (c++ or js).
+ * @return {Server} a Server instance.
+ */
+class Server extends TopologyBase {
+ constructor(host, port, options) {
+ super();
+ var self = this;
+
+ // Filter the options
+ options = filterOptions(options, legalOptionNames);
+
+ // Promise library
+ const promiseLibrary = options.promiseLibrary;
+
+ // Stored options
+ var storeOptions = {
+ force: false,
+ bufferMaxEntries:
+ typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
+ };
+
+ // Shared global store
+ var store = options.store || new Store(self, storeOptions);
+
+ // Detect if we have a socket connection
+ if (host.indexOf('/') !== -1) {
+ if (port != null && typeof port === 'object') {
+ options = port;
+ port = null;
+ }
+ } else if (port == null) {
+ throw MongoError.create({ message: 'port must be specified', driver: true });
+ }
+
+ // Get the reconnect option
+ var reconnect = typeof options.auto_reconnect === 'boolean' ? options.auto_reconnect : true;
+ reconnect = typeof options.autoReconnect === 'boolean' ? options.autoReconnect : reconnect;
+
+ // Clone options
+ var clonedOptions = mergeOptions(
+ {},
+ {
+ host: host,
+ port: port,
+ disconnectHandler: store,
+ cursorFactory: Cursor,
+ reconnect: reconnect,
+ emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
+ size: typeof options.poolSize === 'number' ? options.poolSize : 5,
+ monitorCommands:
+ typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
+ }
+ );
+
+ // Translate any SSL options and other connectivity options
+ clonedOptions = translateOptions(clonedOptions, options);
+
+ // Socket options
+ var socketOptions =
+ options.socketOptions && Object.keys(options.socketOptions).length > 0
+ ? options.socketOptions
+ : options;
+
+ // Translate all the options to the core types
+ clonedOptions = translateOptions(clonedOptions, socketOptions);
+
+ // Define the internal properties
+ this.s = {
+ // Create an instance of a server instance from core module
+ coreTopology: new CServer(clonedOptions),
+ // Server capabilities
+ sCapabilities: null,
+ // Cloned options
+ clonedOptions: clonedOptions,
+ // Reconnect
+ reconnect: clonedOptions.reconnect,
+ // Emit error
+ emitError: clonedOptions.emitError,
+ // Pool size
+ poolSize: clonedOptions.size,
+ // Store Options
+ storeOptions: storeOptions,
+ // Store
+ store: store,
+ // Host
+ host: host,
+ // Port
+ port: port,
+ // Options
+ options: options,
+ // Server Session Pool
+ sessionPool: null,
+ // Active client sessions
+ sessions: new Set(),
+ // Promise library
+ promiseLibrary: promiseLibrary || Promise
+ };
+ }
+
+ // Connect
+ connect(_options, callback) {
+ var self = this;
+ if ('function' === typeof _options) (callback = _options), (_options = {});
+ if (_options == null) _options = this.s.clonedOptions;
+ if (!('function' === typeof callback)) callback = null;
+ _options = Object.assign({}, this.s.clonedOptions, _options);
+ self.s.options = _options;
+
+ // Update bufferMaxEntries
+ self.s.storeOptions.bufferMaxEntries =
+ typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
+
+ // Error handler
+ var connectErrorHandler = function() {
+ return function(err) {
+ // Remove all event handlers
+ var events = ['timeout', 'error', 'close'];
+ events.forEach(function(e) {
+ self.s.coreTopology.removeListener(e, connectHandlers[e]);
+ });
+
+ self.s.coreTopology.removeListener('connect', connectErrorHandler);
+
+ // Try to callback
+ try {
+ callback(err);
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+ };
+
+ // Actual handler
+ var errorHandler = function(event) {
+ return function(err) {
+ if (event !== 'error') {
+ self.emit(event, err);
+ }
+ };
+ };
+
+ // Error handler
+ var reconnectHandler = function() {
+ self.emit('reconnect', self);
+ self.s.store.execute();
+ };
+
+ // Reconnect failed
+ var reconnectFailedHandler = function(err) {
+ self.emit('reconnectFailed', err);
+ self.s.store.flush(err);
+ };
+
+ // Destroy called on topology, perform cleanup
+ var destroyHandler = function() {
+ self.s.store.flush();
+ };
+
+ // relay the event
+ var relay = function(event) {
+ return function(t, server) {
+ self.emit(event, t, server);
+ };
+ };
+
+ // Connect handler
+ var connectHandler = function() {
+ // Clear out all the current handlers left over
+ ['timeout', 'error', 'close', 'destroy'].forEach(function(e) {
+ self.s.coreTopology.removeAllListeners(e);
+ });
+
+ // Set up listeners
+ self.s.coreTopology.on('timeout', errorHandler('timeout'));
+ self.s.coreTopology.once('error', errorHandler('error'));
+ self.s.coreTopology.on('close', errorHandler('close'));
+ // Only called on destroy
+ self.s.coreTopology.on('destroy', destroyHandler);
+
+ // Emit open event
+ self.emit('open', null, self);
+
+ // Return correctly
+ try {
+ callback(null, self);
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+
+ // Set up listeners
+ var connectHandlers = {
+ timeout: connectErrorHandler('timeout'),
+ error: connectErrorHandler('error'),
+ close: connectErrorHandler('close')
+ };
+
+ // Clear out all the current handlers left over
+ [
+ 'timeout',
+ 'error',
+ 'close',
+ 'serverOpening',
+ 'serverDescriptionChanged',
+ 'serverHeartbeatStarted',
+ 'serverHeartbeatSucceeded',
+ 'serverHeartbeatFailed',
+ 'serverClosed',
+ 'topologyOpening',
+ 'topologyClosed',
+ 'topologyDescriptionChanged',
+ 'commandStarted',
+ 'commandSucceeded',
+ 'commandFailed'
+ ].forEach(function(e) {
+ self.s.coreTopology.removeAllListeners(e);
+ });
+
+ // Add the event handlers
+ self.s.coreTopology.once('timeout', connectHandlers.timeout);
+ self.s.coreTopology.once('error', connectHandlers.error);
+ self.s.coreTopology.once('close', connectHandlers.close);
+ self.s.coreTopology.once('connect', connectHandler);
+ // Reconnect server
+ self.s.coreTopology.on('reconnect', reconnectHandler);
+ self.s.coreTopology.on('reconnectFailed', reconnectFailedHandler);
+
+ // Set up SDAM listeners
+ self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
+ self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
+ self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
+ self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
+ self.s.coreTopology.on('serverOpening', relay('serverOpening'));
+ self.s.coreTopology.on('serverClosed', relay('serverClosed'));
+ self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
+ self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
+ self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
+ self.s.coreTopology.on('commandStarted', relay('commandStarted'));
+ self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
+ self.s.coreTopology.on('commandFailed', relay('commandFailed'));
+ self.s.coreTopology.on('attemptReconnect', relay('attemptReconnect'));
+ self.s.coreTopology.on('monitoring', relay('monitoring'));
+
+ // Start connection
+ self.s.coreTopology.connect(_options);
+ }
+}
+
+Object.defineProperty(Server.prototype, 'poolSize', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.connections().length;
+ }
+});
+
+Object.defineProperty(Server.prototype, 'autoReconnect', {
+ enumerable: true,
+ get: function() {
+ return this.s.reconnect;
+ }
+});
+
+Object.defineProperty(Server.prototype, 'host', {
+ enumerable: true,
+ get: function() {
+ return this.s.host;
+ }
+});
+
+Object.defineProperty(Server.prototype, 'port', {
+ enumerable: true,
+ get: function() {
+ return this.s.port;
+ }
+});
+
+/**
+ * Server connect event
+ *
+ * @event Server#connect
+ * @type {object}
+ */
+
+/**
+ * Server close event
+ *
+ * @event Server#close
+ * @type {object}
+ */
+
+/**
+ * Server reconnect event
+ *
+ * @event Server#reconnect
+ * @type {object}
+ */
+
+/**
+ * Server error event
+ *
+ * @event Server#error
+ * @type {MongoError}
+ */
+
+/**
+ * Server timeout event
+ *
+ * @event Server#timeout
+ * @type {object}
+ */
+
+/**
+ * Server parseError event
+ *
+ * @event Server#parseError
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command was started, if command monitoring is enabled
+ *
+ * @event Server#commandStarted
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command succeeded, if command monitoring is enabled
+ *
+ * @event Server#commandSucceeded
+ * @type {object}
+ */
+
+/**
+ * An event emitted indicating a command failed, if command monitoring is enabled
+ *
+ * @event Server#commandFailed
+ * @type {object}
+ */
+
+module.exports = Server;
diff --git a/node_modules/mongodb/lib/topologies/topology_base.js b/node_modules/mongodb/lib/topologies/topology_base.js
new file mode 100644
index 0000000..967b4cd
--- /dev/null
+++ b/node_modules/mongodb/lib/topologies/topology_base.js
@@ -0,0 +1,417 @@
+'use strict';
+
+const EventEmitter = require('events'),
+ MongoError = require('../core').MongoError,
+ f = require('util').format,
+ translateReadPreference = require('../utils').translateReadPreference,
+ ClientSession = require('../core').Sessions.ClientSession;
+
+// The store of ops
+var Store = function(topology, storeOptions) {
+ var self = this;
+ var storedOps = [];
+ storeOptions = storeOptions || { force: false, bufferMaxEntries: -1 };
+
+ // Internal state
+ this.s = {
+ storedOps: storedOps,
+ storeOptions: storeOptions,
+ topology: topology
+ };
+
+ Object.defineProperty(this, 'length', {
+ enumerable: true,
+ get: function() {
+ return self.s.storedOps.length;
+ }
+ });
+};
+
+Store.prototype.add = function(opType, ns, ops, options, callback) {
+ if (this.s.storeOptions.force) {
+ return callback(MongoError.create({ message: 'db closed by application', driver: true }));
+ }
+
+ if (this.s.storeOptions.bufferMaxEntries === 0) {
+ return callback(
+ MongoError.create({
+ message: f(
+ 'no connection available for operation and number of stored operation > %s',
+ this.s.storeOptions.bufferMaxEntries
+ ),
+ driver: true
+ })
+ );
+ }
+
+ if (
+ this.s.storeOptions.bufferMaxEntries > 0 &&
+ this.s.storedOps.length > this.s.storeOptions.bufferMaxEntries
+ ) {
+ while (this.s.storedOps.length > 0) {
+ var op = this.s.storedOps.shift();
+ op.c(
+ MongoError.create({
+ message: f(
+ 'no connection available for operation and number of stored operation > %s',
+ this.s.storeOptions.bufferMaxEntries
+ ),
+ driver: true
+ })
+ );
+ }
+
+ return;
+ }
+
+ this.s.storedOps.push({ t: opType, n: ns, o: ops, op: options, c: callback });
+};
+
+Store.prototype.addObjectAndMethod = function(opType, object, method, params, callback) {
+ if (this.s.storeOptions.force) {
+ return callback(MongoError.create({ message: 'db closed by application', driver: true }));
+ }
+
+ if (this.s.storeOptions.bufferMaxEntries === 0) {
+ return callback(
+ MongoError.create({
+ message: f(
+ 'no connection available for operation and number of stored operation > %s',
+ this.s.storeOptions.bufferMaxEntries
+ ),
+ driver: true
+ })
+ );
+ }
+
+ if (
+ this.s.storeOptions.bufferMaxEntries > 0 &&
+ this.s.storedOps.length > this.s.storeOptions.bufferMaxEntries
+ ) {
+ while (this.s.storedOps.length > 0) {
+ var op = this.s.storedOps.shift();
+ op.c(
+ MongoError.create({
+ message: f(
+ 'no connection available for operation and number of stored operation > %s',
+ this.s.storeOptions.bufferMaxEntries
+ ),
+ driver: true
+ })
+ );
+ }
+
+ return;
+ }
+
+ this.s.storedOps.push({ t: opType, m: method, o: object, p: params, c: callback });
+};
+
+Store.prototype.flush = function(err) {
+ while (this.s.storedOps.length > 0) {
+ this.s.storedOps
+ .shift()
+ .c(
+ err ||
+ MongoError.create({ message: f('no connection available for operation'), driver: true })
+ );
+ }
+};
+
+var primaryOptions = ['primary', 'primaryPreferred', 'nearest', 'secondaryPreferred'];
+var secondaryOptions = ['secondary', 'secondaryPreferred'];
+
+Store.prototype.execute = function(options) {
+ options = options || {};
+ // Get current ops
+ var ops = this.s.storedOps;
+ // Reset the ops
+ this.s.storedOps = [];
+
+ // Unpack options
+ var executePrimary = typeof options.executePrimary === 'boolean' ? options.executePrimary : true;
+ var executeSecondary =
+ typeof options.executeSecondary === 'boolean' ? options.executeSecondary : true;
+
+ // Execute all the stored ops
+ while (ops.length > 0) {
+ var op = ops.shift();
+
+ if (op.t === 'cursor') {
+ if (executePrimary && executeSecondary) {
+ op.o[op.m].apply(op.o, op.p);
+ } else if (
+ executePrimary &&
+ op.o.options &&
+ op.o.options.readPreference &&
+ primaryOptions.indexOf(op.o.options.readPreference.mode) !== -1
+ ) {
+ op.o[op.m].apply(op.o, op.p);
+ } else if (
+ !executePrimary &&
+ executeSecondary &&
+ op.o.options &&
+ op.o.options.readPreference &&
+ secondaryOptions.indexOf(op.o.options.readPreference.mode) !== -1
+ ) {
+ op.o[op.m].apply(op.o, op.p);
+ }
+ } else if (op.t === 'auth') {
+ this.s.topology[op.t].apply(this.s.topology, op.o);
+ } else {
+ if (executePrimary && executeSecondary) {
+ this.s.topology[op.t](op.n, op.o, op.op, op.c);
+ } else if (
+ executePrimary &&
+ op.op &&
+ op.op.readPreference &&
+ primaryOptions.indexOf(op.op.readPreference.mode) !== -1
+ ) {
+ this.s.topology[op.t](op.n, op.o, op.op, op.c);
+ } else if (
+ !executePrimary &&
+ executeSecondary &&
+ op.op &&
+ op.op.readPreference &&
+ secondaryOptions.indexOf(op.op.readPreference.mode) !== -1
+ ) {
+ this.s.topology[op.t](op.n, op.o, op.op, op.c);
+ }
+ }
+ }
+};
+
+Store.prototype.all = function() {
+ return this.s.storedOps;
+};
+
+// Server capabilities
+var ServerCapabilities = function(ismaster) {
+ var setup_get_property = function(object, name, value) {
+ Object.defineProperty(object, name, {
+ enumerable: true,
+ get: function() {
+ return value;
+ }
+ });
+ };
+
+ // Capabilities
+ var aggregationCursor = false;
+ var writeCommands = false;
+ var textSearch = false;
+ var authCommands = false;
+ var listCollections = false;
+ var listIndexes = false;
+ var maxNumberOfDocsInBatch = ismaster.maxWriteBatchSize || 1000;
+ var commandsTakeWriteConcern = false;
+ var commandsTakeCollation = false;
+
+ if (ismaster.minWireVersion >= 0) {
+ textSearch = true;
+ }
+
+ if (ismaster.maxWireVersion >= 1) {
+ aggregationCursor = true;
+ authCommands = true;
+ }
+
+ if (ismaster.maxWireVersion >= 2) {
+ writeCommands = true;
+ }
+
+ if (ismaster.maxWireVersion >= 3) {
+ listCollections = true;
+ listIndexes = true;
+ }
+
+ if (ismaster.maxWireVersion >= 5) {
+ commandsTakeWriteConcern = true;
+ commandsTakeCollation = true;
+ }
+
+ // If no min or max wire version set to 0
+ if (ismaster.minWireVersion == null) {
+ ismaster.minWireVersion = 0;
+ }
+
+ if (ismaster.maxWireVersion == null) {
+ ismaster.maxWireVersion = 0;
+ }
+
+ // Map up read only parameters
+ setup_get_property(this, 'hasAggregationCursor', aggregationCursor);
+ setup_get_property(this, 'hasWriteCommands', writeCommands);
+ setup_get_property(this, 'hasTextSearch', textSearch);
+ setup_get_property(this, 'hasAuthCommands', authCommands);
+ setup_get_property(this, 'hasListCollectionsCommand', listCollections);
+ setup_get_property(this, 'hasListIndexesCommand', listIndexes);
+ setup_get_property(this, 'minWireVersion', ismaster.minWireVersion);
+ setup_get_property(this, 'maxWireVersion', ismaster.maxWireVersion);
+ setup_get_property(this, 'maxNumberOfDocsInBatch', maxNumberOfDocsInBatch);
+ setup_get_property(this, 'commandsTakeWriteConcern', commandsTakeWriteConcern);
+ setup_get_property(this, 'commandsTakeCollation', commandsTakeCollation);
+};
+
+class TopologyBase extends EventEmitter {
+ constructor() {
+ super();
+ this.setMaxListeners(Infinity);
+ }
+
+ // Sessions related methods
+ hasSessionSupport() {
+ return this.logicalSessionTimeoutMinutes != null;
+ }
+
+ startSession(options, clientOptions) {
+ const session = new ClientSession(this, this.s.sessionPool, options, clientOptions);
+
+ session.once('ended', () => {
+ this.s.sessions.delete(session);
+ });
+
+ this.s.sessions.add(session);
+ return session;
+ }
+
+ endSessions(sessions, callback) {
+ return this.s.coreTopology.endSessions(sessions, callback);
+ }
+
+ get clientMetadata() {
+ return this.s.coreTopology.s.options.metadata;
+ }
+
+ // Server capabilities
+ capabilities() {
+ if (this.s.sCapabilities) return this.s.sCapabilities;
+ if (this.s.coreTopology.lastIsMaster() == null) return null;
+ this.s.sCapabilities = new ServerCapabilities(this.s.coreTopology.lastIsMaster());
+ return this.s.sCapabilities;
+ }
+
+ // Command
+ command(ns, cmd, options, callback) {
+ this.s.coreTopology.command(ns.toString(), cmd, translateReadPreference(options), callback);
+ }
+
+ // Insert
+ insert(ns, ops, options, callback) {
+ this.s.coreTopology.insert(ns.toString(), ops, options, callback);
+ }
+
+ // Update
+ update(ns, ops, options, callback) {
+ this.s.coreTopology.update(ns.toString(), ops, options, callback);
+ }
+
+ // Remove
+ remove(ns, ops, options, callback) {
+ this.s.coreTopology.remove(ns.toString(), ops, options, callback);
+ }
+
+ // IsConnected
+ isConnected(options) {
+ options = options || {};
+ options = translateReadPreference(options);
+
+ return this.s.coreTopology.isConnected(options);
+ }
+
+ // IsDestroyed
+ isDestroyed() {
+ return this.s.coreTopology.isDestroyed();
+ }
+
+ // Cursor
+ cursor(ns, cmd, options) {
+ options = options || {};
+ options = translateReadPreference(options);
+ options.disconnectHandler = this.s.store;
+ options.topology = this;
+
+ return this.s.coreTopology.cursor(ns, cmd, options);
+ }
+
+ lastIsMaster() {
+ return this.s.coreTopology.lastIsMaster();
+ }
+
+ selectServer(selector, options, callback) {
+ return this.s.coreTopology.selectServer(selector, options, callback);
+ }
+
+ /**
+ * Unref all sockets
+ * @method
+ */
+ unref() {
+ return this.s.coreTopology.unref();
+ }
+
+ /**
+ * All raw connections
+ * @method
+ * @return {array}
+ */
+ connections() {
+ return this.s.coreTopology.connections();
+ }
+
+ close(forceClosed, callback) {
+ // If we have sessions, we want to individually move them to the session pool,
+ // and then send a single endSessions call.
+ this.s.sessions.forEach(session => session.endSession());
+
+ if (this.s.sessionPool) {
+ this.s.sessionPool.endAllPooledSessions();
+ }
+
+ // We need to wash out all stored processes
+ if (forceClosed === true) {
+ this.s.storeOptions.force = forceClosed;
+ this.s.store.flush();
+ }
+
+ this.s.coreTopology.destroy(
+ {
+ force: typeof forceClosed === 'boolean' ? forceClosed : false
+ },
+ callback
+ );
+ }
+}
+
+// Properties
+Object.defineProperty(TopologyBase.prototype, 'bson', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.s.bson;
+ }
+});
+
+Object.defineProperty(TopologyBase.prototype, 'parserType', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.parserType;
+ }
+});
+
+Object.defineProperty(TopologyBase.prototype, 'logicalSessionTimeoutMinutes', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.logicalSessionTimeoutMinutes;
+ }
+});
+
+Object.defineProperty(TopologyBase.prototype, 'type', {
+ enumerable: true,
+ get: function() {
+ return this.s.coreTopology.type;
+ }
+});
+
+exports.Store = Store;
+exports.ServerCapabilities = ServerCapabilities;
+exports.TopologyBase = TopologyBase;
diff --git a/node_modules/mongodb/lib/url_parser.js b/node_modules/mongodb/lib/url_parser.js
new file mode 100644
index 0000000..c0f10b4
--- /dev/null
+++ b/node_modules/mongodb/lib/url_parser.js
@@ -0,0 +1,623 @@
+'use strict';
+
+const ReadPreference = require('./core').ReadPreference,
+ parser = require('url'),
+ f = require('util').format,
+ Logger = require('./core').Logger,
+ dns = require('dns');
+const ReadConcern = require('./read_concern');
+
+module.exports = function(url, options, callback) {
+ if (typeof options === 'function') (callback = options), (options = {});
+ options = options || {};
+
+ let result;
+ try {
+ result = parser.parse(url, true);
+ } catch (e) {
+ return callback(new Error('URL malformed, cannot be parsed'));
+ }
+
+ if (result.protocol !== 'mongodb:' && result.protocol !== 'mongodb+srv:') {
+ return callback(new Error('Invalid schema, expected `mongodb` or `mongodb+srv`'));
+ }
+
+ if (result.protocol === 'mongodb:') {
+ return parseHandler(url, options, callback);
+ }
+
+ // Otherwise parse this as an SRV record
+ if (result.hostname.split('.').length < 3) {
+ return callback(new Error('URI does not have hostname, domain name and tld'));
+ }
+
+ result.domainLength = result.hostname.split('.').length;
+
+ if (result.pathname && result.pathname.match(',')) {
+ return callback(new Error('Invalid URI, cannot contain multiple hostnames'));
+ }
+
+ if (result.port) {
+ return callback(new Error('Ports not accepted with `mongodb+srv` URIs'));
+ }
+
+ let srvAddress = `_mongodb._tcp.${result.host}`;
+ dns.resolveSrv(srvAddress, function(err, addresses) {
+ if (err) return callback(err);
+
+ if (addresses.length === 0) {
+ return callback(new Error('No addresses found at host'));
+ }
+
+ for (let i = 0; i < addresses.length; i++) {
+ if (!matchesParentDomain(addresses[i].name, result.hostname, result.domainLength)) {
+ return callback(new Error('Server record does not share hostname with parent URI'));
+ }
+ }
+
+ let base = result.auth ? `mongodb://${result.auth}@` : `mongodb://`;
+ let connectionStrings = addresses.map(function(address, i) {
+ if (i === 0) return `${base}${address.name}:${address.port}`;
+ else return `${address.name}:${address.port}`;
+ });
+
+ let connectionString = connectionStrings.join(',') + '/';
+ let connectionStringOptions = [];
+
+ // Add the default database if needed
+ if (result.path) {
+ let defaultDb = result.path.slice(1);
+ if (defaultDb.indexOf('?') !== -1) {
+ defaultDb = defaultDb.slice(0, defaultDb.indexOf('?'));
+ }
+
+ connectionString += defaultDb;
+ }
+
+ // Default to SSL true
+ if (!options.ssl && !result.search) {
+ connectionStringOptions.push('ssl=true');
+ } else if (!options.ssl && result.search && !result.search.match('ssl')) {
+ connectionStringOptions.push('ssl=true');
+ }
+
+ // Keep original uri options
+ if (result.search) {
+ connectionStringOptions.push(result.search.replace('?', ''));
+ }
+
+ dns.resolveTxt(result.host, function(err, record) {
+ if (err && err.code !== 'ENODATA') return callback(err);
+ if (err && err.code === 'ENODATA') record = null;
+
+ if (record) {
+ if (record.length > 1) {
+ return callback(new Error('Multiple text records not allowed'));
+ }
+
+ record = record[0];
+ if (record.length > 1) record = record.join('');
+ else record = record[0];
+
+ if (!record.includes('authSource') && !record.includes('replicaSet')) {
+ return callback(new Error('Text record must only set `authSource` or `replicaSet`'));
+ }
+
+ connectionStringOptions.push(record);
+ }
+
+ // Add any options to the connection string
+ if (connectionStringOptions.length) {
+ connectionString += `?${connectionStringOptions.join('&')}`;
+ }
+
+ parseHandler(connectionString, options, callback);
+ });
+ });
+};
+
+function matchesParentDomain(srvAddress, parentDomain) {
+ let regex = /^.*?\./;
+ let srv = `.${srvAddress.replace(regex, '')}`;
+ let parent = `.${parentDomain.replace(regex, '')}`;
+ if (srv.endsWith(parent)) return true;
+ else return false;
+}
+
+function parseHandler(address, options, callback) {
+ let result, err;
+ try {
+ result = parseConnectionString(address, options);
+ } catch (e) {
+ err = e;
+ }
+
+ return err ? callback(err, null) : callback(null, result);
+}
+
+function parseConnectionString(url, options) {
+ // Variables
+ let connection_part = '';
+ let auth_part = '';
+ let query_string_part = '';
+ let dbName = 'admin';
+
+ // Url parser result
+ let result = parser.parse(url, true);
+ if ((result.hostname == null || result.hostname === '') && url.indexOf('.sock') === -1) {
+ throw new Error('No hostname or hostnames provided in connection string');
+ }
+
+ if (result.port === '0') {
+ throw new Error('Invalid port (zero) with hostname');
+ }
+
+ if (!isNaN(parseInt(result.port, 10)) && parseInt(result.port, 10) > 65535) {
+ throw new Error('Invalid port (larger than 65535) with hostname');
+ }
+
+ if (
+ result.path &&
+ result.path.length > 0 &&
+ result.path[0] !== '/' &&
+ url.indexOf('.sock') === -1
+ ) {
+ throw new Error('Missing delimiting slash between hosts and options');
+ }
+
+ if (result.query) {
+ for (let name in result.query) {
+ if (name.indexOf('::') !== -1) {
+ throw new Error('Double colon in host identifier');
+ }
+
+ if (result.query[name] === '') {
+ throw new Error('Query parameter ' + name + ' is an incomplete value pair');
+ }
+ }
+ }
+
+ if (result.auth) {
+ let parts = result.auth.split(':');
+ if (url.indexOf(result.auth) !== -1 && parts.length > 2) {
+ throw new Error('Username with password containing an unescaped colon');
+ }
+
+ if (url.indexOf(result.auth) !== -1 && result.auth.indexOf('@') !== -1) {
+ throw new Error('Username containing an unescaped at-sign');
+ }
+ }
+
+ // Remove query
+ let clean = url.split('?').shift();
+
+ // Extract the list of hosts
+ let strings = clean.split(',');
+ let hosts = [];
+
+ for (let i = 0; i < strings.length; i++) {
+ let hostString = strings[i];
+
+ if (hostString.indexOf('mongodb') !== -1) {
+ if (hostString.indexOf('@') !== -1) {
+ hosts.push(hostString.split('@').pop());
+ } else {
+ hosts.push(hostString.substr('mongodb://'.length));
+ }
+ } else if (hostString.indexOf('/') !== -1) {
+ hosts.push(hostString.split('/').shift());
+ } else if (hostString.indexOf('/') === -1) {
+ hosts.push(hostString.trim());
+ }
+ }
+
+ for (let i = 0; i < hosts.length; i++) {
+ let r = parser.parse(f('mongodb://%s', hosts[i].trim()));
+ if (r.path && r.path.indexOf('.sock') !== -1) continue;
+ if (r.path && r.path.indexOf(':') !== -1) {
+ // Not connecting to a socket so check for an extra slash in the hostname.
+ // Using String#split as perf is better than match.
+ if (r.path.split('/').length > 1 && r.path.indexOf('::') === -1) {
+ throw new Error('Slash in host identifier');
+ } else {
+ throw new Error('Double colon in host identifier');
+ }
+ }
+ }
+
+ // If we have a ? mark cut the query elements off
+ if (url.indexOf('?') !== -1) {
+ query_string_part = url.substr(url.indexOf('?') + 1);
+ connection_part = url.substring('mongodb://'.length, url.indexOf('?'));
+ } else {
+ connection_part = url.substring('mongodb://'.length);
+ }
+
+ // Check if we have auth params
+ if (connection_part.indexOf('@') !== -1) {
+ auth_part = connection_part.split('@')[0];
+ connection_part = connection_part.split('@')[1];
+ }
+
+ // Check there is not more than one unescaped slash
+ if (connection_part.split('/').length > 2) {
+ throw new Error(
+ "Unsupported host '" +
+ connection_part.split('?')[0] +
+ "', hosts must be URL encoded and contain at most one unencoded slash"
+ );
+ }
+
+ // Check if the connection string has a db
+ if (connection_part.indexOf('.sock') !== -1) {
+ if (connection_part.indexOf('.sock/') !== -1) {
+ dbName = connection_part.split('.sock/')[1];
+ // Check if multiple database names provided, or just an illegal trailing backslash
+ if (dbName.indexOf('/') !== -1) {
+ if (dbName.split('/').length === 2 && dbName.split('/')[1].length === 0) {
+ throw new Error('Illegal trailing backslash after database name');
+ }
+ throw new Error('More than 1 database name in URL');
+ }
+ connection_part = connection_part.split(
+ '/',
+ connection_part.indexOf('.sock') + '.sock'.length
+ );
+ }
+ } else if (connection_part.indexOf('/') !== -1) {
+ // Check if multiple database names provided, or just an illegal trailing backslash
+ if (connection_part.split('/').length > 2) {
+ if (connection_part.split('/')[2].length === 0) {
+ throw new Error('Illegal trailing backslash after database name');
+ }
+ throw new Error('More than 1 database name in URL');
+ }
+ dbName = connection_part.split('/')[1];
+ connection_part = connection_part.split('/')[0];
+ }
+
+ // URI decode the host information
+ connection_part = decodeURIComponent(connection_part);
+
+ // Result object
+ let object = {};
+
+ // Pick apart the authentication part of the string
+ let authPart = auth_part || '';
+ let auth = authPart.split(':', 2);
+
+ // Decode the authentication URI components and verify integrity
+ let user = decodeURIComponent(auth[0]);
+ if (auth[0] !== encodeURIComponent(user)) {
+ throw new Error('Username contains an illegal unescaped character');
+ }
+ auth[0] = user;
+
+ if (auth[1]) {
+ let pass = decodeURIComponent(auth[1]);
+ if (auth[1] !== encodeURIComponent(pass)) {
+ throw new Error('Password contains an illegal unescaped character');
+ }
+ auth[1] = pass;
+ }
+
+ // Add auth to final object if we have 2 elements
+ if (auth.length === 2) object.auth = { user: auth[0], password: auth[1] };
+ // if user provided auth options, use that
+ if (options && options.auth != null) object.auth = options.auth;
+
+ // Variables used for temporary storage
+ let hostPart;
+ let urlOptions;
+ let servers;
+ let compression;
+ let serverOptions = { socketOptions: {} };
+ let dbOptions = { read_preference_tags: [] };
+ let replSetServersOptions = { socketOptions: {} };
+ let mongosOptions = { socketOptions: {} };
+ // Add server options to final object
+ object.server_options = serverOptions;
+ object.db_options = dbOptions;
+ object.rs_options = replSetServersOptions;
+ object.mongos_options = mongosOptions;
+
+ // Let's check if we are using a domain socket
+ if (url.match(/\.sock/)) {
+ // Split out the socket part
+ let domainSocket = url.substring(
+ url.indexOf('mongodb://') + 'mongodb://'.length,
+ url.lastIndexOf('.sock') + '.sock'.length
+ );
+ // Clean out any auth stuff if any
+ if (domainSocket.indexOf('@') !== -1) domainSocket = domainSocket.split('@')[1];
+ domainSocket = decodeURIComponent(domainSocket);
+ servers = [{ domain_socket: domainSocket }];
+ } else {
+ // Split up the db
+ hostPart = connection_part;
+ // Deduplicate servers
+ let deduplicatedServers = {};
+
+ // Parse all server results
+ servers = hostPart
+ .split(',')
+ .map(function(h) {
+ let _host, _port, ipv6match;
+ //check if it matches [IPv6]:port, where the port number is optional
+ if ((ipv6match = /\[([^\]]+)\](?::(.+))?/.exec(h))) {
+ _host = ipv6match[1];
+ _port = parseInt(ipv6match[2], 10) || 27017;
+ } else {
+ //otherwise assume it's IPv4, or plain hostname
+ let hostPort = h.split(':', 2);
+ _host = hostPort[0] || 'localhost';
+ _port = hostPort[1] != null ? parseInt(hostPort[1], 10) : 27017;
+ // Check for localhost?safe=true style case
+ if (_host.indexOf('?') !== -1) _host = _host.split(/\?/)[0];
+ }
+
+ // No entry returned for duplicate server
+ if (deduplicatedServers[_host + '_' + _port]) return null;
+ deduplicatedServers[_host + '_' + _port] = 1;
+
+ // Return the mapped object
+ return { host: _host, port: _port };
+ })
+ .filter(function(x) {
+ return x != null;
+ });
+ }
+
+ // Get the db name
+ object.dbName = dbName || 'admin';
+ // Split up all the options
+ urlOptions = (query_string_part || '').split(/[&;]/);
+ // Ugh, we have to figure out which options go to which constructor manually.
+ urlOptions.forEach(function(opt) {
+ if (!opt) return;
+ var splitOpt = opt.split('='),
+ name = splitOpt[0],
+ value = splitOpt[1];
+
+ // Options implementations
+ switch (name) {
+ case 'slaveOk':
+ case 'slave_ok':
+ serverOptions.slave_ok = value === 'true';
+ dbOptions.slaveOk = value === 'true';
+ break;
+ case 'maxPoolSize':
+ case 'poolSize':
+ serverOptions.poolSize = parseInt(value, 10);
+ replSetServersOptions.poolSize = parseInt(value, 10);
+ break;
+ case 'appname':
+ object.appname = decodeURIComponent(value);
+ break;
+ case 'autoReconnect':
+ case 'auto_reconnect':
+ serverOptions.auto_reconnect = value === 'true';
+ break;
+ case 'ssl':
+ if (value === 'prefer') {
+ serverOptions.ssl = value;
+ replSetServersOptions.ssl = value;
+ mongosOptions.ssl = value;
+ break;
+ }
+ serverOptions.ssl = value === 'true';
+ replSetServersOptions.ssl = value === 'true';
+ mongosOptions.ssl = value === 'true';
+ break;
+ case 'sslValidate':
+ serverOptions.sslValidate = value === 'true';
+ replSetServersOptions.sslValidate = value === 'true';
+ mongosOptions.sslValidate = value === 'true';
+ break;
+ case 'replicaSet':
+ case 'rs_name':
+ replSetServersOptions.rs_name = value;
+ break;
+ case 'reconnectWait':
+ replSetServersOptions.reconnectWait = parseInt(value, 10);
+ break;
+ case 'retries':
+ replSetServersOptions.retries = parseInt(value, 10);
+ break;
+ case 'readSecondary':
+ case 'read_secondary':
+ replSetServersOptions.read_secondary = value === 'true';
+ break;
+ case 'fsync':
+ dbOptions.fsync = value === 'true';
+ break;
+ case 'journal':
+ dbOptions.j = value === 'true';
+ break;
+ case 'safe':
+ dbOptions.safe = value === 'true';
+ break;
+ case 'nativeParser':
+ case 'native_parser':
+ dbOptions.native_parser = value === 'true';
+ break;
+ case 'readConcernLevel':
+ dbOptions.readConcern = new ReadConcern(value);
+ break;
+ case 'connectTimeoutMS':
+ serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
+ replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
+ mongosOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
+ break;
+ case 'socketTimeoutMS':
+ serverOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
+ replSetServersOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
+ mongosOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
+ break;
+ case 'w':
+ dbOptions.w = parseInt(value, 10);
+ if (isNaN(dbOptions.w)) dbOptions.w = value;
+ break;
+ case 'authSource':
+ dbOptions.authSource = value;
+ break;
+ case 'gssapiServiceName':
+ dbOptions.gssapiServiceName = value;
+ break;
+ case 'authMechanism':
+ if (value === 'GSSAPI') {
+ // If no password provided decode only the principal
+ if (object.auth == null) {
+ let urlDecodeAuthPart = decodeURIComponent(authPart);
+ if (urlDecodeAuthPart.indexOf('@') === -1)
+ throw new Error('GSSAPI requires a provided principal');
+ object.auth = { user: urlDecodeAuthPart, password: null };
+ } else {
+ object.auth.user = decodeURIComponent(object.auth.user);
+ }
+ } else if (value === 'MONGODB-X509') {
+ object.auth = { user: decodeURIComponent(authPart) };
+ }
+
+ // Only support GSSAPI or MONGODB-CR for now
+ if (
+ value !== 'GSSAPI' &&
+ value !== 'MONGODB-X509' &&
+ value !== 'MONGODB-CR' &&
+ value !== 'DEFAULT' &&
+ value !== 'SCRAM-SHA-1' &&
+ value !== 'SCRAM-SHA-256' &&
+ value !== 'PLAIN'
+ )
+ throw new Error(
+ 'Only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1 is supported by authMechanism'
+ );
+
+ // Authentication mechanism
+ dbOptions.authMechanism = value;
+ break;
+ case 'authMechanismProperties':
+ {
+ // Split up into key, value pairs
+ let values = value.split(',');
+ let o = {};
+ // For each value split into key, value
+ values.forEach(function(x) {
+ let v = x.split(':');
+ o[v[0]] = v[1];
+ });
+
+ // Set all authMechanismProperties
+ dbOptions.authMechanismProperties = o;
+ // Set the service name value
+ if (typeof o.SERVICE_NAME === 'string') dbOptions.gssapiServiceName = o.SERVICE_NAME;
+ if (typeof o.SERVICE_REALM === 'string') dbOptions.gssapiServiceRealm = o.SERVICE_REALM;
+ if (typeof o.CANONICALIZE_HOST_NAME === 'string')
+ dbOptions.gssapiCanonicalizeHostName =
+ o.CANONICALIZE_HOST_NAME === 'true' ? true : false;
+ }
+ break;
+ case 'wtimeoutMS':
+ dbOptions.wtimeout = parseInt(value, 10);
+ break;
+ case 'readPreference':
+ if (!ReadPreference.isValid(value))
+ throw new Error(
+ 'readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest'
+ );
+ dbOptions.readPreference = value;
+ break;
+ case 'maxStalenessSeconds':
+ dbOptions.maxStalenessSeconds = parseInt(value, 10);
+ break;
+ case 'readPreferenceTags':
+ {
+ // Decode the value
+ value = decodeURIComponent(value);
+ // Contains the tag object
+ let tagObject = {};
+ if (value == null || value === '') {
+ dbOptions.read_preference_tags.push(tagObject);
+ break;
+ }
+
+ // Split up the tags
+ let tags = value.split(/,/);
+ for (let i = 0; i < tags.length; i++) {
+ let parts = tags[i].trim().split(/:/);
+ tagObject[parts[0]] = parts[1];
+ }
+
+ // Set the preferences tags
+ dbOptions.read_preference_tags.push(tagObject);
+ }
+ break;
+ case 'compressors':
+ {
+ compression = serverOptions.compression || {};
+ let compressors = value.split(',');
+ if (
+ !compressors.every(function(compressor) {
+ return compressor === 'snappy' || compressor === 'zlib';
+ })
+ ) {
+ throw new Error('Compressors must be at least one of snappy or zlib');
+ }
+
+ compression.compressors = compressors;
+ serverOptions.compression = compression;
+ }
+ break;
+ case 'zlibCompressionLevel':
+ {
+ compression = serverOptions.compression || {};
+ let zlibCompressionLevel = parseInt(value, 10);
+ if (zlibCompressionLevel < -1 || zlibCompressionLevel > 9) {
+ throw new Error('zlibCompressionLevel must be an integer between -1 and 9');
+ }
+
+ compression.zlibCompressionLevel = zlibCompressionLevel;
+ serverOptions.compression = compression;
+ }
+ break;
+ case 'retryWrites':
+ dbOptions.retryWrites = value === 'true';
+ break;
+ case 'minSize':
+ dbOptions.minSize = parseInt(value, 10);
+ break;
+ default:
+ {
+ let logger = Logger('URL Parser');
+ logger.warn(`${name} is not supported as a connection string option`);
+ }
+ break;
+ }
+ });
+
+ // No tags: should be null (not [])
+ if (dbOptions.read_preference_tags.length === 0) {
+ dbOptions.read_preference_tags = null;
+ }
+
+ // Validate if there are an invalid write concern combinations
+ if (
+ (dbOptions.w === -1 || dbOptions.w === 0) &&
+ (dbOptions.journal === true || dbOptions.fsync === true || dbOptions.safe === true)
+ )
+ throw new Error('w set to -1 or 0 cannot be combined with safe/w/journal/fsync');
+
+ // If no read preference set it to primary
+ if (!dbOptions.readPreference) {
+ dbOptions.readPreference = 'primary';
+ }
+
+ // make sure that user-provided options are applied with priority
+ dbOptions = Object.assign(dbOptions, options);
+
+ // Add servers to result
+ object.servers = servers;
+
+ // Returned parsed object
+ return object;
+}
diff --git a/node_modules/mongodb/lib/utils.js b/node_modules/mongodb/lib/utils.js
new file mode 100644
index 0000000..1eded66
--- /dev/null
+++ b/node_modules/mongodb/lib/utils.js
@@ -0,0 +1,768 @@
+'use strict';
+const MongoError = require('./core/error').MongoError;
+const ReadPreference = require('./core/topologies/read_preference');
+const WriteConcern = require('./write_concern');
+
+var shallowClone = function(obj) {
+ var copy = {};
+ for (var name in obj) copy[name] = obj[name];
+ return copy;
+};
+
+// Figure out the read preference
+var translateReadPreference = function(options) {
+ var r = null;
+ if (options.readPreference) {
+ r = options.readPreference;
+ } else {
+ return options;
+ }
+
+ if (typeof r === 'string') {
+ options.readPreference = new ReadPreference(r);
+ } else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
+ const mode = r.mode || r.preference;
+ if (mode && typeof mode === 'string') {
+ options.readPreference = new ReadPreference(mode, r.tags, {
+ maxStalenessSeconds: r.maxStalenessSeconds
+ });
+ }
+ } else if (!(r instanceof ReadPreference)) {
+ throw new TypeError('Invalid read preference: ' + r);
+ }
+
+ return options;
+};
+
+// Set simple property
+var getSingleProperty = function(obj, name, value) {
+ Object.defineProperty(obj, name, {
+ enumerable: true,
+ get: function() {
+ return value;
+ }
+ });
+};
+
+var formatSortValue = (exports.formatSortValue = function(sortDirection) {
+ var value = ('' + sortDirection).toLowerCase();
+
+ switch (value) {
+ case 'ascending':
+ case 'asc':
+ case '1':
+ return 1;
+ case 'descending':
+ case 'desc':
+ case '-1':
+ return -1;
+ default:
+ throw new Error(
+ 'Illegal sort clause, must be of the form ' +
+ "[['field1', '(ascending|descending)'], " +
+ "['field2', '(ascending|descending)']]"
+ );
+ }
+});
+
+var formattedOrderClause = (exports.formattedOrderClause = function(sortValue) {
+ var orderBy = {};
+ if (sortValue == null) return null;
+ if (Array.isArray(sortValue)) {
+ if (sortValue.length === 0) {
+ return null;
+ }
+
+ for (var i = 0; i < sortValue.length; i++) {
+ if (sortValue[i].constructor === String) {
+ orderBy[sortValue[i]] = 1;
+ } else {
+ orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
+ }
+ }
+ } else if (sortValue != null && typeof sortValue === 'object') {
+ orderBy = sortValue;
+ } else if (typeof sortValue === 'string') {
+ orderBy[sortValue] = 1;
+ } else {
+ throw new Error(
+ 'Illegal sort clause, must be of the form ' +
+ "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
+ );
+ }
+
+ return orderBy;
+});
+
+var checkCollectionName = function checkCollectionName(collectionName) {
+ if ('string' !== typeof collectionName) {
+ throw new MongoError('collection name must be a String');
+ }
+
+ if (!collectionName || collectionName.indexOf('..') !== -1) {
+ throw new MongoError('collection names cannot be empty');
+ }
+
+ if (
+ collectionName.indexOf('$') !== -1 &&
+ collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null
+ ) {
+ throw new MongoError("collection names must not contain '$'");
+ }
+
+ if (collectionName.match(/^\.|\.$/) != null) {
+ throw new MongoError("collection names must not start or end with '.'");
+ }
+
+ // Validate that we are not passing 0x00 in the collection name
+ if (collectionName.indexOf('\x00') !== -1) {
+ throw new MongoError('collection names cannot contain a null character');
+ }
+};
+
+var handleCallback = function(callback, err, value1, value2) {
+ try {
+ if (callback == null) return;
+
+ if (callback) {
+ return value2 ? callback(err, value1, value2) : callback(err, value1);
+ }
+ } catch (err) {
+ process.nextTick(function() {
+ throw err;
+ });
+ return false;
+ }
+
+ return true;
+};
+
+/**
+ * Wrap a Mongo error document in an Error instance
+ * @ignore
+ * @api private
+ */
+var toError = function(error) {
+ if (error instanceof Error) return error;
+
+ var msg = error.err || error.errmsg || error.errMessage || error;
+ var e = MongoError.create({ message: msg, driver: true });
+
+ // Get all object keys
+ var keys = typeof error === 'object' ? Object.keys(error) : [];
+
+ for (var i = 0; i < keys.length; i++) {
+ try {
+ e[keys[i]] = error[keys[i]];
+ } catch (err) {
+ // continue
+ }
+ }
+
+ return e;
+};
+
+/**
+ * @ignore
+ */
+var normalizeHintField = function normalizeHintField(hint) {
+ var finalHint = null;
+
+ if (typeof hint === 'string') {
+ finalHint = hint;
+ } else if (Array.isArray(hint)) {
+ finalHint = {};
+
+ hint.forEach(function(param) {
+ finalHint[param] = 1;
+ });
+ } else if (hint != null && typeof hint === 'object') {
+ finalHint = {};
+ for (var name in hint) {
+ finalHint[name] = hint[name];
+ }
+ }
+
+ return finalHint;
+};
+
+/**
+ * Create index name based on field spec
+ *
+ * @ignore
+ * @api private
+ */
+var parseIndexOptions = function(fieldOrSpec) {
+ var fieldHash = {};
+ var indexes = [];
+ var keys;
+
+ // Get all the fields accordingly
+ if ('string' === typeof fieldOrSpec) {
+ // 'type'
+ indexes.push(fieldOrSpec + '_' + 1);
+ fieldHash[fieldOrSpec] = 1;
+ } else if (Array.isArray(fieldOrSpec)) {
+ fieldOrSpec.forEach(function(f) {
+ if ('string' === typeof f) {
+ // [{location:'2d'}, 'type']
+ indexes.push(f + '_' + 1);
+ fieldHash[f] = 1;
+ } else if (Array.isArray(f)) {
+ // [['location', '2d'],['type', 1]]
+ indexes.push(f[0] + '_' + (f[1] || 1));
+ fieldHash[f[0]] = f[1] || 1;
+ } else if (isObject(f)) {
+ // [{location:'2d'}, {type:1}]
+ keys = Object.keys(f);
+ keys.forEach(function(k) {
+ indexes.push(k + '_' + f[k]);
+ fieldHash[k] = f[k];
+ });
+ } else {
+ // undefined (ignore)
+ }
+ });
+ } else if (isObject(fieldOrSpec)) {
+ // {location:'2d', type:1}
+ keys = Object.keys(fieldOrSpec);
+ keys.forEach(function(key) {
+ indexes.push(key + '_' + fieldOrSpec[key]);
+ fieldHash[key] = fieldOrSpec[key];
+ });
+ }
+
+ return {
+ name: indexes.join('_'),
+ keys: keys,
+ fieldHash: fieldHash
+ };
+};
+
+var isObject = (exports.isObject = function(arg) {
+ return '[object Object]' === Object.prototype.toString.call(arg);
+});
+
+var debugOptions = function(debugFields, options) {
+ var finaloptions = {};
+ debugFields.forEach(function(n) {
+ finaloptions[n] = options[n];
+ });
+
+ return finaloptions;
+};
+
+var decorateCommand = function(command, options, exclude) {
+ for (var name in options) {
+ if (exclude.indexOf(name) === -1) command[name] = options[name];
+ }
+
+ return command;
+};
+
+var mergeOptions = function(target, source) {
+ for (var name in source) {
+ target[name] = source[name];
+ }
+
+ return target;
+};
+
+// Merge options with translation
+var translateOptions = function(target, source) {
+ var translations = {
+ // SSL translation options
+ sslCA: 'ca',
+ sslCRL: 'crl',
+ sslValidate: 'rejectUnauthorized',
+ sslKey: 'key',
+ sslCert: 'cert',
+ sslPass: 'passphrase',
+ // SocketTimeout translation options
+ socketTimeoutMS: 'socketTimeout',
+ connectTimeoutMS: 'connectionTimeout',
+ // Replicaset options
+ replicaSet: 'setName',
+ rs_name: 'setName',
+ secondaryAcceptableLatencyMS: 'acceptableLatency',
+ connectWithNoPrimary: 'secondaryOnlyConnectionAllowed',
+ // Mongos options
+ acceptableLatencyMS: 'localThresholdMS'
+ };
+
+ for (var name in source) {
+ if (translations[name]) {
+ target[translations[name]] = source[name];
+ } else {
+ target[name] = source[name];
+ }
+ }
+
+ return target;
+};
+
+var filterOptions = function(options, names) {
+ var filterOptions = {};
+
+ for (var name in options) {
+ if (names.indexOf(name) !== -1) filterOptions[name] = options[name];
+ }
+
+ // Filtered options
+ return filterOptions;
+};
+
+// Write concern keys
+var writeConcernKeys = ['w', 'j', 'wtimeout', 'fsync'];
+
+// Merge the write concern options
+var mergeOptionsAndWriteConcern = function(targetOptions, sourceOptions, keys, mergeWriteConcern) {
+ // Mix in any allowed options
+ for (var i = 0; i < keys.length; i++) {
+ if (!targetOptions[keys[i]] && sourceOptions[keys[i]] !== undefined) {
+ targetOptions[keys[i]] = sourceOptions[keys[i]];
+ }
+ }
+
+ // No merging of write concern
+ if (!mergeWriteConcern) return targetOptions;
+
+ // Found no write Concern options
+ var found = false;
+ for (i = 0; i < writeConcernKeys.length; i++) {
+ if (targetOptions[writeConcernKeys[i]]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ for (i = 0; i < writeConcernKeys.length; i++) {
+ if (sourceOptions[writeConcernKeys[i]]) {
+ targetOptions[writeConcernKeys[i]] = sourceOptions[writeConcernKeys[i]];
+ }
+ }
+ }
+
+ return targetOptions;
+};
+
+/**
+ * Executes the given operation with provided arguments.
+ *
+ * This method reduces large amounts of duplication in the entire codebase by providing
+ * a single point for determining whether callbacks or promises should be used. Additionally
+ * it allows for a single point of entry to provide features such as implicit sessions, which
+ * are required by the Driver Sessions specification in the event that a ClientSession is
+ * not provided
+ *
+ * @param {object} topology The topology to execute this operation on
+ * @param {function} operation The operation to execute
+ * @param {array} args Arguments to apply the provided operation
+ * @param {object} [options] Options that modify the behavior of the method
+ */
+const executeLegacyOperation = (topology, operation, args, options) => {
+ if (topology == null) {
+ throw new TypeError('This method requires a valid topology instance');
+ }
+
+ if (!Array.isArray(args)) {
+ throw new TypeError('This method requires an array of arguments to apply');
+ }
+
+ options = options || {};
+ const Promise = topology.s.promiseLibrary;
+ let callback = args[args.length - 1];
+
+ // The driver sessions spec mandates that we implicitly create sessions for operations
+ // that are not explicitly provided with a session.
+ let session, opOptions, owner;
+ if (!options.skipSessions && topology.hasSessionSupport()) {
+ opOptions = args[args.length - 2];
+ if (opOptions == null || opOptions.session == null) {
+ owner = Symbol();
+ session = topology.startSession({ owner });
+ const optionsIndex = args.length - 2;
+ args[optionsIndex] = Object.assign({}, args[optionsIndex], { session: session });
+ } else if (opOptions.session && opOptions.session.hasEnded) {
+ throw new MongoError('Use of expired sessions is not permitted');
+ }
+ }
+
+ const makeExecuteCallback = (resolve, reject) =>
+ function executeCallback(err, result) {
+ if (session && session.owner === owner && !options.returnsCursor) {
+ session.endSession(() => {
+ delete opOptions.session;
+ if (err) return reject(err);
+ resolve(result);
+ });
+ } else {
+ if (err) return reject(err);
+ resolve(result);
+ }
+ };
+
+ // Execute using callback
+ if (typeof callback === 'function') {
+ callback = args.pop();
+ const handler = makeExecuteCallback(
+ result => callback(null, result),
+ err => callback(err, null)
+ );
+ args.push(handler);
+
+ try {
+ return operation.apply(null, args);
+ } catch (e) {
+ handler(e);
+ throw e;
+ }
+ }
+
+ // Return a Promise
+ if (args[args.length - 1] != null) {
+ throw new TypeError('final argument to `executeLegacyOperation` must be a callback');
+ }
+
+ return new Promise(function(resolve, reject) {
+ const handler = makeExecuteCallback(resolve, reject);
+ args[args.length - 1] = handler;
+
+ try {
+ return operation.apply(null, args);
+ } catch (e) {
+ handler(e);
+ }
+ });
+};
+
+/**
+ * Applies retryWrites: true to a command if retryWrites is set on the command's database.
+ *
+ * @param {object} target The target command to which we will apply retryWrites.
+ * @param {object} db The database from which we can inherit a retryWrites value.
+ */
+function applyRetryableWrites(target, db) {
+ if (db && db.s.options.retryWrites) {
+ target.retryWrites = true;
+ }
+
+ return target;
+}
+
+/**
+ * Applies a write concern to a command based on well defined inheritance rules, optionally
+ * detecting support for the write concern in the first place.
+ *
+ * @param {Object} target the target command we will be applying the write concern to
+ * @param {Object} sources sources where we can inherit default write concerns from
+ * @param {Object} [options] optional settings passed into a command for write concern overrides
+ * @returns {Object} the (now) decorated target
+ */
+function applyWriteConcern(target, sources, options) {
+ options = options || {};
+ const db = sources.db;
+ const coll = sources.collection;
+
+ if (options.session && options.session.inTransaction()) {
+ // writeConcern is not allowed within a multi-statement transaction
+ if (target.writeConcern) {
+ delete target.writeConcern;
+ }
+
+ return target;
+ }
+
+ const writeConcern = WriteConcern.fromOptions(options);
+ if (writeConcern) {
+ return Object.assign(target, { writeConcern });
+ }
+
+ if (coll && coll.writeConcern) {
+ return Object.assign(target, { writeConcern: Object.assign({}, coll.writeConcern) });
+ }
+
+ if (db && db.writeConcern) {
+ return Object.assign(target, { writeConcern: Object.assign({}, db.writeConcern) });
+ }
+
+ return target;
+}
+
+/**
+ * Resolves a read preference based on well-defined inheritance rules. This method will not only
+ * determine the read preference (if there is one), but will also ensure the returned value is a
+ * properly constructed instance of `ReadPreference`.
+ *
+ * @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
+ * preference, used for determining the inherited read preference.
+ * @param {Object} options The options passed into the method, potentially containing a read preference
+ * @returns {(ReadPreference|null)} The resolved read preference
+ */
+function resolveReadPreference(parent, options) {
+ options = options || {};
+ const session = options.session;
+
+ const inheritedReadPreference = parent.readPreference;
+
+ let readPreference;
+ if (options.readPreference) {
+ readPreference = ReadPreference.fromOptions(options);
+ } else if (session && session.inTransaction() && session.transaction.options.readPreference) {
+ // The transaction’s read preference MUST override all other user configurable read preferences.
+ readPreference = session.transaction.options.readPreference;
+ } else if (inheritedReadPreference != null) {
+ readPreference = inheritedReadPreference;
+ } else {
+ throw new Error('No readPreference was provided or inherited.');
+ }
+
+ return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
+}
+
+/**
+ * Checks if a given value is a Promise
+ *
+ * @param {*} maybePromise
+ * @return true if the provided value is a Promise
+ */
+function isPromiseLike(maybePromise) {
+ return maybePromise && typeof maybePromise.then === 'function';
+}
+
+/**
+ * Applies collation to a given command.
+ *
+ * @param {object} [command] the command on which to apply collation
+ * @param {(Cursor|Collection)} [target] target of command
+ * @param {object} [options] options containing collation settings
+ */
+function decorateWithCollation(command, target, options) {
+ const topology = (target.s && target.s.topology) || target.topology;
+
+ if (!topology) {
+ throw new TypeError('parameter "target" is missing a topology');
+ }
+
+ const capabilities = topology.capabilities();
+ if (options.collation && typeof options.collation === 'object') {
+ if (capabilities && capabilities.commandsTakeCollation) {
+ command.collation = options.collation;
+ } else {
+ throw new MongoError(`Current topology does not support collation`);
+ }
+ }
+}
+
+/**
+ * Applies a read concern to a given command.
+ *
+ * @param {object} command the command on which to apply the read concern
+ * @param {Collection} coll the parent collection of the operation calling this method
+ */
+function decorateWithReadConcern(command, coll, options) {
+ if (options && options.session && options.session.inTransaction()) {
+ return;
+ }
+ let readConcern = Object.assign({}, command.readConcern || {});
+ if (coll.s.readConcern) {
+ Object.assign(readConcern, coll.s.readConcern);
+ }
+
+ if (Object.keys(readConcern).length > 0) {
+ Object.assign(command, { readConcern: readConcern });
+ }
+}
+
+const emitProcessWarning = msg => process.emitWarning(msg, 'DeprecationWarning');
+const emitConsoleWarning = msg => console.error(msg);
+const emitDeprecationWarning = process.emitWarning ? emitProcessWarning : emitConsoleWarning;
+
+/**
+ * Default message handler for generating deprecation warnings.
+ *
+ * @param {string} name function name
+ * @param {string} option option name
+ * @return {string} warning message
+ * @ignore
+ * @api private
+ */
+function defaultMsgHandler(name, option) {
+ return `${name} option [${option}] is deprecated and will be removed in a later version.`;
+}
+
+/**
+ * Deprecates a given function's options.
+ *
+ * @param {object} config configuration for deprecation
+ * @param {string} config.name function name
+ * @param {Array} config.deprecatedOptions options to deprecate
+ * @param {number} config.optionsIndex index of options object in function arguments array
+ * @param {function} [config.msgHandler] optional custom message handler to generate warnings
+ * @param {function} fn the target function of deprecation
+ * @return {function} modified function that warns once per deprecated option, and executes original function
+ * @ignore
+ * @api private
+ */
+function deprecateOptions(config, fn) {
+ if (process.noDeprecation === true) {
+ return fn;
+ }
+
+ const msgHandler = config.msgHandler ? config.msgHandler : defaultMsgHandler;
+
+ const optionsWarned = new Set();
+ function deprecated() {
+ const options = arguments[config.optionsIndex];
+
+ // ensure options is a valid, non-empty object, otherwise short-circuit
+ if (!isObject(options) || Object.keys(options).length === 0) {
+ return fn.apply(this, arguments);
+ }
+
+ config.deprecatedOptions.forEach(deprecatedOption => {
+ if (options.hasOwnProperty(deprecatedOption) && !optionsWarned.has(deprecatedOption)) {
+ optionsWarned.add(deprecatedOption);
+ const msg = msgHandler(config.name, deprecatedOption);
+ emitDeprecationWarning(msg);
+ if (this && this.getLogger) {
+ const logger = this.getLogger();
+ if (logger) {
+ logger.warn(msg);
+ }
+ }
+ }
+ });
+
+ return fn.apply(this, arguments);
+ }
+
+ // These lines copied from https://github.com/nodejs/node/blob/25e5ae41688676a5fd29b2e2e7602168eee4ceb5/lib/internal/util.js#L73-L80
+ // The wrapper will keep the same prototype as fn to maintain prototype chain
+ Object.setPrototypeOf(deprecated, fn);
+ if (fn.prototype) {
+ // Setting this (rather than using Object.setPrototype, as above) ensures
+ // that calling the unwrapped constructor gives an instanceof the wrapped
+ // constructor.
+ deprecated.prototype = fn.prototype;
+ }
+
+ return deprecated;
+}
+
+const SUPPORTS = {};
+// Test asyncIterator support
+try {
+ require('./async/async_iterator');
+ SUPPORTS.ASYNC_ITERATOR = true;
+} catch (e) {
+ SUPPORTS.ASYNC_ITERATOR = false;
+}
+
+class MongoDBNamespace {
+ constructor(db, collection) {
+ this.db = db;
+ this.collection = collection;
+ }
+
+ toString() {
+ return this.collection ? `${this.db}.${this.collection}` : this.db;
+ }
+
+ withCollection(collection) {
+ return new MongoDBNamespace(this.db, collection);
+ }
+
+ static fromString(namespace) {
+ if (!namespace) {
+ throw new Error(`Cannot parse namespace from "${namespace}"`);
+ }
+
+ const index = namespace.indexOf('.');
+ return new MongoDBNamespace(namespace.substring(0, index), namespace.substring(index + 1));
+ }
+}
+
+function* makeCounter(seed) {
+ let count = seed || 0;
+ while (true) {
+ const newCount = count;
+ count += 1;
+ yield newCount;
+ }
+}
+
+/**
+ * Helper function for either accepting a callback, or returning a promise
+ *
+ * @param {Object} parent an instance of parent with promiseLibrary.
+ * @param {object} parent.s an object containing promiseLibrary.
+ * @param {function} parent.s.promiseLibrary an object containing promiseLibrary.
+ * @param {[Function]} callback an optional callback.
+ * @param {Function} fn A function that takes a callback
+ * @returns {Promise|void} Returns nothing if a callback is supplied, else returns a Promise.
+ */
+function maybePromise(parent, callback, fn) {
+ const PromiseLibrary = (parent && parent.s && parent.s.promiseLibrary) || Promise;
+
+ let result;
+ if (typeof callback !== 'function') {
+ result = new PromiseLibrary((resolve, reject) => {
+ callback = (err, res) => {
+ if (err) return reject(err);
+ resolve(res);
+ };
+ });
+ }
+
+ fn(function(err, res) {
+ if (err != null) {
+ try {
+ callback(err);
+ } catch (error) {
+ return process.nextTick(() => {
+ throw error;
+ });
+ }
+ return;
+ }
+
+ callback(err, res);
+ });
+
+ return result;
+}
+
+module.exports = {
+ filterOptions,
+ mergeOptions,
+ translateOptions,
+ shallowClone,
+ getSingleProperty,
+ checkCollectionName,
+ toError,
+ formattedOrderClause,
+ parseIndexOptions,
+ normalizeHintField,
+ handleCallback,
+ decorateCommand,
+ isObject,
+ debugOptions,
+ MAX_JS_INT: Number.MAX_SAFE_INTEGER + 1,
+ mergeOptionsAndWriteConcern,
+ translateReadPreference,
+ executeLegacyOperation,
+ applyRetryableWrites,
+ applyWriteConcern,
+ isPromiseLike,
+ decorateWithCollation,
+ decorateWithReadConcern,
+ deprecateOptions,
+ SUPPORTS,
+ MongoDBNamespace,
+ resolveReadPreference,
+ emitDeprecationWarning,
+ makeCounter,
+ maybePromise
+};
diff --git a/node_modules/mongodb/lib/write_concern.js b/node_modules/mongodb/lib/write_concern.js
new file mode 100644
index 0000000..79b0f09
--- /dev/null
+++ b/node_modules/mongodb/lib/write_concern.js
@@ -0,0 +1,66 @@
+'use strict';
+
+/**
+ * The **WriteConcern** class is a class that represents a MongoDB WriteConcern.
+ * @class
+ * @property {(number|string)} w The write concern
+ * @property {number} wtimeout The write concern timeout
+ * @property {boolean} j The journal write concern
+ * @property {boolean} fsync The file sync write concern
+ * @see https://docs.mongodb.com/manual/reference/write-concern/index.html
+ */
+class WriteConcern {
+ /**
+ * Constructs a WriteConcern from the write concern properties.
+ * @param {(number|string)} [w] The write concern
+ * @param {number} [wtimeout] The write concern timeout
+ * @param {boolean} [j] The journal write concern
+ * @param {boolean} [fsync] The file sync write concern
+ */
+ constructor(w, wtimeout, j, fsync) {
+ if (w != null) {
+ this.w = w;
+ }
+ if (wtimeout != null) {
+ this.wtimeout = wtimeout;
+ }
+ if (j != null) {
+ this.j = j;
+ }
+ if (fsync != null) {
+ this.fsync = fsync;
+ }
+ }
+
+ /**
+ * Construct a WriteConcern given an options object.
+ *
+ * @param {object} options The options object from which to extract the write concern.
+ * @return {WriteConcern}
+ */
+ static fromOptions(options) {
+ if (
+ options == null ||
+ (options.writeConcern == null &&
+ options.w == null &&
+ options.wtimeout == null &&
+ options.j == null &&
+ options.fsync == null)
+ ) {
+ return;
+ }
+
+ if (options.writeConcern) {
+ return new WriteConcern(
+ options.writeConcern.w,
+ options.writeConcern.wtimeout,
+ options.writeConcern.j,
+ options.writeConcern.fsync
+ );
+ }
+
+ return new WriteConcern(options.w, options.wtimeout, options.j, options.fsync);
+ }
+}
+
+module.exports = WriteConcern;
diff --git a/node_modules/mongodb/package.json b/node_modules/mongodb/package.json
new file mode 100644
index 0000000..625e8a3
--- /dev/null
+++ b/node_modules/mongodb/package.json
@@ -0,0 +1,137 @@
+{
+ "_args": [
+ [
+ "mongodb@3.5.5",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "mongodb@3.5.5",
+ "_hasShrinkwrap": false,
+ "_id": "mongodb@3.5.5",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mongodb",
+ "_nodeVersion": "12.10.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mongodb_3.5.5_1583958598032_0.571798636134093"
+ },
+ "_npmUser": {
+ "email": "mbroadst@gmail.com",
+ "name": "mbroadst"
+ },
+ "_npmVersion": "6.10.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mongodb",
+ "raw": "mongodb@3.5.5",
+ "rawSpec": "3.5.5",
+ "scope": null,
+ "spec": "3.5.5",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz",
+ "_shasum": "1334c3e5a384469ac7ef0dea69d59acc829a496a",
+ "_shrinkwrap": null,
+ "_spec": "mongodb@3.5.5",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "bugs": {
+ "url": "https://github.com/mongodb/node-mongodb-native/issues"
+ },
+ "dependencies": {
+ "bl": "^2.2.0",
+ "bson": "^1.1.1",
+ "denque": "^1.4.1",
+ "require_optional": "^1.0.1",
+ "safe-buffer": "^5.1.2",
+ "saslprep": "^1.0.0"
+ },
+ "description": "The official MongoDB driver for Node.js",
+ "devDependencies": {
+ "chai": "^4.1.1",
+ "chai-subset": "^1.6.0",
+ "chalk": "^2.4.2",
+ "co": "4.6.0",
+ "coveralls": "^2.11.6",
+ "eslint": "^4.5.0",
+ "eslint-plugin-prettier": "^2.2.0",
+ "istanbul": "^0.4.5",
+ "jsdoc": "3.5.5",
+ "lodash.camelcase": "^4.3.0",
+ "mocha": "5.2.0",
+ "mocha-sinon": "^2.1.0",
+ "mongodb-extjson": "^2.1.1",
+ "mongodb-mock-server": "^1.0.1",
+ "prettier": "^1.19.1",
+ "semver": "^5.5.0",
+ "sinon": "^4.3.0",
+ "sinon-chai": "^3.2.0",
+ "snappy": "^6.1.2",
+ "standard-version": "^4.4.0",
+ "worker-farm": "^1.5.0",
+ "wtfnode": "^0.8.0",
+ "yargs": "^14.2.0"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 147,
+ "integrity": "sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeaUpGCRA9TVsSAnZWagAAFxoP/RLgiiDog0mhyBPvT6Mv\nn/Xd7OX7pV4P4EHWJxC/L1wHk+DVGn4X80JbOdfnI1xYg3gkmowDxum63K30\n0Fr8QZMiT2KPuSpwSNJNWGUCSz21TTXn4cesuhah/+D7lsL9swf8DTHeM0Ik\nHmrNTJWfCvy8ww+fOpJmmunOH/m87t8Cn8FEJ5hOMDPawLxK3aSmi9PbnUHF\n7/HoWSEEN2lr4YuoWlcSBL/JrT97f2U/MhTW8CPqyyAgrPxTUJ7Ck3jpbDLM\nm+zj4DIz+8ALdPU3XVOWA1i/8RSnkA/RWOVD3TWKQMVW4p//hRvQICp/sKJ+\nyQ1mihO4DFay7klZnRiHvcwT0Qge37VvfrSdB+fa0GAp5qb5k8HYrBltF3pq\nyNdcf8iYVAgEToBKn1JqiEi9C0ERCDdaoD3OYgtmeHw0rJdvX1CKwfyT3h5l\nOFvIqtYTR8jlv6J/9j4kAQuCgOS5ays//Rc/5k5dWiYQgLVy12pbVSB3kzCv\nneExTR+Ah8HxaqXxqFiTljLiDrDhANE+QXqAB36LGJkePo1+KZ9BCwJAk05F\nl+049mVUfeddXfxqJZ4Cnf5FXHcpMnEvec02/cnygmVm9VeVvmihqfA3+OSe\ndHMEsyLTVd/x1AiMD+6Pu2ScRIp7DC1SGdpH7p85xB3DwwcvNvx71vUvhYed\nlcrM\r\n=0Ef1\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "1334c3e5a384469ac7ef0dea69d59acc829a496a",
+ "tarball": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz",
+ "unpackedSize": 1458164
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "gitHead": "d7ac1761bc02ec27d56ffe8bd2fb12a9f5468219",
+ "homepage": "https://github.com/mongodb/node-mongodb-native",
+ "keywords": [
+ "driver",
+ "mongodb",
+ "official"
+ ],
+ "license": "Apache-2.0",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "daprahamian",
+ "email": "dan.aprahamian@gmail.com"
+ },
+ {
+ "name": "mbroadst",
+ "email": "mbroadst@gmail.com"
+ }
+ ],
+ "name": "mongodb",
+ "optionalDependencies": {
+ "saslprep": "^1.0.0"
+ },
+ "peerOptionalDependencies": {
+ "bson-ext": "^2.0.0",
+ "kerberos": "^1.1.0",
+ "mongodb-client-encryption": "^1.0.0",
+ "mongodb-extjson": "^2.1.2",
+ "snappy": "^6.1.1"
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/mongodb/node-mongodb-native.git"
+ },
+ "scripts": {
+ "atlas": "node ./test/tools/atlas_connectivity_tests.js",
+ "bench": "node test/benchmarks/driverBench/",
+ "coverage": "istanbul cover mongodb-test-runner -- -t 60000 test/core test/unit test/functional",
+ "format": "prettier --print-width 100 --tab-width 2 --single-quote --write 'test/**/*.js' 'lib/**/*.js'",
+ "generate-evergreen": "node .evergreen/generate_evergreen_tasks.js",
+ "lint": "eslint lib test",
+ "release": "standard-version -i HISTORY.md",
+ "test": "npm run lint && mocha --recursive test/functional test/unit test/core",
+ "test-nolint": "mocha --recursive test/functional test/unit test/core"
+ },
+ "version": "3.5.5"
+}
diff --git a/node_modules/mongoose-legacy-pluralize/LICENSE b/node_modules/mongoose-legacy-pluralize/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/node_modules/mongoose-legacy-pluralize/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/node_modules/mongoose-legacy-pluralize/README.md b/node_modules/mongoose-legacy-pluralize/README.md
new file mode 100644
index 0000000..3296efb
--- /dev/null
+++ b/node_modules/mongoose-legacy-pluralize/README.md
@@ -0,0 +1,2 @@
+# mongoose-legacy-pluralize
+Legacy pluralization logic for mongoose
diff --git a/node_modules/mongoose-legacy-pluralize/index.js b/node_modules/mongoose-legacy-pluralize/index.js
new file mode 100644
index 0000000..1dd451d
--- /dev/null
+++ b/node_modules/mongoose-legacy-pluralize/index.js
@@ -0,0 +1,95 @@
+module.exports = pluralize;
+
+/**
+ * Pluralization rules.
+ *
+ * These rules are applied while processing the argument to `toCollectionName`.
+ *
+ * @deprecated remove in 4.x gh-1350
+ */
+
+exports.pluralization = [
+ [/(m)an$/gi, '$1en'],
+ [/(pe)rson$/gi, '$1ople'],
+ [/(child)$/gi, '$1ren'],
+ [/^(ox)$/gi, '$1en'],
+ [/(ax|test)is$/gi, '$1es'],
+ [/(octop|vir)us$/gi, '$1i'],
+ [/(alias|status)$/gi, '$1es'],
+ [/(bu)s$/gi, '$1ses'],
+ [/(buffal|tomat|potat)o$/gi, '$1oes'],
+ [/([ti])um$/gi, '$1a'],
+ [/sis$/gi, 'ses'],
+ [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'],
+ [/(hive)$/gi, '$1s'],
+ [/([^aeiouy]|qu)y$/gi, '$1ies'],
+ [/(x|ch|ss|sh)$/gi, '$1es'],
+ [/(matr|vert|ind)ix|ex$/gi, '$1ices'],
+ [/([m|l])ouse$/gi, '$1ice'],
+ [/(kn|w|l)ife$/gi, '$1ives'],
+ [/(quiz)$/gi, '$1zes'],
+ [/s$/gi, 's'],
+ [/([^a-z])$/, '$1'],
+ [/$/gi, 's']
+];
+var rules = exports.pluralization;
+
+/**
+ * Uncountable words.
+ *
+ * These words are applied while processing the argument to `toCollectionName`.
+ * @api public
+ */
+
+exports.uncountables = [
+ 'advice',
+ 'energy',
+ 'excretion',
+ 'digestion',
+ 'cooperation',
+ 'health',
+ 'justice',
+ 'labour',
+ 'machinery',
+ 'equipment',
+ 'information',
+ 'pollution',
+ 'sewage',
+ 'paper',
+ 'money',
+ 'species',
+ 'series',
+ 'rain',
+ 'rice',
+ 'fish',
+ 'sheep',
+ 'moose',
+ 'deer',
+ 'news',
+ 'expertise',
+ 'status',
+ 'media'
+];
+var uncountables = exports.uncountables;
+
+/*!
+ * Pluralize function.
+ *
+ * @author TJ Holowaychuk (extracted from _ext.js_)
+ * @param {String} string to pluralize
+ * @api private
+ */
+
+function pluralize(str) {
+ var found;
+ str = str.toLowerCase();
+ if (!~uncountables.indexOf(str)) {
+ found = rules.filter(function(rule) {
+ return str.match(rule[0]);
+ });
+ if (found[0]) {
+ return str.replace(found[0][0], found[0][1]);
+ }
+ }
+ return str;
+}
diff --git a/node_modules/mongoose-legacy-pluralize/package.json b/node_modules/mongoose-legacy-pluralize/package.json
new file mode 100644
index 0000000..2da292c
--- /dev/null
+++ b/node_modules/mongoose-legacy-pluralize/package.json
@@ -0,0 +1,81 @@
+{
+ "_args": [
+ [
+ "mongoose-legacy-pluralize@1.0.2",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "mongoose-legacy-pluralize@1.0.2",
+ "_id": "mongoose-legacy-pluralize@1.0.2",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mongoose-legacy-pluralize",
+ "_nodeVersion": "8.9.4",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mongoose-legacy-pluralize-1.0.2.tgz_1517182574020_0.22071910346858203"
+ },
+ "_npmUser": {
+ "email": "val@karpov.io",
+ "name": "vkarpov15"
+ },
+ "_npmVersion": "5.6.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mongoose-legacy-pluralize",
+ "raw": "mongoose-legacy-pluralize@1.0.2",
+ "rawSpec": "1.0.2",
+ "scope": null,
+ "spec": "1.0.2",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
+ "_shasum": "3ba9f91fa507b5186d399fb40854bff18fb563e4",
+ "_shrinkwrap": null,
+ "_spec": "mongoose-legacy-pluralize@1.0.2",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "val@karpov.io",
+ "name": "Valeri Karpov"
+ },
+ "bugs": {
+ "url": "https://github.com/vkarpov15/mongoose-legacy-pluralize/issues"
+ },
+ "dependencies": {},
+ "description": "Legacy pluralization logic for mongoose",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==",
+ "shasum": "3ba9f91fa507b5186d399fb40854bff18fb563e4",
+ "tarball": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz"
+ },
+ "gitHead": "94660a1990fd4cb5fc32d0664f13e4109f9c763d",
+ "homepage": "https://github.com/vkarpov15/mongoose-legacy-pluralize",
+ "keywords": [
+ "mongodb",
+ "mongoose"
+ ],
+ "license": "Apache-2.0",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "vkarpov15",
+ "email": "val@karpov.io"
+ }
+ ],
+ "name": "mongoose-legacy-pluralize",
+ "optionalDependencies": {},
+ "peerDependencies": {
+ "mongoose": "*"
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vkarpov15/mongoose-legacy-pluralize.git"
+ },
+ "version": "1.0.2"
+}
diff --git a/node_modules/mongoose/.travis.yml b/node_modules/mongoose/.travis.yml
new file mode 100644
index 0000000..5bdee15
--- /dev/null
+++ b/node_modules/mongoose/.travis.yml
@@ -0,0 +1,23 @@
+language: node_js
+sudo: false
+node_js: [12, 11, 10, 9, 8, 7, 6, 5, 4]
+install:
+ - travis_retry npm install
+before_script:
+ - wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.0.2.tgz
+ - tar -zxvf mongodb-linux-x86_64-ubuntu1604-4.0.2.tgz
+ - mkdir -p ./data/db/27017
+ - mkdir -p ./data/db/27000
+ - printf "\n--timeout 8000" >> ./test/mocha.opts
+ - ./mongodb-linux-x86_64-ubuntu1604-4.0.2/bin/mongod --fork --dbpath ./data/db/27017 --syslog --port 27017
+ - export PATH=`pwd`/mongodb-linux-x86_64-ubuntu1604-4.0.2/bin/:$PATH
+ - sleep 2
+ - mongod --version
+matrix:
+ include:
+ - name: "👕Linter"
+ node_js: 10
+ before_script: skip
+ script: npm run lint
+notifications:
+ email: false
diff --git a/node_modules/mongoose/History.md b/node_modules/mongoose/History.md
new file mode 100644
index 0000000..1e34cc4
--- /dev/null
+++ b/node_modules/mongoose/History.md
@@ -0,0 +1,5668 @@
+5.9.6 / 2020-03-23
+==================
+ * fix(document): allow saving document with nested document array after setting `nestedArr.0` #8689
+ * docs(connections): expand section about multiple connections to describe patterns for exporting schemas #8679
+ * docs(populate): add note about `execPopulate()` to "populate an existing document" section #8671 #8275
+ * docs: fix broken links #8690 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * docs(guide): fix typos #8704 [MateRyze](https://github.com/MateRyze)
+ * docs(guide): fix minor typo #8683 [pkellz](https://github.com/pkellz)
+
+5.9.5 / 2020-03-16
+==================
+ * fix: upgrade mongodb driver -> 3.5.5 #8667 #8664 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * fix(connection): emit "disconnected" after losing connectivity to every member of a replica set with `useUnifiedTopology: true` #8643
+ * fix(array): allow calling `slice()` after `push()` #8668 #8655 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * fix(map): avoid marking map as modified if setting `key` to the same value #8652
+ * fix(updateValidators): don't run `Mixed` update validator on dotted path underneath mixed type #8659
+ * fix(populate): ensure top-level `limit` applies if one document being populated has more than `limit` results #8657
+ * fix(populate): throw error if both `limit` and `perDocumentLimit` are set #8661 #8658 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * docs(findOneAndUpdate): add a section about the `rawResult` option #8662
+ * docs(guide): add section about `loadClass()` #8623
+ * docs(query): improve `Query#populate()` example to clarify that `sort` doesn't affect the original result's order #8647
+
+5.9.4 / 2020-03-09
+==================
+ * fix(document): allow `new Model(doc)` to set immutable properties when doc is a mongoose document #8642
+ * fix(array): make sure you can call `unshift()` after `slice()` #8482
+ * fix(schema): propagate `typePojoToMixed` to implicitly created arrays #8627
+ * fix(schema): also propagate `typePojoToMixed` option to schemas implicitly created because of `typePojoToMixed` #8627
+ * fix(model): support passing `background` option to `syncIndexes()` #8645
+ * docs(schema): add a section about the `_id` path in schemas #8625
+ * docs(virtualtype+populate): document using `match` with virtual populate #8616
+ * docs(guide): fix typo #8648 [sauzy34](https://github.com/sauzy34)
+
+5.9.3 / 2020-03-02
+==================
+ * fix: upgrade mongodb driver -> 3.5.4 #8620
+ * fix(document): set subpath defaults when overwriting single nested subdoc #8603
+ * fix(document): make calling `validate()` with single nested subpath only validate that single nested subpath #8626
+ * fix(browser): make `mongoose.model()` return a class in the browser to allow hydrating populated data in the browser #8605
+ * fix(model): make `syncIndexes()` and `cleanIndexes()` drop compound indexes with `_id` that aren't in the schema #8559
+ * docs(connection+index): add warnings to explain that bufferMaxEntries does nothing with `useUnifiedTopology` #8604
+ * docs(document+model+query): add `options.timestamps` parameter docs to `findOneAndUpdate()` and `findByIdAndUpdate()` #8619
+ * docs: fix out of date links to tumblr #8599
+
+5.9.2 / 2020-02-21
+==================
+ * fix(model): add discriminator key to bulkWrite filters #8590
+ * fix(document): when setting nested array path to non-nested array, wrap values top-down rather than bottom up when possible #8544
+ * fix(document): dont leave nested key as undefined when setting nested key to empty object with minimize #8565
+ * fix(document): avoid throwing error if setting path to Mongoose document with nullish `_doc` #8565
+ * fix(update): handle Binary type correctly with `runValidators` #8580
+ * fix(query): run `deleteOne` hooks only on `Document#deleteOne()` when setting `options.document = true` for `Schema#pre()` #8555
+ * fix(document): allow calling `validate()` in post validate hook without causing parallel validation error #8597
+ * fix(virtualtype): correctly copy options when cloning #8587
+ * fix(collection): skip creating capped collection if `autoCreate` set to `false` #8566
+ * docs(middleware): clarify that updateOne and deleteOne hooks are query middleware by default, not document middleware #8581
+ * docs(aggregate): clarify that `Aggregate#unwind()` can take object parameters as well as strings #8594
+
+5.9.1 / 2020-02-14
+==================
+ * fix(model): set session when calling `save()` with no changes #8571
+ * fix(schema): return correct pathType when single nested path is embedded under a nested path with a numeric name #8583
+ * fix(queryhelpers): remove `Object.values()` for Node.js 4.x-6.x support #8596
+ * fix(cursor): respect sort order when using `eachAsync()` with `parallel` and a sync callback #8577
+ * docs: update documentation of custom _id overriding in discriminators #8591 [sam-mfb](https://github.com/sam-mfb)
+
+5.9.0 / 2020-02-13
+==================
+ * fix: upgrade to MongoDB driver 3.5 #8520 #8563
+ * feat(schematype): support setting default options for schema type (`trim` on all strings, etc.) #8487
+ * feat(populate): add `perDocumentLimit` option that limits per document in `find()` result, rather than across all documents #7318
+ * feat(schematype): enable setting `transform` option on individual schematypes #8403
+ * feat(timestamps): allow setting `currentTime` option for setting custom function to get the current time #3957
+ * feat(connection): add `Connection#watch()` to watch for changes on an entire database #8425
+ * feat(document): add `Document#$op` property to make it easier to tell what operation is running in middleware #8439
+ * feat(populate): support `limit` as top-level populate option #8445
+
+5.8.13 / 2020-02-13
+===================
+ * fix(populate): use safe get to avoid crash if schematype doesn't have options #8586
+
+5.8.12 / 2020-02-12
+===================
+ * fix(query): correctly cast dbref `$id` with `$elemMatch` #8577
+ * fix(populate): handle populating when some embedded discriminator schemas have `refPath` but none of the subdocs have `refPath` #8553
+ * docs: add useUnifiedTopology to homepage example #8558 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * refactor(utils): moving promiseOrCallback to helpers/promiseOrCallback #8573 [hugosenari](https://github.com/hugosenari)
+
+5.8.11 / 2020-01-31
+===================
+ * fix(document): allow calling `validate()` multiple times in parallel on subdocs to avoid errors if Mongoose double-validates [taxilian](https://github.com/taxilian) #8548 #8539
+ * fix(connection): allow calling initial `mongoose.connect()` after connection helpers on the same tick #8534
+ * fix(connection): throw helpful error when callback param to `mongoose.connect()` or `mongoose.createConnection()` is not a function #8556
+ * fix(drivers): avoid unnecessary caught error when importing #8528
+ * fix(discriminator): remove unnecessary `utils.merge()` [samgladstone](https://github.com/samgladstone) #8542
+ * docs: add "built with mongoose" page #8540
+
+5.8.10 / 2020-01-27
+===================
+ * perf(document): improve performance of document creation by skipping unnecessary split() calls #8533 [igrunert-atlassian](https://github.com/igrunert-atlassian)
+ * fix(document): only call validate once for deeply nested subdocuments #8532 #8531 [taxilian](https://github.com/taxilian)
+ * fix(document): create document array defaults in forward order, not reverse #8514
+ * fix(document): allow function as message for date min/max validator #8512
+ * fix(populate): don't try to populate embedded discriminator that has populated path but no `refPath` #8527
+ * fix(document): plugins from base schema when creating a discriminator #8536 [samgladstone](https://github.com/samgladstone)
+ * fix(document): ensure parent and ownerDocument are set for subdocs in document array defaults #8509
+ * fix(document): dont set undefined keys to null if minimize is false #8504
+ * fix(update): bump timestamps when using update aggregation pipelines #8524
+ * fix(model): ensure `cleanIndexes()` drops indexes with different collations #8521
+ * docs(model): document `insertMany` `lean` option #8522
+ * docs(connections): document `authSource` option #8517
+
+5.8.9 / 2020-01-17
+==================
+ * fix(populate): skip populating embedded discriminator array values that don't have a `refPath` #8499
+ * docs(queries): clarify when to use queries versus aggregations #8494
+
+5.8.8 / 2020-01-14
+==================
+ * fix(model): allow using `lean` with `insertMany()` #8507 #8234 [ntsekouras](https://github.com/ntsekouras)
+ * fix(document): don't throw parallel validate error when validating subdoc underneath modified nested path #8486
+ * fix: allow `typePojoToMixed` as top-level option #8501 #8500 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * docs(populate+schematypes): make note of `_id` getter for ObjectIds in populate docs #8483
+
+5.8.7 / 2020-01-10
+==================
+ * fix(documentarray): modify ownerDocument when setting doc array to a doc array thats part of another document #8479
+ * fix(document): ensure that you can call `splice()` after `slice()` on an array #8482
+ * docs(populate): improve cross-db populate docs to include model refs #8497
+
+5.8.6 / 2020-01-07
+====================
+ * chore: merge changes from 4.13.20 and override mistaken publish to latest tag
+
+4.13.20 / 2020-01-07
+====================
+ * fix(schema): make aliases handle mongoose-lean-virtuals #6069
+
+5.8.5 / 2020-01-06
+==================
+ * fix(document): throw error when running `validate()` multiple times on the same document #8468
+ * fix(model): ensure deleteOne() and deleteMany() set discriminator filter even if no conditions passed #8471
+ * fix(document): allow pre('validate') hooks to throw errors with `name = 'ValidationError'` #8466
+ * fix(update): move top level $set of immutable properties to $setOnInsert so upserting with immutable properties actually sets the property #8467
+ * fix(document): avoid double-running validators on single nested subdocs within single nested subdocs #8468
+ * fix(populate): support top-level match option for virtual populate #8475
+ * fix(model): avoid applying skip when populating virtual with count #8476
+
+5.8.4 / 2020-01-02
+==================
+ * fix(populate): ensure populate virtual gets set to empty array if `localField` is undefined in the database #8455
+ * fix(connection): wrap `mongoose.connect()` server selection timeouts in MongooseTimeoutError for more readable stack traces #8451
+ * fix(populate): allow deselecting `foreignField` from projection by prefixing with `-` #8460
+ * fix(populate): support embedded discriminators with `refPath` when not all discriminator schemas have `refPath` #8452
+ * fix(array): allow defining `enum` on array if an array of numbers #8449
+
+5.8.3 / 2019-12-23
+==================
+ * fix: upgrade mongodb -> 3.4.1 #8430 [jaschaio](https://github.com/jaschaio)
+ * fix(populate): don't add empty subdocument to array when populating path underneath a non-existent document array #8432
+ * fix(schema): handle `_id` option for document array schematypes #8450
+ * fix(update): call setters when updating mixed type #8444
+ * docs(connections): add note about MongoTimeoutError.reason #8402
+
+5.8.2 / 2019-12-20
+==================
+ * fix(schema): copy `.add()`-ed paths when calling `.add()` with schema argument #8429
+ * fix(cursor): pull schema-level readPreference when using `Query#cursor()` #8421
+ * fix(cursor): wait for all promises to resolve if `parallel` is greater than number of documents #8422
+ * fix(document): depopulate entire array when setting array path to a partially populated array #8443
+ * fix: handle setDefaultsOnInsert with deeply nested subdocs #8392
+ * fix(document): report `DocumentNotFoundError` if underlying document deleted but no changes made #8428 #8371 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * docs(populate): clarify limitations of `limit` option for populate and suggest workaround #8409
+ * docs(deprecations): explain which connection options are no longer relevant with useUnifiedTopology #8411
+ * chore: allow browser build to be published #8435 #8427 [captaincaius](https://github.com/captaincaius)
+
+5.8.1 / 2019-12-12
+==================
+ * fix(documentarray): dont attempt to cast when modifying array returned from map() #8399
+ * fix(document): update single nested subdoc parent when setting to existing single nested doc #8400
+ * fix(schema): add `$embeddedSchemaType` property to arrays for consistency with document arrays #8389
+
+5.8.0 / 2019-12-09
+==================
+ * feat: wrap server selection timeout errors in `MongooseTimeoutError` to retain original stack trace #8259
+ * feat(model): add `Model.validate()` function that validates a POJO against the model's schema #7587
+ * feat(schema): add `Schema#pick()` function to create a new schema with a picked subset of the original schema's paths #8207
+ * feat(schema): add ability to change CastError message using `cast` option to SchemaType #8300
+ * feat(schema): group indexes defined in schema path with the same name #6499
+ * fix(model): build all indexes even if one index fails #8185 [unusualbob](https://github.com/unusualbob)
+ * feat(browser): pre-compile mongoose/browser #8350 [captaincaius](https://github.com/captaincaius)
+ * fix(connection): throw error when setting unsupported option #8335 #6899 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * feat(schema): support `enum` validator for number type #8139
+ * feat(update): allow using MongoDB 4.2 update aggregation pipelines, with no Mongoose casting #8225
+ * fix(update): make update validators run on all subpaths when setting a nested path, even omitted subpaths #3587
+ * feat(schema): support setting `_id` as an option to single nested schema paths #8137
+ * feat(query): add Query#mongooseOptions() function #8296
+ * feat(array): make `MongooseArray#push()` support using `$position` #4322
+ * feat(schema): make pojo paths optionally become subdoc instead of Mixed #8228 [captaincaius](https://github.com/captaincaius)
+ * feat(model): add Model.cleanIndexes() to drop non-schema indexes #6676
+ * feat(document): make `updateOne()` document middleware pass `this` to post hooks #8262
+ * feat(aggregate): run pre/post aggregate hooks on `explain()` #5887
+ * docs(model+query): add `session` option to docs for findOneAndX() methods #8396
+
+5.7.14 / 2019-12-06
+===================
+ * fix(cursor): wait until all `eachAsync()` functions finish before resolving the promise #8352
+ * fix(update): handle embedded discriminator paths when discriminator key is defined in the update #8378
+ * fix(schematype): handle passing `message` function to `SchemaType#validate()` as positional arg #8360
+ * fix(map): handle cloning a schema that has a map of subdocuments #8357
+ * docs(schema): clarify that `uppercase`, `lowercase`, and `trim` options for SchemaString don't affect RegExp queries #8333
+
+5.7.13 / 2019-11-29
+===================
+ * fix: upgrade mongodb driver -> 3.3.5 #8383
+ * fix(model): catch the error when insertMany fails to initialize the document #8365 #8363 [Fonger](https://github.com/Fonger)
+ * fix(schema): add array.$, array.$.$ subpaths for nested arrays #6405
+ * docs(error): add more detail about the ValidatorError class, including properties #8346
+ * docs(connection): document `Connection#models` property #8314
+
+5.7.12 / 2019-11-19
+===================
+ * fix: avoid throwing error if calling `push()` on a doc array with no parent #8351 #8317 #8312 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * fix(connection): only buffer for "open" events when calling connection helper while connecting #8319
+ * fix(connection): pull default database from connection string if specified #8355 #8354 [zachazar](https://github.com/zachazar)
+ * fix(populate+discriminator): handle populating document whose discriminator value is different from discriminator model name #8324
+ * fix: add `mongoose.isValidObjectId()` function to test whether Mongoose can cast a value to an objectid #3823
+ * fix(model): support setting `excludeIndexes` as schema option for subdocs #8343
+ * fix: add SchemaMapOptions class for options to map schematype #8318
+ * docs(query): remove duplicate omitUndefined options #8349 [mdumandag](https://github.com/mdumandag)
+ * docs(schema): add Schema#paths docs to public API docs #8340
+
+5.7.11 / 2019-11-14
+===================
+ * fix: update mongodb driver -> 3.3.4 #8276
+ * fix(model): throw readable error when casting bulkWrite update without a 'filter' or 'update' #8332 #8331 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * fix(connection): bubble up connected/disconnected events with unified topology #8338 #8337
+ * fix(model): delete $versionError after saving #8326 #8048 [Fonger](https://github.com/Fonger)
+ * test(model): add test for issue #8040 #8341 [Fonger](https://github.com/Fonger)
+
+5.7.10 / 2019-11-11
+===================
+ * perf(cursor): remove unnecessary `setTimeout()` in `eachAsync()`, 4x speedup in basic benchmarks #8310
+ * docs(README): re-order sections for better readability #8321 [dandv](https://github.com/dandv)
+ * chore: make npm test not hard-code file paths #8322 [stieg](https://github.com/stieg)
+
+5.7.9 / 2019-11-08
+==================
+ * fix(schema): support setting schema path to an instance of SchemaTypeOptions to fix integration with mongoose-i18n-localize #8297 #8292
+ * fix(populate): make `retainNullValues` set array element to `null` if foreign doc with that id was not found #8293
+ * fix(document): support getter setting virtual on manually populated doc when calling toJSON() #8295
+ * fix(model): allow objects with `toBSON()` to make it to `save()` #8299
+
+5.7.8 / 2019-11-04
+==================
+ * fix(document): allow manually populating path within document array #8273
+ * fix(populate): update top-level `populated()` when updating document array with populated subpaths #8265
+ * fix(cursor): throw error when using aggregation cursor as async iterator #8280
+ * fix(schema): retain `_id: false` in schema after nesting in another schema #8274
+ * fix(document): make Document class an event emitter to support defining documents without models in node #8272
+ * docs: document return types for `.discriminator()` #8287
+ * docs(connection): add note about exporting schemas, not models, in multi connection paradigm #8275
+ * docs: clarify that transforms defined in `toObject()` options are applied to subdocs #8260
+
+5.7.7 / 2019-10-24
+==================
+ * fix(populate): make populate virtual consistently an empty array if local field is only empty arrays #8230
+ * fix(query): allow findOne(objectid) and find(objectid) #8268
+
+5.7.6 / 2019-10-21
+==================
+ * fix: upgrade mongodb driver -> 3.3.3 to fix issue with failing to connect to a replica set if one member is down #8209
+ * fix(document): fix TypeError when setting a single nested subdoc with timestamps #8251
+ * fix(cursor): fix issue with long-running `eachAsync()` cursor #8249 #8235
+ * fix(connection): ensure repeated `close` events from useUnifiedTopology don't disconnect Mongoose from replica set #8224
+ * fix(document): support calling `Document` constructor directly in Node.js #8237
+ * fix(populate): add document array subpaths to parent doc `populated()` when calling `DocumentArray#push()` #8247
+ * fix(options): add missing minlength and maxlength to SchemaStringOptions #8256
+ * docs: add documentarraypath to API docs, including DocumentArrayPath#discriminator() #8164
+ * docs(schematypes): add a section about the `type` property #8227
+ * docs(api): fix Connection.close return param #8258 [gosuhiman](https://github.com/gosuhiman)
+ * docs: update link to broken image on home page #8253 [krosenk729](https://github.com/krosenk729)
+
+5.7.5 / 2019-10-14
+==================
+ * fix(query): delete top-level `_bsontype` property in queries to prevent silent empty queries #8222
+ * fix(update): handle subdocument pre('validate') errors in update validation #7187
+ * fix(subdocument): make subdocument#isModified use parent document's isModified #8223
+ * docs(index): add favicon to home page #8226
+ * docs: add schema options to API docs #8012
+ * docs(middleware): add note about accessing the document being updated in pre('findOneAndUpdate') #8218
+ * refactor: remove redundant code in ValidationError #8244 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+
+5.7.4 / 2019-10-09
+==================
+ * fix(schema): handle `required: null` and `required: undefined` as `required: false` #8219
+ * fix(update): support updating array embedded discriminator props if discriminator key in $elemMatch #8063
+ * fix(populate): allow accessing populate virtual prop underneath array when virtual defined on top level #8198
+ * fix(model): support passing `options` to `Model.remove()` #8211
+ * fix(document): handle `Document#set()` merge option when setting underneath single nested schema #8201
+ * fix: use options constructor class for all schematypes #8012
+
+5.7.3 / 2019-09-30
+==================
+ * fix: make CoreMongooseArray#includes() handle `fromIndex` parameter #8203
+ * fix(update): cast right hand side of `$pull` as a query instead of an update for document arrays #8166
+ * fix(populate): handle virtual populate of an embedded discriminator nested path #8173
+ * docs(validation): remove deprecated `isAsync` from validation docs in favor of emphasizing promises #8184
+ * docs(documents): add overwriting section #8178
+ * docs(promises): add note about queries being thenable #8110
+ * perf: avoid update validators going into Mixed types #8192 [birdofpreyru](https://github.com/birdofpreyru)
+ * refactor: remove async as a prod dependency #8073
+
+5.7.2 / 2019-09-23
+==================
+ * fix(mongoose): support `mongoose.set('autoIndex', false)` #8158
+ * fix(discriminator): support `tiedValue` parameter for embedded discriminators analagous to top-level discriminators #8164
+ * fix(query): handle `toConstructor()` with entries-style sort syntax #8159
+ * fix(populate): avoid converting mixed paths into arrays if populating an object path under `Mixed` #8157
+ * fix: use $wrapCallback when using promises for mongoose-async-hooks
+ * fix: handle queries with setter that converts value to Number instance #8150
+ * docs: add mongoosejs-cli to readme #8142
+ * docs: fix example typo for Schema.prototype.plugin() #8175 [anaethoss](https://github.com/anaethoss)
+
+5.7.1 / 2019-09-13
+==================
+ * fix(query): fix TypeError when calling `findOneAndUpdate()` with `runValidators` #8151 [fernandolguevara](https://github.com/fernandolguevara)
+ * fix(document): throw strict mode error if setting an immutable path with strict mode: false #8149
+ * fix(mongoose): support passing options object to Mongoose constructor #8144
+ * fix(model): make syncIndexes() handle changes in index key order #8135
+ * fix(error): export StrictModeError as a static property of MongooseError #8148 [ouyuran](https://github.com/ouyuran)
+ * docs(connection+mongoose): add `useUnifiedTopology` option to `connect()` and `openUri()` docs #8146
+
+5.7.0 / 2019-09-09
+==================
+ * feat(document+query): support conditionally immutable schema paths #8001
+ * perf(documentarray): refactor to use ES6 classes instead of mixins, ~30% speedup #7895
+ * feat: use MongoDB driver 3.3.x for MongoDB 4.2 support #8083 #8078
+ * feat(schema+query): add pre('validate') and post('validate') hooks for update validation #7984
+ * fix(timestamps): ensure updatedAt gets incremented consistently using update with and without $set #4768
+ * feat(query): add `Query#get()` to make writing custom setters that handle both queries and documents easier #7312
+ * feat(document): run setters on defaults #8012
+ * feat(document): add `aliases: false` option to `Document#toObject()` #7548
+ * feat(timestamps): support skipping updatedAt and createdAt for individual save() and update() #3934
+ * docs: fix index creation link in guide #8138 [joebowbeer](https://github.com/joebowbeer)
+
+5.6.13 / 2019-09-04
+===================
+ * fix(parallel): fix parallelLimit when fns is empty #8130 #8128 [sibelius](https://github.com/sibelius)
+ * fix(document): ensure nested mixed validator gets called exactly once #8117
+ * fix(populate): handle `justOne = undefined` #8125 [taxilian](https://github.com/taxilian)
+
+5.6.12 / 2019-09-03
+===================
+ * fix(schema): handle required validator correctly with `clone()` #8111
+ * fix(schema): copy schematype getters and setters when cloning #8124 [StphnDamon](https://github.com/StphnDamon)
+ * fix(discriminator): avoid unnecessarily cloning schema to avoid leaking memory on repeated `discriminator()` calls #2874
+ * docs(schematypes): clarify when Mongoose uses `toString()` to convert an object to a string #8112 [TheTrueRandom](https://github.com/TheTrueRandom)
+ * docs(plugins): fix out of date link to npm docs #8100
+ * docs(deprecations): fix typo #8109 [jgcmarins](https://github.com/jgcmarins)
+ * refactor(model): remove dependency on `async.parallelLimit()` for `insertMany()` #8073
+
+5.6.11 / 2019-08-25
+===================
+ * fix(model): allow passing options to `exists()` #8075
+ * fix(document): make `validateUpdatedOnly` option handle pre-existing errors #8091
+ * fix: throw readable error if middleware callback isnt a function #8087
+ * fix: don't throw error if calling `find()` on a nested array #8089
+ * docs(middleware): clarify that you must add middleware before compiling your model #5087
+ * docs(query): add missing options to `setOptions()` #8099
+
+5.6.10 / 2019-08-20
+===================
+ * fix(schema): fix require() path to work around yet another bug in Jest #8053
+ * fix(document): skip casting when initing a populated path #8062
+ * fix(document): prevent double-calling validators on mixed objects with nested properties #8067
+ * fix(query): handle schematype with `null` options when checking immutability #8070 [rich-earth](https://github.com/rich-earth)
+ * fix(schema): support `Schema#path()` to get schema path underneath doc array #8057
+ * docs(faq): add disable color instruction #8066
+
+5.6.9 / 2019-08-07
+==================
+ * fix(model): delete versionError after saving to prevent memory leak #8048
+ * fix(cursor): correctly handle batchSize option with query cursor #8039
+ * fix(populate): handle virtual populate with count = 0 if virtual embedded in doc array #7573
+ * fix(schema): allow declaring ObjectId array with `{ type: 'ObjectID' }`, last 'D' case insensitive #8034
+
+5.6.8 / 2019-08-02
+==================
+ * fix(aggregate): allow modifying pipeline in pre('aggregate') hooks #8017
+ * fix(query): make `findOneAndReplace()` work with `orFail()` #8030
+ * fix(document): allow saving an unchanged document if required populated path is null #8018
+ * fix(debug): support disabling colors in debug mode #8033 [Mangosteen-Yang](https://github.com/Mangosteen-Yang)
+ * docs: add async-await guide #8028 [Rossh87](https://github.com/Rossh87)
+ * docs(plugins): rewrite plugins docs to be more modern and not use strange `= exports` syntax #8026
+ * docs(transactions): clarify relationship between `session` in docs and MongoDB driver ClientSession class, link to driver docs #8009
+
+5.6.7 / 2019-07-26
+==================
+ * fix(document): support validators on nested arrays #7926
+ * fix(timestamps): handle `timestamps: false` in child schema #8007
+ * fix(query): consistently support `new` option to `findOneAndX()` as an alternative to `returnOriginal` #7846
+ * fix(document): make `inspect()` never return `null`, because a document or nested path is never `== null` #7942
+ * docs(query+lean): add links to mongoose-lean-virtuals, mongoose-lean-getters, mongoose-lean-defaults #5606
+ * docs: add example for `Schema#pre(Array)` #8022 [Mangosteen-Yang](https://github.com/Mangosteen-Yang)
+ * docs(schematype): updated comment from Schema.path to proper s.path #8013 [chrisweilacker](https://github.com/chrisweilacker)
+ * chore: upgrade nyc #8015 [kolya182](https://github.com/kolya182)
+
+5.6.6 / 2019-07-22
+==================
+ * fix(populate): handle refPath returning a virtual with `Query#populate()` #7341
+ * fix(populate): handle `refPath` in discriminator when populating top-level model #5109
+ * fix(mongoose): ensure destucturing and named imports work for Mongoose singleton methods like `set()`, etc. #6039
+ * fix(query): add missing options for deleteOne and deleteMany in Query #8004 [Fonger](https://github.com/Fonger)
+ * fix(schema): make embedded discriminators `instanceof` their parent types #5005
+ * fix(array): make `validators` a private property that doesn't show up in for/in #6572
+ * docs(api): fix array API docs that vanished because of #7798 #7979
+ * docs(discriminators+api): add single nested discriminator to discriminator docs and API docs #7983
+ * docs(connection+mongoose): make option lists consistent between `mongoose.connect()`, `mongoose.createConnection()`, and `conn.openUri()` #7976
+ * docs(validation): clarify resolve(false) vs reject() for promise-based async custom validators #7761
+ * docs(guide): use correct `mongoose.set()` instead of `mongoose.use()` #7998
+ * docs: add redis cache example #7997 [usama-asfar](https://github.com/usama-asfar)
+
+5.6.5 / 2019-07-17
+==================
+ * fix(document): handle setting non-schema path to ObjectId or Decimal128 if strict: false #7973
+ * fix(connection): remove backwards-breaking multiple mongoose.connect() call for now #7977
+ * fix(schema): print invalid value in error message when a schema path is set to undefined or null #7956
+ * fix(model): throw readable error if calling `new Model.discriminator()` #7957
+ * fix(mongoose): export `cast()` function #7975 [perfectstorm88](https://github.com/perfectstorm88)
+ * docs(model): fix link to Model.inspect() and add example #7990
+ * docs: fix broken anchor links on validation tutorial #7966
+ * docs(api): fix broken links to split API pages #7978
+ * chore: create LICENSE.md #7989 [Fonger](https://github.com/Fonger)
+
+5.6.4 / 2019-07-08
+==================
+ * fix(schema): support pre(Array, Function) and post(Array, Function) #7803
+ * fix(document): load docs with a `once` property successfully #7958
+ * fix(queryhelpers): ensure parent `select` overwrites child path `select` if parent is nested #7945
+ * fix(schema): make `clone()` correctly copy array embedded discriminators #7954
+ * fix(update): fix error when update property gets casted to null #7949
+ * fix(connection): bubble up attemptReconnect event for now #7872
+ * docs(tutorials): add virtuals tutorial #7965
+ * docs(connection): add section on connection handling #6997
+
+5.6.3 / 2019-07-03
+==================
+ * fix(document): respect projection when running getters #7940
+ * fix(model): call createCollection() in syncIndexes() to ensure the collection exists #7931
+ * fix(document): consistently use post-order traversal for gathering subdocs for hooks #7929
+ * fix(schema): ensure `Schema#pathType()` returns correct path type given non-existent positional path #7935
+ * fix(ChangeStream): set `closed` if emitting close event #7930
+ * fix(connection): bubble up 'attemptReconnect' event from MongoDB connection #7872
+ * docs: fix broken .jade links on search page #7932
+ * docs: correct link to `Query#select()` #7953 [rayhatfield](https://github.com/rayhatfield)
+ * docs(README): add list of related projects #7773
+
+4.13.19 / 2019-07-02
+====================
+ * fix(aggregate): make `setOptions()` work as advertised #7950 #6011 [cdimitroulas](https://github.com/cdimitroulas)
+
+5.6.2 / 2019-06-28
+==================
+ * fix(update): allow using `update()` with immutable `createdAt` #7917
+ * fix(model): pass `doc` parameter to save() error handling middleware #7832
+ * fix(mongoose): add applyPluginsToChildSchemas option to allow opting out of global plugins for child schemas #7916
+ * docs(connection): document `useCache` option for `useDb()` #7923
+ * docs: fix broken link in FAQ #7925 [christophergeiger3](https://github.com/christophergeiger3)
+
+5.6.1 / 2019-06-24
+==================
+ * fix(update): skip setting defaults for single embedded subdocs underneath maps #7909
+ * fix(document): copy date objects correctly when strict = false #7907
+ * feat(mongoose): throw an error if calling `mongoose.connect()` multiple times while connected #7905 [Fonger](https://github.com/Fonger)
+ * fix(document): copies virtuals from array subdocs when casting array of docs with same schema #7898
+ * fix(schema): ensure clone() copies single embedded discriminators correctly #7894
+ * fix(discriminator): merge instead of overwriting conflicting nested schemas in discriminator schema #7884
+ * fix(populate): ignore nullish arguments when calling `populate()` #7913 [rayhatfield](https://github.com/rayhatfield)
+ * docs: add getters/setters tutorial #7919
+ * docs: clean up error docs so they refer to `Error` rather than `MongooseError` #7867
+ * docs: fix a couple broken links #7921 [kizmo04](https://github.com/kizmo04)
+ * refactor: remove unnecessary if #7911 [rayhatfield](https://github.com/rayhatfield)
+
+5.6.0 / 2019-06-14
+==================
+ * feat(schematype): add `immutable` option to disallow changing a given field #7671
+ * docs: split API docs into separate pages to make API documentation more Google-able #7812
+ * perf(array): remove all mixins in favor of ES6 classes, ~20% faster in basic benchmarks #7798
+ * feat(document): use promise rejection error message when async custom validator throws an error #4913
+ * feat(virtual): pass document as 3rd parameter to virtual getters and setters to enable using arrow functions #4143
+ * feat(model): add `Model.exists()` function to quickly check whether a document matching `filter` exists #6872
+ * feat(index+connection): support setting global and connection-level `maxTimeMS`
+ * feat(populate): support setting `ref` to a function for conventional populate #7669
+ * feat(document): add overwrite() function that overwrites all values in a document #7830
+ * feat(populate): support `PopulateOptions#connection` option to allow cross-db populate with refPath #6520
+ * feat(populate): add skipInvalidIds option to silently skip population if id is invalid, instead of throwing #7706
+ * feat(array): skip empty array default if there's a 2dsphere index on a geojson path #3233
+ * feat(query): add `getFilter()` as an alias of `getQuery()` to be more in line with API docs #7839
+ * feat(model): add Model.inspect() to make models not clutter `util.inspect()` #7836
+ * perf(discriminator): skip calling `createIndex()` on indexes that are defined in the base schema #7379
+ * docs: upgrade from Jade to latest Pug #7812
+ * docs(README): update reference to example schema.js #7899 [sharils](https://github.com/sharils)
+ * docs(README): improve variable name #7900 [sharils](https://github.com/sharils)
+ * chore: replace charAt(0) with startsWith #7897 [Fonger](https://github.com/Fonger)
+ * chore: replace indexOf with includes, startsWith and endsWith for String #7897 [Fonger](https://github.com/Fonger)
+
+5.5.15 / 2019-06-12
+===================
+ * fix(connection): reject initial connect promise even if there is an on('error') listener #7850
+ * fix(map): make `of` automatically convert POJOs to schemas unless typeKey is set #7859
+ * fix(update): use discriminator schema to cast update if discriminator key specified in filter #7843
+ * fix(array): copy atomics from source array #7891 #7889 [jyrkive](https://github.com/jyrkive)
+ * fix(schema): return this when Schema.prototype.add is called with Schema #7887 [Mickael-van-der-Beek](https://github.com/Mickael-van-der-Beek)
+ * fix(document): add `numAffected` and `result` to DocumentNotFoundError for better debugging #7892 #7844
+
+5.5.14 / 2019-06-08
+===================
+ * fix(query): correct this scope of setters in update query #7876 [Fonger](https://github.com/Fonger)
+ * fix(model): reset modifiedPaths after successful insertMany #7852 #7873 [Fonger](https://github.com/Fonger)
+ * fix(populate): allow using `refPath` with virtual populate #7848
+ * fix(document): prepend private methods getValue and setValue with $ #7870 [Fonger](https://github.com/Fonger)
+ * fix: update mongodb driver -> 3.2.7 #7871 [Fonger](https://github.com/Fonger)
+ * docs(tutorials): add tutorial about custom casting functions #7045
+ * docs(connection): fix outdated events document #7874 [Fonger](https://github.com/Fonger)
+ * docs: fix typo in lean docs #7875 [tannakartikey](https://github.com/tannakartikey)
+ * docs: move off of KeenIO for tracking and use self-hosted analytics instead
+
+5.5.13 / 2019-06-05
+===================
+ * fix(model): support passing deleteOne options #7860 #7857 [Fonger](https://github.com/Fonger)
+ * fix(update): run setters on array elements when doing $addToSet, $push, etc #4185
+ * fix(model): support getting discriminator by value when creating a new model #7851
+ * docs(transactions): add section about the `withTransaction()` helper #7598
+ * docs(schema): clarify relationship between Schema#static() and Schema#statics #7827
+ * docs(model): fix typo `projetion` to `projection` #7868 [dfdeagle47](https://github.com/dfdeagle47)
+ * docs(schema): correct schema options lists #7828
+
+5.5.12 / 2019-05-31
+===================
+ * fix(document): fix unexpected error when loading a document with a nested property named `schema` #7831
+ * fix(model): skip applying static hooks by default if static name conflicts with query middleware (re: mongoose-delete plugin) #7790
+ * fix(query): apply schema-level projections to the result of `findOneAndReplace()` #7654
+ * fix: upgrade mongodb driver -> 3.2.6
+ * docs(tutorials): add findOneAndUpdate() tutorial #7847
+ * docs(validation): add `updateOne()` and `updateMany()` to list of update validator operations #7845
+ * docs(model): make sure options lists in `update()` API line up #7842
+
+5.5.11 / 2019-05-23
+===================
+ * fix(discriminator): allow numeric discriminator keys for embedded discriminators #7808
+ * chore: add Node.js 12 to travis build matrix #7784
+
+5.5.10 / 2019-05-20
+===================
+ * fix(discriminator): allow user-defined discriminator path in schema #7807
+ * fix(query): ensure `findOneAndReplace()` sends `replacement` to server #7654
+ * fix(cast): allow `[]` as a value when casting `$nin` #7806
+ * docs(model): clarify that setters do run on `update()` by default #7801
+ * docs: fix typo in FAQ #7821 [jaona](https://github.com/jaona)
+
+5.5.9 / 2019-05-16
+==================
+ * fix(query): skip schema setters when casting $regexp $options #7802 [Fonger](https://github.com/Fonger)
+ * fix(populate): don't skip populating doc array properties whose name conflicts with an array method #7782
+ * fix(populate): make populated virtual return undefined if not populated #7795
+ * fix(schema): handle custom setters in arrays of document arrays #7804 [Fonger](https://github.com/Fonger)
+ * docs(tutorials): add query casting tutorial #7789
+
+5.5.8 / 2019-05-13
+==================
+ * fix(document): run pre save hooks on nested child schemas #7792
+ * fix(model): set $session() before validation middleware for bulkWrite/insertMany #7785 #7769 [Fonger](https://github.com/Fonger)
+ * fix(query): make `getPopulatedPaths()` return deeply populated paths #7757
+ * fix(query): suppress findAndModify deprecation warning when using `Model.findOneAndUpdate()` #7794
+ * fix: upgrade mongodb -> 3.2.4 #7794
+ * fix(document): handle a couple edge cases with atomics that happen when schema defines an array property named 'undefined' #7756
+ * docs(discriminator): correct function parameters #7786 [gfpacheco](https://github.com/gfpacheco)
+
+5.5.7 / 2019-05-09
+==================
+ * fix(model): set $session() before pre save middleware runs when calling save() with options #7742
+ * fix(model): set $session before pre remove hooks run when calling remove() with options #7742
+ * fix(schema): support `remove()` on nested path #2398
+ * fix(map): handle setting populated map element to doc #7745
+ * fix(query): return rawResult when inserting with options `{new:false,upsert:true,rawResult:true}` #7774 #7770 [LiaanM](https://github.com/LiaanM)
+ * fix(schematype): remove internal `validators` option because it conflicts with Backbone #7720
+
+5.5.6 / 2019-05-06
+==================
+ * fix(document): stop converting arrays to objects when setting non-schema path to array with strict: false #7733
+ * fix(array): make two Mongoose arrays `assert.deepEqual()` each other if they have the same values #7700
+ * fix(populate): support populating a path in a document array embedded in an array #7647
+ * fix(populate): set populate virtual count to 0 if local field is empty #7731
+ * fix(update): avoid throwing cast error if casting array filter that isn't in schema with strictQuery = false #7728
+ * docs: fix typo in `distinct()` description #7767 [phil-r](https://github.com/phil-r)
+
+5.5.5 / 2019-04-30
+==================
+ * fix(document): ensure nested properties within single nested subdocs get set correctly when overwriting single nested subdoc #7748
+ * fix(document): skip non-object `validators` in schema types #7720
+ * fix: bump mongodb driver -> 3.2.3 #7752
+ * fix(map): disallow setting map key with special properties #7750 [Fonger](https://github.com/Fonger)
+
+5.5.4 / 2019-04-25
+==================
+ * fix(document): avoid calling custom getters when saving #7719
+ * fix(timestamps): handle child schema timestamps correctly when reusing child schemas #7712
+ * fix(query): pass correct callback for _legacyFindAndModify #7736 [Fonger](https://github.com/Fonger)
+ * fix(model+query): allow setting `replacement` parameter for `findOneAndReplace()` #7654
+ * fix(map): make `delete()` unset the key in the database #7746 [Fonger](https://github.com/Fonger)
+ * fix(array): use symbol for `_schema` property to avoid confusing deep equality checks #7700
+ * fix(document): prevent `depopulate()` from removing fields with empty array #7741 #7740 [Fonger](https://github.com/Fonger)
+ * fix: make `MongooseArray#includes` support ObjectIds #7732 #6354 [hansemannn](https://github.com/hansemannn)
+ * fix(document): report correct validation error index when pushing onto doc array #7744 [Fonger](https://github.com/Fonger)
+
+5.5.3 / 2019-04-22
+==================
+ * fix: add findAndModify deprecation warning that references the useFindAndModify option #7644
+ * fix(document): handle pushing a doc onto a discriminator that contains a doc array #7704
+ * fix(update): run setters on array elements when doing $set #7679
+ * fix: correct usage of arguments while buffering commands #7718 [rzymek](https://github.com/rzymek)
+ * fix(document): avoid error clearing modified subpaths if doc not defined #7715 [bitflower](https://github.com/bitflower)
+ * refactor(array): move `_parent` property behind a symbol #7726 #7700
+ * docs(model): list out all operations and options for `bulkWrite()` #7055
+ * docs(aggregate): use `eachAsync()` instead of nonexistent `each()` #7699
+ * docs(validation): add CastError validation example #7514
+ * docs(query+model): list out all options and callback details for Model.updateX() and Query#updateX() #7646
+
+5.5.2 / 2019-04-16
+==================
+ * fix(document): support setting nested path to non-POJO object #7639
+ * perf(connection): remove leaked event handler in `Model.init()` so `deleteModel()` frees all memory #7682
+ * fix(timestamps): handle custom statics that conflict with built-in functions (like mongoose-delete plugin) #7698
+ * fix(populate): make `Document#populated()` work for populated subdocs #7685
+ * fix(document): support `.set()` on document array underneath embedded discriminator path #7656
+
+5.5.1 / 2019-04-11
+==================
+ * fix(document): correctly overwrite all properties when setting a single nested subdoc #7660 #7681
+ * fix(array): allow customization of array required validator #7696 [freewil](https://github.com/freewil)
+ * fix(discriminator): handle embedded discriminators when casting array defaults #7687
+ * fix(collection): ensure collection functions return a promise even if disconnected #7676
+ * fix(schematype): avoid indexing properties with `{ unique: false, index: false }` #7620
+ * fix(aggregate): make `Aggregate#model()` with no arguments return the aggregation's model #7608
+
+5.5.0 / 2019-04-08
+==================
+ * feat(model): support applying hooks to custom static functions #5982
+ * feat(populate): support specifying a function as `match` #7397
+ * perf(buffer): avoid calling `defineProperties()` in Buffer constructor #7331
+ * feat(connection): add `plugin()` for connection-scoped plugins #7378
+ * feat(model): add Model#deleteOne() and corresponding hooks #7538
+ * feat(query): support hooks for `Query#distinct()` #5938
+ * feat(model): print warning when calling create() incorrectly with a session #7535
+ * feat(document): add Document#isEmpty() and corresponding helpers for nested paths #5369
+ * feat(document): add `getters` option to Document#get() #7233
+ * feat(query): add Query#projection() to get or overwrite the current projection #7384
+ * fix(document): set full validator path on validatorProperties if `propsParameter` set on validator #7447
+ * feat(document): add Document#directModifiedPaths() #7373
+ * feat(document): add $locals property #7691
+ * feat(document): add validateUpdatedOnly option that only validates modified paths in `save()` #7492 [captaincaius](https://github.com/captaincaius)
+ * chore: upgrade MongoDB driver to v3.2.0 #7641
+ * fix(schematype): deprecate `isAsync` option for custom validators #6700
+ * chore(mongoose): deprecate global.MONGOOSE_DRIVER_PATH so we can be webpack-warning-free in 6.0 #7501
+
+5.4.23 / 2019-04-08
+===================
+ * fix(document): report cast error when string path in schema is an array in MongoDB #7619
+ * fix(query): set deletedCount on result of remove() #7629
+ * docs(subdocs): add note about parent() and ownerDocument() to subdocument docs #7576
+
+5.4.22 / 2019-04-04
+===================
+ * fix(aggregate): allow modifying options in pre('aggregate') hook #7606
+ * fix(map): correctly init maps of maps when loading from MongoDB #7630
+ * docs(model+query): add `omitUndefined` option to docs for updateX() and findOneAndX() #3486
+ * docs: removed duplicate Query.prototype.merge() reference from doc #7684 [shihabmridha](https://github.com/shihabmridha)
+ * docs(schema): fix shardKey type to object instead of bool #7668 [kyletsang](https://github.com/kyletsang)
+ * docs(api): fix `Model.prototypedelete` link #7665 [pixcai](https://github.com/pixcai)
+
+5.4.21 / 2019-04-02
+===================
+ * fix(updateValidators): run update validators correctly on Decimal128 paths #7561
+ * fix(update): cast array filters in nested doc arrays correctly #7603
+ * fix(document): allow .get() + .set() with aliased paths #7592
+ * fix(document): ensure custom getters on single nested subdocs don't get persisted if toObject.getters = true #7601
+ * fix(document): support setting subdoc path to subdoc copied using object rest `{...doc}` #7645
+ * docs(schema): correct out-of-date list of reserved words #7593
+ * docs(model+query): add link to update results docs and examples of using results of updateOne(), etc. #7582
+ * docs: use atomic as opposed to $atomic consistently #7649 [720degreeLotus](https://github.com/720degreeLotus)
+
+5.4.20 / 2019-03-25
+===================
+ * docs(tutorials): add tutorial about `lean()` #7640
+ * fix(discriminator): fix wrong modelName being used as value to partialFilterExpression index #7635 #7634 [egorovli](https://github.com/egorovli)
+ * fix(document): allow setters to modify `this` when overwriting single nested subdoc #7585
+ * fix(populate): handle count option correctly with multiple docs #7573
+ * fix(date): support declaring min/max validators as functions #7600 [ChienDevIT](https://github.com/ChienDevIT)
+ * fix(discriminator): avoid projecting in embedded discriminator if only auto-selected path is discriminator key #7574
+ * fix(discriminator): use discriminator model when using `new BaseModel()` with discriminator key #7586
+ * fix(timestamps): avoid throwing if doc array has timestamps and array is undefined #7625 [serg33v](https://github.com/serg33v)
+ * docs(document): explain DocumentNotFoundError in save() docs #7580
+ * docs(query): fix .all() param type and add example #7612 [720degreeLotus](https://github.com/720degreeLotus)
+ * docs: add useNewUrlParser to mongoose.connect for some pages #7615 [YC](https://github.com/YC)
+
+5.4.19 / 2019-03-11
+===================
+ * fix(mongoose): ensure virtuals set on subdocs in global plugins get applied #7572
+ * docs(tutorials): add "Working With Dates" tutorial #7597
+ * docs(guide): clarify that versioning only affects array fields #7555
+ * docs(model): list out all bulkWrite() options #7550
+
+5.4.18 / 2019-03-08
+===================
+ * fix(document): handle nested virtuals in populated docs when parent path is projected out #7491
+ * fix(model): make subclassed models handle discriminators correctly #7547
+ * fix(model): remove $versionError from save options for better debug output #7570
+
+5.4.17 / 2019-03-03
+===================
+ * fix(update): handle all positional operator when casting array filters #7540
+ * fix(populate): handle populating nested path where top-level path is a primitive in the db #7545
+ * fix(update): run update validators on array filters #7536
+ * fix(document): clean modified subpaths when sorting an array #7556
+ * fix(model): cast $setOnInsert correctly with nested docs #7534
+ * docs: remove extra curly brace from example #7569 [kolya182](https://github.com/kolya182)
+
+5.4.16 / 2019-02-26
+===================
+ * fix(schema): handle nested objects with `_id: false` #7524
+ * fix(schema): don't throw error if declaring a virtual that starts with a map path name #7464
+ * fix(browser): add stubbed `model()` function so code that uses model doesn't throw #7541 [caub](https://github.com/caub)
+ * fix(schema): merge virtuals correctly #7563 [yoursdearboy](https://github.com/yoursdearboy)
+ * docs(connections): add reconnectFailed to connection docs #7477
+ * docs(index): fix typo #7553 [DenrizSusam](https://github.com/DenrizSusam)
+ * refactor(schema): iterate over paths instead of depending on childSchemas #7554
+
+5.4.15 / 2019-02-22
+===================
+ * fix(update): don't call schematype validators on array if using $pull with runValidators #6971
+ * fix(schema): clone all schema types when cloning an array #7537
+ * docs(connections): improve connectTimeoutMS docs and socketTimeoutMS docs to link to Node.js net.setTimeout() #5169
+ * docs: fix setters example in migration guide #7546 [freewil](https://github.com/freewil)
+
+5.4.14 / 2019-02-19
+===================
+ * fix(populate): make `getters` option handle nested paths #7521
+ * fix(documentarray): report validation errors that occur in an array subdoc created using `create()` and then `set()` #7504
+ * docs(schema): add examples for schema functions that didn't have any #7525
+ * docs: add MongooseError to API docs and add list of error names
+ * docs(CONTRIBUTING): fix link #7530 [sarpik](https://github.com/sarpik)
+
+5.4.13 / 2019-02-15
+===================
+ * fix(query): throw handy error when using updateOne() with overwrite: true and no dollar keys #7475
+ * fix(schema): support inheriting existing schema types using Node.js `util.inherits` like mongoose-float #7486
+ * docs(connections): add list of connection events #7477
+
+5.4.12 / 2019-02-13
+===================
+ * fix(connection): dont emit reconnected due to socketTimeoutMS #7452
+ * fix(schema): revert check for `false` schema paths #7516 #7512
+ * fix(model): don't delete unaliased keys in translateAliases #7510 [chrischen](https://github.com/chrischen)
+ * fix(document): run single nested schematype validator if nested path has a default and subpath is modified #7493
+ * fix(query): copy mongoose options when using `Query#merge()` #1790
+ * fix(timestamps): don't call createdAt getters when setting updatedAt on new doc #7496
+ * docs: improve description of ValidationError #7515 [JulioJu](https://github.com/JulioJu)
+ * docs: add an asterisk before comment, otherwise the comment line is not generated #7513 [JulioJu](https://github.com/JulioJu)
+
+5.4.11 / 2019-02-09
+===================
+ * fix(schema): handle `_id: false` in schema paths as a shortcut for setting the `_id` option to `false` #7480
+ * fix(update): handle $addToSet and $push with ObjectIds and castNonArrays=false #7479
+ * docs(model): document `session` option to `save()` #7484
+ * chore: fix gitignore syntax #7498 [JulioJu](https://github.com/JulioJu)
+ * docs: document that Document#validateSync returns ValidationError #7499
+ * refactor: use consolidated `isPOJO()` function instead of constructor checks #7500
+
+5.4.10 / 2019-02-05
+===================
+ * docs: add search bar and /search page #6706
+ * fix: support dotted aliases #7478 [chrischen](https://github.com/chrischen)
+ * fix(document): copy atomics when setting document array to an existing document array #7472
+ * chore: upgrade to mongodb driver 3.1.13 #7488
+ * docs: remove confusing references to executing a query "immediately" #7461
+ * docs(guides+schematypes): link to custom schematypes docs #7407
+
+5.4.9 / 2019-02-01
+==================
+ * fix(document): make `remove()`, `updateOne()`, and `update()` use the document's associated session #7455
+ * fix(document): support passing args to hooked custom methods #7456
+ * fix(document): avoid double calling single nested getters on `toObject()` #7442
+ * fix(discriminator): handle global plugins modifying top-level discriminator options with applyPluginsToDiscriminators: true #7458
+ * docs(documents): improve explanation of documents and use more modern syntax #7463
+ * docs(middleware+api): fix a couple typos in examples #7474 [arniu](https://github.com/arniu)
+
+5.4.8 / 2019-01-30
+==================
+ * fix(query): fix unhandled error when casting object in array filters #7431
+ * fix(query): cast query $elemMatch to discriminator schema if discriminator key set #7449
+ * docs: add table of contents to all guides #7430
+
+5.4.7 / 2019-01-26
+==================
+ * fix(populate): set `populated()` when using virtual populate #7440
+ * fix(discriminator): defer applying plugins to embedded discriminators until model compilation so global plugins work #7435
+ * fix(schema): report correct pathtype underneath map so setting dotted paths underneath maps works #7448
+ * fix: get debug from options using the get helper #7451 #7446 [LucGranato](https://github.com/LucGranato)
+ * fix: use correct variable name #7443 [esben-semmle](https://github.com/esben-semmle)
+ * docs: fix broken QueryCursor link #7438 [shihabmridha](https://github.com/shihabmridha)
+
+5.4.6 / 2019-01-22
+==================
+ * fix(utils): make minimize leave empty objects in arrays instead of setting the array element to undefined #7322
+ * fix(document): support passing `{document, query}` options to Schema#pre(regex) and Schema#post(regex) #7423
+ * docs: add migrating to 5 guide to docs #7434
+ * docs(deprecations): add instructions for fixing `count()` deprecation #7419
+ * docs(middleware): add description and example for aggregate hooks #7402
+
+4.13.18 / 2019-01-21
+====================
+ * fix(model): handle setting populated path set via `Document#populate()` #7302
+ * fix(cast): backport fix from #7290 to 4.x
+
+5.4.5 / 2019-01-18
+==================
+ * fix(populate): handle nested array `foreignField` with virtual populate #7374
+ * fix(query): support not passing any arguments to `orFail()` #7409
+ * docs(query): document what the resolved value for `deleteOne()`, `deleteMany()`, and `remove()` contains #7324
+ * fix(array): allow opting out of converting non-arrays into arrays with `castNonArrays` option #7371
+ * fix(query): ensure updateOne() doesnt unintentionally double call Schema#post(regexp) #7418
+
+5.4.4 / 2019-01-14
+==================
+ * fix(query): run casting on arrayFilters option #7079
+ * fix(document): support skipping timestamps on save() with `save({ timestamps: false })` #7357
+ * fix(model): apply custom where on `Document#remove()` so we attach the shardKey #7393
+ * docs(mongoose): document `mongoose.connections` #7338
+
+5.4.3 / 2019-01-09
+==================
+ * fix(populate): handle `count` option when using `Document#populate()` on a virtual #7380
+ * fix(connection): set connection state to DISCONNECTED if replica set has no primary #7330
+ * fix(mongoose): apply global plugins to schemas nested underneath embedded discriminators #7370
+ * fix(document): make modifiedPaths() return nested paths 1 level down on initial set #7313
+ * fix(plugins): ensure sharding plugin works even if ObjectId has a `valueOf()` #7353
+
+5.4.2 / 2019-01-03
+==================
+ * fix(document): ensure Document#updateOne() returns a query but still calls hooks #7366
+ * fix(query): allow explicitly projecting out populated paths that are automatically projected in #7383
+ * fix(document): support setting `flattenMaps` option for `toObject()` and `toJSON()` at schema level #7274
+ * fix(query): handle merging objectids with `.where()` #7360
+ * fix(schema): copy `.base` when cloning #7377
+ * docs: remove links to plugins.mongoosejs.com in favor of plugins.mongoosejs.io #7364
+
+5.4.1 / 2018-12-26
+==================
+ * fix(document): ensure doc array defaults get casted #7337
+ * fix(document): make `save()` not crash if nested doc has a property 'get' #7316
+ * fix(schema): allow using Schema.Types.Map as well as Map to declare a map type #7305
+ * fix(map): make set after init mark correct path as modified #7321
+ * fix(mongoose): don't recompile model if same collection and schema passed in to `mongoose.model()` #5767
+ * fix(schema): improve error message when type is invalid #7303
+ * fix(schema): add `populated` to reserved property names #7317
+ * fix(model): don't run built-in middleware on custom methods and ensure timestamp hooks don't run if children don't have timestamps set #7342
+ * docs(schematypes): clarify that you can add arbitrary options to a SchemaType #7340
+ * docs(mongoose): clarify that passing same name+schema to `mongoose.model()` returns the model #5767
+ * docs(index): add useNewUrlParser to example #7368 [JIBIN-P](https://github.com/JIBIN-P)
+ * docs(connection): add useNewUrlParser to examples #7362 [JIBIN-P](https://github.com/JIBIN-P)
+ * docs(discriminators): add back missing example from 'recursive embedded discriminators section' #7349
+ * docs(schema): improve docs for string and boolean cast() #7351
+
+5.4.0 / 2018-12-14
+==================
+ * feat(schematype): add `SchemaType.get()`, custom getters across all instances of a schematype #6912
+ * feat(schematype): add `SchemaType.cast()`, configure casting for individual schematypes #7045
+ * feat(schematype): add `SchemaType.checkRequired()`, configure what values pass `required` check for a schematype #7186 #7150
+ * feat(model): add `Model.findOneAndReplace()` #7162
+ * feat(model): add `Model.events` emitter that emits all `error`'s that occur with a given model #7125
+ * feat(populate): add `count` option to populate virtuals, support returning # of populated docs instead of docs themselves #4469
+ * feat(aggregate): add `.catch()` helper to make aggregations full thenables #7267
+ * feat(query): add hooks for `deleteOne()` and `deleteMany()` #7195
+ * feat(document): add hooks for `updateOne()` #7133
+ * feat(query): add `Query#map()` for synchronously transforming results before post middleware runs #7142
+ * feat(schema): support passing an array of objects or schemas to `Schema` constructor #7218
+ * feat(populate): add `clone` option to ensure multiple docs don't share the same populated doc #3258
+ * feat(query): add `Query#maxTimeMS()` helper #7254
+ * fix(query): deprecate broken `Aggregate#addCursorFlag()` #7120
+ * docs(populate): fix incorrect example #7335 [zcfan](https://github.com/zcfan)
+ * docs(middleware): add `findOneAndDelete` to middleware list #7327 [danielkesselberg](https://github.com/danielkesselberg)
+
+5.3.16 / 2018-12-11
+===================
+ * fix(document): handle `__proto__` in queries #7290
+ * fix(document): use Array.isArray() instead of checking constructor name for arrays #7290
+ * docs(populate): add section about what happens when no document matches #7279
+ * fix(mongoose): avoid crash on `import mongoose, {Schema} from 'mongoose'` #5648
+
+5.3.15 / 2018-12-05
+===================
+ * fix(query): handle `orFail()` with `findOneAndUpdate()` and `findOneAndDelete()` #7297 #7280
+ * fix(document): make `save()` succeed if strict: false with a `collection` property #7276
+ * fix(document): add `flattenMaps` option for toObject() #7274
+ * docs(document): document flattenMaps option #7274
+ * fix(populate): support populating individual subdoc path in document array #7273
+ * fix(populate): ensure `model` option overrides `refPath` #7273
+ * fix(map): don't call subdoc setters on init #7272
+ * fix(document): use internal get() helper instead of lodash.get to support `null` projection param #7271
+ * fix(document): continue running validateSync() for all elements in doc array after first error #6746
+
+5.3.14 / 2018-11-27
+===================
+ * docs(api): use `openUri()` instead of legacy `open()` #7277 [artemjackson](https://github.com/artemjackson)
+ * fix(document): don't mark date underneath single nested as modified if setting to string #7264
+ * fix(update): set timestamps on subdocs if not using $set with no overwrite #7261
+ * fix(document): use symbol instead of `__parent` so user code doesn't conflict #7230
+ * fix(mongoose): allow using `mongoose.model()` without context, like `import {model} from 'mongoose'` #3768
+
+5.3.13 / 2018-11-20
+===================
+ * fix: bump mongodb driver -> 3.1.10 #7266
+ * fix(populate): support setting a model as a `ref` #7253
+ * docs(schematype): add ref() function to document what is a valid `ref` path in a schematype #7253
+ * fix(array): clean modified subpaths when calling `splice()` #7249
+ * docs(compatibility): don't show Mongoose 4.11 as compatible with MongoDB 3.6 re: MongoDB's official compatibility table #7248 [a-harrison](https://github.com/a-harrison)
+ * fix(document): report correct validation error if doc array set to primitive #7242
+ * fix(mongoose): print warning when including server-side lib with jest jsdom environment #7240
+
+5.3.12 / 2018-11-13
+===================
+ * docs(compatibility): don't show Mongoose 4.11 as compatible with MongoDB 3.6 re: MongoDB's official compatibility table #7238 [a-harrison](https://github.com/a-harrison)
+ * fix(populate): use `instanceof` rather than class name for comparison #7237 [ivanseidel](https://github.com/ivanseidel)
+ * docs(api): make options show up as a nested list #7232
+ * fix(document): don't mark array as modified on init if doc array has default #7227
+ * docs(api): link to bulk write result object in `bulkWrite()` docs #7225
+
+5.3.11 / 2018-11-09
+===================
+ * fix(model): make parent pointers non-enumerable so they don't crash JSON.stringify() #7220
+ * fix(document): allow saving docs with nested props with '.' using `checkKeys: false` #7144
+ * docs(lambda): use async/await with lambda example #7019
+
+5.3.10 / 2018-11-06
+===================
+ * fix(discriminator): support reusing a schema for multiple discriminators #7200
+ * fix(cursor): handle `lean(false)` correctly with query cursors #7197
+ * fix(document): avoid manual populate if `ref` not set #7193
+ * fix(schema): handle schema without `.base` for browser build #7170
+ * docs: add further reading section
+
+5.3.9 / 2018-11-02
+==================
+ * fix: upgrade bson dep -> 1.1.0 to match mongodb-core #7213 [NewEraCracker](https://github.com/NewEraCracker)
+ * docs(api): fix broken anchor link #7210 [gfranco93](https://github.com/gfranco93)
+ * fix: don't set parent timestamps because a child has timestamps set to false #7203 #7202 [lineus](https://github.com/lineus)
+ * fix(document): run setter only once when doing `.set()` underneath a single nested subdoc #7196
+ * fix(document): surface errors in subdoc pre validate #7187
+ * fix(query): run default functions after hydrating the loaded document #7182
+ * fix(query): handle strictQuery: 'throw' with nested path correctly #7178
+ * fix(update): update timestamps on replaceOne() #7152
+ * docs(transactions): add example of aborting a transaction #7113
+
+5.3.8 / 2018-10-30
+==================
+ * fix: bump mongodb driver -> 3.1.8 to fix connecting to +srv uri with no credentials #7191 #6881 [lineus](https://github.com/lineus)
+ * fix(document): sets defaults correctly in child docs with projection #7159
+ * fix(mongoose): handle setting custom type on a separate mongoose global #7158
+ * fix: add unnecessary files to npmignore #7157
+ * fix(model): set session when creating new subdoc #7104
+
+5.3.7 / 2018-10-26
+==================
+ * fix(browser): fix buffer usage in browser build #7184 #7173 [lineus](https://github.com/lineus)
+ * fix(document): make depopulate() work on populate virtuals and unpopulated docs #7180 #6075 [lineus](https://github.com/lineus)
+ * fix(document): only pass properties as 2nd arg to custom validator if `propsParameter` set #7145
+ * docs(schematypes): add note about nested paths with `type` getting converted to mixed #7143
+ * fix(update): run update validators on nested doc when $set on an array #7135
+ * fix(update): copy exact errors from array subdoc validation into top-level update validator error #7135
+
+5.3.6 / 2018-10-23
+==================
+ * fix(cursor): fix undefined transforms error
+
+5.3.5 / 2018-10-22
+==================
+ * fix(model): make sure versionKey on `replaceOne()` always gets set at top level to prevent cast errors #7138
+ * fix(cursor): handle non-boolean lean option in `eachAsync()` #7137
+ * fix(update): correct cast update that overwrites a map #7111
+ * fix(schema): handle arrays of mixed correctly #7109
+ * fix(query): use correct path when getting schema for child timestamp update #7106
+ * fix(document): make `$session()` propagate sessions to child docs #7104
+ * fix(document): handle user setting `schema.options.strict = 'throw'` #7103
+ * fix(types): use core Node.js buffer prototype instead of safe-buffer because safe-buffer is broken for Node.js 4.x #7102
+ * fix(document): handle setting single doc with refPath to document #7070
+ * fix(model): handle array filters when updating timestamps for subdocs #7032
+
+5.3.4 / 2018-10-15
+==================
+ * fix(schema): make `add()` and `remove()` return the schema instance #7131 [lineus](https://github.com/lineus)
+ * fix(query): don't require passing model to `cast()` #7118
+ * fix: support `useFindAndModify` as a connection-level option #7110 [lineus](https://github.com/lineus)
+ * fix(populate): handle plus path projection with virtual populate #7050
+ * fix(schema): allow using ObjectId type as schema path type #7049
+ * docs(schematypes): elaborate on how schematypes relate to types #7049
+ * docs(deprecations): add note about gridstore deprecation #6922
+ * docs(guide): add storeSubdocValidationError option to guide #6802
+
+5.3.3 / 2018-10-12
+==================
+ * fix(document): enable storing mongoose validation error in MongoDB by removing `$isValidatorError` property #7127
+ * docs(api): clarify that aggregate triggers aggregate middleware #7126 [lineus](https://github.com/lineus)
+ * fix(connection): handle Model.init() when an index exists on schema + autoCreate == true #7122 [jesstelford](https://github.com/jesstelford)
+ * docs(middleware): explain how to switch between document and query hooks for `remove()` #7093
+ * docs(api): clean up encoding issues in SchemaType.prototype.validate docs #7091
+ * docs(schema): add schema types to api docs and update links on schematypes page #7080 #7076 [lineus](https://github.com/lineus)
+ * docs(model): expand model constructor docs with examples and `fields` param #7077
+ * docs(aggregate): remove incorrect description of noCursorTimeout and add description of aggregate options #7056
+ * docs: re-add array type to API docs #7027
+ * docs(connections): add note about `members.host` errors due to bad host names in replica set #7006
+
+5.3.2 / 2018-10-07
+==================
+ * fix(query): make sure to return correct result from `orFail()` #7101 #7099 [gsandorx](https://github.com/gsandorx)
+ * fix(schema): handle `{ timestamps: false }` correctly #7088 #7074 [lineus](https://github.com/lineus)
+ * docs: fix markdown in options.useCreateIndex documentation #7085 [Cyral](https://github.com/Cyral)
+ * docs(schema): correct field name in timestamps example #7082 [kizmo04](https://github.com/kizmo04)
+ * docs(migrating_to_5): correct markdown syntax #7078 [gwuah](https://github.com/gwuah)
+ * fix(connection): add useFindAndModify option in connect #7059 [NormanPerrin](https://github.com/NormanPerrin)
+ * fix(document): dont mark single nested path as modified if setting to the same value #7048
+ * fix(populate): use WeakMap to track lean populate models rather than leanPopulateSymbol #7026
+ * fix(mongoose): avoid unhandled rejection when `mongoose.connect()` errors with a callback #6997
+ * fix(mongoose): isolate Schema.Types between custom Mongoose instances #6933
+
+5.3.1 / 2018-10-02
+==================
+ * fix(ChangeStream): expose driver's `close()` function #7068 #7022 [lineus](https://github.com/lineus)
+ * fix(model): avoid printing warning if `_id` index is set to "hashed" #7053
+ * fix(populate): handle nested populate underneath lean array correctly #7052
+ * fix(update): make timestamps not crash on a null or undefined update #7041
+ * docs(schematypes+validation): clean up links from validation docs to schematypes docs #7040
+ * fix(model): apply timestamps to nested docs in bulkWrite() #7032
+ * docs(populate): rewrite refPath docs to be simpler and more direct #7013
+ * docs(faq): explain why destructuring imports are not supported in FAQ #7009
+
+5.3.0 / 2018-09-28
+==================
+ * feat(mongoose): support `mongoose.set('debug', WritableStream)` so you can pipe debug to stderr, file, or network #7018
+ * feat(query): add useNestedStrict option #6973 #5144 [lineus](https://github.com/lineus)
+ * feat(query): add getPopulatedPaths helper to Query.prototype #6970 #6677 [lineus](https://github.com/lineus)
+ * feat(model): add `createCollection()` helper to make transactions easier #6948 #6711 [Fonger](https://github.com/Fonger)
+ * feat(schema): add ability to do `schema.add(otherSchema)` to merge hooks, virtuals, etc. #6897
+ * feat(query): add `orFail()` helper that throws an error if no documents match `filter` #6841
+ * feat(mongoose): support global toObject and toJSON #6815
+ * feat(connection): add deleteModel() to remove a model from a connection #6813
+ * feat(mongoose): add top-level mongoose.ObjectId, mongoose.Decimal128 for easier schema declarations #6760
+ * feat(aggregate+query): support for/await/of (async iterators) #6737
+ * feat(mongoose): add global `now()` function that you can stub for testing timestamps #6728
+ * feat(schema): support `schema.pre(RegExp, fn)` and `schema.post(RegExp, fn)` #6680
+ * docs(query): add better docs for the `mongooseOptions()` function #6677
+ * feat(mongoose): add support for global strict object #6858
+ * feat(schema+mongoose): add autoCreate option to automatically create collections #6489
+ * feat(update): update timestamps on nested subdocs when using `$set` #4412
+ * feat(query+schema): add query `remove` hook and ability to switch between query `remove` and document `remove` middleware #3054
+
+5.2.18 / 2018-09-27
+===================
+ * docs(migrating_to_5): add note about overwriting filter properties #7030
+ * fix(query): correctly handle `select('+c')` if c is not in schema #7017
+ * fix(document): check path exists before checking for required #6974
+ * fix(document): retain user-defined key order on initial set with nested docs #6944
+ * fix(populate): handle multiple localFields + foreignFields using `localField: function() {}` syntax #5704
+
+5.2.17 / 2018-09-21
+===================
+ * docs(guide): clarify that Mongoose only increments versionKey on `save()` and add a workaround for `findOneAndUpdate()` #7038
+ * fix(model): correctly handle `createIndex` option to `ensureIndexes()` #7036 #6922 [lineus](https://github.com/lineus)
+ * docs(migrating_to_5): add a note about changing debug output from stderr to stdout #7034 #7018 [lineus](https://github.com/lineus)
+ * fix(query): add `setUpdate()` to allow overwriting update without changing op #7024 #7012 [lineus](https://github.com/lineus)
+ * fix(update): find top-level version key even if there are `$` operators in the update #7003
+ * docs(model+query): explain which operators `count()` supports that `countDocuments()` doesn't #6911
+
+5.2.16 / 2018-09-19
+===================
+ * fix(index): use dynamic require only when needed for better webpack support #7014 #7010 [jaydp17](https://github.com/jaydp17)
+ * fix(map): handle arrays of mixed maps #6995
+ * fix(populate): leave justOne as null if populating underneath a Mixed type #6985
+ * fix(populate): add justOne option to allow overriding any bugs with justOne #6985
+ * fix(query): add option to skip adding timestamps to an update #6980
+ * docs(model+schematype): improve docs about background indexes and init() #6966
+ * fix: bump mongodb -> 3.1.6 to allow connecting to srv url without credentials #6955 #6881 [lineus](https://github.com/lineus)
+ * fix(connection): allow specifying `useCreateIndex` at the connection level, overrides global-level #6922
+ * fix(schema): throw a helpful error if setting `ref` to an invalid value #6915
+
+5.2.15 / 2018-09-15
+===================
+ * fix(populate): handle virtual justOne correctly if it isn't set #6988
+ * fix(populate): consistently use lowercase `model` instead of `Model` so double-populating works with existing docs #6978
+ * fix(model): allow calling `Model.init()` again after calling `dropDatabase()` #6967
+ * fix(populate): find correct justOne when double-populating underneath an array #6798
+ * docs(webpack): make webpack docs use es2015 preset for correct libs and use acorn to test output is valid ES5 #6740
+ * fix(populate): add selectPopulatedPaths option to opt out of auto-adding `populate()`-ed fields to `select()` #6546
+ * fix(model): set timestamps on bulkWrite `insertOne` and `replaceOne` #5708
+
+5.2.14 / 2018-09-09
+===================
+ * docs: fix wording on promise docs to not imply queries only return promises #6983 #6982 [lineus](https://github.com/lineus)
+ * fix(map): throw TypeError if keys are not string #6956
+ * fix(document): ensure you can `validate()` a child doc #6931
+ * fix(populate): avoid cast error if refPath points to localFields with 2 different types #6870
+ * fix(populate): handle populating already-populated paths #6839
+ * fix(schematype): make ObjectIds handle refPaths when checking required #6714
+ * fix(model): set timestamps on bulkWrite() updates #5708
+
+5.2.13 / 2018-09-04
+===================
+ * fix(map): throw TypeError if keys are not string #6968 [Fonger](https://github.com/Fonger)
+ * fix(update): make array op casting work with strict:false and {} #6962 #6952 [lineus](https://github.com/lineus)
+ * fix(document): add doc.deleteOne(), doc.updateOne(), doc.replaceOne() re: deprecation warnings #6959 #6940 [lineus](https://github.com/lineus)
+ * docs(faq+schematypes): add note about map keys needing to be strings #6957 #6956 [lineus](https://github.com/lineus)
+ * fix(schematype): remove unused if statement #6950 #6949 [cacothi](https://github.com/cacothi)
+ * docs: add /docs/deprecations.html for dealing with MongoDB driver deprecation warnings #6922
+ * fix(populate): handle refPath where first element in array has no refPath #6913
+ * fix(mongoose): allow setting useCreateIndex option after creating a model but before initial connection succeeds #6890
+ * fix(updateValidators): ensure $pull validators always get an array #6889
+
+5.2.12 / 2018-08-30
+===================
+ * fix(document): disallow setting `constructor` and `prototype` if strict mode false
+
+4.13.17 / 2018-08-30
+====================
+ * fix(document): disallow setting `constructor` and `prototype` if strict mode false
+
+5.2.11 / 2018-08-30
+===================
+ * fix(document): disallow setting __proto__ if strict mode false
+ * fix(document): run document middleware on docs embedded in maps #6945 #6938 [Fonger](https://github.com/Fonger)
+ * fix(query): make castForQuery return a CastError #6943 #6927 [lineus](https://github.com/lineus)
+ * fix(query): use correct `this` scope when casting query with legacy 2dsphere pairs defined in schema #6939 #6937 [Fonger](https://github.com/Fonger)
+ * fix(document): avoid crash when calling `get()` on deeply nested subdocs #6929 #6925 [jakemccloskey](https://github.com/jakemccloskey)
+ * fix(plugins): make saveSubdocs execute child post save hooks _after_ the actual save #6926
+ * docs: add dbName to api docs for .connect() #6923 [p722](https://github.com/p722)
+ * fix(populate): convert to array when schema specifies array, even if doc doesn't have an array #6908
+ * fix(populate): handle `justOne` virtual populate underneath array #6867
+ * fix(model): dont set versionKey on upsert if it is already `$set` #5973
+
+4.13.16 / 2018-08-30
+====================
+ * fix(document): disallow setting __proto__ if strict mode false
+ * feat(error): backport adding modified paths to VersionError #6928 [freewil](https://github.com/freewil)
+
+5.2.10 / 2018-08-27
+===================
+ * fix: bump mongodb driver -> 3.1.4 #6920 #6903 #6884 #6799 #6741 [Fonger](https://github.com/Fonger)
+ * fix(model): track `session` option for `save()` as the document's `$session()` #6909
+ * fix(query): add Query.getOptions() helper #6907 [Fonger](https://github.com/Fonger)
+ * fix(document): ensure array atomics get cleared after save() #6900
+ * fix(aggregate): add missing redact and readConcern helpers #6895 [Fonger](https://github.com/Fonger)
+ * fix: add global option `mongoose.set('useCreateIndex', true)` to avoid ensureIndex deprecation warning #6890
+ * fix(query): use `projection` option to avoid deprecation warnings #6888 #6880 [Fonger](https://github.com/Fonger)
+ * fix(query): use `findOneAndReplace()` internally if using `overwrite: true` with `findOneAndUpdate()` #6888 [Fonger](https://github.com/Fonger)
+ * fix(document): ensure required cache gets cleared correctly between subsequent saves #6892
+ * fix(aggregate): support session chaining correctly #6886 #6885 [Fonger](https://github.com/Fonger)
+ * fix(query): use `projection` instead of `fields` internally for `find()` and `findOne()` to avoid deprecation warning #6880
+ * fix(populate): add `getters` option to opt in to calling getters on populate #6844
+
+5.2.9 / 2018-08-17
+==================
+ * fix(document): correctly propagate write concern options in save() #6877 [Fonger](https://github.com/Fonger)
+ * fix: upgrade mongodb driver -> 3.1.3 for numerous fixes #6869 #6843 #6692 #6670 [simllll](https://github.com/simllll)
+ * fix: correct `this` scope of default functions for DocumentArray and Array #6868 #6840 [Fonger](https://github.com/Fonger)
+ * fix(types): support casting JSON form of buffers #6866 #6863 [Fonger](https://github.com/Fonger)
+ * fix(query): get global runValidators option correctly #6865 #6578
+ * fix(query): add Query.prototype.setQuery() analogous to `getQuery()` #6855 #6854
+ * docs(connections): add note about the `family` option for IPv4 vs IPv6 and add port to example URIs #6784
+ * fix(query): get global runValidators option correctly #6578
+
+4.13.15 / 2018-08-14
+====================
+ * fix(mongoose): add global `usePushEach` option for easier Mongoose 4.x + MongoDB 3.6 #6858
+ * chore: fix flakey tests for 4.x #6853 [Fonger](https://github.com/Fonger)
+ * feat(error): add version number to VersionError #6852 [freewil](https://github.com/freewil)
+
+5.2.8 / 2018-08-13
+==================
+ * docs: update `execPopulate()` code example #6851 [WJakub](https://github.com/WJakub)
+ * fix(document): allow passing callback to `execPopulate()` #6851
+ * fix(populate): populate with undefined fields without error #6848 #6845 [Fonger](https://github.com/Fonger)
+ * docs(migrating_to_5): Add `objectIdGetter` option docs #6842 [jwalton](https://github.com/jwalton)
+ * chore: run lint in parallel and only on Node.js v10 #6836 [Fonger](https://github.com/Fonger)
+ * fix(populate): throw helpful error if refPath excluded in query #6834
+ * docs(migrating_to_5): add note about removing runSettersOnQuery #6832
+ * fix: use safe-buffer to avoid buffer deprecation errors in Node.js 10 #6829 [Fonger](https://github.com/Fonger)
+ * docs(query): fix broken links #6828 [yaynick](https://github.com/yaynick)
+ * docs(defaults): clarify that defaults only run on undefined #6827
+ * chore: fix flakey tests #6824 [Fonger](https://github.com/Fonger)
+ * docs: fix custom inspect function deprecation warning in Node.js 10 #6821 [yelworc](https://github.com/yelworc)
+ * fix(document): ensure subdocs get set to init state after save() so validators can run again #6818
+ * fix(query): make sure embedded query casting always throws a CastError #6803
+ * fix(document): ensure `required` function only gets called once when validating #6801
+ * docs(connections): note that you must specify port if using `useNewUrlParser: true` #6789
+ * fix(populate): support `options.match` in virtual populate schema definition #6787
+ * fix(update): strip out virtuals from updates if strict: 'throw' rather than returning an error #6731
+
+5.2.7 / 2018-08-06
+==================
+ * fix(model): check `expireAfterSeconds` option when diffing indexes in syncIndexes() #6820 #6819 [christopherhex](https://github.com/christopherhex)
+ * chore: fix some common test flakes in travis #6816 [Fonger](https://github.com/Fonger)
+ * chore: bump eslint and webpack to avoid bad versions of eslint-scope #6814
+ * test(model): add delay to session tests to improve pass rate #6811 [Fonger](https://github.com/Fonger)
+ * fix(model): support options in `deleteMany` #6810 [Fonger](https://github.com/Fonger)
+ * fix(query): don't use $each when pushing an array into an array #6809 [lineus](https://github.com/lineus)
+ * chore: bump mquery so eslint isn't a prod dependency #6800
+ * fix(populate): correctly get schema type when calling `populate()` on already populated path #6798
+ * fix(populate): propagate readConcern options in populate from parent query #6792 #6785 [Fonger](https://github.com/Fonger)
+ * docs(connection): add description of useNewUrlParser option #6789
+ * fix(query): make select('+path') a no-op if no select prop in schema #6785
+ * docs(schematype+validation): document using function syntax for custom validator message #6772
+ * fix(update): throw CastError if updating with `$inc: null` #6770
+ * fix(connection): throw helpful error when calling `createConnection(undefined)` #6763
+
+5.2.6 / 2018-07-30
+==================
+ * fix(document): don't double-call deeply nested custom getters when using `get()` #6779 #6637
+ * fix(query): upgrade mquery for readConcern() helper #6777
+ * docs(schematypes): clean up typos #6773 [sajadtorkamani](https://github.com/sajadtorkamani)
+ * refactor(browser): fix webpack warnings #6771 #6705
+ * fix(populate): make error reported when no `localField` specified catchable #6767
+ * docs(connection): use correct form in createConnection example #6766 [lineus](https://github.com/lineus)
+ * fix(connection): throw helpful error when using legacy `mongoose.connect()` syntax #6756
+ * fix(document): handle overwriting `$session` in `execPopulate()` #6754
+ * fix(query): propagate top-level session down to `populate()` #6754
+ * fix(aggregate): add `session()` helper for consistency with query api #6752
+ * fix(map): avoid infinite recursion when update overwrites a map #6750
+ * fix(model): be consistent about passing noop callback to mongoose.model() `init()` as well as db.model() #6707
+
+5.2.5 / 2018-07-23
+==================
+ * fix(boolean): expose `convertToTrue` and `convertToFalse` for custom boolean casting #6758
+ * docs(schematypes): add note about what values are converted to booleans #6758
+ * fix(document): fix(document): report castError when setting single nested doc to array #6753
+ * docs: prefix mongoose.Schema call with new operator #6751 [sajadtorkamani](https://github.com/sajadtorkamani)
+ * docs(query): add examples and links to schema writeConcern option for writeConcern helpers #6748
+ * docs(middleware): clarify that init middleware is sync #6747
+ * perf(model): create error rather than modifying stack for source map perf #6735
+ * fix(model): throw helpful error when passing object to aggregate() #6732
+ * fix(model): pass Model instance as context to applyGetters when calling getters for virtual populate #6726 [lineus](https://github.com/lineus)
+ * fix(documentarray): remove `isNew` and `save` listeners on CastError because otherwise they never get removed #6723
+ * docs(model+query): clarify when to use `countDocuments()` vs `estimatedDocumentCount()` #6713
+ * fix(populate): correctly set virtual nestedSchemaPath when calling populate() multiple times #6644
+ * docs(connections): add note about the `family` option for IPv4 vs IPv6 and add port to example URIs #6566
+
+5.2.4 / 2018-07-16
+==================
+ * docs: Model.insertMany rawResult option in api docs #6724 [lineus](https://github.com/lineus)
+ * docs: fix typo on migrating to 5 guide #6722 [iagowp](https://github.com/iagowp)
+ * docs: update doc about keepalive #6719 #6718 [simllll](https://github.com/simllll)
+ * fix: ensure debug mode doesn't crash with sessions #6712
+ * fix(document): report castError when setting single nested doc to primitive value #6710
+ * fix(connection): throw helpful error if using `new db.model(foo)(bar)` #6698
+ * fix(model): throw readable error with better stack trace when non-cb passed to $wrapCallback() #6640
+
+5.2.3 / 2018-07-11
+==================
+ * fix(populate): if a getter is defined on the localField, use it when populating #6702 #6618 [lineus](https://github.com/lineus)
+ * docs(schema): add example of nested aliases #6671
+ * fix(query): add `session()` function to queries to avoid positional argument mistakes #6663
+ * docs(transactions): use new session() helper to make positional args less confusing #6663
+ * fix(query+model+schema): add support for `writeConcern` option and writeConcern helpers #6620
+ * docs(guide): add `writeConcern` option and re-add description for `safe` option #6620
+ * docs(schema): fix broken API links #6619
+ * docs(connections): add information re: socketTimeoutMS and connectTimeoutMS #4789
+
+5.2.2 / 2018-07-08
+==================
+ * fix(model+query): add missing estimatedDocumentCount() function #6697
+ * docs(faq): improve array-defaults section #6695 [lineus](https://github.com/lineus)
+ * docs(model): fix countDocuments() docs, bad copy/paste from count() docs #6694 #6643
+ * fix(connection): add `startSession()` helper to connection and mongoose global #6689
+ * fix: upgrade mongodb driver -> 3.1.1 for countDocuments() fix #6688 #6666
+ * docs(compatibility): add MongoDB 4 range #6685
+ * fix(populate): add ability to define refPath as a function #6683 [lineus](https://github.com/lineus)
+ * docs: add rudimentary transactions guide #6672
+ * fix(update): make setDefaultsOnInsert handle nested subdoc updates with deeply nested defaults #6665
+ * docs: use latest acquit-ignore to handle examples that start with acquit:ignore:start #6657
+ * fix(validation): format `properties.message` as well as `message` #6621
+
+5.2.1 / 2018-07-03
+==================
+ * fix(connection): allow setting the mongodb driver's useNewUrlParser option, default to false #6656 #6648 #6647
+ * fix(model): only warn on custom _id index if index only has _id key #6650
+
+5.2.0 / 2018-07-02
+==================
+ * feat(model): add `countDocuments()` #6643
+ * feat(model): make ensureIndexes() fail if specifying an index on _id #6605
+ * feat(mongoose): add `objectIdGetter` option to remove ObjectId.prototype._id #6588
+ * feat: upgrade mongodb -> 3.1.0 for full MongoDB 4.0 support #6579
+ * feat(query): support `runValidators` as a global option #6578
+ * perf(schema): use WeakMap instead of array for schema stack #6503
+ * feat(model): decorate unique discriminator indexes with partialFilterExpressions #6347
+ * feat(model): add `syncIndexes()`, drops indexes that aren't in schema #6281
+ * feat(document): add default getter/setter if virtual doesn't have one #6262
+ * feat(discriminator): support discriminators on nested doc arrays #6202
+ * feat(update): add `Query.prototype.set()` #5770
+
+5.1.8 / 2018-07-02
+==================
+ * fix: don't throw TypeError if calling save() after original save() failed with push() #6638 [evanhenke](https://github.com/evanhenke)
+ * fix(query): add explain() helper and don't hydrate explain output #6625
+ * docs(query): fix `setOptions()` lists #6624
+ * docs: add geojson docs #6607
+ * fix: bump mongodb -> 3.0.11 to avoid cyclic dependency error with retryWrites #6109
+
+5.1.7 / 2018-06-26
+==================
+ * docs: add npm badge to readme #6623 [VFedyk](https://github.com/VFedyk)
+ * fix(document): don't throw parallel save error if post save hooks in parallel #6614 #6611 [lineus](https://github.com/lineus)
+ * fix(populate): allow dynamic ref to handle >1 model getModelsMapForPopulate #6613 #6612 [jimmytsao](https://github.com/jimmytsao)
+ * fix(document): handle `push()` on triple nested document array #6602
+ * docs(validation): improve update validator doc headers #6577 [joeytwiddle](https://github.com/joeytwiddle)
+ * fix(document): handle document arrays in `modifiedPaths()` with includeChildren option #5904
+
+5.1.6 / 2018-06-19
+==================
+ * fix: upgrade mongodb -> 3.0.10
+ * docs(model+document): clarify that `save()` returns `undefined` if passed a callback #6604 [lineus](https://github.com/lineus)
+ * fix(schema): apply alias when adding fields with .add() #6593
+ * docs: add full list of guides and streamline nav #6592
+ * docs(model): add `projection` option to `findOneAndUpdate()` #6590 [lineus](https://github.com/lineus)
+ * docs: support @static JSDoc declaration #6584
+ * fix(query): use boolean casting logic for $exists #6581
+ * fix(query): cast all $text options to correct values #6581
+ * fix(model): add support synchronous pre hooks for `createModel` #6552 [profbiss](https://github.com/profbiss)
+ * docs: add note about the `applyPluginsToDiscriminators` option #4965
+
+5.1.5 / 2018-06-11
+==================
+ * docs(guide): rework query helper example #6575 [lineus](https://github.com/lineus)
+ * fix(populate): handle virtual populate with embedded discriminator under single nested subdoc #6571
+ * docs: add string option to projections that call query select #6563 [lineus](https://github.com/lineus)
+ * style: use ES6 in collection.js #6560 [l33ds](https://github.com/l33ds)
+ * fix(populate): add virtual ref function ability getModelsMapForPopulate #6559 #6554 [lineus](https://github.com/lineus)
+ * docs(queries): fix link #6557 [sun1x](https://github.com/sun1x)
+ * fix(schema): rename indexes -> getIndexes to avoid webpack duplicate declaration #6547
+ * fix(document): support `toString()` as custom method #6538
+ * docs: add @instance for instance methods to be more compliant with JSDoc #6516 [treble-snake](https://github.com/treble-snake)
+ * fix(populate): avoid converting to map when using mongoose-deep-populate #6460
+ * docs(browser): create new browser docs page #6061
+
+5.1.4 / 2018-06-04
+==================
+ * docs(faq): add hr tags for parallel save error #6550 [lineus](https://github.com/lineus)
+ * docs(connection): fix broken link #6545 [iblamefish](https://github.com/iblamefish)
+ * fix(populate): honor subpopulate options #6539 #6528 [lineus](https://github.com/lineus)
+ * fix(populate): allow population of refpath under array #6537 #6509 [lineus](https://github.com/lineus)
+ * fix(query): dont treat $set the same as the other ops in update casting #6535 [lineus](https://github.com/lineus)
+ * fix: bump async -> 2.6.1 #6534 #6505 [lineus](https://github.com/lineus)
+ * fix: support using a function as validation error message #6530 [lucandrade](https://github.com/lucandrade)
+ * fix(populate): propagate `lean()` down to subpopulate #6498 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * docs(lambda): add info on what happens if database does down between lambda function calls #6409
+ * fix(update): allow updating embedded discriminator path if discriminator key is in filter #5841
+
+5.1.3 / 2018-05-28
+==================
+ * fix(document): support set() on path underneath array embedded discriminator #6526
+ * chore: update lodash and nsp dev dependencies #6514 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix(document): throw readable error when saving the same doc instance more than once in parallel #6511 #6456 #4064 [lineus](https://github.com/lineus)
+ * fix(populate): set correct nestedSchemaPath for virtual underneath embedded discriminator #6501 #6487 [lineus](https://github.com/lineus)
+ * docs(query): add section on promises and warning about not mixing promises and callbacks #6495
+ * docs(connection): add concrete example of connecting to multiple hosts #6492 [lineus](https://github.com/lineus)
+ * fix(populate): handle virtual populate under single nested doc under embedded discriminator #6488
+ * fix(schema): collect indexes from embedded discriminators for autoIndex build #6485
+ * fix(document): handle `doc.set()` underneath embedded discriminator #6482
+ * fix(document): handle set() on path under embedded discriminator with object syntax #6482
+ * fix(document): handle setting nested property to object with only non-schema properties #6436
+
+4.13.14 / 2018-05-25
+====================
+ * fix(model): handle retainKeyOrder option in findOneAndUpdate() #6484
+
+5.1.2 / 2018-05-21
+==================
+ * docs(guide): add missing SchemaTypes #6490 [distancesprinter](https://github.com/distancesprinter)
+ * fix(map): make MongooseMap.toJSON return a serialized object #6486 #6478 [lineus](https://github.com/lineus)
+ * fix(query): make CustomQuery inherit from model.Query for hooks #6483 #6455 [lineus](https://github.com/lineus)
+ * fix(document): prevent default falses from being skipped by $__dirty #6481 #6477 [lineus](https://github.com/lineus)
+ * docs(connection): document `useDb()` #6480
+ * fix(model): skip redundant clone in insertMany #6479 [d1manson](https://github.com/d1manson)
+ * fix(aggregate): let replaceRoot accept objects as well as strings #6475 #6474 [lineus](https://github.com/lineus)
+ * docs(model): clarify `emit()` in mapReduce and how map/reduce are run #6465
+ * fix(populate): flatten array to handle multi-level nested `refPath` #6457
+ * fix(date): cast small numeric strings as years #6444 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
+ * fix(populate): remove unmatched ids when using virtual populate on already hydrated document #6435
+ * fix(array): use custom array class to avoid clobbered property names #6431
+ * fix(model): handle hooks for custom methods that return promises #6385
+
+4.13.13 / 2018-05-17
+====================
+ * fix(update): stop clobbering $in when casting update #6441 #6339
+ * fix: upgrade async -> 2.6.0 re: security warning
+
+5.1.1 / 2018-05-14
+==================
+ * docs(schema): add notes in api and guide about schema.methods object #6470 #6440 [lineus](https://github.com/lineus)
+ * fix(error): add modified paths to VersionError #6464 #6433 [paglias](https://github.com/paglias)
+ * fix(populate): only call populate with full param signature when match is not present #6458 #6451 [lineus](https://github.com/lineus)
+ * docs: fix geoNear link in migration guide #6450 [kawache](https://github.com/kawache)
+ * fix(discriminator): throw readable error when `create()` with a non-existent discriminator key #6434
+ * fix(populate): add `retainNullValues` option to avoid stripping out null keys #6432
+ * fix(populate): handle populate in embedded discriminators underneath nested paths #6411
+ * docs(model): add change streams and ToC, make terminology more consistent #5888
+
+5.1.0 / 2018-05-10
+==================
+ * feat(ObjectId): add `_id` getter so you can get a usable id whether or not the path is populated #6415 #6115
+ * feat(model): add Model.startSession() #6362
+ * feat(document): add doc.$session() and set session on doc after query #6362
+ * feat: add Map type that supports arbitrary keys #6287 #681
+ * feat: add `cloneSchemas` option to mongoose global to opt in to always cloning schemas before use #6274
+ * feat(model): add `findOneAndDelete()` and `findByIdAndDelete()` #6164
+ * feat(document): support `$ignore()` on single nested and array subdocs #6152
+ * feat(document): add warning about calling `save()` on subdocs #6152
+ * fix(model): make `save()` use `updateOne()` instead of `update()` #6031
+ * feat(error): add version number to VersionError #5966
+ * fix(query): allow `[]` as a value for `$in` when casting #5913
+ * fix(document): avoid running validators on single nested paths if only a child path is modified #5885
+ * feat(schema): print warning if method conflicts with mongoose internals #5860
+
+5.0.18 / 2018-05-09
+===================
+ * fix(update): stop clobbering $in when casting update #6441 #6339 [lineus](https://github.com/lineus)
+ * fix: upgrade mongodb driver -> 3.0.8 to fix session issue #6437 #6357 [simllll](https://github.com/simllll)
+ * fix: upgrade bson -> 1.0.5 re: https://snyk.io/vuln/npm:bson:20180225 #6423 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix: look for `valueOf()` when casting to Decimal128 #6419 #6418 [lineus](https://github.com/lineus)
+ * fix: populate array of objects with space separated paths #6414 [lineus](https://github.com/lineus)
+ * test: add coverage for `mongoose.pluralize()` #6412 [FastDeath](https://github.com/FastDeath)
+ * fix(document): avoid running default functions on init() if path has value #6410
+ * fix(document): allow saving document with `null` id #6406
+ * fix: prevent casting of populated docs in document.init #6390 [lineus](https://github.com/lineus)
+ * fix: remove `toHexString()` helper that was added in 5.0.15 #6359
+
+5.0.17 / 2018-04-30
+===================
+ * docs(migration): certain chars in passwords may cause connection failures #6401 [markstos](https://github.com/markstos)
+ * fix(document): don't throw when `push()` on a nested doc array #6398
+ * fix(model): apply hooks to custom methods if specified #6385
+ * fix(schema): support opting out of one timestamp field but not the other for `insertMany()` #6381
+ * fix(documentarray): handle `required: true` within documentarray definition #6364
+ * fix(document): ensure `isNew` is set before default functions run on init #3793
+
+5.0.16 / 2018-04-23
+===================
+ * docs(api): sort api methods based on their string property #6374 [lineus](https://github.com/lineus)
+ * docs(connection): fix typo in `createCollection()` #6370 [mattc41190](https://github.com/mattc41190)
+ * docs(document): remove vestigial reference to `numAffected` #6367 [ekulabuhov](https://github.com/ekulabuhov)
+ * docs(schema): fix typo #6366 [dhritzkiv](https://github.com/dhritzkiv)
+ * docs(schematypes): add missing `minlength` and `maxlength` docs #6365 [treble-snake](https://github.com/treble-snake)
+ * docs(queries): fix formatting #6360 [treble-snake](https://github.com/treble-snake)
+ * docs(api): add cursors to API docs #6353 #6344 [lineus](https://github.com/lineus)
+ * docs(aggregate): remove reference to non-existent `.select()` method #6346
+ * fix(update): handle `required` array with update validators and $pull #6341
+ * fix(update): avoid setting __v in findOneAndUpdate if it is `$set` #5973
+
+5.0.15 / 2018-04-16
+===================
+ * fix: add ability for casting from number to decimal128 #6336 #6331 [lineus](https://github.com/lineus)
+ * docs(middleware): enumerate the ways to error out in a hook #6315
+ * fix(document): respect schema-level depopulate option for toObject() #6313
+ * fix: bump mongodb driver -> 3.0.6 #6310
+ * fix(number): check for `valueOf()` function to support Decimal.js #6306 #6299 [lineus](https://github.com/lineus)
+ * fix(query): run array setters on query if input value is an array #6277
+ * fix(versioning): don't require matching version when using array.pull() #6190
+ * fix(document): add `toHexString()` function so you don't need to check whether a path is populated to get an id #6115
+
+5.0.14 / 2018-04-09
+===================
+ * fix(schema): clone aliases and alternative option syntax correctly
+ * fix(query): call utils.toObject in query.count like in query.find #6325 [lineus](https://github.com/lineus)
+ * docs(populate): add middleware examples #6320 [BorntraegerMarc](https://github.com/BorntraegerMarc)
+ * docs(compatibility): fix dead link #6319 [lacivert](https://github.com/lacivert)
+ * docs(api): fix markdown parsing for parameters #6318 #6314 [lineus](https://github.com/lineus)
+ * fix(populate): handle space-delimited paths in array populate #6296 #6284 [lineus](https://github.com/lineus)
+ * fix(populate): support basic virtual populate underneath embedded discriminators #6273
+
+5.0.13 / 2018-04-05
+===================
+ * docs(faq): add middleware to faq arrow function warning #6309 [lineus](https://github.com/lineus)
+ * docs(schema): add example to loadClass() docs #6308
+ * docs: clean up misc typos #6304 [sfrieson](https://github.com/sfrieson)
+ * fix(document): apply virtuals when calling `toJSON()` on a nested path #6294
+ * refactor(connection): use `client.db()` syntax rather than double-parsing the URI #6292 #6286
+ * docs: document new behavior of required validator for arrays #6288 [daltones](https://github.com/daltones)
+ * fix(schema): treat set() options as user-provided options #6274
+ * fix(schema): clone discriminators correctly #6274
+ * fix(update): make setDefaultsOnInsert not create subdoc if only default is id #6269
+ * docs(discriminator): clarify 3rd argument to Model.discriminator() #2596
+
+5.0.12 / 2018-03-27
+===================
+ * docs(query): updating model name in query API docs #6280 [lineus](https://github.com/lineus)
+ * docs: fix typo in tests #6275 [styler](https://github.com/styler)
+ * fix: add missing `.hint()` to aggregate #6272 #6251 [lineus](https://github.com/lineus)
+ * docs(api): add headers to each API docs section for easer nav #6261
+ * fix(query): ensure hooked query functions always run on next tick for chaining #6250
+ * fix(populate): ensure populated array not set to null if it isn't set #6245
+ * fix(connection): set readyState to disconnected if initial connection fails #6244 #6131
+ * docs(model): make `create()` params show up correctly in docs #6242
+ * fix(model): make error handlers work with MongoDB server errors and `insertMany()` #6228
+ * fix(browser): ensure browser document builds defaults for embedded arrays correctly #6175
+ * fix(timestamps): set timestamps when using `updateOne()` and `updateMany()` #6282 [gualopezb](https://github.com/gualopezb)
+
+5.0.11 / 2018-03-19
+===================
+ * fix(update): handle $pull with $in in update validators #6240
+ * fix(query): don't convert undefined to null when casting so driver `ignoreUndefined` option works #6236
+ * docs(middleware): add example of using async/await with middleware #6235
+ * fix(populate): apply justOne option before `completeMany()` so it works with lean() #6234
+ * fix(query): ensure errors in user callbacks aren't caught in init #6195 #6178
+ * docs(connections): document dbName option for Atlas connections #6179
+ * fix(discriminator): make child schema nested paths overwrite parent schema paths #6076
+
+4.13.12 / 2018-03-13
+====================
+ * fix(document): make virtual get() return undefined instead of null if no getters #6223
+ * docs: fix url in useMongoClient error message #6219 #6217 [lineus](https://github.com/lineus)
+ * fix(discriminator): don't copy `discriminators` property from base schema #6122 #6064
+
+5.0.10 / 2018-03-12
+===================
+ * docs(schematype): add notes re: running setters on queries #6209
+ * docs: fix typo #6208 [kamagatos](https://github.com/kamagatos)
+ * fix(query): only call setters once on query filter props for findOneAndUpdate and findOneAndRemove #6203
+ * docs: elaborate on connection string changes in migration guide #6193
+ * fix(document): skip applyDefaults if subdoc is null #6187
+ * docs: fix schematypes docs and link to them #6176
+ * docs(faq): add FAQs re: array defaults and casting aggregation pipelines #6184 #6176 #6170 [lineus](https://github.com/lineus)
+ * fix(document): ensure primitive defaults are set and built-in default functions run before setters #6155
+ * fix(query): handle single embedded embedded discriminators in castForQuery #6027
+
+5.0.9 / 2018-03-05
+==================
+ * perf: bump mongodb -> 3.0.4 to fix SSL perf issue #6065
+
+5.0.8 / 2018-03-03
+==================
+ * docs: remove obsolete references to `emitIndexErrors` #6186 [isaackwan](https://github.com/isaackwan)
+ * fix(query): don't cast findOne() until exec() so setters don't run twice #6157
+ * fix: remove document_provider.web.js file #6186
+ * fix(discriminator): support custom discriminator model names #6100 [wentout](https://github.com/wentout)
+ * fix: support caching calls to `useDb()` #6036 [rocketspacer](https://github.com/rocketspacer)
+ * fix(query): add omitUndefined option so setDefaultsOnInsert can kick in on undefined #6034
+ * fix: upgrade mongodb -> 3.0.3 for reconnectTries: 0 blocking process exit fix #6028
+
+5.0.7 / 2018-02-23
+==================
+ * fix: support eachAsync options with aggregation cursor #6169 #6168 [vichle](https://github.com/vichle)
+ * docs: fix link to MongoDB compound indexes docs #6162 [br0p0p](https://github.com/br0p0p)
+ * docs(aggregate): use eachAsync instead of incorrect `each()` #6160 [simllll](https://github.com/simllll)
+ * chore: fix benchmarks #6158 [pradel](https://github.com/pradel)
+ * docs: remove dead link to old blog post #6154 [markstos](https://github.com/markstos)
+ * fix: don't convert dates to numbers when updating mixed path #6146 #6145 [s4rbagamble](https://github.com/s4rbagamble)
+ * feat(aggregate): add replaceRoot, count, sortByCount helpers #6142 [jakesjews](https://github.com/jakesjews)
+ * fix(document): add includedChildren flag to modifiedPaths() #6134
+ * perf: don't create wrapper function if no hooks specified #6126
+ * fix(schema): allow indexes on single nested subdocs for geoJSON #6113
+ * fix(document): allow depopulating all fields #6073
+ * feat(mongoose): add support for `useFindAndModify` option on singleton #5616
+
+5.0.6 / 2018-02-15
+==================
+ * refactor(query.castUpdate): avoid creating error until necessary #6137
+ * docs(api): fix missing api docs #6136 [lineus](https://github.com/lineus)
+ * fix(schema): copy virtuals when using `clone()` #6133
+ * fix(update): avoid digging into buffers with upsert and replaceOne #6124
+ * fix(schema): support `enum` on arrays of strings #6102
+ * fix(update): cast `$addToSet: [1, 2]` -> `$addToSet: { $each: [1, 2] }` #6086
+
+5.0.5 / 2018-02-13
+==================
+ * docs: make > show up correctly in API docs #6114
+ * fix(query): support `where()` overwriting primitive with object #6097
+ * fix(schematype): don't run internal `resetId` setter on queries with _id #6093
+ * fix(discriminator): don't copy `discriminators` property from base schema #6064
+ * fix(utils): respect `valueOf()` when merging object for update #6059
+ * docs(validation): fix typo 'maxLength' #4720
+ * fix(document): apply defaults after setting initial value so default functions don't see empty doc #3781
+
+5.0.4 / 2018-02-08
+==================
+ * docs: add lambda guide #6107
+ * fix(connection): add `dbName` option to work around `mongodb+srv` not supporting db name in URI #6106
+ * fix(schematype): fix regexp typo in ObjectId #6098 [JoshuaWise](https://github.com/JoshuaWise)
+ * perf(document): re-use the modifiedPaths list #6092 [tarun1793](https://github.com/tarun1793)
+ * fix: use console.info() instead of console.error() for debug output #6088 [yuristsepaniuk](https://github.com/yuristsepaniuk)
+ * docs(validation): clean up runValidators and isAsync options docs for 5.x #6083
+ * docs(model): use array instead of spread consistently for aggregate() #6070
+ * fix(schema): make aliases handle mongoose-lean-virtuals #6069
+ * docs(layout): add link to subdocs guide #6056
+ * fix(query): make strictQuery: true strip out fields that aren't in the schema #6032
+ * docs(guide): add notes for `strictQuery` option #6032
+
+4.13.11 / 2018-02-07
+====================
+ * docs: fix links in 4.x docs #6081
+ * chore: add release script that uses --tag for npm publish for 4.x releases #6063
+
+5.0.3 / 2018-01-31
+==================
+ * fix: consistently use process.nextTick() to avoid sinon.useFakeTimers() causing ops to hang #6074
+ * docs(aggregate): fix typo #6072 [adursun](https://github.com/adursun)
+ * chore: add return type to `mongoose.model()` docs [bryant1410](https://github.com/bryant1410)
+ * fix(document): depopulate push()-ed docs when saving #6048
+ * fix: upgrade mongodb -> 3.0.2 #6019
+
+5.0.2 / 2018-01-28
+==================
+ * fix(schema): do not overwrite default values in schema when nested timestamps are provided #6024 [cdeveas](https://github.com/cdeveas)
+ * docs: fix syntax highlighting in models.jade, schematypes.jade, subdocs.jade #6058 [lineus](https://github.com/lineus)
+ * fix: use lazy loading so we can build mongoose with webpack #5993 #5842
+ * docs(connections): clarify multi-mongos with useMongoClient for 4.x docs #5984
+ * fix(populate): handle populating embedded discriminator paths #5970
+
+4.13.10 / 2018-01-28
+====================
+ * docs(model+query): add lean() option to Model helpers #5996 [aguyinmontreal](https://github.com/aguyinmontreal)
+ * fix: use lazy loading so we can build mongoose with webpack #5993 #5842
+ * docs(connections): clarify multi-mongos with useMongoClient for 4.x docs #5984
+ * fix(populate): handle populating embedded discriminator paths #5970
+ * docs(query+aggregate): add more detail re: maxTimeMS #4066
+
+5.0.1 / 2018-01-19
+==================
+ * fix(document): make validate() not resolve to document #6014
+ * fix(model): make save() not return DocumentNotFoundError if using fire-and-forget writes #6012
+ * fix(aggregate): make options() work as advertised #6011 [spederiva](https://github.com/spederiva)
+ * docs(queries): fix code samples #6008
+
+5.0.0 / 2018-01-17
+==================
+ * test: refactor tests to use start fewer connections #5985 [fenanquin](https://github.com/fenanquin)
+ * feat: add global bufferCommands option #5879
+ * docs: new docs site and build system #5976
+ * test: increase timeout on slow test cases #5968 [fenanquin](https://github.com/fenanquin)
+ * fix: avoid casting out array filter elements #5965
+ * feat: add Model.watch() wrapper #5964
+ * chore: replace istanbul with nyc #5962 [ChristianMurphy](https://github.com/ChristianMurphy)
+
+4.13.9 / 2018-01-07
+===================
+ * chore: update marked (dev dependency) re: security vulnerability #5951 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix: upgrade mongodb -> 2.2.34 for ipv6 and autoReconnect fixes #5794 #5760
+ * docs: use useMongooseAggCursor for aggregate docs #2955
+
+5.0.0-rc2 / 2018-01-04
+======================
+ * fix: add cleaner warning about no longer needing `useMongoClient` in 5.x #5961
+ * chore: update acquit -> 0.5.1 for minor security patch #5961 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * docs: add docs for mongoose 4.x at http://mongoosejs.com/docs/4.x #5959
+ * docs: add link to migration guide #5957
+ * chore: update eslint to version 4.14.0 #5955 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * chore: update mocha to version 4.1.0 [ChristianMurphy](https://github.com/ChristianMurphy)
+
+5.0.0-rc1 / 2018-01-02
+======================
+ * fix(index): use pluralize correctly for `mongoose.model()` #5958
+ * fix: make mquery use native promises by default #5945
+ * fix(connection): ensure 'joined' and 'left' events get bubbled up #5944
+
+5.0.0-rc0 / 2017-12-28
+======================
+ * BREAKING CHANGE: always use mongoose aggregation cursor when using `.aggregate().cursor()` #5941
+ * BREAKING CHANGE: attach query middleware when compiling model #5939
+ * BREAKING CHANGE: `emitIndexErrors` is on by default, failing index build will throw uncaught error if not handled #5910
+ * BREAKING CHANGE: remove precompiled browser bundle #5895
+ * feat: add `mongoose.pluralize()` function #5877
+ * BREAKING CHANGE: remove `passRawResult` option for `findOneAndUpdate`, use `rawResult` #5869
+ * BREAKING CHANGE: implicit async validators (based on number of function args) are removed, return a promise instead #5824
+ * BREAKING CHANGE: fail fast if user sets a unique index on `_id` #5820 [varunjayaraman](https://github.com/varunjayaraman)
+ * BREAKING CHANGE: mapReduce resolves to an object with 2 keys rather than 2 separate args #5816
+ * BREAKING CHANGE: `mongoose.connect()` returns a promise, removed MongooseThenable #5796
+ * BREAKING CHANGE: query stream removed, use `cursor()` instead #5795
+ * BREAKING CHANGE: connection `open()` and `openSet()` removed, use `openUri()` instead #5795
+ * BREAKING CHANGE: use MongoDB driver 3.0.0, drop support for MongoDB server < 3.0.0 #5791 #4740
+ * BREAKING CHANGE: remove support for `$pushAll`, remove `usePushEach` option #5670
+ * BREAKING CHANGE: make date casting use native Date #5395 [varunjayaraman](https://github.com/varunjayaraman)
+ * BREAKING CHANGE: remove `runSettersOnQuery`, always run setters on query #5340
+ * BREAKING CHANGE: array of length 0 now satisfies `required: true` for arays #5139 [wlingke](https://github.com/wlingke)
+ * BREAKING CHANGE: remove `saveErrorIfNotFound`, always error out if `save()` did not update a document #4973
+ * BREAKING CHANGE: don't execute getters in reverse order #4835
+ * BREAKING CHANGE: make boolean casting more strict #4245
+ * BREAKING CHANGE: `toObject()` and `toJSON()` option parameter merges with defaults rather than overwriting #4131
+ * feat: allow setting `default` on `_id` #4069
+ * BREAKING CHANGE: `deleteX()` and `remove()` promise resolves to the write object result #4013
+ * feat: support returning a promise from middleware functions #3779
+ * BREAKING CHANGE: don't return a promise if callback specified #3670
+ * BREAKING CHANGE: only cast `update()`, `updateX()`, `replaceOne()`, `remove()`, `deleteX()` in exec #3529
+ * BREAKING CHANGE: sync errors in middleware functions are now handled #3483
+ * BREAKING CHANGE: post hooks get flow control #3232
+ * BREAKING CHANGE: deduplicate hooks when merging discriminator schema #2945
+ * BREAKING CHANGE: use native promises by default, remove support for mpromise #2917
+ * BREAKING CHANGE: remove `retainKeyOrder`, always use forward order when iterating through objects #2749
+ * BREAKING CHANGE: `aggregate()` no longer accepts a spread #2716
+
+4.13.8 / 2017-12-27
+===================
+ * docs(guide): use more up-to-date syntax for autoIndex example #5933
+ * docs: fix grammar #5927 [abagh0703](https://github.com/abagh0703)
+ * fix: propagate lean options to child schemas #5914
+ * fix(populate): use correct model with discriminators + nested populate #5858
+
+4.13.7 / 2017-12-11
+===================
+ * docs(schematypes): fix typo #5889 [gokaygurcan](https://github.com/gokaygurcan)
+ * fix(cursor): handle `reject(null)` with eachAsync callback #5875 #5874 [ZacharyRSmith](https://github.com/ZacharyRSmith)
+ * fix: disallow setting `mongoose.connection` to invalid values #5871 [jinasonlin](https://github.com/jinasonlin)
+ * docs(middleware): suggest using `return next()` to stop middleware execution #5866
+ * docs(connection): improve connection string query param docs #5864
+ * fix(document): run validate hooks on array subdocs even if not directly modified #5861
+ * fix(discriminator): don't treat $meta as defining projection when querying #5859
+ * fix(types): handle Decimal128 when using bson-ext on server side #5850
+ * fix(document): ensure projection with only $slice isn't treated as inclusive for discriminators #4991
+ * fix(model): throw error when passing non-object to create() #2037
+
+4.13.6 / 2017-12-02
+===================
+ * fix(schema): support strictBool option in schema #5856 [ekulabuhov](https://github.com/ekulabuhov)
+ * fix(update): make upsert option consistently handle truthy values, not just booleans, for updateOne() #5839
+ * refactor: remove unnecessary constructor check #2057
+ * docs(query): correct function signature for .mod() helper #1806
+ * fix(query): report ObjectParameterError when passing non-object as filter to find() and findOne() #1698
+
+4.13.5 / 2017-11-24
+===================
+ * fix(model): handle update cast errors correctly with bulkWrite #5845 [Michael77](https://github.com/Michael77)
+ * docs: add link to bufferCommands option #5844 [ralphite](https://github.com/ralphite)
+ * fix(model): allow virtual ref function to return arrays #5834 [brunohcastro](https://github.com/brunohcastro)
+ * fix(query): don't throw uncaught error if query filter too big #5812
+ * fix(document): if setting unselected nested path, don't overwrite nested path #5800
+ * fix(document): support calling `populate()` on nested document props #5703
+ * fix: add `strictBool` option for schema type boolean #5344 #5211 #4245
+ * docs(faq): add faq re: typeKey #1886
+ * docs(query): add more detailed docs re: options #1702
+
+4.13.4 / 2017-11-17
+===================
+ * fix(aggregate): add chainable .option() helper for setting arbitrary options #5829
+ * fix(aggregate): add `.pipeline()` helper to get the current pipeline #5825
+ * docs: grammar fixes for `unique` FAQ #5823 [mfluehr](https://github.com/mfluehr)
+ * chore: add node 9 to travis #5822 [superheri](https://github.com/superheri)
+ * fix(model): fix infinite recursion with recursive embedded discriminators #5821 [Faibk](https://github.com/Faibk)
+
+4.13.3 / 2017-11-15
+===================
+ * chore: add node 8 to travis #5818 [superheri](https://github.com/superheri)
+ * fix(document): don't apply transforms to nested docs when updating already saved doc #5807
+
+4.13.2 / 2017-11-11
+===================
+ * feat(buffer): add support for subtype prop #5530
+
+4.13.1 / 2017-11-08
+===================
+ * fix: accept multiple paths or array of paths to depopulate #5798 #5797 [adamreisnz](https://github.com/adamreisnz)
+ * fix(document): pass default array as actual array rather than taking first element #5780
+ * fix(model): increment version when $set-ing it in a save() that requires a version bump #5779
+ * fix(query): don't explicitly project in discriminator key if user projected in parent path #5775 #5754
+ * fix(model): cast query option to geoNear() #5765
+ * fix(query): don't treat projection with just $slice as inclusive #5737
+ * fix(discriminator): defer applying embedded discriminator hooks until top-level model is compiled #5706
+ * docs(discriminator): add warning to always attach hooks before calling discriminator() #5706
+
+4.13.0 / 2017-11-02
+===================
+ * feat(aggregate): add $addFields helper #5740 [AyushG3112](https://github.com/AyushG3112)
+ * feat(connection): add connection-level bufferCommands #5720
+ * feat(connection): add createCollection() helper #5712
+ * feat(populate): support setting localField and foreignField to functions #5704 #5602
+ * feat(query): add multipleCastError option for aggregating cast errors when casting update #5609
+ * feat(populate): allow passing a function to virtual ref #5602
+ * feat(schema): add excludeIndexes option to optionally prevent collecting indexes from nested schemas #5575
+ * feat(model): report validation errors from `insertMany()` if using `ordered: false` and `rawResult: true` #5337
+ * feat(aggregate): add pre/post aggregate middleware #5251
+ * feat(schema): allow using `set` as a schema path #1939
+
+4.12.6 / 2017-11-01
+===================
+ * fix(schema): make clone() copy query helpers correctly #5752
+ * fix: undeprecate `ensureIndex()` and use it by default #3280
+
+4.12.5 / 2017-10-29
+===================
+ * fix(query): correctly handle `$in` and required for $pull and update validators #5744
+ * feat(aggegate): add $addFields pipeline operator #5740 [AyushG3112](https://github.com/AyushG3112)
+ * fix(document): catch sync errors in document pre hooks and report as error #5738
+ * fix(populate): handle slice projections correctly when automatically selecting populated fields #5737
+ * fix(discriminator): fix hooks for embedded discriminators #5706 [wlingke](https://github.com/wlingke)
+ * fix(model): throw sane error when customer calls `mongoose.Model()` over `mongoose.model()` #2005
+
+4.12.4 / 2017-10-21
+===================
+ * test(plugins): add coverage for idGetter with id as a schema property #5713 [wlingke](https://github.com/wlingke)
+ * fix(model): avoid copying recursive $$context object when creating discriminator after querying #5721
+ * fix(connection): ensure connection promise helpers are removed before emitting 'connected' #5714
+ * docs(schema): add notes about runSettersOnQuery to schema setters #5705
+ * fix(collection): ensure queued operations run on the next tick #5562
+
+4.12.3 / 2017-10-16
+===================
+ * fix(connection): emit 'reconnect' event as well as 'reconnected' for consistency with driver #5719
+ * fix: correctly bubble up left/joined events for replica set #5718
+ * fix(connection): allow passing in `autoIndex` as top-level option rather than requiring `config.autoIndex` #5711
+ * docs(connection): improve docs regarding reconnectTries, autoReconnect, and bufferMaxEntries #5711
+ * fix(query): handle null with addToSet/push/pull/pullAll update validators #5710
+ * fix(model): handle setDefaultsOnInsert option for bulkWrite updateOne and updateMany #5708
+ * fix(query): avoid infinite recursion edge case when cloning a buffer #5702
+
+4.12.2 / 2017-10-14
+===================
+ * docs(faq): add FAQ about using arrow functions for getters/setters, virtuals, and methods #5700
+ * docs(schema): document the childSchemas property and add to public API #5695
+ * fix(query): don't project in populated field if parent field is already projected in #5669
+ * fix: bump mongodb -> 2.2.33 for issue with autoReconnect #4513
+
+4.12.1 / 2017-10-08
+===================
+ * fix(document): create new doc when setting single nested, no more set() on copy of priorVal #5693
+ * fix(model): recursively call applyMethods on child schemas for global plugins #5690
+ * docs: fix bad promise lib example on home page #5686
+ * fix(query): handle false when checking for inclusive/exclusive projection #5685
+ * fix(discriminator): allow reusing child schema #5684
+ * fix: make addToSet() on empty array with subdoc trigger manual population #5504
+
+4.12.0 / 2017-10-02
+===================
+ * docs(validation): add docs coverage for ValidatorError.reason #5681
+ * feat(discriminator): always add discriminatorKey to base schema to allow updating #5613
+ * fix(document): make nested docs no longer inherit parent doc's schema props #5586 #5546 #5470
+ * feat(query): run update validators on $pull and $pullAll #5555
+ * feat(query): add .error() helper to query to error out in pre hooks #5520
+ * feat(connection): add dropCollection() helper #5393
+ * feat(schema): add schema-level collation option #5295
+ * feat(types): add `discriminator()` function for single nested subdocs #5244
+ * feat(document): add $isDeleted() getter/setter for better support for soft deletes #4428
+ * feat(connection): bubble up reconnectFailed event when driver gives up reconnecting #4027
+ * fix(query): report error if passing array or other non-object as filter to update query #3677
+ * fix(collection): use createIndex() instead of deprecated ensureIndex() #3280
+
+4.11.14 / 2017-09-30
+====================
+ * chore: add nsp check to the CI build #5679 [hairyhenderson](https://github.com/hairyhenderson)
+ * fix: bump mquery because of security issue with debug package #5677 #5675 [jonathanprl](https://github.com/jonathanprl)
+ * fix(populate): automatically select() populated()-ed fields #5669
+ * fix(connection): make force close work as expected #5664
+ * fix(document): treat $elemMatch as inclusive projection #5661
+ * docs(model/query): clarify which functions fire which middleware #5654
+ * fix(model): make `init()` public and return a promise that resolves when indexes are done building #5563
+
+4.11.13 / 2017-09-24
+====================
+ * fix(query): correctly run replaceOne with update validators #5665 [sime1](https://github.com/sime1)
+ * fix(schema): replace mistype in setupTimestamp method #5656 [zipp3r](https://github.com/zipp3r)
+ * fix(query): avoid throwing cast error for strict: throw with nested id in query #5640
+ * fix(model): ensure class gets combined schema when using class syntax with discriminators #5635
+ * fix(document): handle setting doc array to array of top-level docs #5632
+ * fix(model): handle casting findOneAndUpdate() with overwrite and upsert #5631
+ * fix(update): correctly handle $ in updates #5628
+ * fix(types): handle manual population consistently for unshift() and splice() #5504
+
+4.11.12 / 2017-09-18
+====================
+ * docs(model): asterisk should not render as markdown bullet #5644 [timkinnane](https://github.com/timkinnane)
+ * docs: use useMongoClient in connection example #5627 [GabrielNicolasAvellaneda](https://github.com/GabrielNicolasAvellaneda)
+ * fix(connection): call callback when initial connection failed #5626
+ * fix(query): apply select correctly if a given nested schema is used for 2 different paths #5603
+ * fix(document): add graceful fallback for setting a doc array value and `pull()`-ing a doc #3511
+
+4.11.11 / 2017-09-10
+====================
+ * fix(connection): properly set readyState in response to driver 'close' and 'reconnect' events #5604
+ * fix(document): ensure single embedded doc setters only get called once, with correct value #5601
+ * fix(timestamps): allow enabling updatedAt without createdAt #5598
+ * test: improve unique validator test by making create run before ensureIndex #5595 #5562
+ * fix(query): ensure find callback only gets called once when post init hook throws error #5592
+
+4.11.10 / 2017-09-03
+====================
+ * docs: add KeenIO tracking #5612
+ * fix(schema): ensure validators declared with `.validate()` get copied with clone() #5607
+ * fix: remove unnecessary jest warning #5480
+ * fix(discriminator): prevent implicit discriminator schema id from clobbering base schema custom id #5591
+ * fix(schema): hide schema objectid warning for non-hex strings of length 24 #5587
+ * docs(populate): use story schema defined key author instead of creator #5578 [dmric](https://github.com/dmric)
+ * docs(document): describe usage of `.set()` #5576
+ * fix(document): ensure correct scope in single nested validators #5569
+ * fix(populate): don't mark path as populated until populate() is done #5564
+ * fix(document): make push()-ing a doc onto an empty array act as manual population #5504
+ * fix(connection): emit timeout event on socket timeout #4513
+
+4.11.9 / 2017-08-27
+===================
+ * fix(error): avoid using arguments.callee because that breaks strict mode #5572
+ * docs(schematypes): fix spacing #5567
+ * fix(query): enforce binary subtype always propagates to mongodb #5551
+ * fix(query): only skip castForQuery for mongoose arrays #5536
+ * fix(browser): rely on browser entrypoint to decide whether to use BrowserDocument or NodeDocument #5480
+
+4.11.8 / 2017-08-23
+===================
+ * feat: add warning about using schema ObjectId as type ObjectId #5571 [efkan](https://github.com/efkan)
+ * fix(schema): allow setting `id` property after schema was created #5570 #5548
+ * docs(populate): remove confusing _ from populate docs #5560
+ * fix(connection): expose parsed uri fields (host, port, dbname) when using openUri() #5556
+ * docs: added type boolean to options documentation #5547 [ndabAP](https://github.com/ndabAP)
+ * test: add test coverage for stopping/starting server #5524
+ * fix(aggregate): pull read preference from schema by default #5522
+
+4.11.7 / 2017-08-14
+===================
+ * fix: correct properties when calling toJSON() on populated virtual #5544 #5442 [davidwu226](https://github.com/davidwu226)
+ * docs: fix spelling #5535 [et](https://github.com/et)
+ * fix(error): always set name before stack #5533
+ * fix: add warning about running jest in jsdom environment #5532 #5513 #4943
+ * fix(document): ensure overwriting a doc array cleans out individual docs #5523
+ * fix(schema): handle creating arrays of single nested using type key #5521
+ * fix: upgrade mongodb -> 2.2.31 to support user/pass options #5419
+
+4.11.6 / 2017-08-07
+===================
+ * fix: limiting number of async operations per time in insertMany #5529 [andresattler](https://github.com/andresattler)
+ * fix: upgrade mongodb -> 2.2.30 #5517
+ * fix(browserDocument): prevent stack overflow caused by double-wrapping embedded doc save() in jest #5513
+ * fix(document): clear single nested doc when setting to empty object #5506
+ * fix(connection): emit reconnected and disconnected events correctly with useMongoClient #5498
+ * fix(populate): ensure nested virtual populate gets set even if top-level property is null #5431
+
+4.11.5 / 2017-07-30
+===================
+ * docs: fix link to $lookup #5516 [TalhaAwan](https://github.com/TalhaAwan)
+ * fix: better parallelization for eachAsync #5502 [lchenay](https://github.com/lchenay)
+ * docs(document): copy docs for save from model to doc #5493
+ * fix(document): handle dotted virtuals in toJSON output #5473
+ * fix(populate): restore user-provided limit after mutating so cursor() works with populate limit #5468
+ * fix(query): don't throw StrictModeError if geo query with upsert #5467
+ * fix(populate): propagate readPreference from query to populate queries by default #5460
+ * docs: warn not to use arrow functions for statics and methods #5458
+ * fix(query): iterate over all condition keys for setDefaultsOnInsert #5455
+ * docs(connection): clarify server/replset/mongos option deprecation with useMongoClient #5442
+
+4.11.4 / 2017-07-23
+===================
+ * fix: handle next() errors in `eachAsync()` #5486 [lchenay](https://github.com/lchenay)
+ * fix(schema): propagate runSettersOnQuery option to implicitly created schemas #5479 [https://github.com/ValYouW]
+ * fix(query): run castConditions() correctly in update ops #5477
+ * fix(query): ensure castConditions called for findOne and findOneAnd* #5477
+ * docs: clarify relationship between $lookup and populate #5475 [TalhaAwan](https://github.com/TalhaAwan)
+ * test: add coverage for arrays of arrays [zbjornson](https://github.com/zbjornson)
+ * fix(middleware): ensure that error handlers for save get doc as 2nd param #5466
+ * fix: handle strict: false correctly #5454 #5453 [wookieb](https://github.com/wookieb)
+ * fix(query): apply schema excluded paths if only projection is a $slice #5450
+ * fix(query): correct discriminator handling for schema `select: false` fields in schema #5448
+ * fix(cursor): call next() in series when parallel option used #5446
+ * chore: load bundled driver first to avoid packaging problem #5443 [prototypeme](https://github.com/prototypeme)
+ * fix(query): defer condition casting until final exec #5434
+ * fix(aggregate): don't rely on mongodb aggregate to put a cursor in the callback #5394
+ * docs(aggregate): add useMongooseAggCursor docs #5394
+ * docs(middleware): clarify context for document, query, and model middleware #5381
+
+4.11.3 / 2017-07-14
+===================
+ * fix(connection): remove .then() before resolving to prevent infinite recursion #5471
+
+4.11.2 / 2017-07-13
+===================
+ * docs: fix comment typo in connect example #5435 [ConnorMcF](https://github.com/ConnorMcF)
+ * fix(update): correctly cast document array in update validators with exec() #5430
+ * fix(connection): handle autoIndex with useMongoClient #5423
+ * fix(schema): handle `type: [Array]` in schemas #5416
+ * fix(timestamps): if overwrite is set and there's a $set, use $set instead of top-level update #5413
+ * fix(document): don't double-validate deeply nested doc array elements #5411
+ * fix(schematype): clone default objects so default not shared across object instances unless `shared` specified #5407
+ * fix(document): reset down the nested subdocs when resetting parent doc #5406
+ * fix: don't pass error arg twice to error handlers #5405
+ * fix(connection): make openUri() return connection decorated with then() and catch() #5404
+ * fix: enforce $set on an array must be an array #5403
+ * fix(document): don't crash if calling `validateSync()` after overwriting doc array index #5389
+ * fix(discriminator): ensure discriminator key doesn't count as user-selected field for projection #4629
+
+4.11.1 / 2017-07-02
+===================
+* docs: populate virtuals fix justOne description #5427 [fredericosilva](https://github.com/fredericosilva)
+ * fix(connection): make sure to call onOpen in openUri() #5404
+ * docs(query): justOne is actually single, and it default to false #5402 [zbjornson](https://github.com/zbjornson)
+ * docs: fix small typo in lib/schema.js #5398 #5396 [pjo336](https://github.com/pjo336)
+ * fix: emit remove on single nested subdocs when removing parent #5388
+ * fix(update): handle update with defaults and overwrite but no update validators #5384
+ * fix(populate): handle undefined refPath values in middle of array #5377
+ * fix(document): ensure consistent setter context for single nested #5363
+ * fix(query): support runSettersOnQuery as query option #5350
+
+4.11.0 / 2017-06-25
+===================
+ * feat(query): execute setters with query as context for `runSettersOnQuery` #5339
+ * feat(model): add translateAliases function #5338 [rocketspacer](https://github.com/rocketspacer)
+ * feat(connection): add `useMongoClient` and `openUri` functions, deprecate current connect logic #5304
+ * refactor(schema): make id virtual not access doc internals #5279
+ * refactor: handle non-boolean lean #5279
+ * feat(cursor): add addCursorFlag() support to query and agg cursors #4814
+ * feat(cursor): add parallel option to eachAsync #4244
+ * feat(schema): allow setting custom error constructor for custom validators #4009
+
+4.10.8 / 2017-06-21
+===================
+ * docs: fix small formatting typo on schematypes #5374 [gianpaj](https://github.com/gianpaj)
+ * fix(model): allow null as an _id #5370
+ * fix(populate): don't throw async uncaught exception if model not found in populate #5364
+ * fix: correctly cast decimals in update #5361
+ * fix(error): don't use custom getter for ValidationError message #5359
+ * fix(query): handle runSettersOnQuery in built-in _id setter #5351
+ * fix(document): ensure consistent context for nested doc custom validators #5347
+
+4.10.7 / 2017-06-18
+===================
+ * docs(validation): show overriding custom validator error with 2nd cb arg #5358
+ * fix: `parseOption` mutates user passed option map #5357 [igwejk](https://github.com/igwejk)
+ * docs: fix guide.jade typo #5356 [CalebAnderson2014](https://github.com/CalebAnderson2014)
+ * fix(populate): don't set populate virtual to ids when match fails #5336
+ * fix(query): callback with cast error if remove and delete* args have a cast error #5323
+
+4.10.6 / 2017-06-12
+===================
+ * fix(cursor): handle custom model option for populate #5334
+ * fix(populate): handle empty virtual populate with Model.populate #5331
+ * fix(model): make ensureIndexes() run with autoIndex: false unless called internally #5328 #5324 #5317
+ * fix: wait for all connections to close before resolving disconnect() promise #5316
+ * fix(document): handle setting populated path with custom typeKey in schema #5313
+ * fix(error): add toJSON helper to ValidationError so `message` shows up with JSON.stringify #5309
+ * feat: add `getPromiseConstructor()` to prevent need for `mongoose.Promise.ES6` #5305
+ * fix(document): handle conditional required with undefined props #5296
+ * fix(model): clone options before inserting in save() #5294
+ * docs(populate): clarify that multiple populate() calls on same path overwrite #5274
+
+4.10.5 / 2017-06-06
+===================
+ * chore: improve contrib guide for building docs #5312
+ * fix(populate): handle init-ing nested virtuals properly #5311
+ * fix(update): report update validator error if required path under single nested doc not set
+ * fix(schema): remove default validate pre hook that was causing issues with jest #4943
+
+4.10.4 / 2017-05-29
+===================
+ * chore: dont store test data in same directory #5303
+ * chore: add data dirs to npmignore #5301 [Starfox64](https://github.com/Starfox64)
+ * docs(query): add docs about runSettersOnQuery #5300
+
+4.10.3 / 2017-05-27
+===================
+ * docs: correct inconsistent references to updateOne and replaceOne #5297 [dhritzkiv](https://github.com/dhritzkiv)
+ * docs: fix dropdowns in docs #5292 [nathanallen](https://github.com/nathanallen)
+ * docs: add description of alias option #5287
+ * fix(document): prevent infinite loop if validating nested array #5282
+ * fix(schema): correctly handle ref ObjectIds from different mongoose libs #5259
+ * fix(schema): load child class methods after base class methods to allow override #5227
+
+4.10.2 / 2017-05-22
+===================
+ * fix: bump ms -> 2.0.0 and mquery -> 2.3.1 for minor security vulnerability #5275
+
+4.10.1 / 2017-05-21
+===================
+ * fix(aggregate): handle sorting by text score correctly #5258
+ * fix(populate): handle doc.populate() with virtuals #5240
+ * fix(schema): enforce that `_id` is never null #5236
+
+4.10.0 / 2017-05-18
+===================
+ * fix(schema): update clone method to include indexes #5268 [clozanosanchez](https://github.com/clozanosanchez)
+ * feat(schema): support aliases #5184 [rocketspacer](https://github.com/rocketspacer)
+ * feat(aggregate): add mongoose-specific aggregation cursor option #5145
+ * refactor(model): make sharding into a plugin instead of core #5105
+ * fix(document): make nested doc mongoose internals not enumerable again #5078
+ * feat(model): pass params to pre hooks #5064
+ * feat(timestamps): support already defined timestamp paths in schema #4868
+ * feat(query): add runSettersOnQuery option #4569
+ * fix(query): add strictQuery option that throws when not querying on field not in schema #4136
+ * fix(update): more complete handling for overwrite option with update validators #3556
+ * feat: support `unique: true` in arrays via the mongoose-unique-array plugin #3347
+ * fix(model): always emit 'index', even if no indexes #3347
+ * fix(schema): set unique indexes on primitive arrays #3347
+ * feat(validation): include failed paths in error message and inspect output #3064 #2135
+ * fix(model): return saved docs when create() fails #2190
+
+4.9.10 / 2017-05-17
+===================
+ * fix(connection): ensure callback arg to openSet() is handled properly #5249
+ * docs: remove dead plugins repo and add content links #5247
+ * fix(model): skip index build if connecting after model init and autoIndex false #5176
+
+4.9.9 / 2017-05-13
+==================
+ * docs: correct value for Query#regex() #5230
+ * fix(connection): don't throw if .catch() on open() promise #5229
+ * fix(schema): allow update with $currentDate for updatedAt to succeed #5222
+ * fix(model): versioning doesn't fail if version key undefined #5221 [basileos](https://github.com/basileos)
+ * fix(document): don't emit model error if callback specified for consistency with docs #5216
+ * fix(document): handle errors in subdoc pre validate #5215
+
+4.9.8 / 2017-05-07
+==================
+ * docs(subdocs): rewrite subdocs guide #5217
+ * fix(document): avoid circular JSON if error in doc array under single nested subdoc #5208
+ * fix(document): set intermediate empty objects for deeply nested undefined paths before path itself #5206
+ * fix(schema): throw error if first param to schema.plugin() is not a function #5201
+ * perf(document): major speedup in validating subdocs (50x in some cases) #5191
+
+4.9.7 / 2017-04-30
+==================
+ * docs: fix typo #5204 [phutchins](https://github.com/phutchins)
+ * fix(schema): ensure correct path for deeply nested schema indexes #5199
+ * fix(schema): make remove a reserved name #5197
+ * fix(model): handle Decimal type in insertMany correctly #5190
+ * fix: upgrade kareem to handle async pre hooks correctly #5188
+ * docs: add details about unique not being a validator #5179
+ * fix(validation): handle returning a promise with isAsync: true #5171
+
+4.9.6 / 2017-04-23
+==================
+ * fix: update `parentArray` references when directly assigning document arrays #5192 [jhob](https://github.com/jhob)
+ * docs: improve schematype validator docs #5178 [milesbarr](https://github.com/milesbarr)
+ * fix(model): modify discriminator() class in place #5175
+ * fix(model): handle bulkWrite updateMany casting #5172 [tzellman](https://github.com/tzellman)
+ * docs(model): fix replaceOne example for bulkWrite #5168
+ * fix(document): don't create a new array subdoc when creating schema array #5162
+ * fix(model): merge query hooks from discriminators #5147
+ * fix(document): add parent() function to subdocument to match array subdoc #5134
+
+4.9.5 / 2017-04-16
+==================
+ * fix(query): correct $pullAll casting of null #5164 [Sebmaster](https://github.com/Sebmaster)
+ * docs: add advanced schemas docs for loadClass #5157
+ * fix(document): handle null/undefined gracefully in applyGetters() #5143
+ * fix(model): add resolveToObject option for mapReduce with ES6 promises #4945
+
+4.9.4 / 2017-04-09
+==================
+ * fix(schema): clone query middleware correctly #5153 #5141 [clozanosanchez](https://github.com/clozanosanchez)
+ * docs(aggregate): fix typo #5142
+ * fix(query): cast .$ update to underlying array type #5130
+ * fix(populate): don't mutate populate result in place #5128
+ * fix(query): handle $setOnInsert consistent with $set #5126
+ * docs(query): add strict mode option for findOneAndUpdate #5108
+
+4.9.3 / 2017-04-02
+==================
+ * docs: document.js fixes for functions prepended with `$` #5131 [krmannix](https://github.com/krmannix)
+ * fix: Avoid exception on constructor check #5129 [monkbroc](https://github.com/monkbroc)
+ * docs(schematype): explain how to use `isAsync` with validate() #5125
+ * docs(schematype): explain custom message with required function #5123
+ * fix(populate): only apply refPath duplicate id optimization if not array #5114
+ * fix(document): copy non-objects to doc when init() #5111
+ * perf(populate): dont clone whole options every time #5103
+ * feat(document): add isDirectSelected() to minimize isSelected() changes #5063
+ * docs(schematypes): explain some subtleties with arrays #5059
+
+4.9.2 / 2017-03-26
+==================
+ * fix(discriminator): handle class names consistently #5104
+ * fix(schema): make clone() work with reusing discriminator schemas #5098
+ * fix(querycursor): run pre find hooks with .cursor() #5096
+ * fix(connection): throw error if username:password includes @ or : #5091
+ * fix(timestamps): handle overwriting createdAt+updatedAt consistently #5088
+ * fix(document): ensure subdoc post save runs after parent save #5085
+ * docs(model): improve update docs #5076 [bertolo1988](https://github.com/bertolo1988)
+
+4.9.1 / 2017-03-19
+==================
+ * fix(query): handle $type for arrays #5080 #5079 [zoellner](https://github.com/zoellner)
+ * fix(model): handle ordered param for `insertMany` validation errors #5072 [sjorssnoeren](https://github.com/sjorssnoeren)
+ * fix(populate): avoid duplicate ids in dynref queries #5054
+ * fix(timestamps): dont set timestamps in update if user set it #5045
+ * fix(update): dont double-call setters on arrays #5041
+ * fix: upgrade driver -> 2.2.25 for jest fix #5033
+ * fix(model): get promise each time save() is called rather than once #5030
+ * fix(connection): make connect return value consistent #5006
+
+4.9.0 / 2017-03-13
+==================
+ * feat(document): return this from `depopulate()` #5027
+ * fix(drivers): stop emitting timeouts as errors #5026
+ * feat(schema): add a clone() function for schemas #4983
+ * feat(query): add rawResult option to replace passRawResult, deprecate passRawResult #4977 #4925
+ * feat(schematype): support isAsync validator option and handle returning promises from validators, deprecate implicit async validators #4290
+ * feat(query): add `replaceOne()`, `deleteOne()`, `deleteMany()` #3998
+ * feat(model): add `bulkWrite()` #3998
+
+4.8.7 / 2017-03-12
+==================
+ * fix(model): if last arg in spread is falsy, treat it as a callback #5061
+ * fix(document): use $hook instead of hook to enable 'hook' as a path name #5047
+ * fix(populate): dont select foreign field if parent field is selected #5037
+ * fix(populate): handle passing no args to query.populate #5036
+ * fix(update): use correct method for casting nested arrays #5032
+ * fix(discriminator): handle array discriminators when casting $push #5009
+
+4.8.6 / 2017-03-05
+==================
+ * docs(document): remove text that implies that transform is false by default #5023
+ * fix(applyHooks): dont wrap a function if it is already wrapped #5019
+ * fix(document): ensure nested docs' toObject() clones #5008
+
+4.8.5 / 2017-02-25
+==================
+ * fix: check for empty schemaPath before accessing property $isMongooseDocumentArray #5017 [https://github.com/randyhoulahan](randyhoulahan)
+ * fix(discriminators): handle create() and push() for embedded discriminators #5001
+ * fix(querycursor): ensure close emitted after last data event #4998
+ * fix(discriminators): remove fields not selected in child when querying by base model #4991
+
+4.8.4 / 2017-02-19
+==================
+ * docs(discriminators): explain embedded discriminators #4997
+ * fix(query): fix TypeError when findOneAndUpdate errors #4990
+ * fix(update): handle nested single embedded in update validators correctly #4989
+ * fix(browser): make browser doc constructor not crash #4987
+
+4.8.3 / 2017-02-15
+==================
+ * chore: upgrade mongodb driver -> 2.2.24
+ * docs(connections): addd some details about callbacks #4986
+ * fix: ensure class is created with new keyword #4972 #4947 [benhjames](https://github.com/benhjames)
+ * fix(discriminator): add applyPluginsToDiscriminators option #4965
+ * fix(update): properly cast array subdocs when casting update #4960
+ * fix(populate): ensure foreign field is selected for virtual populate #4959
+ * docs(query): document some query callback params #4949
+ * fix(document): ensure errors in validators get caught #2185
+
+4.8.2 / 2017-02-10
+==================
+ * fix(update): actually run validators on addToSet #4953
+ * fix(update): improve buffer error handling #4944 [ValYouW](https://github.com/ValYouW)
+ * fix(discriminator): handle subclassing with loadClass correctly #4942
+ * fix(query): allow passing Map to sort() #4941
+ * fix(document): handle setting discriminator doc #4935
+ * fix(schema): return correct value from pre init hook #4928
+ * fix(query): ensure consistent params in error handlers if pre hook errors #4927
+
+4.8.1 / 2017-01-30
+==================
+ * fix(query): handle $exists for arrays and embedded docs #4937
+ * fix(query): handle passing string to hint() #4931
+
+4.8.0 / 2017-01-28
+==================
+ * feat(schema): add saveErrorIfNotFound option and $where property #4924 #4004
+ * feat(query): add $in implicitly if passed an array #4912 [QuotableWater7](https://github.com/QuotableWater7)
+ * feat(aggregate): helper for $facet #4904 [varunjayaraman](https://github.com/varunjayaraman)
+ * feat(query): add collation method #4839
+ * feat(schema): propogate strict option to implicit array subschemas #4831 [dkrosso](https://github.com/dkrosso)
+ * feat(aggregate): add helper for graphLookup #4819 [varunjayaraman](https://github.com/varunjayaraman)
+ * feat(types): support Decimal128 #4759
+ * feat(aggregate): add eachAsync() to aggregate cursor #4300
+ * feat(query): add updateOne and updateMany #3997
+ * feat(model): support options for insertMany #3893
+ * fix(document): run validation on single nested docs if not directly modified #3884
+ * feat(model): use discriminator constructor based on discriminatorKey in create() #3624
+ * feat: pass collection as context to debug function #3261
+ * feat(query): support push and addToSet for update validators #2933
+ * perf(document): refactor registerHooksFromSchema so hooks are defined on doc prototype #2754
+ * feat(types): add discriminator() function to doc arrays #2723 #1856
+ * fix(populate): return an error if sorting underneath a doc array #2202
+
+4.7.9 / 2017-01-27
+==================
+ * fix(query): handle casting $exists under $not #4933
+ * chore: upgrade mongodb -> 2.2.22 re: #4931
+
+4.7.8 / 2017-01-23
+==================
+ * fix(populate): better handling for virtual populate under arrays #4923
+ * docs: upgrade contributors count #4918 [AdamZaczek](https://github.com/AdamZaczek)
+ * fix(query): don't set nested path default if setting parent path #4911
+ * docs(promise): add missing bracket #4907
+ * fix(connection): ensure error handling is consistently async #4905
+ * fix: handle authMechanism in query string #4900
+ * fix(document): ensure error handlers run for validate #4885
+
+4.7.7 / 2017-01-15
+==================
+ * fix(utils): don't crash if to[key] is null #4881
+ * fix: upgrade mongodb -> 2.2.21 #4867
+ * fix: add a toBSON to documents for easier querying #4866
+ * fix: suppress bluebird warning #4854 [davidwu226](https://github.com/davidwu226)
+ * fix(populate): handle nested virtuals in virtual populate #4851
+
+4.7.6 / 2017-01-02
+==================
+ * fix(model): allow passing non-array to insertMany #4846
+ * fix(populate): use base model name if no discriminator for backwards compat #4843
+ * fix: allow internal validate callback to be optional #4842 [arciisine](https://github.com/arciisine)
+ * fix(document): don't skip pointCut if save not defined (like in browser doc) #4841
+ * chore: improve benchmarks #4838 [billouboq](https://github.com/billouboq)
+ * perf: remove some unused parameters #4837 [billouboq](https://github.com/billouboq)
+ * fix(query): don't call error handler if passRawResult is true and no error occurred #4836
+
+4.7.5 / 2016-12-26
+==================
+ * docs(model): fix spelling mistake #4828 [paulinoj](https://github.com/paulinoj)
+ * fix(aggregate): remove unhandled rejection when using aggregate.then() #4824
+ * perf: remove try/catch that kills optimizer #4821
+ * fix(model): handles populating with discriminators that may not have a ref #4817
+ * fix(document): handle setting array of discriminators #3575
+
+4.7.4 / 2016-12-21
+==================
+ * docs: fix typo #4810 [GEEKIAM](https://github.com/GEEKIAM)
+ * fix(query): timestamps with $push + $each #4805
+ * fix(document): handle buffers correctly in minimize #4800
+ * fix: don't disallow overwriting default and cast fns #4795 [pdspicer](https://github.com/pdspicer)
+ * fix(document): don't convert single nested docs to POJOs #4793
+ * fix(connection): handle reconnect to replica set correctly #4972 [gfzabarino](https://github.com/gfzabarino)
+
+4.7.3 / 2016-12-16
+==================
+ * fix: upgrade mongodb driver -> 2.2.16 for several bug fixes and 3.4 support #4799
+ * fix(model): ensure discriminator key is correct for child schema on discriminator #4790
+ * fix(document): handle mark valid in subdocs correctly #4778
+ * fix(query): check for objects consistently #4775
+
+4.7.2 / 2016-12-07
+==================
+ * test(populate): fix justOne test #4772 [cblanc](https://github.com/cblanc)
+ * chore: fix benchmarks #4769 [billouboq](https://github.com/billouboq)
+ * fix(document): handle setting subdoc to null after setting parent doc #4766
+ * fix(query): support passRawResult with lean #4762 #4761 [mhfrantz](https://github.com/mhfrantz)
+ * fix(query): throw StrictModeError if upsert with nonexisting field in condition #4757
+ * test: fix a couple of sort tests #4756 [japod](https://github.com/japod)
+ * chore: upgrade mongodb driver -> 2.2.12 #4753 [mdlavin](https://github.com/mdlavin)
+ * fix(query): handle update with upsert and overwrite correctly #4749
+
+4.7.1 / 2016-11-30
+==================
+ * fix(schema): throw error if you use prototype as a schema path #4746
+ * fix(schema): throw helpful error if you define a virtual with the same path as a real path #4744
+ * fix(connection): make createConnection not throw rejected promises #4742
+ * fix(populate): allow specifiying options in model schema #4741
+ * fix(document): handle selected nested elements with defaults #4739
+ * fix(query): add model to cast error if possible #4729
+ * fix(query): handle timestamps with overwrite #4054
+
+4.7.0 / 2016-11-23
+==================
+ * docs: clean up schematypes #4732 [kidlj](https://github.com/kidlj)
+ * perf: only get stack when necessary with VersionError #4726 [Sebmaster](https://github.com/Sebmaster)
+ * fix(query): ensure correct casting when setting array element #4724
+ * fix(connection): ensure db name gets set when you pass 4 params #4721
+ * fix: prevent TypeError in node v7 #4719 #4706
+ * feat(document): support .set() on virtual subpaths #4716
+ * feat(populate): support populate virtuals on nested schemas #4715
+ * feat(querycursor): support transform option and .map() #4714 #4705 [cblanc](https://github.com/cblanc)
+ * fix(document): dont set defaults on not-selected nested paths #4707
+ * fix(populate): don't throw if empty string passed to populate #4702
+ * feat(model): add `loadClass()` function for importing schema from ES6 class #4668 [rockmacaca](https://github.com/rockmacaca)
+
+4.6.8 / 2016-11-14
+==================
+ * fix(querycursor): clear stack when iterating onto next doc #4697
+ * fix: handle null keys in validation error #4693 #4689 [arciisine](https://github.com/arciisine)
+ * fix(populate): handle pre init middleware correctly with populate virtuals #4683
+ * fix(connection): ensure consistent return value for open and openSet #4659
+ * fix(schema): handle falsy defaults for arrays #4620
+
+4.6.7 / 2016-11-10
+==================
+ * fix(document): only invalidate in subdoc if using update validators #4681
+ * fix(document): don't create subdocs when excluded in projection #4669
+ * fix(document): ensure single embedded schema validator runs with correct context #4663
+ * fix(document): make sure to depopulate top level for sharding #4658
+ * fix(connection): throw more helpful error when .model() called incorrectly #4652
+ * fix(populate): throw more descriptive error when trying to populate a virtual that doesn't have proper options #4602
+ * fix(document): ensure subtype gets set properly when saving with a buffer id #4506
+ * fix(query): handle setDefaultsOnInsert with defaults on doc arrays #4456
+ * fix(drivers): make debug output better by calling toBSON() #4356
+
+4.6.6 / 2016-11-03
+==================
+ * chore: upgrade deps #4674 [TrejGun](https://github.com/TrejGun)
+ * chore: run tests on node v7 #4673 [TrejGun](https://github.com/TrejGun)
+ * perf: make setDefaultsOnInsert more efficient if upsert is off #4672 [CamHenlin](https://github.com/CamHenlin)
+ * fix(populate): ensure document array is returned #4656
+ * fix(query): cast doc arrays with positionals correctly for update #4655
+ * fix(document): ensure single nested doc validators run with correct context #4654
+ * fix: handle reconnect failed error in new version of driver #4653 [loris](https://github.com/loris)
+ * fix(populate): if setting a populated doc, take its id #4632
+ * fix(populate): handle populated virtuals in init #4618
+
+4.6.5 / 2016-10-23
+==================
+ * docs: fix grammar issues #4642 #4640 #4639 [silvermanj7](https://github.com/silvermanj7)
+ * fix(populate): filter out nonexistant values for dynref #4637
+ * fix(query): handle $type as a schematype operator #4632
+ * fix(schema): better handling for uppercase: false and lowercase: false #4622
+ * fix(query): don't run transforms on updateForExec() #4621
+ * fix(query): handle id = 0 in findById #4610
+ * fix(query): handle buffers in mergeClone #4609
+ * fix(document): handle undefined with conditional validator for validateSync #4607
+ * fix: upgrade to mongodb driver 2.2.11 #4581
+ * docs(schematypes): clarify schema.path() #4518
+ * fix(query): ensure path is defined before checking in timestamps #4514
+ * fix(model): set version key in upsert #4505
+ * fix(document): never depopulate top-level doc #3057
+ * refactor: ensure sync for setting non-capped collections #2690
+
+4.6.4 / 2016-10-16
+==================
+ * fix(query): cast $not correctly #4616 #4592 [prssn](https://github.com/prssn)
+ * fix: address issue with caching global plugins #4608 #4601 [TrejGun](https://github.com/TrejGun)
+ * fix(model): make sure to depopulate in insertMany #4590
+ * fix(model): buffer autoIndex if bufferCommands disabled #4589
+ * fix(populate): copy ids array before modifying #4585
+ * feat(schema): add retainKeyOrder prop #4542
+ * fix(document): return isModified true for children of direct modified paths #4528
+ * fix(connection): add dropDatabase() helper #4490
+ * fix(model): add usePushEach option for schemas #4455
+ * docs(connections): add some warnings about buffering #4413
+ * fix: add ability to set promise implementation in browser #4395
+
+4.6.3 / 2016-10-05
+==================
+ * fix(document): ensure single nested docs get initialized correctly when setting nested paths #4578
+ * fix: turn off transforms when writing nested docs to db #4574
+ * fix(document): don't set single nested subdocs to null when removing parent doc #4566
+ * fix(model): ensure versionKey gets set in insertMany #4561
+ * fix(schema): handle typeKey in arrays #4548
+ * feat(schema): set $implicitlyCreated on schema if created by interpretAsType #4443
+
+4.6.2 / 2016-09-30
+==================
+ * chore: upgrade to async 2.0.1 internally #4579 [billouboq](https://github.com/billouboq)
+ * fix(types): ensure nested single doc schema errors reach update validators #4557 #4519
+ * fix(connection): handle rs names with leading numbers (muri 1.1.1) #4556
+ * fix(model): don't throw if method name conflicts with Object.prototype prop #4551
+ * docs: fix broken link #4544 [VFedyk](https://github.com/VFedyk)
+ * fix: allow overwriting model on mongoose singleton #4541 [Nainterceptor](https://github.com/Nainterceptor)
+ * fix(document): don't use init: true when building doc defaults #4540
+ * fix(connection): use replSet option if replset not specified #4535
+ * fix(query): cast $not objects #4495
+
+4.6.1 / 2016-09-20
+==================
+ * fix(query): improve handling of $not with $elemMatch #4531 #3719 [timbowhite](https://github.com/timbowhite)
+ * fix: upgrade mongodb -> 2.2.10 #4517
+ * chore: fix webpack build issue #4512 [saiichihashimoto](https://github.com/saiichihashimoto)
+ * fix(query): emit error on next tick when exec callback errors #4500
+ * test: improve test case #4496 [isayme](https://github.com/isayme)
+ * fix(schema): use same check for array types and top-level types #4493
+ * style: fix indentation in docs #4489 [dhurlburtusa](https://github.com/dhurlburtusa)
+ * fix(schema): expose original object passed to constructor #4486
+ * fix(query): handle findOneAndUpdate with array of arrays #4484 #4470 [fedotov](https://github.com/fedotov)
+ * feat(document): add $ignore to make a path ignored #4480
+ * fix(query): properly handle setting single embedded in update #4475 #4466 #4465
+ * fix(updateValidators): handle single nested schema subpaths correctly #4479
+ * fix(model): throw handy error when method name conflicts with property name #4475
+ * fix(schema): handle .set() with array field #4472
+ * fix(query): check nested path when avoiding double-validating Mixed #4441
+ * fix(schema): handle calling path.trim() with no args correctly #4042
+
+4.6.0 / 2016-09-02
+==================
+ * docs(document): clarify the findById and findByIdAndUpdate examples #4471 [mdcanham](https://github.com/mdcanham)
+ * docs(schematypes): add details re: options #4452
+ * docs(middleware): add docs for insertMany hooks #4451
+ * fix(schema): create new array when copying from existing object to preserve change tracking #4449
+ * docs: fix typo in index.jade #4448
+ * fix(query): allow array for populate options #4446
+ * fix(model): create should not cause unhandle reject promise #4439
+ * fix: upgrade to mongodb driver 2.2.9 #4363 #4341 #4311 (see [comments here](https://github.com/mongodb/js-bson/commit/aa0b54597a0af28cce3530d2144af708e4b66bf0#commitcomment-18850498) if you use node 0.10)
+
+4.5.10 / 2016-08-23
+===================
+ * docs: fix typo on documents.jade #4444 [Gabri3l](https://github.com/Gabri3l)
+ * chore: upgrade mocha to 3.0.2 #4437 [TrejGun](https://github.com/TrejGun)
+ * fix: subdocuments causing error with parent timestamp on update #4434 [dyang108](https://github.com/dyang108)
+ * fix(query): don't crash if timestamps on and update doesn't have a path #4425 #4424 #4418
+ * fix(query): ensure single nested subdoc is hydrated when running update validators #4420
+ * fix(query): cast non-$geometry operators for $geoWithin #4419
+ * docs: update contributor count #4415 [AdamZaczek](https://github.com/AdamZaczek)
+ * docs: add more clarification re: the index event #4410
+ * fix(document): only skip modifying subdoc path if parent is direct modified #4405
+ * fix(schema): throw cast error if provided date invalid #4404
+ * feat(error): use util.inspect() so CastError never prints "[object Object]" #4398
+ * fix(model): dont error if the discriminator key is unchanged #4387
+ * fix(query): don't throw unhandled rejection with bluebird when using cbs #4379
+
+4.5.9 / 2016-08-14
+==================
+ * docs: add mixed schema doc for Object literal #4400 [Kikobeats](https://github.com/Kikobeats)
+ * fix(query): cast $geoWithin and convert mongoose objects to POJOs before casting #4392
+ * fix(schematype): dont cast defaults without parent doc #4390
+ * fix(query): disallow passing empty string to findOne() #4378
+ * fix(document): set single nested doc isNew correctly #4369
+ * fix(types): checks field name correctly with nested arrays and populate #4365
+ * fix(drivers): make debug output copy-pastable into mongodb shell #4352
+ * fix(services): run update validators on nested paths #4332
+ * fix(model): handle typeKey with discriminators #4339
+ * fix(query): apply timestamps to child schemas when explicitly specified in update #4049
+ * fix(schema): set prefix as nested path with add() #1730
+
+4.5.8 / 2016-08-01
+==================
+ * fix(model): make changing the discriminator key cause a cast error #4374
+ * fix(query): pass projection fields to cursor #4371 #4342 [Corei13](https://github.com/Corei13)
+ * fix(document): support multiple paths for isModified #4370 [adambuczynski](https://github.com/adambuczynski)
+ * fix(querycursor): always cast fields before returning cursor #4355
+ * fix(query): support projection as alias for fields in findOneAndUpdate #4315
+ * fix(schema): treat index false + unique false as no index #4304
+ * fix(types): dont mark single nested subpath as modified if whole doc already modified #4224
+
+4.5.7 / 2016-07-25
+==================
+ * fix(document): ensure no unhandled rejections if callback specified for save #4364
+
+4.5.6 / 2016-07-23
+==================
+ * fix(schema): don't overwrite createdAt if it isn't selected #4351 [tusbar](https://github.com/tusbar)
+ * docs(api): fix link to populate() and add a new one from depopulate() #4345 [Delapouite](https://github.com/Delapouite)
+ * fix(types): ownerDocument() works properly with single nested docs #4344 [vichle](https://github.com/vichle)
+ * fix(populate): dont use findOne when justOne option set #4329
+ * fix(document): dont trigger .then() deprecated warning when calling doc.remove() #4291
+ * docs(connection): add promiseLibrary option #4280
+ * fix(plugins): apply global plugins to subschemas #4271
+ * fix(model): ensure `ensureIndex()` never calls back in the same tick #4246
+ * docs(schema): improve post hook docs on schema #4238
+
+4.5.5 / 2016-07-18
+==================
+ * fix(document): handle setting root to empty obj if minimize false #4337
+ * fix: downgrade to mongodb 2.1.18 #4335 #4334 #4328 #4323
+ * perf(types): remove defineProperty usage in documentarray #4333
+ * fix(query): correctly pass model in .toConstructor() #4318
+ * fix(services): avoid double-validating mixed types with update validators #4305
+ * docs(middleware): add docs describing error handling middleware #4229
+ * fix(types): throw correct error when invalidating doc array #3602
+
+4.5.4 / 2016-07-11
+==================
+ * fix(types): fix removing embedded documents #4309 [RoCat](https://github.com/RoCat)
+ * docs: various docs improvements #4302 #4294 [simonxca](https://github.com/simonxca)
+ * fix: upgrade mongodb -> 2.1.21 #4295 #4202 [RoCat](https://github.com/RoCat)
+ * fix(populate): convert single result to array for virtual populate because of lean #4288
+ * fix(populate): handle empty results for populate virtuals properly #4285 #4284
+ * fix(query): dont cast $inc to number if type is long #4283
+ * fix(types): allow setting single nested doc to null #4281
+ * fix(populate): handle deeply nested virtual populate #4278
+ * fix(document): allow setting empty obj if strict mode is false #4274
+ * fix(aggregate): allow passing obj to .unwind() #4239
+ * docs(document): add return statements to transform examples #1963
+
+4.5.3 / 2016-06-30
+==================
+ * fix(query): pass correct options to QueryCursor #4277 #4266
+ * fix(querycursor): handle lean option correctly #4276 [gchudnov](https://github.com/gchudnov)
+ * fix(document): fix error handling when no error occurred #4275
+ * fix(error): use strict mode for version error #4272
+ * docs(populate): fix crashing compilation for populate.jade #4267
+ * fix(populate): support `justOne` option for populate virtuals #4263
+ * fix(populate): ensure model param gets used for populate virtuals #4261 #4243
+ * fix(querycursor): add ability to properly close the cursor #4258
+ * docs(model): correct link to Document #4250
+ * docs(populate): correct path for refPath populate #4240
+ * fix(document): support validator.isEmail as validator #4064
+
+4.5.2 / 2016-06-24
+==================
+ * fix(connection): add checks for collection presence for `onOpen` and `onClose` #4259 [nodkz](https://github.com/nodkz)
+ * fix(cast): allow strings for $type operator #4256
+ * fix(querycursor): support lean() #4255 [pyramation](https://github.com/pyramation)
+ * fix(aggregate): allow setting noCursorTimeout option #4241
+ * fix(document): handle undefined for Array.pull #4222 [Sebmaster](https://github.com/Sebmaster)
+ * fix(connection): ensure promise.catch() catches initial connection error #4135
+ * fix(document): show additional context for VersionError #2633
+
+4.5.1 / 2016-06-18
+==================
+ * fix(model): ensure wrapped insertMany() returns a promise #4237
+ * fix(populate): dont overwrite populateVirtuals when populating multiple paths #4234
+ * docs(model): clarify relationship between create() and save() #4233
+ * fix(types): handle option param in subdoc remove() #4231 [tdebarochez](https://github.com/tdebarochez)
+ * fix(document): dedupe modified paths #4226 #4223 [adambuczynski](https://github.com/adambuczynski)
+ * fix(model): don't modify user-provided options object #4221
+ * fix(document): handle setting nested path to empty object #4218 #4182
+ * fix(document): clean subpaths when removing single nested #4216
+ * fix(document): don't force transform on subdocs with inspect #4213
+ * fix(error): allow setting .messages object #4207
+
+4.5.0 / 2016-06-13
+==================
+ * feat(query): added Query.prototype.catch() #4215 #4173 [adambuczynski](https://github.com/adambuczynski)
+ * feat(query): add Query.prototype.cursor() as a .stream() alternative #4117 #3637 #1907
+ * feat(document): add markUnmodified() function #4092 [vincentcr](https://github.com/vincentcr)
+ * feat(aggregate): convert aggregate object to a thenable #3995 #3946 [megagon](https://github.com/megagon)
+ * perf(types): remove defineProperties call for array (**Note:** Because of this, a mongoose array will no longer `assert.deepEqual()` a plain old JS array) #3886
+ * feat(model): add hooks for insertMany() #3846
+ * feat(schema): add support for custom query methods #3740 #2372
+ * feat(drivers): emit error on 'serverClosed' because that means that reconnect failed #3615
+ * feat(model): emit error event when callback throws exception #3499
+ * feat(model): inherit options from discriminator base schema #3414 #1818
+ * feat(populate): expose mongoose-populate-virtuals inspired populate API #2562
+ * feat(document): trigger remove hooks on subdocs when removing parent #2348
+ * feat(schema): add support for express-style error handling middleware #2284
+ * fix(model): disallow setting discriminator key #2041
+ * feat(schema): add support for nested arrays #1361
+
+4.4.20 / 2016-06-05
+===================
+ * docs: clarify command buffering when using driver directly #4195
+ * fix(promise): correct broken mpromise .catch() #4189
+ * fix(document): clean modified subpaths when set path to empty obj #4182
+ * fix(query): support minDistance with query casting and `.near()` #4179
+ * fix(model): remove unnecessary .save() promise #4177
+ * fix(schema): cast all valid ObjectId strings to object ids #3365
+ * docs: remove unclear "unsafe" term in query docs #3282
+
+4.4.19 / 2016-05-21
+===================
+ * fix(model): handle insertMany if timestamps not set #4171
+
+4.4.18 / 2016-05-21
+===================
+ * docs: add missing period #4170 [gitname](https://github.com/gitname)
+ * docs: change build badge to svg #4158 [a0viedo](https://github.com/a0viedo)
+ * fix(model): update timestamps when setting `createdAt` #4155
+ * fix(utils): make sure to require in document properly #4152
+ * fix(model): throw overwrite error when discriminator name conflicts #4148
+
+4.4.17 / 2016-05-13
+===================
+ * docs: remove repetition in QueryStream docs #4147 [hugoabonizio](https://github.com/hugoabonizio)
+ * fix(document): dont double-validate doc array elements #4145
+ * fix(document): call required function with correct scope #4142 [JedWatson](https://github.com/JedWatson)
+
+4.4.16 / 2016-05-09
+===================
+ * refactor(document): use function reference #4133 [dciccale](https://github.com/dciccale)
+ * docs(querystream): clarify `destroy()` and close event #4126 [AnthonyCC](https://github.com/AnthonyCC)
+ * test: make before hook fail fast if it can't connect #4121
+ * docs: add description of CastError constructor params #4120
+ * fix(schematype): ensure single embedded defaults have $parent #4115
+ * fix(document): mark nested paths for validation #4111
+ * fix(schema): make sure element is always a subdoc in doc array validation #3816
+
+4.4.15 / 2016-05-06
+===================
+ * fix(schema): support overwriting array default #4109
+ * fix(populate): assign values when resolving each populate #4104
+ * fix(aggregate): dont send async option to server #4101
+ * fix(model): ensure isNew set to false after insertMany #4099
+ * fix(connection): emit on error if listeners and no callback #4098
+ * fix(document): treat required fn that returns false as required: false #4094
+
+4.4.14 / 2016-04-27
+===================
+ * fix: upgrade mongodb -> 2.1.18 #4102
+ * feat(connection): allow setting mongos as a uri query param #4093 #4035 [burtonjc](https://github.com/burtonjc)
+ * fix(populate): make sure to use correct assignment order for each model #4073
+ * fix(schema): add complete set of geospatial operators for single embedded subdocs #4014
+
+3.8.40 / 2016-04-24
+===================
+ * upgraded; mquery -> 1.10.0 #3989
+
+4.4.13 / 2016-04-21
+===================
+ * docs: add docs favicons #4082 [robertjustjones](https://github.com/robertjustjones)
+ * docs(model): correct Model.remove() return value #4075 [Jokero](https://github.com/Jokero)
+ * fix(query): add $geoWithin query casting for single embedded docs #4044
+ * fix(schema): handle setting trim option to falsy #4042
+ * fix(query): handle setDefaultsOnInsert with empty update #3835
+
+4.4.12 / 2016-04-08
+===================
+ * docs(query): document context option for update and findOneAndUpdate #4055
+ * docs(query): correct link to $geoWithin docs #4050
+ * fix(project): upgrade to mongodb driver 2.1.16 #4048 [schmalliso](https://github.com/schmalliso)
+ * docs(validation): fix validation docs #4028
+ * fix(types): improve .id() check for document arrays #4011
+ * fix(query): remove premature return when using $rename #3171
+ * docs(connection): clarify relationship between models and connections #2157
+
+4.4.11 / 2016-04-03
+===================
+ * fix: upgrade to mongodb driver 2.1.14 #4036 #4030 #3945
+ * fix(connection): allow connecting with { mongos: true } to handle query params #4032 [burtonjc](https://github.com/burtonjc)
+ * docs(connection): add autoIndex example #4026 [tilleps](https://github.com/tilleps)
+ * fix(query): handle passRawResult option when zero results #4023
+ * fix(populate): clone options before modifying #4022
+ * docs: add missing whitespace #4019 [chenxsan](https://github.com/chenxsan)
+ * chore: upgrade to ESLint 2.4.0 #4015 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix(types): single nested subdocs get ids by default #4008
+ * chore(project): add dependency status badge #4007 [Maheshkumar-Kakade](http://github.com/Maheshkumar-Kakade)
+ * fix: make sure timestamps don't trigger unnecessary updates #4005 #3991 [tommarien](https://github.com/tommarien)
+ * fix(document): inspect inherits schema options #4001
+ * fix(populate): don't mark populated path as modified if setting to object w/ same id #3992
+ * fix(document): support kind argument to invalidate #3965
+
+4.4.10 / 2016-03-24
+===================
+ * fix(document): copy isNew when copying a document #3982
+ * fix(document): don't override defaults with undefined keys #3981
+ * fix(populate): merge multiple deep populate options for the same path #3974
+
+4.4.9 / 2016-03-22
+==================
+ * fix: upgrade mongodb -> 2.1.10 re https://jira.mongodb.org/browse/NODE-679 #4010
+ * docs: add syntax highlighting for acquit examples #3975
+
+4.4.8 / 2016-03-18
+==================
+ * docs(aggregate): clarify promises #3990 [megagon](https://github.com/megagon)
+ * fix: upgrade mquery -> 1.10 #3988 [matskiv](https://github.com/matskiv)
+ * feat(connection): 'all' event for repl sets #3986 [xizhibei](https://github.com/xizhibei)
+ * docs(types): clarify Array.pull #3985 [seriousManual](https://github.com/seriousManual)
+ * feat(query): support array syntax for .sort() via mquery 1.9 #3980
+ * fix(populate): support > 3 level nested populate #3973
+ * fix: MongooseThenable exposes connection correctly #3972
+ * docs(connection): add note about reconnectTries and reconnectInterval #3969
+ * feat(document): invalidate returns the new validationError #3964
+ * fix(query): .eq() as shorthand for .equals #3953 [Fonger](https://github.com/Fonger)
+ * docs(connection): clarify connection string vs passed options #3941
+ * docs(query): select option for findOneAndUpdate #3933
+ * fix(error): ValidationError.properties no longer enumerable #3925
+ * docs(validation): clarify how required validators work with nested schemas #3915
+ * fix: upgrade mongodb driver -> 2.1.8 to make partial index errors more sane #3864
+
+4.4.7 / 2016-03-11
+==================
+ * fix(query): stop infinite recursion caused by merging a mongoose buffer #3961
+ * fix(populate): handle deep populate array -> array #3954
+ * fix(schema): allow setting timestamps with .set() #3952 #3951 #3907 [Fonger](https://github.com/Fonger)
+ * fix: MongooseThenable doesn't overwrite constructors #3940
+ * fix(schema): don't cast boolean to date #3935
+ * fix(drivers): support sslValidate in connection string #3929
+ * fix(types): correct markModified() for single nested subdocs #3910
+ * fix(drivers): catch and report any errors that occur in driver methods #3906
+ * fix(populate): get subpopulate model correctly when array under nested #3904
+ * fix(document): allow fields named 'pre' and 'post' #3902
+ * docs(query): clarify runValidators and setDefaultsOnInsert options #3892
+ * docs(validation): show how to use custom required messages in schema #2616
+
+4.4.6 / 2016-03-02
+==================
+ * fix: upgrade mongodb driver to 2.1.7 #3938
+ * docs: fix plugins link #3917 #3909 [fbertone](https://github.com/fbertone)
+ * fix(query): sort+select with count works #3914
+ * fix(query): improve mergeUpdate's ability to handle nested docs #3890
+
+4.4.5 / 2016-02-24
+==================
+ * fix(query): ability to select a length field (upgrade to mquery 1.7.0) #3903
+ * fix: include nested CastError as reason for array CastError #3897 [kotarou3](https://github.com/kotarou3)
+ * fix(schema): check for doc existence before taking fields #3889
+ * feat(schema): useNestedStrict option to take nested strict mode for update #3883
+ * docs(validation): clarify relationship between required and checkRequired #3822
+ * docs(populate): dynamic reference docs #3809
+ * docs: expand dropdown when clicking on file name #3807
+ * docs: plugins.mongoosejs.io is up #3127
+ * fix(schema): ability to add a virtual with same name as removed path #2398
+
+4.4.4 / 2016-02-17
+==================
+ * fix(schema): handle field selection when casting single nested subdocs #3880
+ * fix(populate): populating using base model with multiple child models in result #3878
+ * fix: ability to properly use return value of `mongoose.connect()` #3874
+ * fix(populate): dont hydrate populated subdoc if lean option set #3873
+ * fix(connection): dont re-auth if already connected with useDb #3871
+ * docs: cover how to set underlying driver's promise lib #3869
+ * fix(document): handle conflicting names in validation errors with subdocs #3867
+ * fix(populate): set undefined instead of null consistently when populate couldn't find results #3859
+ * docs: link to `execPopulate()` in `doc.populate()` docs #3836
+ * docs(plugin): link to the `mongoose.plugin()` function #3732
+
+4.4.3 / 2016-02-09
+==================
+ * fix: upgrade to mongodb 2.1.6 to remove kerberos log output #3861 #3860 [cartuchogl](https://github.com/cartuchogl)
+ * fix: require('mongoose') is no longer a pseudo-promise #3856
+ * fix(query): update casting for single nested docs #3820
+ * fix(populate): deep populating multiple paths with same options #3808
+ * docs(middleware): clarify save/validate hook order #1149
+
+4.4.2 / 2016-02-05
+==================
+ * fix(aggregate): handle calling .cursor() with no options #3855
+ * fix: upgrade mongodb driver to 2.1.5 for GridFS memory leak fix #3854
+ * docs: fix schematype.html conflict #3853 #3850 #3843
+ * fix(model): bluebird unhandled rejection with ensureIndexes() on init #3837
+ * docs: autoIndex option for createConnection #3805
+
+4.4.1 / 2016-02-03
+==================
+ * fix: linting broke some cases where we use `== null` as shorthand #3852
+ * docs: fix up schematype.html conflict #3848 #3843 [mynameiscoffey](https://github.com/mynameiscoffey)
+ * fix: backwards breaking change with `.connect()` return value #3847
+ * docs: downgrade dox and highlight.js to fix docs build #3845
+ * docs: clean up typo #3842 [Flash-](https://github.com/Flash-)
+ * fix(document): storeShard handles undefined values #3841
+ * chore: more linting #3838 [TrejGun](https://github.com/TrejGun)
+ * fix(schema): handle `text: true` as a way to declare a text index #3824
+
+4.4.0 / 2016-02-02
+==================
+ * docs: fix expireAfterSeconds index option name #3831 [Flash-](https://github.com/Flash-)
+ * chore: run lint after test #3829 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * chore: use power-assert instead of assert #3828 [TrejGun](https://github.com/TrejGun)
+ * chore: stricter lint #3827 [TrejGun](https://github.com/TrejGun)
+ * feat(types): casting moment to date #3813 [TrejGun](https://github.com/TrejGun)
+ * chore: comma-last lint for test folder #3810 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix: upgrade async mpath, mpromise, muri, and sliced #3801 [TrejGun](https://github.com/TrejGun)
+ * fix(query): geo queries now return proper ES2015 promises #3800 [TrejGun](https://github.com/TrejGun)
+ * perf(types): use `Object.defineProperties()` for array #3799 [TrejGun](https://github.com/TrejGun)
+ * fix(model): mapReduce, ensureIndexes, remove, and save properly return ES2015 promises #3795 #3628 #3595 [TrejGun](https://github.com/TrejGun)
+ * docs: fixed dates in History.md #3791 [Jokero](https://github.com/Jokero)
+ * feat: connect, open, openSet, and disconnect return ES2015 promises #3790 #3622 [TrejGun](https://github.com/TrejGun)
+ * feat: custom type for int32 via mongoose-int32 npm package #3652 #3102
+ * feat: basic custom schema type API #995
+ * feat(model): `insertMany()` for more performant bulk inserts #723
+
+4.3.7 / 2016-01-23
+==================
+ * docs: grammar fix in timestamps docs #3786 [zclancy](https://github.com/zclancy)
+ * fix(document): setting nested populated docs #3783 [slamuu](https://github.com/slamuu)
+ * fix(document): don't call post save hooks twice for pushed docs #3780
+ * fix(model): handle `_id=0` correctly #3776
+ * docs(middleware): async post hooks #3770
+ * docs: remove confusing sentence #3765 [marcusmellis89](https://github.com/marcusmellis89)
+
+3.8.39 / 2016-01-15
+===================
+ * fixed; casting a number to a buffer #3764
+ * fixed; enumerating virtual property with nested objects #3743 [kusold](https://github.com/kusold)
+
+4.3.6 / 2016-01-15
+==================
+ * fix(types): casting a number to a buffer #3764
+ * fix: add "listener" to reserved keywords #3759
+ * chore: upgrade uglify #3757 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix: broken execPopulate() in 4.3.5 #3755 #3753
+ * fix: ability to remove() a single embedded doc #3754
+ * style: comma-last in test folder #3751 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * docs: clarify versionKey option #3747
+ * fix: improve colorization for arrays #3744 [TrejGun](https://github.com/TrejGun)
+ * fix: webpack build #3713
+
+4.3.5 / 2016-01-09
+==================
+ * fix(query): throw when 4th parameter to update not a function #3741 [kasselTrankos](https://github.com/kasselTrankos)
+ * fix(document): separate error type for setting an object to a primitive #3735
+ * fix(populate): Model.populate returns ES6 promise #3734
+ * fix(drivers): re-register event handlers after manual reconnect #3729
+ * docs: broken links #3727
+ * fix(validation): update validators run array validation #3724
+ * docs: clarify the need to use markModified with in-place date ops #3722
+ * fix(document): mark correct path as populated when manually populating array #3721
+ * fix(aggregate): support for array pipeline argument to append #3718 [dbkup](https://github.com/dbkup)
+ * docs: clarify `.connect()` callback #3705
+ * fix(schema): properly validate nested single nested docs #3702
+ * fix(types): handle setting documentarray of wrong type #3701
+ * docs: broken links #3700
+ * fix(drivers): debug output properly displays '0' #3689
+
+3.8.38 / 2016-01-07
+===================
+ * fixed; aggregate.append an array #3730 [dbkup](https://github.com/dbkup)
+
+4.3.4 / 2015-12-23
+==================
+ * fix: upgrade mongodb driver to 2.1.2 for repl set error #3712 [sansmischevia](https://github.com/sansmischevia)
+ * docs: validation docs typo #3709 [ivanmaeder](https://github.com/ivanmaeder)
+ * style: remove unused variables #3708 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix(schema): duck-typing for schemas #3703 [mgcrea](https://github.com/mgcrea)
+ * docs: connection sample code issue #3697
+ * fix(schema): duck-typing for schemas #3693 [mgcrea](https://github.com/mgcrea)
+ * docs: clarify id schema option #3638
+
+4.3.3 / 2015-12-18
+==================
+ * fix(connection): properly support 'replSet' as well as 'replset' #3688 [taxilian](https://github.com/taxilian)
+ * fix(document): single nested doc pre hooks called before nested doc array #3687 [aliatsis](https://github.com/aliatsis)
+
+4.3.2 / 2015-12-17
+==================
+ * fix(document): .set() into single nested schemas #3686
+ * fix(connection): support 'replSet' as well as 'replset' option #3685
+ * fix(document): bluebird unhandled rejection when validating doc arrays #3681
+ * fix(document): hooks for doc arrays in single nested schemas #3680
+ * fix(document): post hooks for single nested schemas #3679
+ * fix: remove unused npm module #3674 [sybarite](https://github.com/sybarite)
+ * fix(model): don't swallow exceptions in nested doc save callback #3671
+ * docs: update keepAlive info #3667 [ChrisZieba](https://github.com/ChrisZieba)
+ * fix(document): strict 'throw' throws a specific mongoose error #3662
+ * fix: flakey test #3332
+ * fix(query): more robust check for RegExp #2969
+
+4.3.1 / 2015-12-11
+==================
+ * feat(aggregate): `.sample()` helper #3665
+ * fix(query): bitwise query operators with buffers #3663
+ * docs(migration): clarify `new` option and findByIdAndUpdate #3661
+
+4.3.0 / 2015-12-09
+==================
+ * feat(query): support for mongodb 3.2 bitwise query operators #3660
+ * style: use comma-last style consistently #3657 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * feat: upgrade mongodb driver to 2.1.0 for full MongoDB 3.2 support #3656
+ * feat(aggregate): `.lookup()` helper #3532
+
+4.2.10 / 2015-12-08
+===================
+ * fixed; upgraded marked #3653 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * docs; cross-db populate #3648
+ * docs; update mocha URL #3646 [ojhaujjwal](https://github.com/ojhaujjwal)
+ * fixed; call close callback asynchronously #3645
+ * docs; virtuals.html issue #3644 [Psarna94](https://github.com/Psarna94)
+ * fixed; single embedded doc casting on init #3642
+ * docs; validation docs improvements #3640
+
+4.2.9 / 2015-12-02
+==================
+ * docs; defaults docs #3625
+ * fix; nested numeric keys causing an embedded document crash #3623
+ * fix; apply path getters before virtual getters #3618
+ * fix; casting for arrays in single nested schemas #3616
+
+4.2.8 / 2015-11-25
+==================
+ * docs; clean up README links #3612 [ReadmeCritic](https://github.com/ReadmeCritic)
+ * fix; ESLint improvements #3605 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fix; assigning single nested subdocs #3601
+ * docs; describe custom logging functions in `mongoose.set()` docs #3557
+
+4.2.7 / 2015-11-20
+==================
+ * fixed; readPreference connection string option #3600
+ * fixed; pulling from manually populated arrays #3598 #3579
+ * docs; FAQ about OverwriteModelError #3597 [stcruy](https://github.com/stcruy)
+ * fixed; setting single embedded schemas to null #3596
+ * fixed; indexes for single embedded schemas #3594
+ * docs; clarify projection for `findOne()` #3593 [gunar](https://github.com/gunar)
+ * fixed; .ownerDocument() method on single embedded schemas #3589
+ * fixed; properly throw casterror for query on single embedded schema #3580
+ * upgraded; mongodb driver -> 2.0.49 for reconnect issue fix #3481
+
+4.2.6 / 2015-11-16
+==================
+ * fixed; ability to manually populate an array #3575
+ * docs; clarify `isAsync` parameter to hooks #3573
+ * fixed; use captureStackTrace if possible instead #3571
+ * fixed; crash with buffer and update validators #3565 [johnpeb](https://github.com/johnpeb)
+ * fixed; update casting with operators overwrite: true #3564
+ * fixed; validation with single embedded docs #3562
+ * fixed; inline docs inherit parents $type key #3560
+ * docs; bad grammar in populate docs #3559 [amaurymedeiros](https://github.com/amaurymedeiros)
+ * fixed; properly handle populate option for find() #2321
+
+3.8.37 / 2015-11-16
+===================
+ * fixed; use retainKeyOrder for cloning update op #3572
+
+4.2.5 / 2015-11-09
+==================
+ * fixed; handle setting fields in pre update hooks with exec #3549
+ * upgraded; ESLint #3547 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; bluebird unhandled rejections with cast errors and .exec #3543
+ * fixed; min/max validators handling undefined #3539
+ * fixed; standalone mongos connections #3537
+ * fixed; call `.toObject()` when setting a single nested doc #3535
+ * fixed; single nested docs now have methods #3534
+ * fixed; single nested docs with .create() #3533 #3521 [tusbar](https://github.com/tusbar)
+ * docs; deep populate docs #3528
+ * fixed; deep populate schema ref handling #3507
+ * upgraded; mongodb driver -> 2.0.48 for sort overflow issue #3493
+ * docs; clarify default ids for discriminators #3482
+ * fixed; properly support .update(doc) #3221
+
+4.2.4 / 2015-11-02
+==================
+ * fixed; upgraded `ms` package for security vulnerability #3524 [fhemberger](https://github.com/fhemberger)
+ * fixed; ESlint rules #3517 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * docs; typo in aggregation docs #3513 [rafakato](https://github.com/rafakato)
+ * fixed; add `dontThrowCastError` option to .update() for promises #3512
+ * fixed; don't double-cast buffers in node 4.x #3510 #3496
+ * fixed; population with single embedded schemas #3501
+ * fixed; pre('set') hooks work properly #3479
+ * docs; promises guide #3441
+
+4.2.3 / 2015-10-26
+==================
+ * docs; remove unreferenced function in middleware.jade #3506
+ * fixed; handling auth with no username/password #3500 #3498 #3484 [mleanos](https://github.com/mleanos)
+ * fixed; more ESlint rules #3491 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; swallowing exceptions in save callback #3478
+ * docs; fixed broken links in subdocs guide #3477
+ * fixed; casting booleans to numbers #3475
+ * fixed; report CastError for subdoc arrays in findOneAndUpdate #3468
+ * fixed; geoNear returns ES6 promise #3458
+
+4.2.2 / 2015-10-22
+==================
+ * fixed; go back to old pluralization code #3490
+
+4.2.1 / 2015-10-22
+==================
+ * fixed; pluralization issues #3492 [ChristianMurphy](https://github.com/ChristianMurphy)
+
+4.2.0 / 2015-10-22
+==================
+ * added; support for skipVersioning for document arrays #3467 [chazmo03](https://github.com/chazmo03)
+ * added; ability to customize schema 'type' key #3459 #3245
+ * fixed; writeConcern for index builds #3455
+ * added; emit event when individual index build starts #3440 [objectiveSee](https://github.com/objectiveSee)
+ * added; 'context' option for update validators #3430
+ * refactor; pluralization now in separate pluralize-mongoose npm module #3415 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * added; customizable error validation messages #3406 [geronime](https://github.com/geronime)
+ * added; support for passing 'minimize' option to update #3381
+ * added; ability to customize debug logging format #3261
+ * added; baseModelName property for discriminator models #3202
+ * added; 'emitIndexErrors' option #3174
+ * added; 'async' option for aggregation cursor to support buffering #3160
+ * added; ability to skip validation for individual save() calls #2981
+ * added; single embedded schema support #2689 #585
+ * added; depopulate function #2509
+
+4.1.12 / 2015-10-19
+===================
+ * docs; use readPreference instead of slaveOk for Query.setOptions docs #3471 [buunguyen](https://github.com/buunguyen)
+ * fixed; more helpful error when regexp contains null bytes #3456
+ * fixed; x509 auth issue #3454 [NoxHarmonium](https://github.com/NoxHarmonium)
+
+3.8.36 / 2015-10-18
+===================
+ * fixed; Make array props non-enumerable #3461 [boblauer](https://github.com/boblauer)
+
+4.1.11 / 2015-10-12
+===================
+ * fixed; update timestamps for update() if they're enabled #3450 [isayme](https://github.com/isayme)
+ * fixed; unit test error on node 0.10 #3449 [isayme](https://github.com/isayme)
+ * docs; timestamp option docs #3448 [isayme](https://github.com/isayme)
+ * docs; fix unexpected indent #3443 [isayme](https://github.com/isayme)
+ * fixed; use ES6 promises for Model.prototype.remove() #3442
+ * fixed; don't use unused 'safe' option for index builds #3439
+ * fixed; elemMatch casting bug #3437 #3435 [DefinitelyCarter](https://github.com/DefinitelyCarter)
+ * docs; schema.index docs #3434
+ * fixed; exceptions in save() callback getting swallowed on mongodb 2.4 #3371
+
+4.1.10 / 2015-10-05
+===================
+ * docs; improve virtuals docs to explain virtuals schema option #3433 [zoyaH](https://github.com/zoyaH)
+ * docs; MongoDB server version compatibility guide #3427
+ * docs; clarify that findById and findByIdAndUpdate fire hooks #3422
+ * docs; clean up Model.save() docs #3420
+ * fixed; properly handle projection with just id #3407 #3412
+ * fixed; infinite loop when database document is corrupted #3405
+ * docs; clarify remove middleware #3388
+
+4.1.9 / 2015-09-28
+==================
+ * docs; minlength and maxlength string validation docs #3368 #3413 [cosmosgenius](https://github.com/cosmosgenius)
+ * fixed; linting for infix operators #3397 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; proper casting for $all #3394
+ * fixed; unhandled rejection warnings with .create() #3391
+ * docs; clarify update validators on paths that aren't explicitly set #3386
+ * docs; custom validator examples #2778
+
+4.1.8 / 2015-09-21
+==================
+ * docs; fixed typo in example #3390 [kmctown](https://github.com/kmctown)
+ * fixed; error in toObject() #3387 [guumaster](https://github.com/guumaster)
+ * fixed; handling for casting null dates #3383 [alexmingoia](https://github.com/alexmingoia)
+ * fixed; passing composite ids to `findByIdAndUpdate` #3380
+ * fixed; linting #3376 #3375 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; added NodeJS v4 to Travis #3374 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; casting $elemMatch inside of $not #3373 [gaguirre](https://github.com/gaguirre)
+ * fixed; handle case where $slice is 0 #3369
+ * fixed; avoid running getters if path is populated #3357
+ * fixed; cast documents to objects when setting to a nested path #3346
+
+4.1.7 / 2015-09-14
+==================
+ * docs; typos in SchemaType documentation #3367 [jasson15](https://github.com/jasson15)
+ * fixed; MONGOOSE_DRIVER_PATH env variable again #3360
+ * docs; added validateSync docs #3353
+ * fixed; set findOne op synchronously in query #3344
+ * fixed; handling for `.pull()` on a documentarray without an id #3341
+ * fixed; use natural order for cloning update conditions #3338
+ * fixed; issue with strict mode casting for mixed type updates #3337
+
+4.1.6 / 2015-09-08
+==================
+ * fixed; MONGOOSE_DRIVER_PATH env variable #3345 [g13013](https://github.com/g13013)
+ * docs; global autoIndex option #3335 [albertorestifo](https://github.com/albertorestifo)
+ * docs; model documentation typos #3330
+ * fixed; report reason for CastError #3320
+ * fixed; .populate() no longer returns true after re-assigning #3308
+ * fixed; discriminators with aggregation geoNear #3304
+ * docs; discriminator docs #2743
+
+4.1.5 / 2015-09-01
+==================
+ * fixed; document.remove() removing all docs #3326 #3325
+ * fixed; connect() checks for rs_name in options #3299
+ * docs; examples for schema.set() #3288
+ * fixed; checkKeys issue with bluebird #3286 [gregthegeek](https://github.com/gregthegeek)
+
+4.1.4 / 2015-08-31
+==================
+ * fixed; ability to set strict: false for update #3305
+ * fixed; .create() properly uses ES6 promises #3297
+ * fixed; pre hooks on nested subdocs #3291 #3284 [aliatsis](https://github.com/aliatsis)
+ * docs; remove unclear text in .remove() docs #3282
+ * fixed; pre hooks called twice for 3rd-level nested doc #3281
+ * fixed; nested transforms #3279
+ * upgraded; mquery -> 1.6.3 #3278 #3272
+ * fixed; don't swallow callback errors by default #3273 #3222
+ * fixed; properly get nested paths from nested schemas #3265
+ * fixed; remove() with id undefined deleting all docs #3260 [thanpolas](https://github.com/thanpolas)
+ * fixed; handling for non-numeric projections #3256
+ * fixed; findById with id undefined returning first doc #3255
+ * fixed; use retainKeyOrder for update #3215
+ * added; passRawResult option to findOneAndUpdate for backwards compat #3173
+
+4.1.3 / 2015-08-16
+==================
+ * fixed; getUpdate() in pre update hooks #3520 [gregthegeek](https://github.com/gregthegeek)
+ * fixed; handleArray() ensures arg is an array #3238 [jloveridge](https://github.com/jloveridge)
+ * fixed; refresh required path cache when recreating docs #3199
+ * fixed; $ operator on unwind aggregation helper #3197
+ * fixed; findOneAndUpdate() properly returns raw result as third arg to callback #3173
+ * fixed; querystream with dynamic refs #3108
+
+3.8.35 / 2015-08-14
+===================
+ * fixed; handling for minimize on nested objects #2930
+ * fixed; don't crash when schema.path.options undefined #1824
+
+4.1.2 / 2015-08-10
+==================
+ * fixed; better handling for Jade templates #3241 [kbadk](https://github.com/kbadk)
+ * added; ESlint trailing spaces #3234 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * added; ESlint #3191 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; properly emit event on disconnect #3183
+ * fixed; copy options properly using Query.toConstructor() #3176
+ * fixed; setMaxListeners() issue in browser build #3170
+ * fixed; node driver -> 2.0.40 to not store undefined keys as null #3169
+ * fixed; update validators handle positional operator #3167
+ * fixed; handle $all + $elemMatch query casting #3163
+ * fixed; post save hooks don't swallow extra args #3155
+ * docs; spelling mistake in index.jade #3154
+ * fixed; don't crash when toObject() has no fields #3130
+ * fixed; apply toObject() recursively for find and update queries #3086 [naoina](https://github.com/naoina)
+
+4.1.1 / 2015-08-03
+==================
+ * fixed; aggregate exec() crash with no callback #3212 #3198 [jpgarcia](https://github.com/jpgarcia)
+ * fixed; pre init hooks now properly synchronous #3207 [burtonjc](https://github.com/burtonjc)
+ * fixed; updateValidators doesn't flatten dates #3206 #3194 [victorkohl](https://github.com/victorkohl)
+ * fixed; default fields don't make document dirty between saves #3205 [burtonjc](https://github.com/burtonjc)
+ * fixed; save passes 0 as numAffected rather than undefined when no change #3195 [burtonjc](https://github.com/burtonjc)
+ * fixed; better handling for positional operator in update #3185
+ * fixed; use Travis containers #3181 [ChristianMurphy](https://github.com/ChristianMurphy)
+ * fixed; leaked variable #3180 [ChristianMurphy](https://github.com/ChristianMurphy)
+
+4.1.0 / 2015-07-24
+==================
+ * added; `schema.queue()` now public #3193
+ * added; raw result as third parameter to findOneAndX callback #3173
+ * added; ability to run validateSync() on only certain fields #3153
+ * added; subPopulate #3103 [timbur](https://github.com/timbur)
+ * added; $isDefault function on documents #3077
+ * added; additional properties for built-in validator messages #3063 [KLicheR](https://github.com/KLicheR)
+ * added; getQuery() and getUpdate() functions for Query #3013
+ * added; export DocumentProvider #2996
+ * added; ability to remove path from schema #2993 [JohnnyEstilles](https://github.com/JohnnyEstilles)
+ * added; .explain() helper for aggregate #2714
+ * added; ability to specify which ES6-compatible promises library mongoose uses #2688
+ * added; export Aggregate #1910
+
+4.0.8 / 2015-07-20
+==================
+ * fixed; assignment with document arrays #3178 [rosston](https://github.com/rosston)
+ * docs; remove duplicate paragraph #3164 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * docs; improve findOneAndXYZ parameter descriptions #3159 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * docs; add findOneAndRemove to list of supported middleware #3158
+ * docs; clarify ensureIndex #3156
+ * fixed; refuse to save/remove document without id #3118
+ * fixed; hooks next() no longer accidentally returns promise #3104
+ * fixed; strict mode for findOneAndUpdate #2947
+ * added; .min.js.gz file for browser component #2806
+
+3.8.34 / 2015-07-20
+===================
+ * fixed; allow using $rename #3171
+ * fixed; no longer modifies update arguments #3008
+
+4.0.7 / 2015-07-11
+==================
+ * fixed; documentarray id method when using object id #3157 [siboulet](https://github.com/siboulet)
+ * docs; improve findById docs #3147
+ * fixed; update validators handle null properly #3136 [odeke-em](https://github.com/odeke-em)
+ * docs; jsdoc syntax errors #3128 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * docs; fix typo #3126 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * docs; proper formatting in queries.jade #3121 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * docs; correct example for string maxlength validator #3111 [rhmeeuwisse](https://github.com/rhmeeuwisse)
+ * fixed; setDefaultsOnInsert with arrays #3107
+ * docs; LearnBoost -> Automattic in package.json #3099
+ * docs; pre update hook example #3094 [danpe](https://github.com/danpe)
+ * docs; clarify query middleware example #3051
+ * fixed; ValidationErrors in strict mode #3046
+ * fixed; set findOneAndUpdate properties before hooks run #3024
+
+3.8.33 / 2015-07-10
+===================
+ * upgraded; node driver -> 1.4.38
+ * fixed; dont crash when `match` validator undefined
+
+4.0.6 / 2015-06-21
+==================
+ * upgraded; node driver -> 2.0.34 #3087
+ * fixed; apply setters on addToSet, etc #3067 [victorkohl](https://github.com/victorkohl)
+ * fixed; missing semicolons #3065 [sokolikp](https://github.com/sokolikp)
+ * fixed; proper handling for async doc hooks #3062 [gregthegeek](https://github.com/gregthegeek)
+ * fixed; dont set failed populate field to null if other docs are successfully populated #3055 [eloytoro](https://github.com/eloytoro)
+ * fixed; setDefaultsOnInsert with document arrays #3034 [taxilian](https://github.com/taxilian)
+ * fixed; setters fired on array items #3032
+ * fixed; stop validateSync() on first error #3025 [victorkohl](https://github.com/victorkohl)
+ * docs; improve query docs #3016
+ * fixed; always exclude _id when its deselected #3010
+ * fixed; enum validator kind property #3009
+ * fixed; mquery collection names #3005
+ * docs; clarify mongos option #3000
+ * docs; clarify that query builder has a .then() #2995
+ * fixed; race condition in dynamic ref #2992
+
+3.8.31 / 2015-06-20
+===================
+ * fixed; properly handle text search with discriminators and $meta #2166
+
+4.0.5 / 2015-06-05
+==================
+ * fixed; ObjectIds and buffers when mongodb driver is a sibling dependency #3050 #3048 #3040 #3031 #3020 #2988 #2951
+ * fixed; warn user when 'increment' is used in schema #3039
+ * fixed; setDefaultsOnInsert with array in schema #3035
+ * fixed; dont use default Object toString to cast to string #3030
+ * added; npm badge #3020 [odeke-em](https://github.com/odeke-em)
+ * fixed; proper handling for calling .set() with a subdoc #2782
+ * fixed; dont throw cast error when using $rename on non-string path #1845
+
+3.8.30 / 2015-06-05
+===================
+ * fixed; enable users to set all options with tailable() #2883
+
+4.0.4 / 2015-05-28
+==================
+ * docs; findAndModify new parameter correct default value #3012 [JonForest](https://github.com/JonForest)
+ * docs; clarify pluralization rules #2999 [anonmily](https://github.com/anonmily)
+ * fix; discriminators with schema methods #2978
+ * fix; make `isModified` a schema reserved keyword #2975
+ * fix; properly fire setters when initializing path with object #2943
+ * fix; can use `setDefaultsOnInsert` without specifying `runValidators` #2938
+ * fix; always set validation errors `kind` property #2885
+ * upgraded; node driver -> 2.0.33 #2865
+
+3.8.29 / 2015-05-27
+===================
+ * fixed; Handle JSON.stringify properly for nested docs #2990
+
+4.0.3 / 2015-05-13
+==================
+ * upgraded; mquery -> 1.5.1 #2983
+ * docs; clarify context for query middleware #2974
+ * docs; fix missing type -> kind rename in History.md #2961
+ * fixed; broken ReadPreference include on Heroku #2957
+ * docs; correct form for cursor aggregate option #2955
+ * fixed; sync post hooks now properly called after function #2949 #2925
+ * fixed; fix sub-doc validate() function #2929
+ * upgraded; node driver -> 2.0.30 #2926
+ * docs; retainKeyOrder for save() #2924
+ * docs; fix broken class names #2913
+ * fixed; error when using node-clone on a doc #2909
+ * fixed; no more hard references to bson #2908 #2906
+ * fixed; dont overwrite array values #2907 [naoina](https://github.com/naoina)
+ * fixed; use readPreference=primary for findOneAndUpdate #2899 #2823
+ * docs; clarify that update validators only run on $set and $unset #2889
+ * fixed; set kind consistently for built-in validators #2885
+ * docs; single field populated documents #2884
+ * fixed; nested objects are now enumerable #2880 [toblerpwn](https://github.com/toblerpwn)
+ * fixed; properly populate field when ref, lean, stream used together #2841
+ * docs; fixed migration guide jade error #2807
+
+3.8.28 / 2015-05-12
+===================
+ * fixed; proper handling for toJSON options #2910
+ * fixed; dont attach virtuals to embedded docs in update() #2046
+
+4.0.2 / 2015-04-23
+==================
+ * fixed; error thrown when calling .validate() on subdoc not in an array #2902
+ * fixed; rename define() to play nice with webpack #2900 [jspears](https://github.com/jspears)
+ * fixed; pre validate called twice with discriminators #2892
+ * fixed; .inspect() on mongoose.Types #2875
+ * docs; correct callback params for Model.update #2872
+ * fixed; setDefaultsOnInsert now works when runValidators not specified #2870
+ * fixed; Document now wraps EventEmitter.addListener #2867
+ * fixed; call non-hook functions in schema queue #2856
+ * fixed; statics can be mocked out for tests #2848 [ninelb](https://github.com/ninelb)
+ * upgraded; mquery 1.4.0 for bluebird bug fix #2846
+ * fixed; required validators run first #2843
+ * docs; improved docs for new option to findAndMody #2838
+ * docs; populate example now uses correct field #2837 [swilliams](https://github.com/swilliams)
+ * fixed; pre validate changes causing VersionError #2835
+ * fixed; get path from correct place when setting CastError #2832
+ * docs; improve docs for Model.update() function signature #2827 [irnc](https://github.com/irnc)
+ * fixed; populating discriminators #2825 [chetverikov](https://github.com/chetverikov)
+ * fixed; discriminators with nested schemas #2821
+ * fixed; CastErrors with embedded docs #2819
+ * fixed; post save hook context #2816
+ * docs; 3.8.x -> 4.x migration guide #2807
+ * fixed; proper _distinct copying for query #2765 [cdelauder](https://github.com/cdelauder)
+
+3.8.27 / 2015-04-22
+===================
+ * fixed; dont duplicate db calls on Q.ninvoke() #2864
+ * fixed; Model.find arguments naming in docs #2828
+ * fixed; Support ipv6 in connection strings #2298
+
+3.8.26 / 2015-04-07
+===================
+ * fixed; TypeError when setting date to undefined #2833
+ * fixed; handle CastError properly in distinct() with no callback #2786
+ * fixed; broken links in queries docs #2779
+ * fixed; dont mark buffer as modified when setting type initially #2738
+ * fixed; dont crash when using slice with populate #1934
+
+4.0.1 / 2015-03-28
+==================
+ * fixed; properly handle empty cast doc in update() with promises #2796
+ * fixed; unstable warning #2794
+ * fixed; findAndModify docs now show new option is false by default #2793
+
+4.0.0 / 2015-03-25
+==================
+ * fixed; on-the-fly schema docs typo #2783 [artiifix](https://github.com/artiifix)
+ * fixed; cast error validation handling #2775 #2766 #2678
+ * fixed; discriminators with populate() #2773 #2719 [chetverikov](https://github.com/chetverikov)
+ * fixed; increment now a reserved path #2709
+ * fixed; avoid sending duplicate object ids in populate() #2683
+ * upgraded; mongodb to 2.0.24 to properly emit reconnect event multiple times #2656
+
+4.0.0-rc4 / 2015-03-14
+======================
+ * fixed; toObject virtuals schema option handled properly #2751
+ * fixed; update validators work on document arrays #2733
+ * fixed; check for cast errors on $set #2729
+ * fixed; instance field set for all schema types #2727 [csdco](https://github.com/csdco)
+ * fixed; dont run other validators if required fails #2725
+ * fixed; custom getters execute on ref paths #2610
+ * fixed; save defaults if they were set when doc was loaded from db #2558
+ * fixed; pre validate now runs before pre save #2462
+ * fixed; no longer throws errors with --use_strict #2281
+
+3.8.25 / 2015-03-13
+===================
+ * fixed; debug output reverses order of aggregation keys #2759
+ * fixed; $eq is a valid query selector in 3.0 #2752
+ * fixed; upgraded node driver to 1.4.32 for handling non-numeric poolSize #2682
+ * fixed; update() with overwrite sets _id for nested docs #2658
+ * fixed; casting for operators in $elemMatch #2199
+
+4.0.0-rc3 / 2015-02-28
+======================
+ * fixed; update() pre hooks run before validators #2706
+ * fixed; setters not called on arrays of refs #2698 [brandom](https://github.com/brandom)
+ * fixed; use node driver 2.0.18 for nodejs 0.12 support #2685
+ * fixed; comments reference file that no longer exists #2681
+ * fixed; populated() returns _id of manually populated doc #2678
+ * added; ability to exclude version key in toObject() #2675
+ * fixed; dont allow setting nested path to a string #2592
+ * fixed; can cast objects with _id field to ObjectIds #2581
+ * fixed; on-the-fly schema getters #2360
+ * added; strict option for findOneAndUpdate() #1967
+
+3.8.24 / 2015-02-25
+===================
+ * fixed; properly apply child schema transforms #2691
+ * fixed; make copy of findOneAndUpdate options before modifying #2687
+ * fixed; apply defaults when parent path is selected #2670 #2629
+ * fixed; properly get ref property for nested paths #2665
+ * fixed; node driver makes copy of authenticate options before modifying them #2619
+ * fixed; dont block process exit when auth fails #2599
+ * fixed; remove redundant clone in update() #2537
+
+4.0.0-rc2 / 2015-02-10
+======================
+ * added; io.js to travis build
+ * removed; browser build dependencies not installed by default
+ * added; dynamic refpaths #2640 [chetverikov](https://github.com/chetverikov)
+ * fixed; dont call child schema transforms on parent #2639 [chetverikov](https://github.com/chetverikov)
+ * fixed; get rid of remove option if new is set in findAndModify #2598
+ * fixed; aggregate all document array validation errors #2589
+ * fixed; custom setters called when setting value to undefined #1892
+
+3.8.23 / 2015-02-06
+===================
+ * fixed; unset opts.remove when upsert is true #2519
+ * fixed; array saved as object when path is object in array #2442
+ * fixed; inline transforms #2440
+ * fixed; check for callback in count() #2204
+ * fixed; documentation for selecting fields #1534
+
+4.0.0-rc1 / 2015-02-01
+======================
+ * fixed; use driver 2.0.14
+ * changed; use transform: true by default #2245
+
+4.0.0-rc0 / 2015-01-31
+===================
+ * fixed; wrong order for distinct() params #2628
+ * fixed; handling no query argument to remove() #2627
+ * fixed; createModel and discriminators #2623 [ashaffer](https://github.com/ashaffer)
+ * added; pre('count') middleware #2621
+ * fixed; double validation calls on document arrays #2618
+ * added; validate() catches cast errors #2611
+ * fixed; respect replicaSet parameter in connection string #2609
+ * added; can explicitly exclude paths from versioning #2576 [csabapalfi](https://github.com/csabapalfi)
+ * upgraded; driver to 2.0.15 #2552
+ * fixed; save() handles errors more gracefully in ES6 #2371
+ * fixed; undefined is now a valid argument to findOneAndUpdate #2272
+ * changed; `new` option to findAndModify ops is false by default #2262
+
+3.8.22 / 2015-01-24
+===================
+ * upgraded; node-mongodb-native to 1.4.28 #2587 [Climax777](https://github.com/Climax777)
+ * added; additional documentation for validators #2449
+ * fixed; stack overflow when creating massive arrays #2423
+ * fixed; undefined is a valid id for queries #2411
+ * fixed; properly create nested schema index when same schema used twice #2322
+ * added; link to plugin generator in docs #2085 [huei90](https://github.com/huei90)
+ * fixed; optional arguments documentation for findOne() #1971 [nachinius](https://github.com/nachinius)
+
+3.9.7 / 2014-12-19
+===================
+ * added; proper cursors for aggregate #2539 [changyy](https://github.com/changyy)
+ * added; min/max built-in validators for dates #2531 [bshamblen](https://github.com/bshamblen)
+ * fixed; save and validate are now reserved keywords #2380
+ * added; basic documentation for browser component #2256
+ * added; find and findOne hooks (query middleware) #2138
+ * fixed; throw a DivergentArrayError when saving positional operator queries #2031
+ * added; ability to use options as a document property #1416
+ * fixed; document no longer inherits from event emitter and so domain and _events are no longer reserved #1351
+ * removed; setProfiling #1349
+
+3.8.21 / 2014-12-18
+===================
+ * fixed; syntax in index.jade #2517 [elderbas](https://github.com/elderbas)
+ * fixed; writable statics #2510 #2528
+ * fixed; overwrite and explicit $set casting #2515
+
+3.9.6 / 2014-12-05
+===================
+ * added; correctly run validators on each element of array when entire array is modified #661 #1227
+ * added; castErrors in validation #1013 [jondavidjohn](https://github.com/jondavidjohn)
+ * added; specify text indexes in schema fields #1401 [sr527](https://github.com/sr527)
+ * added; ability to set field with validators to undefined #1594 [alabid](https://github.com/alabid)
+ * added; .create() returns an array when passed an array #1746 [alabid](https://github.com/alabid)
+ * added; test suite and docs for use with co and yield #2177 #2474
+ * fixed; subdocument toObject() transforms #2447 [chmanie](https://github.com/chmanie)
+ * fixed; Model.create() with save errors #2484
+ * added; pass options to .save() and .remove() #2494 [jondavidjohn](https://github.com/jondavidjohn)
+
+3.8.20 / 2014-12-01
+===================
+ * fixed; recursive readPref #2490 [kjvalencik](https://github.com/kjvalencik)
+ * fixed; make sure to copy parameters to update() before modifying #2406 [alabid](https://github.com/alabid)
+ * fixed; unclear documentation about query callbacks #2319
+ * fixed; setting a schema-less field to an empty object #2314 [alabid](https://github.com/alabid)
+ * fixed; registering statics and methods for discriminators #2167 [alabid](https://github.com/alabid)
+
+3.9.5 / 2014-11-10
+===================
+ * added; ability to disable autoIndex on a per-connection basis #1875 [sr527](https://github.com/sr527)
+ * fixed; `geoNear()` no longer enforces legacy coordinate pairs - supports GeoJSON #1987 [alabid](https://github.com/alabid)
+ * fixed; browser component works when minified with mangled variable names #2302
+ * fixed; `doc.errors` now cleared before `validate()` called #2302
+ * added; `execPopulate()` function to make `doc.populate()` compatible with promises #2317
+ * fixed; `count()` no longer throws an error when used with `sort()` #2374
+ * fixed; `save()` no longer recursively calls `save()` on populated fields #2418
+
+3.8.19 / 2014-11-09
+===================
+ * fixed; make sure to not override subdoc _ids on find #2276 [alabid](https://github.com/alabid)
+ * fixed; exception when comparing two documents when one lacks _id #2333 [slawo](https://github.com/slawo)
+ * fixed; getters for properties with non-strict schemas #2439 [alabid](https://github.com/alabid)
+ * fixed; inconsistent URI format in docs #2414 [sr527](https://github.com/sr527)
+
+3.9.4 / 2014-10-25
+==================
+ * fixed; statics no longer can be overwritten #2343 [nkcmr](https://github.com/chetverikov)
+ * added; ability to set single populated paths to documents #1530
+ * added; setDefaultsOnInsert and runValidator options for findOneAndUpdate() #860
+
+3.8.18 / 2014-10-22
+==================
+ * fixed; Dont use all toObject options in save #2340 [chetverikov](https://github.com/chetverikov)
+
+3.9.3 / 2014-10-01
+=================
+ * added; support for virtuals that return objects #2294
+ * added; ability to manually hydrate POJOs into mongoose objects #2292
+ * added; setDefaultsOnInsert and runValidator options for update() #860
+
+3.8.17 / 2014-09-29
+==================
+ * fixed; use schema options retainKeyOrder in save() #2274
+ * fixed; fix skip in populate when limit is set #2252
+ * fixed; fix stack overflow when passing MongooseArray to findAndModify #2214
+ * fixed; optimize .length usage in populate #2289
+
+3.9.2 / 2014-09-08
+==================
+ * added; test coverage for browser component #2255
+ * added; in-order execution of validators #2243
+ * added; custom fields for validators #2132
+ * removed; exception thrown when find() used with count() #1950
+
+3.8.16 / 2014-09-08
+==================
+ * fixed; properly remove modified array paths if array has been overwritten #1638
+ * fixed; key check errors #1884
+ * fixed; make sure populate on an array always returns a Mongoose array #2214
+ * fixed; SSL connections with node 0.11 #2234
+ * fixed; return sensible strings for promise errors #2239
+
+3.9.1 / 2014-08-17
+==================
+ * added; alpha version of browser-side schema validation #2254
+ * added; support passing a function to schemas `required` field #2247
+ * added; support for setting updatedAt and createdAt timestamps #2227
+ * added; document.validate() returns a promise #2131
+
+3.8.15 / 2014-08-17
+==================
+ * fixed; Replica set connection string example in docs #2246
+ * fixed; bubble up parseError event #2229
+ * fixed; removed buggy populate cache #2176
+ * fixed; dont $inc versionKey if its being $set #1933
+ * fixed; cast $or and $and in $pull #1932
+ * fixed; properly cast to schema in stream() #1862
+ * fixed; memory leak in nested objects #1565 #2211 [devongovett](https://github.com/devongovett)
+
+3.8.14 / 2014-07-26
+==================
+ * fixed; stringifying MongooseArray shows nested arrays #2002
+ * fixed; use populated doc schema in toObject and toJSON by default #2035
+ * fixed; dont crash on arrays containing null #2140
+ * fixed; model.update w/ upsert has same return values on .exec and promise #2143
+ * fixed; better handling for populate limit with multiple documents #2151
+ * fixed; dont prevent users from adding weights to text index #2183
+ * fixed; helper for aggregation cursor #2187
+ * updated; node-mongodb-native to 1.4.7
+
+3.8.13 / 2014-07-15
+==================
+ * fixed; memory leak with isNew events #2159
+ * fixed; docs for overwrite option for update() #2144
+ * fixed; storeShard() handles dates properly #2127
+ * fixed; sub-doc changes not getting persisted to db after save #2082
+ * fixed; populate with _id: 0 actually removes _id instead of setting to undefined #2123
+ * fixed; save versionKey on findOneAndUpdate w/ upsert #2122
+ * fixed; fix typo in 2.8 docs #2120 [shakirullahi](https://github.com/shakirullahi)
+ * fixed; support maxTimeMs #2102 [yuukinajima](https://github.com/yuukinajima)
+ * fixed; support $currentDate #2019
+ * fixed; $addToSet handles objects without _ids properly #1973
+ * fixed; dont crash on invalid nearSphere query #1874
+
+3.8.12 / 2014-05-30
+==================
+ * fixed; single-server reconnect event fires #1672
+ * fixed; sub-docs not saved when pushed into populated array #1794
+ * fixed; .set() sometimes converts embedded docs to pojos #1954 [archangel-irk](https://github.com/archangel-irk)
+ * fixed; sub-doc changes not getting persisted to db after save #2082
+ * fixed; custom getter might cause mongoose to mistakenly think a path is dirty #2100 [pgherveou](https://github.com/pgherveou)
+ * fixed; chainable helper for allowDiskUse option in aggregation #2114
+
+3.9.0 (unstable) / 2014-05-22
+==================
+ * changed; added `domain` to reserved keywords #1338 #2052 [antoinepairet](https://github.com/antoinepairet)
+ * added; asynchronous post hooks #1977 #2081 [chopachom](https://github.com/chopachom) [JasonGhent](https://github.com/JasonGhent)
+ * added; using model for population, cross-db populate [mihai-chiorean](https://github.com/mihai-chiorean)
+ * added; can define a type for schema validators
+ * added; `doc.remove()` returns a promise #1619 [refack](https://github.com/refack)
+ * added; internal promises for hooks, pre-save hooks run in parallel #1732 [refack](https://github.com/refack)
+ * fixed; geoSearch hanging when no results returned #1846 [ghartnett](https://github.com/ghartnett)
+ * fixed; do not set .type property on ValidationError, use .kind instead #1323
+
+3.8.11 / 2014-05-22
+==================
+ * updated; node-mongodb-native to 1.4.5
+ * reverted; #2052, fixes #2097
+
+3.8.10 / 2014-05-20
+==================
+
+ * updated; node-mongodb-native to 1.4.4
+ * fixed; _.isEqual false negatives bug in js-bson #2070
+ * fixed; missing check for schema.options #2014
+ * fixed; missing support for $position #2024
+ * fixed; options object corruption #2049
+ * fixed; improvements to virtuals docs #2055
+ * fixed; added `domain` to reserved keywords #2052 #1338
+
+3.8.9 / 2014-05-08
+==================
+
+ * updated; mquery to 0.7.0
+ * updated; node-mongodb-native to 1.4.3
+ * fixed; $near failing against MongoDB 2.6
+ * fixed; relying on .options() to determine if collection exists
+ * fixed; $out aggregate helper
+ * fixed; all test failures against MongoDB 2.6.1, with caveat #2065
+
+3.8.8 / 2014-02-22
+==================
+
+ * fixed; saving Buffers #1914
+ * updated; expose connection states for user-land #1926 [yorkie](https://github.com/yorkie)
+ * updated; mquery to 0.5.3
+ * updated; added get / set to reserved path list #1903 [tstrimple](https://github.com/tstrimple)
+ * docs; README code highlighting, syntax fixes #1930 [IonicaBizau](https://github.com/IonicaBizau)
+ * docs; fixes link in the doc at #1925 [kapeels](https://github.com/kapeels)
+ * docs; add a missed word 'hook' for the description of the post-hook api #1924 [ipoval](https://github.com/ipoval)
+
+3.8.7 / 2014-02-09
+==================
+
+ * fixed; sending safe/read options in Query#exec #1895
+ * fixed; findOneAnd..() with sort #1887
+
+3.8.6 / 2014-01-30
+==================
+
+ * fixed; setting readPreferences #1895
+
+3.8.5 / 2014-01-23
+==================
+
+ * fixed; ssl setting when using URI #1882
+ * fixed; findByIdAndUpdate now respects the overwrite option #1809 [owenallenaz](https://github.com/owenallenaz)
+
+3.8.4 / 2014-01-07
+==================
+
+ * updated; mongodb driver to 1.3.23
+ * updated; mquery to 0.4.1
+ * updated; mpromise to 0.4.3
+ * fixed; discriminators now work when selecting fields #1820 [daemon1981](https://github.com/daemon1981)
+ * fixed; geoSearch with no results timeout #1846 [ghartnett](https://github.com/ghartnett)
+ * fixed; infitite recursion in ValidationError #1834 [chetverikov](https://github.com/chetverikov)
+
+3.8.3 / 2013-12-17
+==================
+
+ * fixed; setting empty array with model.update #1838
+ * docs; fix url
+
+3.8.2 / 2013-12-14
+==================
+
+ * fixed; enum validation of multiple values #1778 [heroicyang](https://github.com/heroicyang)
+ * fixed; global var leak #1803
+ * fixed; post remove now fires on subdocs #1810
+ * fixed; no longer set default empty array for geospatial-indexed fields #1668 [shirish87](https://github.com/shirish87)
+ * fixed; model.stream() not hydrating discriminators correctly #1792 [j](https://github.com/j)
+ * docs: Stablility -> Stability [nikmartin](https://github.com/nikmartin)
+ * tests; improve shard error handling
+
+3.8.1 / 2013-11-19
+==================
+
+ * fixed; mishandling of Dates with minimize/getters #1764
+ * fixed; Normalize bugs.email, so `npm` will shut up #1769 [refack](https://github.com/refack)
+ * docs; Improve the grammar where "lets us" was used #1777 [alexyoung](https://github.com/alexyoung)
+ * docs; Fix some grammatical issues in the documentation #1777 [alexyoung](https://github.com/alexyoung)
+ * docs; fix Query api exposure
+ * docs; fix return description
+ * docs; Added Notes on findAndUpdate() #1750 [sstadelman](https://github.com/sstadelman)
+ * docs; Update version number in README #1762 [Fodi69](https://github.com/Fodi69)
+
+3.8.0 / 2013-10-31
+==================
+
+ * updated; warn when using an unstable version
+ * updated; error message returned in doc.save() #1595
+ * updated; mongodb driver to 1.3.19 (fix error swallowing behavior)
+ * updated; mquery to 0.3.2
+ * updated; mocha to 1.12.0
+ * updated; mpromise 0.3.0
+ * updated; sliced 0.0.5
+ * removed; mongoose.Error.DocumentError (never used)
+ * removed; namedscope (undocumented and broken) #679 #642 #455 #379
+ * changed; no longer offically supporting node 0.6.x
+ * changed; query.within getter is now a method -> query.within()
+ * changed; query.intersects getter is now a method -> query.intersects()
+ * added; custom error msgs for built-in validators #747
+ * added; discriminator support #1647 #1003 [j](https://github.com/j)
+ * added; support disabled collection name pluralization #1350 #1707 [refack](https://github.com/refack)
+ * added; support for GeoJSON to Query#near [ebensing](https://github.com/ebensing)
+ * added; stand-alone base query support - query.toConstructor() [ebensing](https://github.com/ebensing)
+ * added; promise support to geoSearch #1614 [ebensing](https://github.com/ebensing)
+ * added; promise support for geoNear #1614 [ebensing](https://github.com/ebensing)
+ * added; connection.useDb() #1124 [ebensing](https://github.com/ebensing)
+ * added; promise support to model.mapReduce()
+ * added; promise support to model.ensureIndexes()
+ * added; promise support to model.populate()
+ * added; benchmarks [ebensing](https://github.com/ebensing)
+ * added; publicly exposed connection states #1585
+ * added; $geoWithin support #1529 $1455 [ebensing](https://github.com/ebensing)
+ * added; query method chain validation
+ * added; model.update `overwrite` option
+ * added; model.geoNear() support #1563 [ebensing](https://github.com/ebensing)
+ * added; model.geoSearch() support #1560 [ebensing](https://github.com/ebensing)
+ * added; MongooseBuffer#subtype()
+ * added; model.create() now returns a promise #1340
+ * added; support for `awaitdata` query option
+ * added; pass the doc to doc.remove() callback #1419 [JoeWagner](https://github.com/JoeWagner)
+ * added; aggregation query builder #1404 [njoyard](https://github.com/njoyard)
+ * fixed; document.toObject when using `minimize` and `getters` options #1607 [JedWatson](https://github.com/JedWatson)
+ * fixed; Mixed types can now be required #1722 [Reggino](https://github.com/Reggino)
+ * fixed; do not pluralize model names not ending with letters #1703 [refack](https://github.com/refack)
+ * fixed; repopulating modified populated paths #1697
+ * fixed; doc.equals() when _id option is set to false #1687
+ * fixed; strict mode warnings #1686
+ * fixed; $near GeoJSON casting #1683
+ * fixed; nearSphere GeoJSON query builder
+ * fixed; population field selection w/ strings #1669
+ * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing)
+ * fixed; handle another versioning edge case #1520
+ * fixed; excluding subdocument fields #1280 [ebensing](https://github.com/ebensing)
+ * fixed; allow array properties to be set to null with findOneAndUpdate [aheuermann](https://github.com/aheuermann)
+ * fixed; subdocuments now use own toJSON opts #1376 [ebensing](https://github.com/ebensing)
+ * fixed; model#geoNear fulfills promise when results empty #1658 [ebensing](https://github.com/ebensing)
+ * fixed; utils.merge no longer overrides props and methods #1655 [j](https://github.com/j)
+ * fixed; subdocuments now use their own transform #1412 [ebensing](https://github.com/ebensing)
+ * fixed; model.remove() removes only what is necessary #1649
+ * fixed; update() now only runs with cb or explicit true #1644
+ * fixed; casting ref docs on creation #1606 [ebensing](https://github.com/ebensing)
+ * fixed; model.update "overwrite" option works as documented
+ * fixed; query#remove() works as documented
+ * fixed; "limit" correctly applies to individual items on population #1490 [ebensing](https://github.com/ebensing)
+ * fixed; issue with positional operator on ref docs #1572 [ebensing](https://github.com/ebensing)
+ * fixed; benchmarks to actually output valid json
+ * deprecated; promise#addBack (use promise#onResolve)
+ * deprecated; promise#complete (use promise#fulfill)
+ * deprecated; promise#addCallback (use promise#onFulFill)
+ * deprecated; promise#addErrback (use promise#onReject)
+ * deprecated; query.nearSphere() (use query.near)
+ * deprecated; query.center() (use query.circle)
+ * deprecated; query.centerSphere() (use query.circle)
+ * deprecated; query#slaveOk (use query#read)
+ * docs; custom validator messages
+ * docs; 10gen -> MongoDB
+ * docs; add Date method caveats #1598
+ * docs; more validation details
+ * docs; state which branch is stable/unstable
+ * docs; mention that middleware does not run on Models
+ * docs; promise.fulfill()
+ * docs; fix readme spelling #1483 [yorchopolis](https://github.com/yorchopolis)
+ * docs; fixed up the README and examples [ebensing](https://github.com/ebensing)
+ * website; add "show code" for properties
+ * website; move "show code" links down
+ * website; update guide
+ * website; add unstable docs
+ * website; many improvements
+ * website; fix copyright #1439
+ * website; server.js -> static.js #1546 [nikmartin](https://github.com/nikmartin)
+ * tests; refactor 1703
+ * tests; add test generator
+ * tests; validate formatMessage() throws
+ * tests; add script for continuously running tests
+ * tests; fixed versioning tests
+ * tests; race conditions in tests
+ * tests; added for nested and/or queries
+ * tests; close some test connections
+ * tests; validate db contents
+ * tests; remove .only
+ * tests; close some test connections
+ * tests; validate db contents
+ * tests; remove .only
+ * tests; replace deprecated method names
+ * tests; convert id to string
+ * tests; fix sharding tests for MongoDB 2.4.5
+ * tests; now 4-5 seconds faster
+ * tests; fix race condition
+ * make; suppress warning msg in test
+ * benchmarks; updated for pull requests
+ * examples; improved and expanded [ebensing](https://github.com/ebensing)
+
+3.7.4 (unstable) / 2013-10-01
+=============================
+
+ * updated; mquery to 0.3.2
+ * removed; mongoose.Error.DocumentError (never used)
+ * added; custom error msgs for built-in validators #747
+ * added; discriminator support #1647 #1003 [j](https://github.com/j)
+ * added; support disabled collection name pluralization #1350 #1707 [refack](https://github.com/refack)
+ * fixed; do not pluralize model names not ending with letters #1703 [refack](https://github.com/refack)
+ * fixed; repopulating modified populated paths #1697
+ * fixed; doc.equals() when _id option is set to false #1687
+ * fixed; strict mode warnings #1686
+ * fixed; $near GeoJSON casting #1683
+ * fixed; nearSphere GeoJSON query builder
+ * fixed; population field selection w/ strings #1669
+ * docs; custom validator messages
+ * docs; 10gen -> MongoDB
+ * docs; add Date method caveats #1598
+ * docs; more validation details
+ * website; add "show code" for properties
+ * website; move "show code" links down
+ * tests; refactor 1703
+ * tests; add test generator
+ * tests; validate formatMessage() throws
+
+3.7.3 (unstable) / 2013-08-22
+=============================
+
+ * updated; warn when using an unstable version
+ * updated; mquery to 0.3.1
+ * updated; mocha to 1.12.0
+ * updated; mongodb driver to 1.3.19 (fix error swallowing behavior)
+ * changed; no longer offically supporting node 0.6.x
+ * added; support for GeoJSON to Query#near [ebensing](https://github.com/ebensing)
+ * added; stand-alone base query support - query.toConstructor() [ebensing](https://github.com/ebensing)
+ * added; promise support to geoSearch #1614 [ebensing](https://github.com/ebensing)
+ * added; promise support for geoNear #1614 [ebensing](https://github.com/ebensing)
+ * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing)
+ * fixed; handle another versioning edge case #1520
+ * fixed; excluding subdocument fields #1280 [ebensing](https://github.com/ebensing)
+ * fixed; allow array properties to be set to null with findOneAndUpdate [aheuermann](https://github.com/aheuermann)
+ * fixed; subdocuments now use own toJSON opts #1376 [ebensing](https://github.com/ebensing)
+ * fixed; model#geoNear fulfills promise when results empty #1658 [ebensing](https://github.com/ebensing)
+ * fixed; utils.merge no longer overrides props and methods #1655 [j](https://github.com/j)
+ * fixed; subdocuments now use their own transform #1412 [ebensing](https://github.com/ebensing)
+ * make; suppress warning msg in test
+ * docs; state which branch is stable/unstable
+ * docs; mention that middleware does not run on Models
+ * tests; add script for continuously running tests
+ * tests; fixed versioning tests
+ * benchmarks; updated for pull requests
+
+3.7.2 (unstable) / 2013-08-15
+==================
+
+ * fixed; model.remove() removes only what is necessary #1649
+ * fixed; update() now only runs with cb or explicit true #1644
+ * tests; race conditions in tests
+ * website; update guide
+
+3.7.1 (unstable) / 2013-08-13
+=============================
+
+ * updated; driver to 1.3.18 (fixes memory leak)
+ * added; connection.useDb() #1124 [ebensing](https://github.com/ebensing)
+ * added; promise support to model.mapReduce()
+ * added; promise support to model.ensureIndexes()
+ * added; promise support to model.populate()
+ * fixed; casting ref docs on creation #1606 [ebensing](https://github.com/ebensing)
+ * fixed; model.update "overwrite" option works as documented
+ * fixed; query#remove() works as documented
+ * fixed; "limit" correctly applies to individual items on population #1490 [ebensing](https://github.com/ebensing)
+ * fixed; issue with positional operator on ref docs #1572 [ebensing](https://github.com/ebensing)
+ * fixed; benchmarks to actually output valid json
+ * tests; added for nested and/or queries
+ * tests; close some test connections
+ * tests; validate db contents
+ * tests; remove .only
+ * tests; close some test connections
+ * tests; validate db contents
+ * tests; remove .only
+ * tests; replace deprecated method names
+ * tests; convert id to string
+ * docs; promise.fulfill()
+
+3.7.0 (unstable) / 2013-08-05
+===================
+
+ * changed; query.within getter is now a method -> query.within()
+ * changed; query.intersects getter is now a method -> query.intersects()
+ * deprecated; promise#addBack (use promise#onResolve)
+ * deprecated; promise#complete (use promise#fulfill)
+ * deprecated; promise#addCallback (use promise#onFulFill)
+ * deprecated; promise#addErrback (use promise#onReject)
+ * deprecated; query.nearSphere() (use query.near)
+ * deprecated; query.center() (use query.circle)
+ * deprecated; query.centerSphere() (use query.circle)
+ * deprecated; query#slaveOk (use query#read)
+ * removed; namedscope (undocumented and broken) #679 #642 #455 #379
+ * added; benchmarks [ebensing](https://github.com/ebensing)
+ * added; publicly exposed connection states #1585
+ * added; $geoWithin support #1529 $1455 [ebensing](https://github.com/ebensing)
+ * added; query method chain validation
+ * added; model.update `overwrite` option
+ * added; model.geoNear() support #1563 [ebensing](https://github.com/ebensing)
+ * added; model.geoSearch() support #1560 [ebensing](https://github.com/ebensing)
+ * added; MongooseBuffer#subtype()
+ * added; model.create() now returns a promise #1340
+ * added; support for `awaitdata` query option
+ * added; pass the doc to doc.remove() callback #1419 [JoeWagner](https://github.com/JoeWagner)
+ * added; aggregation query builder #1404 [njoyard](https://github.com/njoyard)
+ * updated; integrate mquery #1562 [ebensing](https://github.com/ebensing)
+ * updated; error msg in doc.save() #1595
+ * updated; bump driver to 1.3.15
+ * updated; mpromise 0.3.0
+ * updated; sliced 0.0.5
+ * tests; fix sharding tests for MongoDB 2.4.5
+ * tests; now 4-5 seconds faster
+ * tests; fix race condition
+ * docs; fix readme spelling #1483 [yorchopolis](https://github.com/yorchopolis)
+ * docs; fixed up the README and examples [ebensing](https://github.com/ebensing)
+ * website; add unstable docs
+ * website; many improvements
+ * website; fix copyright #1439
+ * website; server.js -> static.js #1546 [nikmartin](https://github.com/nikmartin)
+ * examples; improved and expanded [ebensing](https://github.com/ebensing)
+
+3.6.20 (stable) / 2013-09-23
+===================
+
+ * fixed; repopulating modified populated paths #1697
+ * fixed; doc.equals w/ _id false #1687
+ * fixed; strict mode warning #1686
+ * docs; near/nearSphere
+
+3.6.19 (stable) / 2013-09-04
+==================
+
+ * fixed; population field selection w/ strings #1669
+ * docs; Date method caveats #1598
+
+3.6.18 (stable) / 2013-08-22
+===================
+
+ * updated; warn when using an unstable version of mongoose
+ * updated; mocha to 1.12.0
+ * updated; mongodb driver to 1.3.19 (fix error swallowing behavior)
+ * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing)
+ * fixed; properly exclude subdocument fields #1280 [ebensing](https://github.com/ebensing)
+ * fixed; cast error in findAndModify #1643 [aheuermann](https://github.com/aheuermann)
+ * website; update guide
+ * website; added documentation for safe:false and versioning interaction
+ * docs; mention that middleware dont run on Models
+ * docs; fix indexes link
+ * make; suppress warning msg in test
+ * tests; moar
+
+3.6.17 / 2013-08-13
+===================
+
+ * updated; driver to 1.3.18 (fixes memory leak)
+ * fixed; casting ref docs on creation #1606
+ * docs; query options
+
+3.6.16 / 2013-08-08
+===================
+
+ * added; publicly expose connection states #1585
+ * fixed; limit applies to individual items on population #1490 [ebensing](https://github.com/ebensing)
+ * fixed; positional operator casting in updates #1572 [ebensing](https://github.com/ebensing)
+ * updated; MongoDB driver to 1.3.17
+ * updated; sliced to 0.0.5
+ * website; tweak homepage
+ * tests; fixed + added
+ * docs; fix some examples
+ * docs; multi-mongos support details
+ * docs; auto open browser after starting static server
+
+3.6.15 / 2013-07-16
+==================
+
+ * added; mongos failover support #1037
+ * updated; make schematype return vals return self #1580
+ * docs; add note to model.update #571
+ * docs; document third param to document.save callback #1536
+ * tests; tweek mongos test timeout
+
+3.6.14 / 2013-07-05
+===================
+
+ * updated; driver to 1.3.11
+ * fixed; issue with findOneAndUpdate not returning null on upserts #1533 [ebensing](https://github.com/ebensing)
+ * fixed; missing return statement in SchemaArray#$geoIntersects() #1498 [bsrykt](https://github.com/bsrykt)
+ * fixed; wrong isSelected() behavior #1521 [kyano](https://github.com/kyano)
+ * docs; note about toObject behavior during save()
+ * docs; add callbacks details #1547 [nikmartin](https://github.com/nikmartin)
+
+3.6.13 / 2013-06-27
+===================
+
+ * fixed; calling model.distinct without conditions #1541
+ * fixed; regression in Query#count() #1542
+ * now working on 3.6.13
+
+3.6.12 / 2013-06-25
+===================
+
+ * updated; driver to 1.3.10
+ * updated; clearer capped collection error message #1509 [bitmage](https://github.com/bitmage)
+ * fixed; MongooseBuffer subtype loss during casting #1517 [zedgu](https://github.com/zedgu)
+ * fixed; docArray#id when doc.id is disabled #1492
+ * fixed; docArray#id now supports matches on populated arrays #1492 [pgherveou](https://github.com/pgherveou)
+ * website; fix example
+ * website; improve _id disabling example
+ * website; fix typo #1494 [dejj](https://github.com/dejj)
+ * docs; added a 'Requesting new features' section #1504 [shovon](https://github.com/shovon)
+ * docs; improve subtypes description
+ * docs; clarify _id disabling
+ * docs: display by alphabetical order the methods list #1508 [nicolasleger](https://github.com/nicolasleger)
+ * tests; refactor isSelected checks
+ * tests; remove pointless test
+ * tests; fixed timeouts
+
+3.6.11 / 2013-05-15
+===================
+
+ * updated; driver to 1.3.5
+ * fixed; compat w/ Object.create(null) #1484 #1485
+ * fixed; cloning objects w/ missing constructors
+ * fixed; prevent multiple min number validators #1481 [nrako](https://github.com/nrako)
+ * docs; add doc.increment() example
+ * docs; add $size example
+ * docs; add "distinct" example
+
+3.6.10 / 2013-05-09
+==================
+
+ * update driver to 1.3.3
+ * fixed; increment() works without other changes #1475
+ * website; fix links to posterous
+ * docs; fix link #1472
+
+3.6.9 / 2013-05-02
+==================
+
+ * fixed; depopulation of mixed documents #1471
+ * fixed; use of $options in array #1462
+ * tests; fix race condition
+ * docs; fix default example
+
+3.6.8 / 2013-04-25
+==================
+
+ * updated; driver to 1.3.0
+ * fixed; connection.model should retain options #1458 [vedmalex](https://github.com/vedmalex)
+ * tests; 4-5 seconds faster
+
+3.6.7 / 2013-04-19
+==================
+
+ * fixed; population regression in 3.6.6 #1444
+
+3.6.6 / 2013-04-18
+==================
+
+ * fixed; saving populated new documents #1442
+ * fixed; population regession in 3.6.5 #1441
+ * website; fix copyright #1439
+
+3.6.5 / 2013-04-15
+==================
+
+ * fixed; strict:throw edge case using .set(path, val)
+ * fixed; schema.pathType() on some numbericAlpha paths
+ * fixed; numbericAlpha path versioning
+ * fixed; setting nested mixed paths #1418
+ * fixed; setting nested objects with null prop #1326
+ * fixed; regression in v3.6 population performance #1426 [vedmalex](https://github.com/vedmalex)
+ * fixed; read pref typos #1422 [kyano](https://github.com/kyano)
+ * docs; fix method example
+ * website; update faq
+ * website; add more deep links
+ * website; update poolSize docs
+ * website; add 3.6 release notes
+ * website; note about keepAlive
+
+3.6.4 / 2013-04-03
+==================
+
+ * fixed; +field conflict with $slice #1370
+ * fixed; nested deselection conflict #1333
+ * fixed; RangeError in ValidationError.toString() #1296
+ * fixed; do not save user defined transforms #1415
+ * tests; fix race condition
+
+3.6.3 / 2013-04-02
+==================
+
+ * fixed; setting subdocuments deeply nested fields #1394
+ * fixed; regression: populated streams #1411
+ * docs; mention hooks/validation with findAndModify
+ * docs; mention auth
+ * docs; add more links
+ * examples; add document methods example
+ * website; display "see" links for properties
+ * website; clean up homepage
+
+3.6.2 / 2013-03-29
+==================
+
+ * fixed; corrupted sub-doc array #1408
+ * fixed; document#update returns a Query #1397
+ * docs; readpref strategy
+
+3.6.1 / 2013-03-27
+==================
+
+ * added; populate support to findAndModify varients #1395
+ * added; text index type to schematypes
+ * expose allowed index types as Schema.indexTypes
+ * fixed; use of `setMaxListeners` as path
+ * fixed; regression in node 0.6 on docs with > 10 arrays
+ * fixed; do not alter schema arguments #1364
+ * fixed; subdoc#ownerDocument() #1385
+ * website; change search id
+ * website; add search from google [jackdbernier](https://github.com/jackdbernier)
+ * website; fix link
+ * website; add 3.5.x docs release
+ * website; fix link
+ * docs; fix geometry
+ * docs; hide internal constructor
+ * docs; aggregation does not cast arguments #1399
+ * docs; querystream options
+ * examples; added for population
+
+3.6.0 / 2013-03-18
+==================
+
+ * changed; cast 'true'/'false' to boolean #1282 [mgrach](https://github.com/mgrach)
+ * changed; Buffer arrays can now contain nulls
+ * added; QueryStream transform option
+ * added; support for authSource driver option
+ * added; {mongoose,db}.modelNames()
+ * added; $push w/ $slice,$sort support (MongoDB 2.4)
+ * added; hashed index type (MongoDB 2.4)
+ * added; support for mongodb 2.4 geojson (MongoDB 2.4)
+ * added; value at time of validation error
+ * added; support for object literal schemas
+ * added; bufferCommands schema option
+ * added; allow auth option in connections #1360 [geoah](https://github.com/geoah)
+ * added; performance improvements to populate() [263ece9](https://github.com/LearnBoost/mongoose/commit/263ece9)
+ * added; allow adding uncasted docs to populated arrays and properties #570
+ * added; doc#populated(path) stores original populated _ids
+ * added; lean population #1260
+ * added; query.populate() now accepts an options object
+ * added; document#populate(opts, callback)
+ * added; Model.populate(docs, opts, callback)
+ * added; support for rich nested path population
+ * added; doc.array.remove(value) subdoc with _id value support #1278
+ * added; optionally allow non-strict sets and updates
+ * added; promises/A+ comformancy with [mpromise](https://github.com/aheckmann/mpromise)
+ * added; promise#then
+ * added; promise#end
+ * fixed; use of `model` as doc property
+ * fixed; lean population #1382
+ * fixed; empty object mixed defaults #1380
+ * fixed; populate w/ deselected _id using string syntax
+ * fixed; attempted save of divergent populated arrays #1334 related
+ * fixed; better error msg when attempting toObject as property name
+ * fixed; non population buffer casting from doc
+ * fixed; setting populated paths #570
+ * fixed; casting when added docs to populated arrays #570
+ * fixed; prohibit updating arrays selected with $elemMatch #1334
+ * fixed; pull / set subdoc combination #1303
+ * fixed; multiple bg index creation #1365
+ * fixed; manual reconnection to single mongod
+ * fixed; Constructor / version exposure #1124
+ * fixed; CastError race condition
+ * fixed; no longer swallowing misuse of subdoc#invalidate()
+ * fixed; utils.clone retains RegExp opts
+ * fixed; population of non-schema property
+ * fixed; allow updating versionKey #1265
+ * fixed; add EventEmitter props to reserved paths #1338
+ * fixed; can now deselect populated doc _ids #1331
+ * fixed; properly pass subtype to Binary in MongooseBuffer
+ * fixed; casting _id from document with non-ObjectId _id
+ * fixed; specifying schema type edge case { path: [{type: "String" }] }
+ * fixed; typo in schemdate #1329 [jplock](https://github.com/jplock)
+ * updated; driver to 1.2.14
+ * updated; muri to 0.3.1
+ * updated; mpromise to 0.2.1
+ * updated; mocha 1.8.1
+ * updated; mpath to 0.1.1
+ * deprecated; pluralization will die in 4.x
+ * refactor; rename private methods to something unusable as doc properties
+ * refactor MongooseArray#remove
+ * refactor; move expires index to SchemaDate #1328
+ * refactor; internal document properties #1171 #1184
+ * tests; added
+ * docs; indexes
+ * docs; validation
+ * docs; populate
+ * docs; populate
+ * docs; add note about stream compatibility with node 0.8
+ * docs; fix for private names
+ * docs; Buffer -> mongodb.Binary #1363
+ * docs; auth options
+ * docs; improved
+ * website; update FAQ
+ * website; add more api links
+ * website; add 3.5.x docs to prior releases
+ * website; Change mongoose-types to an active repo [jackdbernier](https://github.com/jackdbernier)
+ * website; compat with node 0.10
+ * website; add news section
+ * website; use T for generic type
+ * benchmark; make adjustable
+
+3.6.0rc1 / 2013-03-12
+======================
+
+ * refactor; rename private methods to something unusable as doc properties
+ * added; {mongoose,db}.modelNames()
+ * added; $push w/ $slice,$sort support (MongoDB 2.4)
+ * added; hashed index type (MongoDB 2.4)
+ * added; support for mongodb 2.4 geojson (MongoDB 2.4)
+ * added; value at time of validation error
+ * added; support for object literal schemas
+ * added; bufferCommands schema option
+ * added; allow auth option in connections #1360 [geoah](https://github.com/geoah)
+ * fixed; lean population #1382
+ * fixed; empty object mixed defaults #1380
+ * fixed; populate w/ deselected _id using string syntax
+ * fixed; attempted save of divergent populated arrays #1334 related
+ * fixed; better error msg when attempting toObject as property name
+ * fixed; non population buffer casting from doc
+ * fixed; setting populated paths #570
+ * fixed; casting when added docs to populated arrays #570
+ * fixed; prohibit updating arrays selected with $elemMatch #1334
+ * fixed; pull / set subdoc combination #1303
+ * fixed; multiple bg index creation #1365
+ * fixed; manual reconnection to single mongod
+ * fixed; Constructor / version exposure #1124
+ * fixed; CastError race condition
+ * fixed; no longer swallowing misuse of subdoc#invalidate()
+ * fixed; utils.clone retains RegExp opts
+ * fixed; population of non-schema property
+ * fixed; allow updating versionKey #1265
+ * fixed; add EventEmitter props to reserved paths #1338
+ * fixed; can now deselect populated doc _ids #1331
+ * updated; muri to 0.3.1
+ * updated; driver to 1.2.12
+ * updated; mpromise to 0.2.1
+ * deprecated; pluralization will die in 4.x
+ * docs; Buffer -> mongodb.Binary #1363
+ * docs; auth options
+ * docs; improved
+ * website; add news section
+ * benchmark; make adjustable
+
+3.6.0rc0 / 2013-02-03
+======================
+
+ * changed; cast 'true'/'false' to boolean #1282 [mgrach](https://github.com/mgrach)
+ * changed; Buffer arrays can now contain nulls
+ * fixed; properly pass subtype to Binary in MongooseBuffer
+ * fixed; casting _id from document with non-ObjectId _id
+ * fixed; specifying schema type edge case { path: [{type: "String" }] }
+ * fixed; typo in schemdate #1329 [jplock](https://github.com/jplock)
+ * refactor; move expires index to SchemaDate #1328
+ * refactor; internal document properties #1171 #1184
+ * added; performance improvements to populate() [263ece9](https://github.com/LearnBoost/mongoose/commit/263ece9)
+ * added; allow adding uncasted docs to populated arrays and properties #570
+ * added; doc#populated(path) stores original populated _ids
+ * added; lean population #1260
+ * added; query.populate() now accepts an options object
+ * added; document#populate(opts, callback)
+ * added; Model.populate(docs, opts, callback)
+ * added; support for rich nested path population
+ * added; doc.array.remove(value) subdoc with _id value support #1278
+ * added; optionally allow non-strict sets and updates
+ * added; promises/A+ comformancy with [mpromise](https://github.com/aheckmann/mpromise)
+ * added; promise#then
+ * added; promise#end
+ * updated; mocha 1.8.1
+ * updated; muri to 0.3.0
+ * updated; mpath to 0.1.1
+ * updated; docs
+
+3.5.16 / 2013-08-13
+===================
+
+ * updated; driver to 1.3.18
+
+3.5.15 / 2013-07-26
+==================
+
+ * updated; sliced to 0.0.5
+ * updated; driver to 1.3.12
+ * fixed; regression in Query#count() due to driver change
+ * tests; fixed timeouts
+ * tests; handle differing test uris
+
+3.5.14 / 2013-05-15
+===================
+
+ * updated; driver to 1.3.5
+ * fixed; compat w/ Object.create(null) #1484 #1485
+ * fixed; cloning objects missing constructors
+ * fixed; prevent multiple min number validators #1481 [nrako](https://github.com/nrako)
+
+3.5.13 / 2013-05-09
+==================
+
+ * update driver to 1.3.3
+ * fixed; use of $options in array #1462
+
+3.5.12 / 2013-04-25
+===================
+
+ * updated; driver to 1.3.0
+ * fixed; connection.model should retain options #1458 [vedmalex](https://github.com/vedmalex)
+ * fixed; read pref typos #1422 [kyano](https://github.com/kyano)
+
+3.5.11 / 2013-04-03
+==================
+
+ * fixed; +field conflict with $slice #1370
+ * fixed; RangeError in ValidationError.toString() #1296
+ * fixed; nested deselection conflict #1333
+ * remove time from Makefile
+
+3.5.10 / 2013-04-02
+==================
+
+ * fixed; setting subdocuments deeply nested fields #1394
+ * fixed; do not alter schema arguments #1364
+
+3.5.9 / 2013-03-15
+==================
+
+ * updated; driver to 1.2.14
+ * added; support for authSource driver option (mongodb 2.4)
+ * added; QueryStream transform option (node 0.10 helper)
+ * fixed; backport for saving required populated buffers
+ * fixed; pull / set subdoc combination #1303
+ * fixed; multiple bg index creation #1365
+ * test; added for saveable required populated buffers
+ * test; added for #1365
+ * test; add authSource test
+
+3.5.8 / 2013-03-12
+==================
+
+ * added; auth option in connection [geoah](https://github.com/geoah)
+ * fixed; CastError race condition
+ * docs; add note about stream compatibility with node 0.8
+
+3.5.7 / 2013-02-22
+==================
+
+ * updated; driver to 1.2.13
+ * updated; muri to 0.3.1 #1347
+ * fixed; utils.clone retains RegExp opts #1355
+ * fixed; deepEquals RegExp support
+ * tests; fix a connection test
+ * website; clean up docs [afshinm](https://github.com/afshinm)
+ * website; update homepage
+ * website; migragtion: emphasize impact of strict docs #1264
+
+3.5.6 / 2013-02-14
+==================
+
+ * updated; driver to 1.2.12
+ * fixed; properly pass Binary subtype
+ * fixed; add EventEmitter props to reserved paths #1338
+ * fixed; use correct node engine version
+ * fixed; display empty docs as {} in log output #953 follow up
+ * improved; "bad $within $box argument" error message
+ * populate; add unscientific benchmark
+ * website; add stack overflow to help section
+ * website; use better code font #1336 [risseraka](https://github.com/risseraka)
+ * website; clarify where help is available
+ * website; fix source code links #1272 [floatingLomas](https://github.com/floatingLomas)
+ * docs; be specific about _id schema option #1103
+ * docs; add ensureIndex error handling example
+ * docs; README
+ * docs; CONTRIBUTING.md
+
+3.5.5 / 2013-01-29
+==================
+
+ * updated; driver to 1.2.11
+ * removed; old node < 0.6x shims
+ * fixed; documents with Buffer _ids equality
+ * fixed; MongooseBuffer properly casts numbers
+ * fixed; reopening closed connection on alt host/port #1287
+ * docs; fixed typo in Readme #1298 [rened](https://github.com/rened)
+ * docs; fixed typo in migration docs [Prinzhorn](https://github.com/Prinzhorn)
+ * docs; fixed incorrect annotation in SchemaNumber#min [bilalq](https://github.com/bilalq)
+ * docs; updated
+
+3.5.4 / 2013-01-07
+==================
+
+ * changed; "_pres" & "_posts" are now reserved pathnames #1261
+ * updated; driver to 1.2.8
+ * fixed; exception when reopening a replica set. #1263 [ethankan](https://github.com/ethankan)
+ * website; updated
+
+3.5.3 / 2012-12-26
+==================
+
+ * added; support for geo object notation #1257
+ * fixed; $within query casting with arrays
+ * fixed; unix domain socket support #1254
+ * updated; driver to 1.2.7
+ * updated; muri to 0.0.5
+
+3.5.2 / 2012-12-17
+==================
+
+ * fixed; using auth with replica sets #1253
+
+3.5.1 / 2012-12-12
+==================
+
+ * fixed; regression when using subdoc with `path` as pathname #1245 [daeq](https://github.com/daeq)
+ * fixed; safer db option checks
+ * updated; driver to 1.2.5
+ * website; add more examples
+ * website; clean up old docs
+ * website; fix prev release urls
+ * docs; clarify streaming with HTTP responses
+
+3.5.0 / 2012-12-10
+==================
+
+ * added; paths to CastErrors #1239
+ * added; support for mongodb connection string spec #1187
+ * added; post validate event
+ * added; Schema#get (to retrieve schema options)
+ * added; VersionError #1071
+ * added; npmignore [hidekiy](https://github.com/hidekiy)
+ * update; driver to 1.2.3
+ * fixed; stackoverflow in setter #1234
+ * fixed; utils.isObject()
+ * fixed; do not clobber user specified driver writeConcern #1227
+ * fixed; always pass current document to post hooks
+ * fixed; throw error when user attempts to overwrite a model
+ * fixed; connection.model only caches on connection #1209
+ * fixed; respect conn.model() creation when matching global model exists #1209
+ * fixed; passing model name + collection name now always honors collection name
+ * fixed; setting virtual field to an empty object #1154
+ * fixed; subclassed MongooseErrors exposure, now available in mongoose.Error.xxxx
+ * fixed; model.remove() ignoring callback when executed twice [daeq](https://github.com/daeq) #1210
+ * docs; add collection option to schema api docs #1222
+ * docs; NOTE about db safe options
+ * docs; add post hooks docs
+ * docs; connection string options
+ * docs; middleware is not executed with Model.remove #1241
+ * docs; {g,s}etter introspection #777
+ * docs; update validation docs
+ * docs; add link to plugins page
+ * docs; clarify error returned by unique indexes #1225
+ * docs; more detail about disabling autoIndex behavior
+ * docs; add homepage section to package (npm docs mongoose)
+ * docs; more detail around collection name pluralization #1193
+ * website; add .important css
+ * website; update models page
+ * website; update getting started
+ * website; update quick start
+
+3.4.0 / 2012-11-10
+==================
+
+ * added; support for generic toJSON/toObject transforms #1160 #1020 #1197
+ * added; doc.set() merge support #1148 [NuORDER](https://github.com/NuORDER)
+ * added; query#add support #1188 [aleclofabbro](https://github.com/aleclofabbro)
+ * changed; adding invalid nested paths to non-objects throws 4216f14
+ * changed; fixed; stop invalid function cloning (internal fix)
+ * fixed; add query $and casting support #1180 [anotheri](https://github.com/anotheri)
+ * fixed; overwriting of query arguments #1176
+ * docs; fix expires examples
+ * docs; transforms
+ * docs; schema `collection` option docs [hermanjunge](https://github.com/hermanjunge)
+ * website; updated
+ * tests; added
+
+3.3.1 / 2012-10-11
+==================
+
+ * fixed; allow goose.connect(uris, dbname, opts) #1144
+ * docs; persist API private checked state across page loads
+
+3.3.0 / 2012-10-10
+==================
+
+ * fixed; passing options as 2nd arg to connect() #1144
+ * fixed; race condition after no-op save #1139
+ * fixed; schema field selection application in findAndModify #1150
+ * fixed; directly setting arrays #1126
+ * updated; driver to 1.1.11
+ * updated; collection pluralization rules [mrickard](https://github.com/mrickard)
+ * tests; added
+ * docs; updated
+
+3.2.2 / 2012-10-08
+==================
+
+ * updated; driver to 1.1.10 #1143
+ * updated; use sliced 0.0.3
+ * fixed; do not recast embedded docs unnecessarily
+ * fixed; expires schema option helper #1132
+ * fixed; built in string setters #1131
+ * fixed; debug output for Dates/ObjectId properties #1129
+ * docs; fixed Javascript syntax error in example [olalonde](https://github.com/olalonde)
+ * docs; fix toJSON example #1137
+ * docs; add ensureIndex production notes
+ * docs; fix spelling
+ * docs; add blogposts about v3
+ * website; updated
+ * removed; undocumented inGroupsOf util
+ * tests; added
+
+3.2.1 / 2012-09-28
+==================
+
+ * fixed; remove query batchSize option default of 1000 https://github.com/learnboost/mongoose/commit/3edaa8651
+ * docs; updated
+ * website; updated
+
+3.2.0 / 2012-09-27
+==================
+
+ * added; direct array index assignment with casting support `doc.array.set(index, value)`
+ * fixed; QueryStream#resume within same tick as pause() #1116
+ * fixed; default value validatation #1109
+ * fixed; array splice() not casting #1123
+ * fixed; default array construction edge case #1108
+ * fixed; query casting for inequalities in arrays #1101 [dpatti](https://github.com/dpatti)
+ * tests; added
+ * website; more documentation
+ * website; fixed layout issue #1111 [SlashmanX](https://github.com/SlashmanX)
+ * website; refactored [guille](https://github.com/guille)
+
+3.1.2 / 2012-09-10
+==================
+
+ * added; ReadPreferrence schema option #1097
+ * updated; driver to 1.1.7
+ * updated; default query batchSize to 1000
+ * fixed; we now cast the mapReduce query option #1095
+ * fixed; $elemMatch+$in with field selection #1091
+ * fixed; properly cast $elemMatch+$in conditions #1100
+ * fixed; default field application of subdocs #1027
+ * fixed; querystream prematurely dying #1092
+ * fixed; querystream never resumes when paused at getMore boundries #1092
+ * fixed; querystream occasionally emits data events after destroy #1092
+ * fixed; remove unnecessary ObjectId creation in querystream
+ * fixed; allow ne(boolean) again #1093
+ * docs; add populate/field selection syntax notes
+ * docs; add toObject/toJSON options detail
+ * docs; `read` schema option
+
+3.1.1 / 2012-08-31
+==================
+
+ * updated; driver to 1.1.6
+
+3.1.0 / 2012-08-29
+==================
+
+ * changed; fixed; directly setting nested objects now overwrites entire object (previously incorrectly merged them)
+ * added; read pref support (mongodb 2.2) 205a709c
+ * added; aggregate support (mongodb 2.2) f3a5bd3d
+ * added; virtual {g,s}etter introspection (#1070)
+ * updated; docs [brettz9](https://github.com/brettz9)
+ * updated; driver to 1.1.5
+ * fixed; retain virtual setter return values (#1069)
+
+3.0.3 / 2012-08-23
+==================
+
+ * fixed; use of nested paths beginning w/ numbers #1062
+ * fixed; query population edge case #1053 #1055 [jfremy](https://github.com/jfremy)
+ * fixed; simultaneous top and sub level array modifications #1073
+ * added; id and _id schema option aliases + tests
+ * improve debug formatting to allow copy/paste logged queries into mongo shell [eknkc](https://github.com/eknkc)
+ * docs
+
+3.0.2 / 2012-08-17
+==================
+
+ * added; missing support for v3 sort/select syntax to findAndModify helpers (#1058)
+ * fixed; replset fullsetup event emission
+ * fixed; reconnected event for replsets
+ * fixed; server reconnection setting discovery
+ * fixed; compat with non-schema path props using positional notation (#1048)
+ * fixed; setter/casting order (#665)
+ * docs; updated
+
+3.0.1 / 2012-08-11
+==================
+
+ * fixed; throw Error on bad validators (1044)
+ * fixed; typo in EmbeddedDocument#parentArray [lackac]
+ * fixed; repair mongoose.SchemaTypes alias
+ * updated; docs
+
+3.0.0 / 2012-08-07
+==================
+
+ * removed; old subdocument#commit method
+ * fixed; setting arrays of matching docs [6924cbc2]
+ * fixed; doc!remove event now emits in save order as save for consistency
+ * fixed; pre-save hooks no longer fire on subdocuments when validation fails
+ * added; subdoc#parent() and subdoc#parentArray() to access subdocument parent objects
+ * added; query#lean() helper
+
+3.0.0rc0 / 2012-08-01
+=====================
+
+ * fixed; allow subdoc literal declarations containing "type" pathname (#993)
+ * fixed; unsetting a default array (#758)
+ * fixed; boolean $in queries (#998)
+ * fixed; allow use of `options` as a pathname (#529)
+ * fixed; `model` is again a permitted schema path name
+ * fixed; field selection option on subdocs (#1022)
+ * fixed; handle another edge case with subdoc saving (#975)
+ * added; emit save err on model if listening
+ * added; MongoDB TTL collection support (#1006)
+ * added; $center options support
+ * added; $nearSphere and $polygon support
+ * updated; driver version to 1.1.2
+
+3.0.0alpha2 / 2012-07-18
+=========================
+
+ * changed; index errors are now emitted on their model and passed to an optional callback (#984)
+ * fixed; specifying index along with sparse/unique option no longer overwrites (#1004)
+ * fixed; never swallow connection errors (#618)
+ * fixed; creating object from model with emded object no longer overwrites defaults [achurkin] (#859)
+ * fixed; stop needless validation of unchanged/unselected fields (#891)
+ * fixed; document#equals behavior of objectids (#974)
+ * fixed; honor the minimize schema option (#978)
+ * fixed; provide helpful error msgs when reserved schema path is used (#928)
+ * fixed; callback to conn#disconnect is optional (#875)
+ * fixed; handle missing protocols in connection urls (#987)
+ * fixed; validate args to query#where (#969)
+ * fixed; saving modified/removed subdocs (#975)
+ * fixed; update with $pull from Mixed array (#735)
+ * fixed; error with null shard key value
+ * fixed; allow unsetting enums (#967)
+ * added; support for manual index creation (#984)
+ * added; support for disabled auto-indexing (#984)
+ * added; support for preserving MongooseArray#sort changes (#752)
+ * added; emit state change events on connection
+ * added; support for specifying BSON subtype in MongooseBuffer#toObject [jcrugzz]
+ * added; support for disabled versioning (#977)
+ * added; implicit "new" support for models and Schemas
+
+3.0.0alpha1 / 2012-06-15
+=========================
+
+ * removed; doc#commit (use doc#markModified)
+ * removed; doc.modified getter (#950)
+ * removed; mongoose{connectSet,createSetConnection}. use connect,createConnection instead
+ * removed; query alias methods 1149804c
+ * removed; MongooseNumber
+ * changed; now creating indexes in background by default
+ * changed; strict mode now enabled by default (#952)
+ * changed; doc#modifiedPaths is now a method (#950)
+ * changed; getters no longer cast (#820); casting happens during set
+ * fixed; no need to pass updateArg to findOneAndUpdate (#931)
+ * fixed: utils.merge bug when merging nested non-objects. [treygriffith]
+ * fixed; strict:throw should produce errors in findAndModify (#963)
+ * fixed; findAndUpdate no longer overwrites document (#962)
+ * fixed; setting default DocumentArrays (#953)
+ * fixed; selection of _id with schema deselection (#954)
+ * fixed; ensure promise#error emits instanceof Error
+ * fixed; CursorStream: No stack overflow on any size result (#929)
+ * fixed; doc#remove now passes safe options
+ * fixed; invalid use of $set during $pop
+ * fixed; array#{$pop,$shift} mirror MongoDB behavior
+ * fixed; no longer test non-required vals in string match (#934)
+ * fixed; edge case with doc#inspect
+ * fixed; setter order (#665)
+ * fixed; setting invalid paths in strict mode (#916)
+ * fixed; handle docs without id in DocumentArray#id method (#897)
+ * fixed; do not save virtuals during model.update (#894)
+ * fixed; sub doc toObject virtuals application (#889)
+ * fixed; MongooseArray#pull of ObjectId (#881)
+ * fixed; handle passing db name with any repl set string
+ * fixed; default application of selected fields (#870)
+ * fixed; subdoc paths reported in validation errors (#725)
+ * fixed; incorrect reported num of affected docs in update ops (#862)
+ * fixed; connection assignment in Model#model (#853)
+ * fixed; stringifying arrays of docs (#852)
+ * fixed; modifying subdoc and parent array works (#842)
+ * fixed; passing undefined to next hook (#785)
+ * fixed; Query#{update,remove}() works without callbacks (#788)
+ * fixed; set/updating nested objects by parent pathname (#843)
+ * fixed; allow null in number arrays (#840)
+ * fixed; isNew on sub doc after insertion error (#837)
+ * fixed; if an insert fails, set isNew back to false [boutell]
+ * fixed; isSelected when only _id is selected (#730)
+ * fixed; setting an unset default value (#742)
+ * fixed; query#sort error messaging (#671)
+ * fixed; support for passing $options with $regex
+ * added; array of object literal notation in schema creates DocumentArrays
+ * added; gt,gte,lt,lte query support for arrays (#902)
+ * added; capped collection support (#938)
+ * added; document versioning support
+ * added; inclusion of deselected schema path (#786)
+ * added; non-atomic array#pop
+ * added; EmbeddedDocument constructor is now exposed in DocArray#create 7cf8beec
+ * added; mapReduce support (#678)
+ * added; support for a configurable minimize option #to{Object,JSON}(option) (#848)
+ * added; support for strict: `throws` [regality]
+ * added; support for named schema types (#795)
+ * added; to{Object,JSON} schema options (#805)
+ * added; findByIdAnd{Update,Remove}()
+ * added; findOneAnd{Update,Remove}()
+ * added; query.setOptions()
+ * added; instance.update() (#794)
+ * added; support specifying model in populate() [DanielBaulig]
+ * added; `lean` query option [gitfy]
+ * added; multi-atomic support to MongooseArray#nonAtomicPush
+ * added; support for $set + other $atomic ops on single array
+ * added; tests
+ * updated; driver to 1.0.2
+ * updated; query.sort() syntax to mirror query.select()
+ * updated; clearer cast error msg for array numbers
+ * updated; docs
+ * updated; doc.clone 3x faster (#950)
+ * updated; only create _id if necessary (#950)
+
+2.7.3 / 2012-08-01
+==================
+
+ * fixed; boolean $in queries (#998)
+ * fixed field selection option on subdocs (#1022)
+
+2.7.2 / 2012-07-18
+==================
+
+ * fixed; callback to conn#disconnect is optional (#875)
+ * fixed; handle missing protocols in connection urls (#987)
+ * fixed; saving modified/removed subdocs (#975)
+ * updated; tests
+
+2.7.1 / 2012-06-26
+===================
+
+ * fixed; sharding: when a document holds a null as a value of the shard key
+ * fixed; update() using $pull on an array of Mixed (gh-735)
+ * deprecated; MongooseNumber#{inc, increment, decrement} methods
+ * tests; now using mocha
+
+2.7.0 / 2012-06-14
+===================
+
+ * added; deprecation warnings to methods being removed in 3.x
+
+2.6.8 / 2012-06-14
+===================
+
+ * fixed; edge case when using 'options' as a path name (#961)
+
+2.6.7 / 2012-06-08
+===================
+
+ * fixed; ensure promise#error always emits instanceof Error
+ * fixed; selection of _id w/ another excluded path (#954)
+ * fixed; setting default DocumentArrays (#953)
+
+2.6.6 / 2012-06-06
+===================
+
+ * fixed; stack overflow in query stream with large result sets (#929)
+ * added; $gt, $gte, $lt, $lte support to arrays (#902)
+ * fixed; pass option `safe` along to doc#remove() calls
+
+2.6.5 / 2012-05-24
+===================
+
+ * fixed; do not save virtuals in Model.update (#894)
+ * added; missing $ prefixed query aliases (going away in 3.x) (#884) [timoxley]
+ * fixed; setting invalid paths in strict mode (#916)
+ * fixed; resetting isNew after insert failure (#837) [boutell]
+
+2.6.4 / 2012-05-15
+===================
+
+ * updated; backport string regex $options to 2.x
+ * updated; use driver 1.0.2 (performance improvements) (#914)
+ * fixed; calling MongooseDocumentArray#id when the doc has no _id (#897)
+
+2.6.3 / 2012-05-03
+===================
+
+ * fixed; repl-set connectivity issues during failover on MongoDB 2.0.1
+ * updated; driver to 1.0.0
+ * fixed; virtuals application of subdocs when using toObject({ virtuals: true }) (#889)
+ * fixed; MongooseArray#pull of ObjectId correctly updates the array itself (#881)
+
+2.6.2 / 2012-04-30
+===================
+
+ * fixed; default field application of selected fields (#870)
+
+2.6.1 / 2012-04-30
+===================
+
+ * fixed; connection assignment in mongoose#model (#853, #877)
+ * fixed; incorrect reported num of affected docs in update ops (#862)
+
+2.6.0 / 2012-04-19
+===================
+
+ * updated; hooks.js to 0.2.1
+ * fixed; issue with passing undefined to a hook callback. thanks to [chrisleishman] for reporting.
+ * fixed; updating/setting nested objects in strict schemas (#843) as reported by [kof]
+ * fixed; Query#{update,remove}() work without callbacks again (#788)
+ * fixed; modifying subdoc along with parent array $atomic op (#842)
+
+2.5.14 / 2012-04-13
+===================
+
+ * fixed; setting an unset default value (#742)
+ * fixed; doc.isSelected(otherpath) when only _id is selected (#730)
+ * updated; docs
+
+2.5.13 / 2012-03-22
+===================
+
+ * fixed; failing validation of unselected required paths (#730,#713)
+ * fixed; emitting connection error when only one listener (#759)
+ * fixed; MongooseArray#splice was not returning values (#784) [chrisleishman]
+
+2.5.12 / 2012-03-21
+===================
+
+ * fixed; honor the `safe` option in all ensureIndex calls
+ * updated; node-mongodb-native driver to 0.9.9-7
+
+2.5.11 / 2012-03-15
+===================
+
+ * added; introspection for getters/setters (#745)
+ * updated; node-mongodb-driver to 0.9.9-5
+ * added; tailable method to Query (#769) [holic]
+ * fixed; Number min/max validation of null (#764) [btamas]
+ * added; more flexible user/password connection options (#738) [KarneAsada]
+
+2.5.10 / 2012-03-06
+===================
+
+ * updated; node-mongodb-native driver to 0.9.9-4
+ * added; Query#comment()
+ * fixed; allow unsetting arrays
+ * fixed; hooking the set method of subdocuments (#746)
+ * fixed; edge case in hooks
+ * fixed; allow $id and $ref in queries (fixes compatibility with mongoose-dbref) (#749) [richtera]
+ * added; default path selection to SchemaTypes
+
+2.5.9 / 2012-02-22
+===================
+
+ * fixed; properly cast nested atomic update operators for sub-documents
+
+2.5.8 / 2012-02-21
+===================
+
+ * added; post 'remove' middleware includes model that was removed (#729) [timoxley]
+
+2.5.7 / 2012-02-09
+===================
+
+ * fixed; RegExp validators on node >= v0.6.x
+
+2.5.6 / 2012-02-09
+===================
+
+ * fixed; emit errors returned from db.collection() on the connection (were being swallowed)
+ * added; can add multiple validators in your schema at once (#718) [diogogmt]
+ * fixed; strict embedded documents (#717)
+ * updated; docs [niemyjski]
+ * added; pass number of affected docs back in model.update/save
+
+2.5.5 / 2012-02-03
+===================
+
+ * fixed; RangeError: maximum call stack exceed error when removing docs with Number _id (#714)
+
+2.5.4 / 2012-02-03
+===================
+
+ * fixed; RangeError: maximum call stack exceed error (#714)
+
+2.5.3 / 2012-02-02
+===================
+
+ * added; doc#isSelected(path)
+ * added; query#equals()
+ * added; beta sharding support
+ * added; more descript error msgs (#700) [obeleh]
+ * added; document.modifiedPaths (#709) [ljharb]
+ * fixed; only functions can be added as getters/setters (#707,704) [ljharb]
+
+2.5.2 / 2012-01-30
+===================
+
+ * fixed; rollback -native driver to 0.9.7-3-5 (was causing timeouts and other replica set weirdness)
+ * deprecated; MongooseNumber (will be moved to a separate repo for 3.x)
+ * added; init event is emitted on schemas
+
+2.5.1 / 2012-01-27
+===================
+
+ * fixed; honor strict schemas in Model.update (#699)
+
+2.5.0 / 2012-01-26
+===================
+
+ * added; doc.toJSON calls toJSON on embedded docs when exists [jerem]
+ * added; populate support for refs of type Buffer (#686) [jerem]
+ * added; $all support for ObjectIds and Dates (#690)
+ * fixed; virtual setter calling on instantiation when strict: true (#682) [hunterloftis]
+ * fixed; doc construction triggering getters (#685)
+ * fixed; MongooseBuffer check in deepEquals (#688)
+ * fixed; range error when using Number _ids with `instance.save()` (#691)
+ * fixed; isNew on embedded docs edge case (#680)
+ * updated; driver to 0.9.8-3
+ * updated; expose `model()` method within static methods
+
+2.4.10 / 2012-01-10
+===================
+
+ * added; optional getter application in .toObject()/.toJSON() (#412)
+ * fixed; nested $operators in $all queries (#670)
+ * added; $nor support (#674)
+ * fixed; bug when adding nested schema (#662) [paulwe]
+
+2.4.9 / 2012-01-04
+===================
+
+ * updated; driver to 0.9.7-3-5 to fix Linux performance degradation on some boxes
+
+2.4.8 / 2011-12-22
+===================
+
+ * updated; bump -native to 0.9.7.2-5
+ * fixed; compatibility with date.js (#646) [chrisleishman]
+ * changed; undocumented schema "lax" option to "strict"
+ * fixed; default value population for strict schemas
+ * updated; the nextTick helper for small performance gain. 1bee2a2
+
+2.4.7 / 2011-12-16
+===================
+
+ * fixed; bug in 2.4.6 with path setting
+ * updated; bump -native to 0.9.7.2-1
+ * added; strict schema option [nw]
+
+2.4.6 / 2011-12-16
+===================
+
+ * fixed; conflicting mods on update bug [sirlantis]
+ * improved; doc.id getter performance
+
+2.4.5 / 2011-12-14
+===================
+
+ * fixed; bad MongooseArray behavior in 2.4.2 - 2.4.4
+
+2.4.4 / 2011-12-14
+===================
+
+ * fixed; MongooseArray#doAtomics throwing after sliced
+
+2.4.3 / 2011-12-14
+===================
+
+ * updated; system.profile schema for MongoDB 2x
+
+2.4.2 / 2011-12-12
+===================
+
+ * fixed; partially populating multiple children of subdocs (#639) [kenpratt]
+ * fixed; allow Update of numbers to null (#640) [jerem]
+
+2.4.1 / 2011-12-02
+===================
+
+ * added; options support for populate() queries
+ * updated; -native driver to 0.9.7-1.4
+
+2.4.0 / 2011-11-29
+===================
+
+ * added; QueryStreams (#614)
+ * added; debug print mode for development
+ * added; $within support to Array queries (#586) [ggoodale]
+ * added; $centerSphere query support
+ * fixed; $within support
+ * added; $unset is now used when setting a path to undefined (#519)
+ * added; query#batchSize support
+ * updated; docs
+ * updated; -native driver to 0.9.7-1.3 (provides Windows support)
+
+2.3.13 / 2011-11-15
+===================
+
+ * fixed; required validation for Refs (#612) [ded]
+ * added; $nearSphere support for Arrays (#610)
+
+2.3.12 / 2011-11-09
+===================
+
+ * fixed; regression, objects passed to Model.update should not be changed (#605)
+ * fixed; regression, empty Model.update should not be executed
+
+2.3.11 / 2011-11-08
+===================
+
+ * fixed; using $elemMatch on arrays of Mixed types (#591)
+ * fixed; allow using $regex when querying Arrays (#599)
+ * fixed; calling Model.update with no atomic keys (#602)
+
+2.3.10 / 2011-11-05
+===================
+
+ * fixed; model.update casting for nested paths works (#542)
+
+2.3.9 / 2011-11-04
+==================
+
+ * fixed; deepEquals check for MongooseArray returned false
+ * fixed; reset modified flags of embedded docs after save [gitfy]
+ * fixed; setting embedded doc with identical values no longer marks modified [gitfy]
+ * updated; -native driver to 0.9.6.23 [mlazarov]
+ * fixed; Model.update casting (#542, #545, #479)
+ * fixed; populated refs no longer fail required validators (#577)
+ * fixed; populating refs of objects with custom ids works
+ * fixed; $pop & $unset work with Model.update (#574)
+ * added; more helpful debugging message for Schema#add (#578)
+ * fixed; accessing .id when no _id exists now returns null (#590)
+
+2.3.8 / 2011-10-26
+==================
+
+ * added; callback to query#findOne is now optional (#581)
+
+2.3.7 / 2011-10-24
+==================
+
+ * fixed; wrapped save/remove callbacks in nextTick to mitigate -native swallowing thrown errors
+
+2.3.6 / 2011-10-21
+==================
+
+ * fixed; exclusion of embedded doc _id from query results (#541)
+
+2.3.5 / 2011-10-19
+==================
+
+ * fixed; calling queries without passing a callback works (#569)
+ * fixed; populate() works with String and Number _ids too (#568)
+
+2.3.4 / 2011-10-18
+==================
+
+ * added; Model.create now accepts an array as a first arg
+ * fixed; calling toObject on a DocumentArray with nulls no longer throws
+ * fixed; calling inspect on a DocumentArray with nulls no longer throws
+ * added; MongooseArray#unshift support
+ * fixed; save hooks now fire on embedded documents [gitfy] (#456)
+ * updated; -native driver to 0.9.6-22
+ * fixed; correctly pass $addToSet op instead of $push
+ * fixed; $addToSet properly detects dates
+ * fixed; $addToSet with multiple items works
+ * updated; better node 0.6 Buffer support
+
+2.3.3 / 2011-10-12
+==================
+
+ * fixed; population conditions in multi-query settings [vedmalex] (#563)
+ * fixed; now compatible with Node v0.5.x
+
+2.3.2 / 2011-10-11
+==================
+
+ * fixed; population of null subdoc properties no longer hangs (#561)
+
+2.3.1 / 2011-10-10
+==================
+
+ * added; support for Query filters to populate() [eneko]
+ * fixed; querying with number no longer crashes mongodb (#555) [jlbyrey]
+ * updated; version of -native driver to 0.9.6-21
+ * fixed; prevent query callbacks that throw errors from corrupting -native connection state
+
+2.3.0 / 2011-10-04
+==================
+
+ * fixed; nulls as default values for Boolean now works as expected
+ * updated; version of -native driver to 0.9.6-20
+
+2.2.4 / 2011-10-03
+==================
+
+ * fixed; populate() works when returned array contains undefined/nulls
+
+2.2.3 / 2011-09-29
+==================
+
+ * updated; version of -native driver to 0.9.6-19
+
+2.2.2 / 2011-09-28
+==================
+
+ * added; $regex support to String [davidandrewcope]
+ * added; support for other contexts like repl etc (#535)
+ * fixed; clear modified state properly after saving
+ * added; $addToSet support to Array
+
+2.2.1 / 2011-09-22
+==================
+
+ * more descript error when casting undefined to string
+ * updated; version of -native driver to 0.9.6-18
+
+2.2.0 / 2011-09-22
+==================
+
+ * fixed; maxListeners warning on schemas with many arrays (#530)
+ * changed; return / apply defaults based on fields selected in query (#423)
+ * fixed; correctly detect Mixed types within schema arrays (#532)
+
+2.1.4 / 2011-09-20
+==================
+
+ * fixed; new private methods that stomped on users code
+ * changed; finished removing old "compat" support which did nothing
+
+2.1.3 / 2011-09-16
+==================
+
+ * updated; version of -native driver to 0.9.6-15
+ * added; emit `error` on connection when open fails [edwardhotchkiss]
+ * added; index support to Buffers (thanks justmoon for helping track this down)
+ * fixed; passing collection name via schema in conn.model() now works (thanks vedmalex for reporting)
+
+2.1.2 / 2011-09-07
+==================
+
+ * fixed; Query#find with no args no longer throws
+
+2.1.1 / 2011-09-07
+==================
+
+ * added; support Model.count(fn)
+ * fixed; compatibility with node >=0.4.0 < 0.4.3
+ * added; pass model.options.safe through with .save() so w:2, wtimeout:5000 options work [andrewjstone]
+ * added; support for $type queries
+ * added; support for Query#or
+ * added; more tests
+ * optimized populate queries
+
+2.1.0 / 2011-09-01
+==================
+
+ * changed; document#validate is a public method
+ * fixed; setting number to same value no longer marks modified (#476) [gitfy]
+ * fixed; Buffers shouldn't have default vals
+ * added; allow specifying collection name in schema (#470) [ixti]
+ * fixed; reset modified paths and atomics after saved (#459)
+ * fixed; set isNew on embedded docs to false after save
+ * fixed; use self to ensure proper scope of options in doOpenSet (#483) [andrewjstone]
+
+2.0.4 / 2011-08-29
+==================
+
+ * Fixed; Only send the depopulated ObjectId instead of the entire doc on save (DBRefs)
+ * Fixed; Properly cast nested array values in Model.update (the data was stored in Mongo incorrectly but recast on document fetch was "fixing" it)
+
+2.0.3 / 2011-08-28
+==================
+
+ * Fixed; manipulating a populated array no longer causes infinite loop in BSON serializer during save (#477)
+ * Fixed; populating an empty array no longer hangs foreeeeeeeever (#481)
+
+2.0.2 / 2011-08-25
+==================
+
+ * Fixed; Maintain query option key order (fixes 'bad hint' error from compound query hints)
+
+2.0.1 / 2011-08-25
+==================
+
+ * Fixed; do not over-write the doc when no valide props exist in Model.update (#473)
+
+2.0.0 / 2011-08-24
+===================
+
+ * Added; support for Buffers [justmoon]
+ * Changed; improved error handling [maelstrom]
+ * Removed: unused utils.erase
+ * Fixed; support for passing other context object into Schemas (#234) [Sija]
+ * Fixed; getters are no longer circular refs to themselves (#366)
+ * Removed; unused compat.js
+ * Fixed; getter/setter scopes are set properly
+ * Changed; made several private properties more obvious by prefixing _
+ * Added; DBRef support [guille]
+ * Changed; removed support for multiple collection names per model
+ * Fixed; no longer applying setters when document returned from db
+ * Changed; default auto_reconnect to true
+ * Changed; Query#bind no longer clones the query
+ * Fixed; Model.update now accepts $pull, $inc and friends (#404)
+ * Added; virtual type option support [nw]
+
+1.8.4 / 2011-08-21
+===================
+
+ * Fixed; validation bug when instantiated with non-schema properties (#464) [jmreidy]
+
+1.8.3 / 2011-08-19
+===================
+
+ * Fixed; regression in connection#open [jshaw86]
+
+1.8.2 / 2011-08-17
+===================
+
+ * fixed; reset connection.readyState after failure [tomseago]
+ * fixed; can now query positionally for non-embedded docs (arrays of numbers/strings etc)
+ * fixed; embedded document query casting
+ * added; support for passing options to node-mongo-native db, server, and replsetserver [tomseago]
+
+1.8.1 / 2011-08-10
+===================
+
+ * fixed; ObjectIds were always marked modified
+ * fixed; can now query using document instances
+ * fixed; can now query/update using documents with subdocs
+
+1.8.0 / 2011-08-04
+===================
+
+ * fixed; can now use $all with String and Number
+ * fixed; can query subdoc array with $ne: null
+ * fixed; instance.subdocs#id now works with custom _ids
+ * fixed; do not apply setters when doc returned from db (change in bad behavior)
+
+1.7.4 / 2011-07-25
+===================
+
+ * fixed; sparse now a valid seperate schema option
+ * fixed; now catching cast errors in queries
+ * fixed; calling new Schema with object created in vm.runInNewContext now works (#384) [Sija]
+ * fixed; String enum was disallowing null
+ * fixed; Find by nested document _id now works (#389)
+
+1.7.3 / 2011-07-16
+===================
+
+ * fixed; MongooseArray#indexOf now works with ObjectIds
+ * fixed; validation scope now set properly (#418)
+ * fixed; added missing colors dependency (#398)
+
+1.7.2 / 2011-07-13
+===================
+
+ * changed; node-mongodb-native driver to v0.9.6.7
+
+1.7.1 / 2011-07-12
+===================
+
+ * changed; roll back node-mongodb-native driver to v0.9.6.4
+
+1.7.0 / 2011-07-12
+===================
+
+ * fixed; collection name misspelling [mathrawka]
+ * fixed; 2nd param is required for ReplSetServers [kevinmarvin]
+ * fixed; MongooseArray behaves properly with Object.keys
+ * changed; node-mongodb-native driver to v0.9.6.6
+ * fixed/changed; Mongodb segfault when passed invalid ObjectId (#407)
+ - This means invalid data passed to the ObjectId constructor will now error
+
+1.6.0 / 2011-07-07
+===================
+
+ * changed; .save() errors are now emitted on the instances db instead of the instance 9782463fc
+ * fixed; errors occurring when creating indexes now properly emit on db
+ * added; $maxDistance support to MongooseArrays
+ * fixed; RegExps now work with $all
+ * changed; node-mongodb-native driver to v0.9.6.4
+ * fixed; model names are now accessible via .modelName
+ * added; Query#slaveOk support
+
+1.5.0 / 2011-06-27
+===================
+
+ * changed; saving without a callback no longer ignores the error (@bnoguchi)
+ * changed; hook-js version bump to 0.1.9
+ * changed; node-mongodb-native version bumped to 0.9.6.1 - When .remove() doesn't
+ return an error, null is no longer passed.
+ * fixed; two memory leaks (@justmoon)
+ * added; sparse index support
+ * added; more ObjectId conditionals (gt, lt, gte, lte) (@phillyqueso)
+ * added; options are now passed in model#remote (@JerryLuke)
+
+1.4.0 / 2011-06-10
+===================
+
+ * bumped hooks-js dependency (fixes issue passing null as first arg to next())
+ * fixed; document#inspect now works properly with nested docs
+ * fixed; 'set' now works as a schema attribute (GH-365)
+ * fixed; _id is now set properly within pre-init hooks (GH-289)
+ * added; Query#distinct / Model#distinct support (GH-155)
+ * fixed; embedded docs now can use instance methods (GH-249)
+ * fixed; can now overwrite strings conflicting with schema type
+
+1.3.7 / 2011-06-03
+===================
+
+ * added MongooseArray#splice support
+ * fixed; 'path' is now a valid Schema pathname
+ * improved hooks (utilizing https://github.com/bnoguchi/hooks-js)
+ * fixed; MongooseArray#$shift now works (never did)
+ * fixed; Document.modified no longer throws
+ * fixed; modifying subdoc property sets modified paths for subdoc and parent doc
+ * fixed; marking subdoc path as modified properly persists the value to the db
+ * fixed; RexExps can again be saved ( #357 )
+
+1.3.6 / 2011-05-18
+===================
+
+ * fixed; corrected casting for queries against array types
+ * added; Document#set now accepts Document instances
+
+1.3.5 / 2011-05-17
+===================
+
+ * fixed; $ne queries work properly with single vals
+ * added; #inspect() methods to improve console.log output
+
+1.3.4 / 2011-05-17
+===================
+
+ * fixed; find by Date works as expected (#336)
+ * added; geospatial 2d index support
+ * added; support for $near (#309)
+ * updated; node-mongodb-native driver
+ * fixed; updating numbers work (#342)
+ * added; better error msg when try to remove an embedded doc without an _id (#307)
+ * added; support for 'on-the-fly' schemas (#227)
+ * changed; virtual id getters can now be skipped
+ * fixed; .index() called on subdoc schema now works as expected
+ * fixed; db.setProfile() now buffers until the db is open (#340)
+
+1.3.3 / 2011-04-27
+===================
+
+ * fixed; corrected query casting on nested mixed types
+
+1.3.2 / 2011-04-27
+===================
+
+ * fixed; query hints now retain key order
+
+1.3.1 / 2011-04-27
+===================
+
+ * fixed; setting a property on an embedded array no longer overwrites entire array (GH-310)
+ * fixed; setting nested properties works when sibling prop is named "type"
+ * fixed; isModified is now much finer grained when .set() is used (GH-323)
+ * fixed; mongoose.model() and connection.model() now return the Model (GH-308, GH-305)
+ * fixed; can now use $gt, $lt, $gte, $lte with String schema types (GH-317)
+ * fixed; .lowercase() -> .toLowerCase() in pluralize()
+ * fixed; updating an embedded document by index works (GH-334)
+ * changed; .save() now passes the instance to the callback (GH-294, GH-264)
+ * added; can now query system.profile and system.indexes collections
+ * added; db.model('system.profile') is now included as a default Schema
+ * added; db.setProfiling(level, ms, callback)
+ * added; Query#hint() support
+ * added; more tests
+ * updated node-mongodb-native to 0.9.3
+
+1.3.0 / 2011-04-19
+===================
+
+ * changed; save() callbacks now fire only once on failed validation
+ * changed; Errors returned from save() callbacks now instances of ValidationError
+ * fixed; MongooseArray#indexOf now works properly
+
+1.2.0 / 2011-04-11
+===================
+
+ * changed; MongooseNumber now casts empty string to null
+
+1.1.25 / 2011-04-08
+===================
+
+ * fixed; post init now fires at proper time
+
+1.1.24 / 2011-04-03
+===================
+
+ * fixed; pushing an array onto an Array works on existing docs
+
+1.1.23 / 2011-04-01
+===================
+
+ * Added Model#model
+
+1.1.22 / 2011-03-31
+===================
+
+ * Fixed; $in queries on mixed types now work
+
+1.1.21 / 2011-03-31
+===================
+
+ * Fixed; setting object root to null/undefined works
+
+1.1.20 / 2011-03-31
+===================
+
+ * Fixed; setting multiple props on null field works
+
+1.1.19 / 2011-03-31
+===================
+
+ * Fixed; no longer using $set on paths to an unexisting fields
+
+1.1.18 / 2011-03-30
+===================
+
+ * Fixed; non-mixed type object setters work after initd from null
+
+1.1.17 / 2011-03-30
+===================
+
+ * Fixed; nested object property access works when root initd with null value
+
+1.1.16 / 2011-03-28
+===================
+
+ * Fixed; empty arrays are now saved
+
+1.1.15 / 2011-03-28
+===================
+
+ * Fixed; `null` and `undefined` are set atomically.
+
+1.1.14 / 2011-03-28
+===================
+
+ * Changed; more forgiving date casting, accepting '' as null.
+
+1.1.13 / 2011-03-26
+===================
+
+ * Fixed setting values as `undefined`.
+
+1.1.12 / 2011-03-26
+===================
+
+ * Fixed; nested objects now convert to JSON properly
+ * Fixed; setting nested objects directly now works
+ * Update node-mongodb-native
+
+1.1.11 / 2011-03-25
+===================
+
+ * Fixed for use of `type` as a key.
+
+1.1.10 / 2011-03-23
+===================
+
+ * Changed; Make sure to only ensure indexes while connected
+
+1.1.9 / 2011-03-2
+==================
+
+ * Fixed; Mixed can now default to empty arrays
+ * Fixed; keys by the name 'type' are now valid
+ * Fixed; null values retrieved from the database are hydrated as null values.
+ * Fixed repeated atomic operations when saving a same document twice.
+
+1.1.8 / 2011-03-23
+==================
+
+ * Fixed 'id' overriding. [bnoguchi]
+
+1.1.7 / 2011-03-22
+==================
+
+ * Fixed RegExp query casting when querying against an Array of Strings [bnoguchi]
+ * Fixed getters/setters for nested virtualsl. [bnoguchi]
+
+1.1.6 / 2011-03-22
+==================
+
+ * Only doValidate when path exists in Schema [aheckmann]
+ * Allow function defaults for Array types [aheckmann]
+ * Fix validation hang [aheckmann]
+ * Fix setting of isRequired of SchemaType [aheckmann]
+ * Fix SchemaType#required(false) filter [aheckmann]
+ * More backwards compatibility [aheckmann]
+ * More tests [aheckmann]
+
+1.1.5 / 2011-03-14
+==================
+
+ * Added support for `uri, db, fn` and `uri, fn` signatures for replica sets.
+ * Improved/extended replica set tests.
+
+1.1.4 / 2011-03-09
+==================
+
+ * Fixed; running an empty Query doesn't throw. [aheckmann]
+ * Changed; Promise#addBack returns promise. [aheckmann]
+ * Added streaming cursor support. [aheckmann]
+ * Changed; Query#update defaults to use$SetOnSave now. [brian]
+ * Added more docs.
+
+1.1.3 / 2011-03-04
+==================
+
+ * Added Promise#resolve [aheckmann]
+ * Fixed backward compatibility with nulls [aheckmann]
+ * Changed; Query#{run,exec} return promises [aheckmann]
+
+1.1.2 / 2011-03-03
+==================
+
+ * Restored Query#exec and added notion of default operation [brian]
+ * Fixed ValidatorError messages [brian]
+
+1.1.1 / 2011-03-01
+==================
+
+ * Added SchemaType String `lowercase`, `uppercase`, `trim`.
+ * Public exports (`Model`, `Document`) and tests.
+ * Added ObjectId casting support for `Document`s.
+
+1.1.0 / 2011-02-25
+==================
+
+ * Added support for replica sets.
+
+1.0.16 / 2011-02-18
+===================
+
+ * Added $nin as another whitelisted $conditional for SchemaArray [brian]
+ * Changed #with to #where [brian]
+ * Added ability to use $in conditional with Array types [brian]
+
+1.0.15 / 2011-02-18
+===================
+
+ * Added `id` virtual getter for documents to easily access the hexString of
+ the `_id`.
+
+1.0.14 / 2011-02-17
+===================
+
+ * Fix for arrays within subdocuments [brian]
+
+1.0.13 / 2011-02-16
+===================
+
+ * Fixed embedded documents saving.
+
+1.0.12 / 2011-02-14
+===================
+
+ * Minor refactorings [brian]
+
+1.0.11 / 2011-02-14
+===================
+
+ * Query refactor and $ne, $slice, $or, $size, $elemMatch, $nin, $exists support [brian]
+ * Named scopes sugar [brian]
+
+1.0.10 / 2011-02-11
+===================
+
+ * Updated node-mongodb-native driver [thanks John Allen]
+
+1.0.9 / 2011-02-09
+==================
+
+ * Fixed single member arrays as defaults [brian]
+
+1.0.8 / 2011-02-09
+==================
+
+ * Fixed for collection-level buffering of commands [gitfy]
+ * Fixed `Document#toJSON` [dalejefferson]
+ * Fixed `Connection` authentication [robrighter]
+ * Fixed clash of accessors in getters/setters [eirikurn]
+ * Improved `Model#save` promise handling
+
+1.0.7 / 2011-02-05
+==================
+
+ * Fixed memory leak warnings for test suite on 0.3
+ * Fixed querying documents that have an array that contain at least one
+ specified member. [brian]
+ * Fixed default value for Array types (fixes GH-210). [brian]
+ * Fixed example code.
+
+1.0.6 / 2011-02-03
+==================
+
+ * Fixed `post` middleware
+ * Fixed; it's now possible to instantiate a model even when one of the paths maps
+ to an undefined value [brian]
+
+1.0.5 / 2011-02-02
+==================
+
+ * Fixed; combo $push and $pushAll auto-converts into a $pushAll [brian]
+ * Fixed; combo $pull and $pullAll auto-converts to a single $pullAll [brian]
+ * Fixed; $pullAll now removes said members from array before save (so it acts just
+ like pushAll) [brian]
+ * Fixed; multiple $pulls and $pushes become a single $pullAll and $pushAll.
+ Moreover, $pull now modifies the array before save to reflect the immediate
+ change [brian]
+ * Added tests for nested shortcut getters [brian]
+ * Added tests that show that Schemas with nested Arrays don't apply defaults
+ [brian]
+
+1.0.4 / 2011-02-02
+==================
+
+ * Added MongooseNumber#toString
+ * Added MongooseNumber unit tests
+
+1.0.3 / 2011-02-02
+==================
+
+ * Make sure safe mode works with Model#save
+ * Changed Schema options: safe mode is now the default
+ * Updated node-mongodb-native to HEAD
+
+1.0.2 / 2011-02-02
+==================
+
+ * Added a Model.create shortcut for creating documents. [brian]
+ * Fixed; we can now instantiate models with hashes that map to at least one
+ null value. [brian]
+ * Fixed Schema with more than 2 nested levels. [brian]
+
+1.0.1 / 2011-02-02
+==================
+
+ * Improved `MongooseNumber`, works almost like the native except for `typeof`
+ not being `'number'`.
diff --git a/node_modules/mongoose/LICENSE.md b/node_modules/mongoose/LICENSE.md
new file mode 100644
index 0000000..14cdf56
--- /dev/null
+++ b/node_modules/mongoose/LICENSE.md
@@ -0,0 +1,21 @@
+# MIT License
+
+Copyright (c) 2010 LearnBoost
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/mongoose/README.md b/node_modules/mongoose/README.md
new file mode 100644
index 0000000..e6e3914
--- /dev/null
+++ b/node_modules/mongoose/README.md
@@ -0,0 +1,369 @@
+# Mongoose
+
+Mongoose is a [MongoDB](https://www.mongodb.org/) object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks.
+
+[](http://slack.mongoosejs.io)
+[](https://travis-ci.org/Automattic/mongoose)
+[](http://badge.fury.io/js/mongoose)
+
+[](https://www.npmjs.com/package/mongoose)
+
+## Documentation
+
+The official documentation website is [mongoosejs.com](http://mongoosejs.com/).
+
+[Mongoose 5.0.0](https://github.com/Automattic/mongoose/blob/master/History.md#500--2018-01-17) was released on January 17, 2018. You can find more details on [backwards breaking changes in 5.0.0 on our docs site](https://mongoosejs.com/docs/migrating_to_5.html).
+
+## Support
+
+ - [Stack Overflow](http://stackoverflow.com/questions/tagged/mongoose)
+ - [Bug Reports](https://github.com/Automattic/mongoose/issues/)
+ - [Mongoose Slack Channel](http://slack.mongoosejs.io/)
+ - [Help Forum](http://groups.google.com/group/mongoose-orm)
+ - [MongoDB Support](https://docs.mongodb.org/manual/support/)
+
+## Plugins
+
+Check out the [plugins search site](http://plugins.mongoosejs.io/) to see hundreds of related modules from the community. Next, learn how to write your own plugin from the [docs](http://mongoosejs.com/docs/plugins.html) or [this blog post](http://thecodebarbarian.com/2015/03/06/guide-to-mongoose-plugins).
+
+## Contributors
+
+Pull requests are always welcome! Please base pull requests against the `master`
+branch and follow the [contributing guide](https://github.com/Automattic/mongoose/blob/master/CONTRIBUTING.md).
+
+If your pull requests makes documentation changes, please do **not**
+modify any `.html` files. The `.html` files are compiled code, so please make
+your changes in `docs/*.pug`, `lib/*.js`, or `test/docs/*.js`.
+
+View all 400+ [contributors](https://github.com/Automattic/mongoose/graphs/contributors).
+
+## Installation
+
+First install [Node.js](http://nodejs.org/) and [MongoDB](https://www.mongodb.org/downloads). Then:
+
+```sh
+$ npm install mongoose
+```
+
+## Importing
+
+```javascript
+// Using Node.js `require()`
+const mongoose = require('mongoose');
+
+// Using ES6 imports
+import mongoose from 'mongoose';
+```
+
+## Mongoose for Enterprise
+
+Available as part of the Tidelift Subscription
+
+The maintainers of mongoose and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-mongoose?utm_source=npm-mongoose&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+
+## Overview
+
+### Connecting to MongoDB
+
+First, we need to define a connection. If your app uses only one database, you should use `mongoose.connect`. If you need to create additional connections, use `mongoose.createConnection`.
+
+Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters `host, database, port, options`.
+
+```js
+await mongoose.connect('mongodb://localhost/my_database', {
+ useNewUrlParser: true,
+ useUnifiedTopology: true
+});
+```
+
+Once connected, the `open` event is fired on the `Connection` instance. If you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. Otherwise, `mongoose.createConnection` return value is a `Connection`.
+
+**Note:** _If the local connection fails then try using 127.0.0.1 instead of localhost. Sometimes issues may arise when the local hostname has been changed._
+
+**Important!** Mongoose buffers all the commands until it's connected to the database. This means that you don't have to wait until it connects to MongoDB in order to define models, run queries, etc.
+
+### Defining a Model
+
+Models are defined through the `Schema` interface.
+
+```js
+const Schema = mongoose.Schema;
+const ObjectId = Schema.ObjectId;
+
+const BlogPost = new Schema({
+ author: ObjectId,
+ title: String,
+ body: String,
+ date: Date
+});
+```
+
+Aside from defining the structure of your documents and the types of data you're storing, a Schema handles the definition of:
+
+* [Validators](http://mongoosejs.com/docs/validation.html) (async and sync)
+* [Defaults](http://mongoosejs.com/docs/api.html#schematype_SchemaType-default)
+* [Getters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-get)
+* [Setters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set)
+* [Indexes](http://mongoosejs.com/docs/guide.html#indexes)
+* [Middleware](http://mongoosejs.com/docs/middleware.html)
+* [Methods](http://mongoosejs.com/docs/guide.html#methods) definition
+* [Statics](http://mongoosejs.com/docs/guide.html#statics) definition
+* [Plugins](http://mongoosejs.com/docs/plugins.html)
+* [pseudo-JOINs](http://mongoosejs.com/docs/populate.html)
+
+The following example shows some of these features:
+
+```js
+const Comment = new Schema({
+ name: { type: String, default: 'hahaha' },
+ age: { type: Number, min: 18, index: true },
+ bio: { type: String, match: /[a-z]/ },
+ date: { type: Date, default: Date.now },
+ buff: Buffer
+});
+
+// a setter
+Comment.path('name').set(function (v) {
+ return capitalize(v);
+});
+
+// middleware
+Comment.pre('save', function (next) {
+ notify(this.get('email'));
+ next();
+});
+```
+
+Take a look at the example in [`examples/schema/schema.js`](https://github.com/Automattic/mongoose/blob/master/examples/schema/schema.js) for an end-to-end example of a typical setup.
+
+### Accessing a Model
+
+Once we define a model through `mongoose.model('ModelName', mySchema)`, we can access it through the same function
+
+```js
+const MyModel = mongoose.model('ModelName');
+```
+
+Or just do it all at once
+
+```js
+const MyModel = mongoose.model('ModelName', mySchema);
+```
+
+The first argument is the _singular_ name of the collection your model is for. **Mongoose automatically looks for the _plural_ version of your model name.** For example, if you use
+
+```js
+const MyModel = mongoose.model('Ticket', mySchema);
+```
+
+Then Mongoose will create the model for your __tickets__ collection, not your __ticket__ collection.
+
+Once we have our model, we can then instantiate it, and save it:
+
+```js
+const instance = new MyModel();
+instance.my.key = 'hello';
+instance.save(function (err) {
+ //
+});
+```
+
+Or we can find documents from the same collection
+
+```js
+MyModel.find({}, function (err, docs) {
+ // docs.forEach
+});
+```
+
+You can also `findOne`, `findById`, `update`, etc.
+
+```js
+const instance = await MyModel.findOne({ ... });
+console.log(instance.my.key); // 'hello'
+```
+
+For more details check out [the docs](http://mongoosejs.com/docs/queries.html).
+
+**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this case access your model through the connection you created:
+
+```js
+const conn = mongoose.createConnection('your connection string');
+const MyModel = conn.model('ModelName', schema);
+const m = new MyModel;
+m.save(); // works
+```
+
+vs
+
+```js
+const conn = mongoose.createConnection('your connection string');
+const MyModel = mongoose.model('ModelName', schema);
+const m = new MyModel;
+m.save(); // does not work b/c the default connection object was never connected
+```
+
+### Embedded Documents
+
+In the first example snippet, we defined a key in the Schema that looks like:
+
+```
+comments: [Comment]
+```
+
+Where `Comment` is a `Schema` we created. This means that creating embedded documents is as simple as:
+
+```js
+// retrieve my model
+const BlogPost = mongoose.model('BlogPost');
+
+// create a blog post
+const post = new BlogPost();
+
+// create a comment
+post.comments.push({ title: 'My comment' });
+
+post.save(function (err) {
+ if (!err) console.log('Success!');
+});
+```
+
+The same goes for removing them:
+
+```js
+BlogPost.findById(myId, function (err, post) {
+ if (!err) {
+ post.comments[0].remove();
+ post.save(function (err) {
+ // do something
+ });
+ }
+});
+```
+
+Embedded documents enjoy all the same features as your models. Defaults, validators, middleware. Whenever an error occurs, it's bubbled to the `save()` error callback, so error handling is a snap!
+
+
+### Middleware
+
+See the [docs](http://mongoosejs.com/docs/middleware.html) page.
+
+#### Intercepting and mutating method arguments
+
+You can intercept method arguments via middleware.
+
+For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to a new value:
+
+```js
+schema.pre('set', function (next, path, val, typel) {
+ // `this` is the current Document
+ this.emit('set', path, val);
+
+ // Pass control to the next pre
+ next();
+});
+```
+
+Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments. To do so, just pass the new values to `next`:
+
+```js
+.pre(method, function firstPre (next, methodArg1, methodArg2) {
+ // Mutate methodArg1
+ next("altered-" + methodArg1.toString(), methodArg2);
+});
+
+// pre declaration is chainable
+.pre(method, function secondPre (next, methodArg1, methodArg2) {
+ console.log(methodArg1);
+ // => 'altered-originalValOfMethodArg1'
+
+ console.log(methodArg2);
+ // => 'originalValOfMethodArg2'
+
+ // Passing no arguments to `next` automatically passes along the current argument values
+ // i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)`
+ // and also equivalent to, with the example method arg
+ // values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')`
+ next();
+});
+```
+
+#### Schema gotcha
+
+`type`, when used in a schema has special meaning within Mongoose. If your schema requires using `type` as a nested property you must use object notation:
+
+```js
+new Schema({
+ broken: { type: Boolean },
+ asset: {
+ name: String,
+ type: String // uh oh, it broke. asset will be interpreted as String
+ }
+});
+
+new Schema({
+ works: { type: Boolean },
+ asset: {
+ name: String,
+ type: { type: String } // works. asset is an object with a type property
+ }
+});
+```
+
+### Driver Access
+
+Mongoose is built on top of the [official MongoDB Node.js driver](https://github.com/mongodb/node-mongodb-native). Each mongoose model keeps a reference to a [native MongoDB driver collection](http://mongodb.github.io/node-mongodb-native/2.1/api/Collection.html). The collection object can be accessed using `YourModel.collection`. However, using the collection object directly bypasses all mongoose features, including hooks, validation, etc. The one
+notable exception that `YourModel.collection` still buffers
+commands. As such, `YourModel.collection.find()` will **not**
+return a cursor.
+
+## API Docs
+
+Find the API docs [here](http://mongoosejs.com/docs/api.html), generated using [dox](https://github.com/tj/dox)
+and [acquit](https://github.com/vkarpov15/acquit).
+
+## Related Projects
+
+#### MongoDB Runners
+
+- [run-rs](https://www.npmjs.com/package/run-rs)
+- [mongodb-memory-server](https://www.npmjs.com/package/mongodb-memory-server)
+- [mongodb-topology-manager](https://www.npmjs.com/package/mongodb-topology-manager)
+
+#### Unofficial CLIs
+
+- [mongoosejs-cli](https://www.npmjs.com/package/mongoosejs-cli)
+
+#### Data Seeding
+
+- [dookie](https://www.npmjs.com/package/dookie)
+- [seedgoose](https://www.npmjs.com/package/seedgoose)
+- [mongoose-data-seed](https://www.npmjs.com/package/mongoose-data-seed)
+
+#### Express Session Stores
+
+- [connect-mongodb-session](https://www.npmjs.com/package/connect-mongodb-session)
+- [connect-mongo](https://www.npmjs.com/package/connect-mongo)
+
+## License
+
+Copyright (c) 2010 LearnBoost <dev@learnboost.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/mongoose/SECURITY.md b/node_modules/mongoose/SECURITY.md
new file mode 100644
index 0000000..41b89d8
--- /dev/null
+++ b/node_modules/mongoose/SECURITY.md
@@ -0,0 +1 @@
+Please follow the instructions on [Tidelift's security page](https://tidelift.com/docs/security) to report a security issue.
diff --git a/node_modules/mongoose/browser.js b/node_modules/mongoose/browser.js
new file mode 100644
index 0000000..4cf8228
--- /dev/null
+++ b/node_modules/mongoose/browser.js
@@ -0,0 +1,8 @@
+/**
+ * Export lib/mongoose
+ *
+ */
+
+'use strict';
+
+module.exports = require('./lib/browser');
diff --git a/node_modules/mongoose/build-browser.js b/node_modules/mongoose/build-browser.js
new file mode 100644
index 0000000..6f4aa16
--- /dev/null
+++ b/node_modules/mongoose/build-browser.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const config = require('./webpack.config.js');
+const webpack = require('webpack');
+
+const compiler = webpack(config);
+
+console.log('Starting browser build...');
+compiler.run((err, stats) => {
+ if (err) {
+ console.err(stats.toString());
+ console.err('Browser build unsuccessful.');
+ process.exit(1);
+ }
+ console.log(stats.toString());
+ console.log('Browser build successful.');
+ process.exit(0);
+});
diff --git a/node_modules/mongoose/dist/browser.umd.js b/node_modules/mongoose/dist/browser.umd.js
new file mode 100644
index 0000000..4eded6c
--- /dev/null
+++ b/node_modules/mongoose/dist/browser.umd.js
@@ -0,0 +1,1539 @@
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.mongoose=e():t.mongoose=e()}("undefined"!=typeof self?self:this,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=92)}([function(t,e,r){"use strict";e.arrayAtomicsSymbol=Symbol("mongoose#Array#_atomics"),e.arrayParentSymbol=Symbol("mongoose#Array#_parent"),e.arrayPathSymbol=Symbol("mongoose#Array#_path"),e.arraySchemaSymbol=Symbol("mongoose#Array#_schema"),e.documentArrayParent=Symbol("mongoose:documentArrayParent"),e.documentSchemaSymbol=Symbol("mongoose#Document#schema"),e.getSymbol=Symbol("mongoose#Document#get"),e.modelSymbol=Symbol("mongoose#Model"),e.objectIdSymbol=Symbol("mongoose#ObjectId"),e.populateModelSymbol=Symbol("mongoose.PopulateOptions#Model"),e.schemaTypeSymbol=Symbol("mongoose#schemaType"),e.validatorErrorSymbol=Symbol("mongoose:validatorError")},function(t,e,r){"use strict";(function(t){
+/*!
+ * The buffer module from node.js, for the browser.
+ *
+ * @author Feross Aboukhadijeh
+ * @license MIT
+ */
+var n=r(94),i=r(95),o=r(96);function s(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function a(t,e){if(s()=s())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s().toString(16)+" bytes");return 0|t}function d(t,e){if(u.isBuffer(t))return t.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(t)||t instanceof ArrayBuffer))return t.byteLength;"string"!=typeof t&&(t=""+t);var r=t.length;if(0===r)return 0;for(var n=!1;;)switch(e){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return L(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return U(t).length;default:if(n)return L(t).length;e=(""+e).toLowerCase(),n=!0}}function y(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function v(t,e,r,n,i){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return-1;r=t.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof e&&(e=u.from(e,n)),u.isBuffer(e))return 0===e.length?-1:_(t,e,r,n,i);if("number"==typeof e)return e&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(t,e,r):Uint8Array.prototype.lastIndexOf.call(t,e,r):_(t,[e],r,n,i);throw new TypeError("val must be string, number or Buffer")}function _(t,e,r,n,i){var o,s=1,a=t.length,u=e.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(t.length<2||e.length<2)return-1;s=2,a/=2,u/=2,r/=2}function c(t,e){return 1===s?t[e]:t.readUInt16BE(e*s)}if(i){var l=-1;for(o=r;oa&&(r=a-u),o=r;o>=0;o--){for(var f=!0,h=0;hi&&(n=i):n=i;var o=e.length;if(o%2!=0)throw new TypeError("Invalid hex string");n>o/2&&(n=o/2);for(var s=0;s>8,i=r%256,o.push(i),o.push(n);return o}(e,t.length-r),t,r,n)}function E(t,e,r){return 0===e&&r===t.length?n.fromByteArray(t):n.fromByteArray(t.slice(e,r))}function A(t,e,r){r=Math.min(t.length,r);for(var n=[],i=e;i239?4:c>223?3:c>191?2:1;if(i+f<=r)switch(f){case 1:c<128&&(l=c);break;case 2:128==(192&(o=t[i+1]))&&(u=(31&c)<<6|63&o)>127&&(l=u);break;case 3:o=t[i+1],s=t[i+2],128==(192&o)&&128==(192&s)&&(u=(15&c)<<12|(63&o)<<6|63&s)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:o=t[i+1],s=t[i+2],a=t[i+3],128==(192&o)&&128==(192&s)&&128==(192&a)&&(u=(15&c)<<18|(63&o)<<12|(63&s)<<6|63&a)>65535&&u<1114112&&(l=u)}null===l?(l=65533,f=1):l>65535&&(l-=65536,n.push(l>>>10&1023|55296),l=56320|1023&l),n.push(l),i+=f}return function(t){var e=t.length;if(e<=$)return String.fromCharCode.apply(String,t);var r="",n=0;for(;nthis.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t||(t="utf8");;)switch(t){case"hex":return N(this,e,r);case"utf8":case"utf-8":return A(this,e,r);case"ascii":return j(this,e,r);case"latin1":case"binary":return x(this,e,r);case"base64":return E(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return P(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}.apply(this,arguments)},u.prototype.equals=function(t){if(!u.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t||0===u.compare(this,t)},u.prototype.inspect=function(){var t="",r=e.INSPECT_MAX_BYTES;return this.length>0&&(t=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(t+=" ... ")),""},u.prototype.compare=function(t,e,r,n,i){if(!u.isBuffer(t))throw new TypeError("Argument must be a Buffer");if(void 0===e&&(e=0),void 0===r&&(r=t?t.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),e<0||r>t.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&e>=r)return 0;if(n>=i)return-1;if(e>=r)return 1;if(e>>>=0,r>>>=0,n>>>=0,i>>>=0,this===t)return 0;for(var o=i-n,s=r-e,a=Math.min(o,s),c=this.slice(n,i),l=t.slice(e,r),f=0;fi)&&(r=i),t.length>0&&(r<0||e<0)||e>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return m(this,t,e,r);case"utf8":case"utf-8":return g(this,t,e,r);case"ascii":return b(this,t,e,r);case"latin1":case"binary":return w(this,t,e,r);case"base64":return O(this,t,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,t,e,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var $=4096;function j(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;in)&&(r=n);for(var i="",o=e;or)throw new RangeError("Trying to access beyond buffer length")}function T(t,e,r,n,i,o){if(!u.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>i||et.length)throw new RangeError("Index out of range")}function B(t,e,r,n){e<0&&(e=65535+e+1);for(var i=0,o=Math.min(t.length-r,2);i>>8*(n?i:1-i)}function C(t,e,r,n){e<0&&(e=4294967295+e+1);for(var i=0,o=Math.min(t.length-r,4);i>>8*(n?i:3-i)&255}function D(t,e,r,n,i,o){if(r+n>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function M(t,e,r,n,o){return o||D(t,0,r,4),i.write(t,e,r,n,23,4),r+4}function R(t,e,r,n,o){return o||D(t,0,r,8),i.write(t,e,r,n,52,8),r+8}u.prototype.slice=function(t,e){var r,n=this.length;if(t=~~t,e=void 0===e?n:~~e,t<0?(t+=n)<0&&(t=0):t>n&&(t=n),e<0?(e+=n)<0&&(e=0):e>n&&(e=n),e0&&(i*=256);)n+=this[t+--e]*i;return n},u.prototype.readUInt8=function(t,e){return e||k(t,1,this.length),this[t]},u.prototype.readUInt16LE=function(t,e){return e||k(t,2,this.length),this[t]|this[t+1]<<8},u.prototype.readUInt16BE=function(t,e){return e||k(t,2,this.length),this[t]<<8|this[t+1]},u.prototype.readUInt32LE=function(t,e){return e||k(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},u.prototype.readUInt32BE=function(t,e){return e||k(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},u.prototype.readIntLE=function(t,e,r){t|=0,e|=0,r||k(t,e,this.length);for(var n=this[t],i=1,o=0;++o=(i*=128)&&(n-=Math.pow(2,8*e)),n},u.prototype.readIntBE=function(t,e,r){t|=0,e|=0,r||k(t,e,this.length);for(var n=e,i=1,o=this[t+--n];n>0&&(i*=256);)o+=this[t+--n]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*e)),o},u.prototype.readInt8=function(t,e){return e||k(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},u.prototype.readInt16LE=function(t,e){e||k(t,2,this.length);var r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt16BE=function(t,e){e||k(t,2,this.length);var r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt32LE=function(t,e){return e||k(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},u.prototype.readInt32BE=function(t,e){return e||k(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},u.prototype.readFloatLE=function(t,e){return e||k(t,4,this.length),i.read(this,t,!0,23,4)},u.prototype.readFloatBE=function(t,e){return e||k(t,4,this.length),i.read(this,t,!1,23,4)},u.prototype.readDoubleLE=function(t,e){return e||k(t,8,this.length),i.read(this,t,!0,52,8)},u.prototype.readDoubleBE=function(t,e){return e||k(t,8,this.length),i.read(this,t,!1,52,8)},u.prototype.writeUIntLE=function(t,e,r,n){(t=+t,e|=0,r|=0,n)||T(this,t,e,r,Math.pow(2,8*r)-1,0);var i=1,o=0;for(this[e]=255&t;++o=0&&(o*=256);)this[e+i]=t/o&255;return e+r},u.prototype.writeUInt8=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,1,255,0),u.TYPED_ARRAY_SUPPORT||(t=Math.floor(t)),this[e]=255&t,e+1},u.prototype.writeUInt16LE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8):B(this,t,e,!0),e+2},u.prototype.writeUInt16BE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[e]=t>>>8,this[e+1]=255&t):B(this,t,e,!1),e+2},u.prototype.writeUInt32LE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t):C(this,t,e,!0),e+4},u.prototype.writeUInt32BE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t):C(this,t,e,!1),e+4},u.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e|=0,!n){var i=Math.pow(2,8*r-1);T(this,t,e,r,i-1,-i)}var o=0,s=1,a=0;for(this[e]=255&t;++o>0)-a&255;return e+r},u.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e|=0,!n){var i=Math.pow(2,8*r-1);T(this,t,e,r,i-1,-i)}var o=r-1,s=1,a=0;for(this[e+o]=255&t;--o>=0&&(s*=256);)t<0&&0===a&&0!==this[e+o+1]&&(a=1),this[e+o]=(t/s>>0)-a&255;return e+r},u.prototype.writeInt8=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,1,127,-128),u.TYPED_ARRAY_SUPPORT||(t=Math.floor(t)),t<0&&(t=255+t+1),this[e]=255&t,e+1},u.prototype.writeInt16LE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8):B(this,t,e,!0),e+2},u.prototype.writeInt16BE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[e]=t>>>8,this[e+1]=255&t):B(this,t,e,!1),e+2},u.prototype.writeInt32LE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24):C(this,t,e,!0),e+4},u.prototype.writeInt32BE=function(t,e,r){return t=+t,e|=0,r||T(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),u.TYPED_ARRAY_SUPPORT?(this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t):C(this,t,e,!1),e+4},u.prototype.writeFloatLE=function(t,e,r){return M(this,t,e,!0,r)},u.prototype.writeFloatBE=function(t,e,r){return M(this,t,e,!1,r)},u.prototype.writeDoubleLE=function(t,e,r){return R(this,t,e,!0,r)},u.prototype.writeDoubleBE=function(t,e,r){return R(this,t,e,!1,r)},u.prototype.copy=function(t,e,r,n){if(r||(r=0),n||0===n||(n=this.length),e>=t.length&&(e=t.length),e||(e=0),n>0&&n=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e=0;--i)t[i+e]=this[i+r];else if(o<1e3||!u.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,r=void 0===r?this.length:r>>>0,t||(t=0),"number"==typeof t)for(o=e;o55295&&r<57344){if(!i){if(r>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(s+1===n){(e-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(e-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320)}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((e-=1)<0)break;o.push(r)}else if(r<2048){if((e-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(r<65536){if((e-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function U(t){return n.toByteArray(function(t){if((t=function(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}(t).replace(F,"")).length<2)return"";for(;t.length%4!=0;)t+="=";return t}(t))}function V(t,e,r,n){for(var i=0;i=e.length||i>=t.length);++i)e[i+r]=t[i];return i}}).call(this,r(11))},function(t,e,r){"use strict";(function(t){
+/*!
+ * Module dependencies.
+ */
+var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(110),o=r(44),s=r(62),a=r(45).Buffer,u=r(19),c=r(12),l=r(112),f=r(46),h=r(20),p=r(65),d=r(64),y=r(27),v=r(24),_=r(47),m=void 0;e.specialProperties=_,
+/*!
+ * Produces a collection name from model `name`. By default, just returns
+ * the model name
+ *
+ * @param {String} name a model name
+ * @param {Function} pluralize function that pluralizes the collection name
+ * @return {String} a collection name
+ * @api private
+ */
+e.toCollectionName=function(t,e){return"system.profile"===t?t:"system.indexes"===t?t:"function"==typeof e?e(t):t},
+/*!
+ * Determines if `a` and `b` are deep equal.
+ *
+ * Modified from node/lib/assert.js
+ *
+ * @param {any} a a value to compare to `b`
+ * @param {any} b a value to compare to `a`
+ * @return {Boolean}
+ * @api private
+ */
+e.deepEqual=function t(r,i){if(r===i)return!0;if(r instanceof Date&&i instanceof Date)return r.getTime()===i.getTime();if(p(r,"ObjectID")&&p(i,"ObjectID")||p(r,"Decimal128")&&p(i,"Decimal128"))return r.toString()===i.toString();if(r instanceof RegExp&&i instanceof RegExp)return r.source===i.source&&r.ignoreCase===i.ignoreCase&&r.multiline===i.multiline&&r.global===i.global;if("object"!==(void 0===r?"undefined":n(r))&&"object"!==(void 0===i?"undefined":n(i)))return r==i;if(null===r||null===i||void 0===r||void 0===i)return!1;if(r.prototype!==i.prototype)return!1;if(r instanceof Number&&i instanceof Number)return r.valueOf()===i.valueOf();if(a.isBuffer(r))return e.buffer.areEqual(r,i);y(r)&&(r=r.toObject()),y(i)&&(i=i.toObject());var o=void 0,s=void 0,u=void 0,c=void 0;try{o=Object.keys(r),s=Object.keys(i)}catch(t){return!1}if(o.length!==s.length)return!1;for(o.sort(),s.sort(),c=o.length-1;c>=0;c--)if(o[c]!==s[c])return!1;for(c=o.length-1;c>=0;c--)if(!t(r[u=o[c]],i[u]))return!1;return!0},
+/*!
+ * Get the last element of an array
+ */
+e.last=function(t){if(t.length>0)return t[t.length-1]},e.clone=f,
+/*!
+ * ignore
+ */
+e.promiseOrCallback=v,
+/*!
+ * ignore
+ */
+e.omit=function(t,e){if(null==e)return Object.assign({},t);Array.isArray(e)||(e=[e]);var r=Object.assign({},t),n=!0,i=!1,o=void 0;try{for(var s,a=e[Symbol.iterator]();!(n=(s=a.next()).done);n=!0){delete r[s.value]}}catch(t){i=!0,o=t}finally{try{!n&&a.return&&a.return()}finally{if(i)throw o}}return r},
+/*!
+ * Shallow copies defaults into options.
+ *
+ * @param {Object} defaults
+ * @param {Object} options
+ * @return {Object} the merged object
+ * @api private
+ */
+e.options=function(t,e){var r=Object.keys(t),n=r.length,i=void 0;for(e=e||{};n--;)(i=r[n])in e||(e[i]=t[i]);return e},
+/*!
+ * Generates a random string
+ *
+ * @api private
+ */
+e.random=function(){return Math.random().toString().substr(3)},
+/*!
+ * Merges `from` into `to` without overwriting existing properties.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ * @api private
+ */
+e.merge=function t(r,n,i,o){i=i||{};var s=Object.keys(n),a=0,u=s.length,l=void 0;o=o||"";for(var f=i.omitNested||{};a [1,2,3,4]
+ *
+ * @param {Array} arr
+ * @param {Function} [filter] If passed, will be invoked with each item in the array. If `filter` returns a falsy value, the item will not be included in the results.
+ * @return {Array}
+ * @private
+ */
+e.array.flatten=function t(e,r,n){return n||(n=[]),e.forEach(function(e){Array.isArray(e)?t(e,r,n):r&&!r(e)||n.push(e)}),n};
+/*!
+ * ignore
+ */
+var b=Object.prototype.hasOwnProperty;e.hasUserDefinedProperty=function(t,r){if(null==t)return!1;if(Array.isArray(r)){var i=!0,o=!1,s=void 0;try{for(var a,u=r[Symbol.iterator]();!(i=(a=u.next()).done);i=!0){var c=a.value;if(e.hasUserDefinedProperty(t,c))return!0}}catch(t){o=!0,s=t}finally{try{!i&&u.return&&u.return()}finally{if(o)throw s}}return!1}if(b.call(t,r))return!0;if("object"===(void 0===t?"undefined":n(t))&&r in t){var l=t[r];return l!==Object.prototype[r]&&l!==Array.prototype[r]}return!1};
+/*!
+ * ignore
+ */
+var w=Math.pow(2,32)-1;e.isArrayIndex=function(t){return"number"==typeof t?t>=0&&t<=w:"string"==typeof t&&(!!/^\d+$/.test(t)&&((t=+t)>=0&&t<=w))},
+/*!
+ * Removes duplicate values from an array
+ *
+ * [1, 2, 3, 3, 5] => [1, 2, 3, 5]
+ * [ ObjectId("550988ba0c19d57f697dc45e"), ObjectId("550988ba0c19d57f697dc45e") ]
+ * => [ObjectId("550988ba0c19d57f697dc45e")]
+ *
+ * @param {Array} arr
+ * @return {Array}
+ * @private
+ */
+e.array.unique=function(t){for(var e={},r={},n=[],i=t.length,o=0;o=i)return t;switch(t){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch(t){return"[Circular]"}default:return t}}),a=n[r];r=3&&(n.depth=arguments[2]),arguments.length>=4&&(n.colors=arguments[3]),y(r)?n.showHidden=r:r&&e._extend(n,r),g(n.showHidden)&&(n.showHidden=!1),g(n.depth)&&(n.depth=2),g(n.colors)&&(n.colors=!1),g(n.customInspect)&&(n.customInspect=!0),n.colors&&(n.stylize=c),f(n,t,n.depth)}function c(t,e){var r=u.styles[e];return r?"["+u.colors[r][0]+"m"+t+"["+u.colors[r][1]+"m":t}function l(t,e){return t}function f(t,r,n){if(t.customInspect&&r&&E(r.inspect)&&r.inspect!==e.inspect&&(!r.constructor||r.constructor.prototype!==r)){var i=r.inspect(n,t);return m(i)||(i=f(t,i,n)),i}var o=function(t,e){if(g(e))return t.stylize("undefined","undefined");if(m(e)){var r="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(r,"string")}if(_(e))return t.stylize(""+e,"number");if(y(e))return t.stylize(""+e,"boolean");if(v(e))return t.stylize("null","null")}(t,r);if(o)return o;var s=Object.keys(r),a=function(t){var e={};return t.forEach(function(t,r){e[t]=!0}),e}(s);if(t.showHidden&&(s=Object.getOwnPropertyNames(r)),S(r)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return h(r);if(0===s.length){if(E(r)){var u=r.name?": "+r.name:"";return t.stylize("[Function"+u+"]","special")}if(b(r))return t.stylize(RegExp.prototype.toString.call(r),"regexp");if(O(r))return t.stylize(Date.prototype.toString.call(r),"date");if(S(r))return h(r)}var c,l="",w=!1,A=["{","}"];(d(r)&&(w=!0,A=["[","]"]),E(r))&&(l=" [Function"+(r.name?": "+r.name:"")+"]");return b(r)&&(l=" "+RegExp.prototype.toString.call(r)),O(r)&&(l=" "+Date.prototype.toUTCString.call(r)),S(r)&&(l=" "+h(r)),0!==s.length||w&&0!=r.length?n<0?b(r)?t.stylize(RegExp.prototype.toString.call(r),"regexp"):t.stylize("[Object]","special"):(t.seen.push(r),c=w?function(t,e,r,n,i){for(var o=[],s=0,a=e.length;s=0&&0,t+e.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60)return r[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+r[1];return r[0]+e+" "+t.join(", ")+" "+r[1]}(c,l,A)):A[0]+l+A[1]}function h(t){return"["+Error.prototype.toString.call(t)+"]"}function p(t,e,r,n,i,o){var s,a,u;if((u=Object.getOwnPropertyDescriptor(e,i)||{value:e[i]}).get?a=u.set?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):u.set&&(a=t.stylize("[Setter]","special")),x(n,i)||(s="["+i+"]"),a||(t.seen.indexOf(u.value)<0?(a=v(r)?f(t,u.value,null):f(t,u.value,r-1)).indexOf("\n")>-1&&(a=o?a.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+a.split("\n").map(function(t){return" "+t}).join("\n")):a=t.stylize("[Circular]","special")),g(s)){if(o&&i.match(/^\d+$/))return a;(s=JSON.stringify(""+i)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=t.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=t.stylize(s,"string"))}return s+": "+a}function d(t){return Array.isArray(t)}function y(t){return"boolean"==typeof t}function v(t){return null===t}function _(t){return"number"==typeof t}function m(t){return"string"==typeof t}function g(t){return void 0===t}function b(t){return w(t)&&"[object RegExp]"===A(t)}function w(t){return"object"===(void 0===t?"undefined":n(t))&&null!==t}function O(t){return w(t)&&"[object Date]"===A(t)}function S(t){return w(t)&&("[object Error]"===A(t)||t instanceof Error)}function E(t){return"function"==typeof t}function A(t){return Object.prototype.toString.call(t)}function $(t){return t<10?"0"+t.toString(10):t.toString(10)}e.debuglog=function(r){if(g(s)&&(s=t.env.NODE_DEBUG||""),r=r.toUpperCase(),!a[r])if(new RegExp("\\b"+r+"\\b","i").test(s)){var n=t.pid;a[r]=function(){var t=e.format.apply(e,arguments);console.error("%s %d: %s",r,n,t)}}else a[r]=function(){};return a[r]},e.inspect=u,u.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},u.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},e.isArray=d,e.isBoolean=y,e.isNull=v,e.isNullOrUndefined=function(t){return null==t},e.isNumber=_,e.isString=m,e.isSymbol=function(t){return"symbol"===(void 0===t?"undefined":n(t))},e.isUndefined=g,e.isRegExp=b,e.isObject=w,e.isDate=O,e.isError=S,e.isFunction=E,e.isPrimitive=function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"===(void 0===t?"undefined":n(t))||void 0===t},e.isBuffer=r(99);var j=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function x(t,e){return Object.prototype.hasOwnProperty.call(t,e)}e.log=function(){console.log("%s - %s",function(){var t=new Date,e=[$(t.getHours()),$(t.getMinutes()),$(t.getSeconds())].join(":");return[t.getDate(),j[t.getMonth()],e].join(" ")}(),e.format.apply(e,arguments))},e.inherits=r(100),e._extend=function(t,e){if(!e||!w(e))return t;for(var r=Object.keys(e),n=r.length;n--;)t[r[n]]=e[r[n]];return t};var N="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function P(t,e){if(!t){var r=new Error("Promise was rejected with a falsy value");r.reason=t,t=r}return e(t)}e.promisify=function(t){if("function"!=typeof t)throw new TypeError('The "original" argument must be of type Function');if(N&&t[N]){var e;if("function"!=typeof(e=t[N]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(e,N,{value:e,enumerable:!1,writable:!1,configurable:!0}),e}function e(){for(var e,r,n=new Promise(function(t,n){e=t,r=n}),i=[],o=0;o0?".":"")+F[y],V||(this.$set(q,{}),this.isSelected(q)||this.unmarkModified(q),V=this.$__getValue(q));var H=void 0;if(F.length<=1)H=t;else{for(y=0;y0&&null!=e[0]&&null!=e[0].$__&&null!=e[0].$__.populated){var ot=Object.keys(e[0].$__.populated),st=!0,at=!1,ut=void 0;try{for(var ct,lt=function(){var r=ct.value;s.populated(t+"."+r,e.map(function(t){return t.populated(r)}),e[0].$__.populated[r].options)},ft=ot[Symbol.iterator]();!(st=(ct=ft.next()).done);st=!0)lt()}catch(t){at=!0,ut=t}finally{try{!st&&ft.return&&ft.return()}finally{if(at)throw ut}}nt=!0}if(!nt&&this.$__.populated){if(Array.isArray(e)&&this.$__.populated[t])for(var ht=0;ht0){var r=this.get(t);return null==r||"object"===(void 0===r?"undefined":i(r))&&(k.isPOJO(r)?function t(e){if(null==e)return!0;if("object"!==(void 0===e?"undefined":i(e))||Array.isArray(e))return!1;var r=!0;var n=!1;var o=void 0;try{for(var s,a=Object.keys(e)[Symbol.iterator]();!(r=(s=a.next()).done);r=!0){var u=s.value;if(!t(e[u]))return!1}}catch(t){n=!0,o=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!0}(r):0===Object.keys(r.toObject(e)).length)}return 0===Object.keys(this.toObject(e)).length},W.prototype.modifiedPaths=function(t){t=t||{};var e=this;return Object.keys(this.$__.activePaths.states.modify).reduce(function(r,n){var o=n.split(".");if(r=r.concat(o.reduce(function(t,e,r){return t.concat(o.slice(0,r).concat(e).join("."))},[]).filter(function(t){return-1===r.indexOf(t)})),!t.includeChildren)return r;var s=e.get(n);if(null!=s&&"object"===(void 0===s?"undefined":i(s)))if(s._doc&&(s=s._doc),Array.isArray(s)){for(var a=s.length,u=0;ue.path?1:0});var r=[],n=void 0,i=void 0;return e.forEach(function(t){t&&(null==n||0!==t.path.indexOf(n)?(n=t.path+".",r.push(t),i=t):null!=i&&null!=i.value&&null!=i.value[D]&&i.value.hasAtomics()&&(i.value[D]={},i.value[D].$set=i.value))}),i=n=null,r},W.prototype.$__setSchema=function(t){t.plugin(A,{deduplicate:!0}),b(t.tree,this,void 0,t.options);var e=!0,r=!1,n=void 0;try{for(var i,o=Object.keys(t.virtuals)[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var s=i.value;t.virtuals[s]._applyDefaultGetters()}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this.schema=t,this[R]=t},W.prototype.$__getArrayPathsToValidate=function(){return L||(L=r(17)),this.$__.activePaths.map("init","modify",function(t){return this.$__getValue(t)}.bind(this)).filter(function(t){return t&&t instanceof Array&&t.isMongooseDocumentArray&&t.length}).reduce(function(t,e){return t.concat(e)},[]).filter(function(t){return t})},W.prototype.$__getAllSubdocs=function(){L||(L=r(17)),V=V||r(25);var t=this;return Object.keys(this._doc).reduce(function(e,r){return function t(e,r,n){var i=e;return n&&(i=e instanceof W&&e[R].paths[n]?e._doc[n]:e[n]),i instanceof V?r.push(i):i instanceof Map?r=Array.from(i.keys()).reduce(function(e,r){return t(i.get(r),e,null)},r):i&&i.$isSingleNested?(r=Object.keys(i._doc).reduce(function(e,r){return t(i._doc,e,r)},r)).push(i):i&&i.isMongooseDocumentArray?i.forEach(function(e){e&&e._doc&&(r=Object.keys(e._doc).reduce(function(r,n){return t(e._doc,r,n)},r),e instanceof V&&r.push(e))}):i instanceof W&&i.$__isNested&&(r=Object.keys(i).reduce(function(e,r){return t(i,e,r)},r)),r}(t,e,r)},[])},W.prototype.$__handleReject=function(t){this.listeners("error").length?this.emit("error",t):this.constructor.listeners&&this.constructor.listeners("error").length?this.constructor.emit("error",t):this.listeners&&this.listeners("error").length&&this.emit("error",t)},W.prototype.$toObject=function(t,e){var r={transform:!0,flattenDecimals:!0},i=e?"toJSON":"toObject",o=S(this,"constructor.base.options."+i,{}),s=S(this,"schema.options",{});r=k.options(r,T(o)),r=k.options(r,T(s[i]||{})),"flattenMaps"in(t=k.isPOJO(t)?T(t):{})||(t.flattenMaps=r.flattenMaps);var a=void 0;a=null!=t.minimize?t.minimize:null!=r.minimize?r.minimize:s.minimize;var u=Object.assign(k.clone(t),{_isNested:!0,json:e,minimize:a});if(k.hasUserDefinedProperty(t,"getters")&&(u.getters=t.getters),k.hasUserDefinedProperty(t,"virtuals")&&(u.virtuals=t.virtuals),(t.depopulate||S(t,"_parentOptions.depopulate",!1))&&t._isNested&&this.$__.wasPopulated)return T(this._id,u);(t=k.options(r,t))._isNested=!0,t.json=e,t.minimize=a,u._parentOptions=t,u._skipSingleNestedGetters=!0;var c=Object.assign({},u);c._skipSingleNestedGetters=!1;var l=t.transform,f=T(this._doc,u)||{};t.getters&&(!function(t,e,r){var n=t.schema,i=Object.keys(n.paths),o=i.length,s=void 0,a=t._doc,u=void 0;if(!a)return e;for(;o--;){var c=(s=i[o]).split("."),l=c.length,f=l-1,h=e,p=void 0;if(a=t._doc,t.isSelected(s))for(var d=0;d1&&(this.defaultValue=d.args(arguments)),this.defaultValue)},m.prototype.index=function(t){return this._index=t,d.expires(this._index),this},m.prototype.unique=function(t){if(!1===this._index){if(!t)return;throw new Error('Path "'+this.path+'" may not have `index` set to false and `unique` set to true')}return null==this._index||!0===this._index?this._index={}:"string"==typeof this._index&&(this._index={type:this._index}),this._index.unique=t,this},m.prototype.text=function(t){if(!1===this._index){if(!t)return;throw new Error('Path "'+this.path+'" may not have `index` set to false and `text` set to true')}return null===this._index||void 0===this._index||"boolean"==typeof this._index?this._index={}:"string"==typeof this._index&&(this._index={type:this._index}),this._index.text=t,this},m.prototype.sparse=function(t){if(!1===this._index){if(!t)return;throw new Error('Path "'+this.path+'" may not have `index` set to false and `sparse` set to true')}return null==this._index||"boolean"==typeof this._index?this._index={}:"string"==typeof this._index&&(this._index={type:this._index}),this._index.sparse=t,this},m.prototype.immutable=function(t){return this.$immutable=t,l(this),this},m.prototype.set=function(t){if("function"!=typeof t)throw new TypeError("A setter must be a function.");return this.setters.push(t),this},m.prototype.get=function(t){if("function"!=typeof t)throw new TypeError("A getter must be a function.");return this.getters.push(t),this},m.prototype.validate=function(t,e,r){if("function"==typeof t||t&&"RegExp"===d.getFunctionName(t.constructor)){var n=void 0;return"function"==typeof e?(n={validator:t,message:e}).type=r||"user defined":e instanceof Object&&!r?((n=d.clone(e)).message||(n.message=n.msg),n.validator=t,n.type=n.type||"user defined"):(null==e&&(e=o.messages.general.default),r||(r="user defined"),n={message:e,type:r,validator:t}),n.isAsync&&g(),this.validators.push(n),this}var s,a=void 0,u=void 0;for(a=0,s=arguments.length;a0&&null==t)return this.validators=this.validators.filter(function(t){return t.validator!==this.requiredValidator},this),this.isRequired=!1,delete this.originalRequiredValue,this;if("object"===(void 0===t?"undefined":i(t))&&(e=(r=t).message||e,t=t.isRequired),!1===t)return this.validators=this.validators.filter(function(t){return t.validator!==this.requiredValidator},this),this.isRequired=!1,delete this.originalRequiredValue,this;var n=this;this.isRequired=!0,this.requiredValidator=function(e){var r=c(this,"$__.cachedRequired");if(null!=r&&!this.isSelected(n.path)&&!this.isModified(n.path))return!0;if(null!=r&&n.path in r){var i=!r[n.path]||n.checkRequired(e,this);return delete r[n.path],i}return"function"==typeof t&&!t.apply(this)||n.checkRequired(e,this)},this.originalRequiredValue=t,"string"==typeof t&&(e=t,t=void 0);var s=e||o.messages.general.required;return this.validators.unshift(Object.assign({},r,{validator:this.requiredValidator,message:s,type:"required"})),this},m.prototype.ref=function(t){return this.options.ref=t,this},m.prototype.getDefault=function(t,e){var r="function"==typeof this.defaultValue?this.defaultValue.call(t):this.defaultValue;if(null!==r&&void 0!==r){"object"!==(void 0===r?"undefined":i(r))||this.options&&this.options.shared||(r=d.clone(r));var n=this.applySetters(r,t,e);return n&&n.$isSingleNested&&(n.$parent=t),n}return r},
+/*!
+ * Applies setters without casting
+ *
+ * @api private
+ */
+m.prototype._applySetters=function(t,e,r,n){for(var i=t,o=this.setters,s=o.length,a=this.caster;s--;)i=o[s].call(e,i,this);if(Array.isArray(i)&&a&&a.setters){for(var u=[],c=0;c0&&"required"===this.validators[0].type))return null;a=[this.validators[0]]}return a.forEach(function(a){if(!n&&null!=a&&"object"===(void 0===a?"undefined":i(a))){var u=a.validator,c=d.clone(a);c.path=r&&r.path?r.path:o,c.value=t;var l=void 0;if(!u.isAsync)if(u instanceof RegExp)s(u.test(t),c);else if("function"==typeof u){try{l=c.propsParameter?u.call(e,t,c):u.call(e,t)}catch(t){l=!1,c.reason=t}if(null!=l&&"function"==typeof l.then)return;s(l,c)}}}),n},m._isRef=function(t,e,r,i){var o=i&&t.options&&(t.options.ref||t.options.refPath);if(!o&&r&&null!=r.$__){var s=r.$__fullPath(t.path);o=(r.ownerDocument?r.ownerDocument():r).populated(s)||r.populated(t.path)}if(o){if(null==e)return!0;if(!n.isBuffer(e)&&"Binary"!==e._bsontype&&d.isObject(e))return!0}return!1},m.prototype.$conditionalHandlers={$all:function(t){var e=this;return Array.isArray(t)?t.map(function(t){return e.castForQuery(t)}):[this.castForQuery(t)]},$eq:b,$in:w,$ne:b,$nin:w,$exists:a,$type:u},
+/*!
+ * Wraps `castForQuery` to handle context
+ */
+m.prototype.castForQueryWrapper=function(t){return this.$$context=t.context,"$conditional"in t?this.castForQuery(t.$conditional,t.val):t.$skipQueryCastForUpdate||t.$applySetters?this._castForQuery(t.val):this.castForQuery(t.val)},m.prototype.castForQuery=function(t,e){var r=void 0;if(2===arguments.length){if(!(r=this.$conditionalHandlers[t]))throw new Error("Can't use "+t);return r.call(this,e)}return e=t,this._castForQuery(e)},
+/*!
+ * Internal switch for runSetters
+ *
+ * @api private
+ */
+m.prototype._castForQuery=function(t){return this.applySetters(t,this.$$context)},m.checkRequired=function(t){return arguments.length>0&&(this._checkRequired=t),this._checkRequired},m.prototype.checkRequired=function(t){return null!=t},
+/*!
+ * ignore
+ */
+m.prototype.clone=function(){var t=Object.assign({},this.options),e=new this.constructor(this.path,t,this.instance);return e.validators=this.validators.slice(),void 0!==this.requiredValidator&&(e.requiredValidator=this.requiredValidator),void 0!==this.defaultValue&&(e.defaultValue=this.defaultValue),void 0!==this.$immutable&&void 0===this.options.immutable&&(e.$immutable=this.$immutable,l(e)),void 0!==this._index&&(e._index=this._index),void 0!==this.selected&&(e.selected=this.selected),void 0!==this.isRequired&&(e.isRequired=this.isRequired),void 0!==this.originalRequiredValue&&(e.originalRequiredValue=this.originalRequiredValue),e.getters=this.getters.slice(),e.setters=this.setters.slice(),e},
+/*!
+ * Module exports.
+ */
+t.exports=e=m,e.CastError=v,e.ValidatorError=_}).call(this,r(1).Buffer)},function(t,e,r){"use strict";var n,i,o=t.exports={};function s(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function u(t){if(n===setTimeout)return setTimeout(t,0);if((n===s||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:s}catch(t){n=s}try{i="function"==typeof clearTimeout?clearTimeout:a}catch(t){i=a}}();var c,l=[],f=!1,h=-1;function p(){f&&c&&(f=!1,c.length?l=c.concat(l):h=-1,l.length&&d())}function d(){if(!f){var t=u(p);f=!0;for(var e=l.length;e;){for(c=l,l=[];++h1)for(var r=1;r0&&a.length>o&&!a.warned){a.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=t,u.type=e,u.count=a.length,function(t){console&&console.warn&&console.warn(t)}(u)}return t}function h(t,e,r){var n={fired:!1,wrapFn:void 0,target:t,type:e,listener:r},i=function(){for(var t=[],e=0;e0&&(o=e[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var u=i[t];if(void 0===u)return!1;if("function"==typeof u)s(u,this,e);else{var c=u.length,l=y(u,c);for(r=0;r=0;s--)if(r[s]===e||r[s].listener===e){a=r[s].listener,o=s;break}if(o<0)return this;0===o?r.shift():function(t,e){for(;e+1=0;n--)this.removeListener(t,e[n]);return this},u.prototype.listeners=function(t){return p(this,t,!0)},u.prototype.rawListeners=function(t){return p(this,t,!1)},u.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):d.call(t,e)},u.prototype.listenerCount=d,u.prototype.eventNames=function(){return this._eventsCount>0?n(this._events):[]}},function(t,e,r){"use strict";t.exports=r(14).get().Decimal128},function(t,e,r){"use strict";(function(e){
+/*!
+ * Determines if `arg` is an object.
+ *
+ * @param {Object|Array|String|Function|RegExp|any} arg
+ * @api private
+ * @return {Boolean}
+ */
+t.exports=function(t){return!!e.isBuffer(t)||"[object Object]"===Object.prototype.toString.call(t)}}).call(this,r(1).Buffer)},function(t,e,r){"use strict";(function(e){var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(113);
+/*!
+ * The buffer module from node.js, for the browser.
+ *
+ * @author Feross Aboukhadijeh
+ * @license MIT
+ */
+function o(t,e){if(t===e)return 0;for(var r=t.length,n=e.length,i=0,o=Math.min(r,n);i=0;u--)if(l[u]!==f[u])return!1;for(u=l.length-1;u>=0;u--)if(s=l[u],!b(t[s],e[s],r,n))return!1;return!0}(t,e,r,i))}return r?t===e:t==e}function w(t){return"[object Arguments]"==Object.prototype.toString.call(t)}function O(t,e){if(!t||!e)return!1;if("[object RegExp]"==Object.prototype.toString.call(e))return e.test(t);try{if(t instanceof e)return!0}catch(t){}return!Error.isPrototypeOf(e)&&!0===e.call({},t)}function S(t,e,r,n){var i;if("function"!=typeof e)throw new TypeError('"block" argument must be a function');"string"==typeof r&&(n=r,r=null),i=function(t){var e;try{t()}catch(t){e=t}return e}(e),n=(r&&r.name?" ("+r.name+").":".")+(n?" "+n:"."),t&&!i&&m(i,r,"Missing expected exception"+n);var o="string"==typeof n,s=!t&&a.isError(i),u=!t&&i&&!r;if((s&&o&&O(i,r)||u)&&m(i,r,"Got unwanted exception"+n),t&&i&&r&&!O(i,r)||!t&&i)throw i}p.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=function(t){return v(_(t.actual),128)+" "+t.operator+" "+v(_(t.expected),128)}(this),this.generatedMessage=!0);var e=t.stackStartFunction||m;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else{var r=new Error;if(r.stack){var n=r.stack,i=y(e),o=n.indexOf("\n"+i);if(o>=0){var s=n.indexOf("\n",o+1);n=n.substring(s+1)}this.stack=n}}},a.inherits(p.AssertionError,Error),p.fail=m,p.ok=g,p.equal=function(t,e,r){t!=e&&m(t,e,r,"==",p.equal)},p.notEqual=function(t,e,r){t==e&&m(t,e,r,"!=",p.notEqual)},p.deepEqual=function(t,e,r){b(t,e,!1)||m(t,e,r,"deepEqual",p.deepEqual)},p.deepStrictEqual=function(t,e,r){b(t,e,!0)||m(t,e,r,"deepStrictEqual",p.deepStrictEqual)},p.notDeepEqual=function(t,e,r){b(t,e,!1)&&m(t,e,r,"notDeepEqual",p.notDeepEqual)},p.notDeepStrictEqual=function t(e,r,n){b(e,r,!0)&&m(e,r,n,"notDeepStrictEqual",t)},p.strictEqual=function(t,e,r){t!==e&&m(t,e,r,"===",p.strictEqual)},p.notStrictEqual=function(t,e,r){t===e&&m(t,e,r,"!==",p.notStrictEqual)},p.throws=function(t,e,r){S(!0,t,e,r)},p.doesNotThrow=function(t,e,r){S(!1,t,e,r)},p.ifError=function(t){if(t)throw t},p.strict=i(function t(e,r){e||m(e,!0,r,"==",t)},p,{equal:p.strictEqual,deepEqual:p.deepStrictEqual,notEqual:p.notStrictEqual,notDeepEqual:p.notDeepStrictEqual}),p.strict.strict=p.strict;var E=Object.keys||function(t){var e=[];for(var r in t)u.call(t,r)&&e.push(r);return e}}).call(this,r(11))},function(t,e,r){"use strict";
+/*!
+ * ignore
+ */e.internalToObjectOptions={transform:!1,virtuals:!1,getters:!1,_skipDepopulateTopLevel:!0,depopulate:!0,flattenDecimals:!1}},function(t,e,r){"use strict";function n(t,e){if(!(this instanceof n))return new n(t,e);this._bsontype="Long",this.low_=0|t,this.high_=0|e}n.prototype.toInt=function(){return this.low_},n.prototype.toNumber=function(){return this.high_*n.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()},n.prototype.toJSON=function(){return this.toString()},n.prototype.toString=function(t){var e=t||10;if(e<2||36=0?this.low_:n.TWO_PWR_32_DBL_+this.low_},n.prototype.getNumBitsAbs=function(){if(this.isNegative())return this.equals(n.MIN_VALUE)?64:this.negate().getNumBitsAbs();for(var t=0!==this.high_?this.high_:this.low_,e=31;e>0&&0==(t&1<0},n.prototype.greaterThanOrEqual=function(t){return this.compare(t)>=0},n.prototype.compare=function(t){if(this.equals(t))return 0;var e=this.isNegative(),r=t.isNegative();return e&&!r?-1:!e&&r?1:this.subtract(t).isNegative()?-1:1},n.prototype.negate=function(){return this.equals(n.MIN_VALUE)?n.MIN_VALUE:this.not().add(n.ONE)},n.prototype.add=function(t){var e=this.high_>>>16,r=65535&this.high_,i=this.low_>>>16,o=65535&this.low_,s=t.high_>>>16,a=65535&t.high_,u=t.low_>>>16,c=0,l=0,f=0,h=0;return f+=(h+=o+(65535&t.low_))>>>16,h&=65535,l+=(f+=i+u)>>>16,f&=65535,c+=(l+=r+a)>>>16,l&=65535,c+=e+s,c&=65535,n.fromBits(f<<16|h,c<<16|l)},n.prototype.subtract=function(t){return this.add(t.negate())},n.prototype.multiply=function(t){if(this.isZero())return n.ZERO;if(t.isZero())return n.ZERO;if(this.equals(n.MIN_VALUE))return t.isOdd()?n.MIN_VALUE:n.ZERO;if(t.equals(n.MIN_VALUE))return this.isOdd()?n.MIN_VALUE:n.ZERO;if(this.isNegative())return t.isNegative()?this.negate().multiply(t.negate()):this.negate().multiply(t).negate();if(t.isNegative())return this.multiply(t.negate()).negate();if(this.lessThan(n.TWO_PWR_24_)&&t.lessThan(n.TWO_PWR_24_))return n.fromNumber(this.toNumber()*t.toNumber());var e=this.high_>>>16,r=65535&this.high_,i=this.low_>>>16,o=65535&this.low_,s=t.high_>>>16,a=65535&t.high_,u=t.low_>>>16,c=65535&t.low_,l=0,f=0,h=0,p=0;return h+=(p+=o*c)>>>16,p&=65535,f+=(h+=i*c)>>>16,h&=65535,f+=(h+=o*u)>>>16,h&=65535,l+=(f+=r*c)>>>16,f&=65535,l+=(f+=i*u)>>>16,f&=65535,l+=(f+=o*a)>>>16,f&=65535,l+=e*c+r*u+i*a+o*s,l&=65535,n.fromBits(h<<16|p,l<<16|f)},n.prototype.div=function(t){if(t.isZero())throw Error("division by zero");if(this.isZero())return n.ZERO;if(this.equals(n.MIN_VALUE)){if(t.equals(n.ONE)||t.equals(n.NEG_ONE))return n.MIN_VALUE;if(t.equals(n.MIN_VALUE))return n.ONE;var e=this.shiftRight(1).div(t).shiftLeft(1);if(e.equals(n.ZERO))return t.isNegative()?n.ONE:n.NEG_ONE;var r=this.subtract(t.multiply(e));return e.add(r.div(t))}if(t.equals(n.MIN_VALUE))return n.ZERO;if(this.isNegative())return t.isNegative()?this.negate().div(t.negate()):this.negate().div(t).negate();if(t.isNegative())return this.div(t.negate()).negate();var i=n.ZERO;for(r=this;r.greaterThanOrEqual(t);){e=Math.max(1,Math.floor(r.toNumber()/t.toNumber()));for(var o=Math.ceil(Math.log(e)/Math.LN2),s=o<=48?1:Math.pow(2,o-48),a=n.fromNumber(e),u=a.multiply(t);u.isNegative()||u.greaterThan(r);)e-=s,u=(a=n.fromNumber(e)).multiply(t);a.isZero()&&(a=n.ONE),i=i.add(a),r=r.subtract(u)}return i},n.prototype.modulo=function(t){return this.subtract(this.div(t).multiply(t))},n.prototype.not=function(){return n.fromBits(~this.low_,~this.high_)},n.prototype.and=function(t){return n.fromBits(this.low_&t.low_,this.high_&t.high_)},n.prototype.or=function(t){return n.fromBits(this.low_|t.low_,this.high_|t.high_)},n.prototype.xor=function(t){return n.fromBits(this.low_^t.low_,this.high_^t.high_)},n.prototype.shiftLeft=function(t){if(0===(t&=63))return this;var e=this.low_;if(t<32){var r=this.high_;return n.fromBits(e<>>32-t)}return n.fromBits(0,e<>>t|e<<32-t,e>>t)}return n.fromBits(e>>t-32,e>=0?0:-1)},n.prototype.shiftRightUnsigned=function(t){if(0===(t&=63))return this;var e=this.high_;if(t<32){var r=this.low_;return n.fromBits(r>>>t|e<<32-t,e>>>t)}return 32===t?n.fromBits(e,0):n.fromBits(e>>>t-32,0)},n.fromInt=function(t){if(-128<=t&&t<128){var e=n.INT_CACHE_[t];if(e)return e}var r=new n(0|t,t<0?-1:0);return-128<=t&&t<128&&(n.INT_CACHE_[t]=r),r},n.fromNumber=function(t){return isNaN(t)||!isFinite(t)?n.ZERO:t<=-n.TWO_PWR_63_DBL_?n.MIN_VALUE:t+1>=n.TWO_PWR_63_DBL_?n.MAX_VALUE:t<0?n.fromNumber(-t).negate():new n(t%n.TWO_PWR_32_DBL_|0,t/n.TWO_PWR_32_DBL_|0)},n.fromBits=function(t,e){return new n(t,e)},n.fromString=function(t,e){if(0===t.length)throw Error("number format error: empty string");var r=e||10;if(r<2||36=0)throw Error('number format error: interior "-" character: '+t);for(var i=n.fromNumber(Math.pow(r,8)),o=n.ZERO,s=0;s0&&!r[i]&&(r[i]=!0,o.emit("error",r));try{t(r)}catch(r){return e.nextTick(function(){throw r})}}}):new(n.get())(function(t,e){r(function(r,n){return null!=r?(null!=o&&o.listeners("error").length>0&&!r[i]&&(r[i]=!0,o.emit("error",r)),e(r)):arguments.length>2?t(Array.prototype.slice.call(arguments,1)):void t(n)})})}}).call(this,r(8))},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(61)(),i=r(18).EventEmitter,o=r(29),s=r(50),a=r(22).internalToObjectOptions,u=r(5),c=r(24),l=r(3),f=r(0).documentArrayParent,h=r(0).validatorErrorSymbol;function p(t,e,r,i,o){null!=e&&e.isMongooseDocumentArray?(this.__parentArray=e,this[f]=e.$parent()):(this.__parentArray=void 0,this[f]=void 0),this.$setIndex(o),this.$isDocumentArrayElement=!0,n.call(this,t,i,r);var s=this;this.on("isNew",function(t){s.isNew=t}),s.on("save",function(){s.constructor.emit("save",s)})}
+/*!
+ * Inherit from Document
+ */for(var d in p.prototype=Object.create(n.prototype),p.prototype.constructor=p,i.prototype)p[d]=i.prototype[d];p.prototype.toBSON=function(){return this.toObject(a)},
+/*!
+ * ignore
+ */
+p.prototype.$setIndex=function(t){if(this.__index=t,null!=u(this,"$__.validationError",null)){var e=Object.keys(this.$__.validationError.errors),r=!0,n=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(r=(o=s.next()).done);r=!0){var a=o.value;this.invalidate(a,this.$__.validationError.errors[a])}}catch(t){n=!0,i=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw i}}}},p.prototype.markModified=function(t){this.$__.activePaths.modify(t),this.__parentArray&&(this.isNew?this.__parentArray._markModified():this.__parentArray._markModified(this,t))},
+/*!
+ * ignore
+ */
+p.prototype.populate=function(){throw new Error('Mongoose does not support calling populate() on nested docs. Instead of `doc.arr[0].populate("path")`, use `doc.populate("arr.0.path")`')},p.prototype.save=function(t,e){var r=this;return"function"==typeof t&&(e=t,t={}),(t=t||{}).suppressWarning||console.warn("mongoose: calling `save()` on a subdoc does **not** save the document to MongoDB, it only runs save middleware. Use `subdoc.save({ suppressWarning: true })` to hide this warning if you're sure this behavior is right for your app."),c(e,function(t){r.$__save(t)})},p.prototype.$__save=function(t){var e=this;return s(function(){return t(null,e)})},
+/*!
+ * no-op for hooks
+ */
+p.prototype.$__remove=function(t){return t(null,this)},p.prototype.remove=function(t,e){if("function"!=typeof t||e||(e=t,t=void 0),!this.__parentArray||t&&t.noop)return e&&e(null),this;var r=void 0;if(!this.willRemove){if(!(r=this._doc._id))throw new Error("For your own good, Mongoose does not know how to remove an EmbeddedDocument that has no _id");this.__parentArray.pull({_id:r}),this.willRemove=!0,
+/*!
+ * Registers remove event listeners for triggering
+ * on subdocuments.
+ *
+ * @param {EmbeddedDocument} sub
+ * @api private
+ */
+function(t){var e=t.ownerDocument();function r(){e.removeListener("save",r),e.removeListener("remove",r),t.emit("remove",t),t.constructor.emit("remove",t),e=t=null}e.on("save",r),e.on("remove",r)}(this)}return e&&e(null),this},p.prototype.update=function(){throw new Error("The #update method is not available on EmbeddedDocuments")},p.prototype.inspect=function(){return this.toObject({transform:!1,virtuals:!1,flattenDecimals:!1})},l.inspect.custom&&(
+/*!
+ * Avoid Node deprecation warning DEP0079
+ */
+p.prototype[l.inspect.custom]=p.prototype.inspect),p.prototype.invalidate=function(t,e,r){if(n.prototype.invalidate.call(this,t,e,r),!this[f]||null==this.__index){if(e[h]||e instanceof o)return!0;throw e}var i=this.__index,s=[this.__parentArray.$path(),i,t].join(".");return this[f].invalidate(s,e,r),!0},p.prototype.$markValid=function(t){if(this[f]){var e=this.__index;if(void 0!==e){var r=[this.__parentArray.$path(),e,t].join(".");this[f].$markValid(r)}}},
+/*!
+ * ignore
+ */
+p.prototype.$ignore=function(t){if(n.prototype.$ignore.call(this,t),this[f]){var e=this.__index;if(void 0!==e){var r=[this.__parentArray.$path(),e,t].join(".");this[f].$ignore(r)}}},p.prototype.$isValid=function(t){return void 0===this.__index||!this[f]||(!this[f].$__.validationError||!this[f].$__.validationError.errors[this.$__fullPath(t)])},p.prototype.ownerDocument=function(){if(this.$__.ownerDocument)return this.$__.ownerDocument;var t=this[f];if(!t)return this;for(;t[f]||t.$parent;)t=t[f]||t.$parent;return this.$__.ownerDocument=t,this.$__.ownerDocument},p.prototype.$__fullPath=function(t){if(!this.$__.fullPath){var e=this;if(!e[f])return t;for(var r=[];e[f]||e.$parent;)e[f]?r.unshift(e.__parentArray.$path()):r.unshift(e.$basePath),e=e[f]||e.$parent;this.$__.fullPath=r.join("."),this.$__.ownerDocument||(this.$__.ownerDocument=e)}return t?this.$__.fullPath+"."+t:this.$__.fullPath},p.prototype.parent=function(){return this[f]},p.prototype.parentArray=function(){return this.__parentArray},
+/*!
+ * Module exports.
+ */
+t.exports=p},function(t,e,r){"use strict";(function(e){if(void 0!==e)var n=r(1).Buffer;var i=r(15);function o(t,e){if(!(this instanceof o))return new o(t,e);if(!(null==t||"string"==typeof t||n.isBuffer(t)||t instanceof Uint8Array||Array.isArray(t)))throw new Error("only String, Buffer, Uint8Array or Array accepted");if(this._bsontype="Binary",t instanceof Number?(this.sub_type=t,this.position=0):(this.sub_type=null==e?s:e,this.position=0),null==t||t instanceof Number)void 0!==n?this.buffer=i.allocBuffer(o.BUFFER_SIZE):"undefined"!=typeof Uint8Array?this.buffer=new Uint8Array(new ArrayBuffer(o.BUFFER_SIZE)):this.buffer=new Array(o.BUFFER_SIZE),this.position=0;else{if("string"==typeof t)if(void 0!==n)this.buffer=i.toBuffer(t);else{if("undefined"==typeof Uint8Array&&"[object Array]"!==Object.prototype.toString.call(t))throw new Error("only String, Buffer, Uint8Array or Array accepted");this.buffer=a(t)}else this.buffer=t;this.position=t.length}}o.prototype.put=function(t){if(null!=t.length&&"number"!=typeof t&&1!==t.length)throw new Error("only accepts single character String, Uint8Array or Array");if("number"!=typeof t&&t<0||t>255)throw new Error("only accepts number in a valid unsigned byte range 0-255");var e=null;if(e="string"==typeof t?t.charCodeAt(0):null!=t.length?t[0]:t,this.buffer.length>this.position)this.buffer[this.position++]=e;else if(void 0!==n&&n.isBuffer(this.buffer)){var r=i.allocBuffer(o.BUFFER_SIZE+this.buffer.length);this.buffer.copy(r,0,0,this.buffer.length),this.buffer=r,this.buffer[this.position++]=e}else{r=null,r="[object Uint8Array]"===Object.prototype.toString.call(this.buffer)?new Uint8Array(new ArrayBuffer(o.BUFFER_SIZE+this.buffer.length)):new Array(o.BUFFER_SIZE+this.buffer.length);for(var s=0;sthis.position?e+t.length:this.position;else if(void 0!==n&&"string"==typeof t&&n.isBuffer(this.buffer))this.buffer.write(t,e,"binary"),this.position=e+t.length>this.position?e+t.length:this.position;else if("[object Uint8Array]"===Object.prototype.toString.call(t)||"[object Array]"===Object.prototype.toString.call(t)&&"string"!=typeof t){for(o=0;othis.position?e:this.position}else if("string"==typeof t){for(o=0;othis.position?e:this.position}},o.prototype.read=function(t,e){if(e=e&&e>0?e:this.position,this.buffer.slice)return this.buffer.slice(t,t+e);for(var r="undefined"!=typeof Uint8Array?new Uint8Array(new ArrayBuffer(e)):new Array(e),n=0;n=0?this.low_:n.TWO_PWR_32_DBL_+this.low_},n.prototype.getNumBitsAbs=function(){if(this.isNegative())return this.equals(n.MIN_VALUE)?64:this.negate().getNumBitsAbs();for(var t=0!==this.high_?this.high_:this.low_,e=31;e>0&&0==(t&1<0},n.prototype.greaterThanOrEqual=function(t){return this.compare(t)>=0},n.prototype.compare=function(t){if(this.equals(t))return 0;var e=this.isNegative(),r=t.isNegative();return e&&!r?-1:!e&&r?1:this.subtract(t).isNegative()?-1:1},n.prototype.negate=function(){return this.equals(n.MIN_VALUE)?n.MIN_VALUE:this.not().add(n.ONE)},n.prototype.add=function(t){var e=this.high_>>>16,r=65535&this.high_,i=this.low_>>>16,o=65535&this.low_,s=t.high_>>>16,a=65535&t.high_,u=t.low_>>>16,c=0,l=0,f=0,h=0;return f+=(h+=o+(65535&t.low_))>>>16,h&=65535,l+=(f+=i+u)>>>16,f&=65535,c+=(l+=r+a)>>>16,l&=65535,c+=e+s,c&=65535,n.fromBits(f<<16|h,c<<16|l)},n.prototype.subtract=function(t){return this.add(t.negate())},n.prototype.multiply=function(t){if(this.isZero())return n.ZERO;if(t.isZero())return n.ZERO;if(this.equals(n.MIN_VALUE))return t.isOdd()?n.MIN_VALUE:n.ZERO;if(t.equals(n.MIN_VALUE))return this.isOdd()?n.MIN_VALUE:n.ZERO;if(this.isNegative())return t.isNegative()?this.negate().multiply(t.negate()):this.negate().multiply(t).negate();if(t.isNegative())return this.multiply(t.negate()).negate();if(this.lessThan(n.TWO_PWR_24_)&&t.lessThan(n.TWO_PWR_24_))return n.fromNumber(this.toNumber()*t.toNumber());var e=this.high_>>>16,r=65535&this.high_,i=this.low_>>>16,o=65535&this.low_,s=t.high_>>>16,a=65535&t.high_,u=t.low_>>>16,c=65535&t.low_,l=0,f=0,h=0,p=0;return h+=(p+=o*c)>>>16,p&=65535,f+=(h+=i*c)>>>16,h&=65535,f+=(h+=o*u)>>>16,h&=65535,l+=(f+=r*c)>>>16,f&=65535,l+=(f+=i*u)>>>16,f&=65535,l+=(f+=o*a)>>>16,f&=65535,l+=e*c+r*u+i*a+o*s,l&=65535,n.fromBits(h<<16|p,l<<16|f)},n.prototype.div=function(t){if(t.isZero())throw Error("division by zero");if(this.isZero())return n.ZERO;if(this.equals(n.MIN_VALUE)){if(t.equals(n.ONE)||t.equals(n.NEG_ONE))return n.MIN_VALUE;if(t.equals(n.MIN_VALUE))return n.ONE;var e=this.shiftRight(1).div(t).shiftLeft(1);if(e.equals(n.ZERO))return t.isNegative()?n.ONE:n.NEG_ONE;var r=this.subtract(t.multiply(e));return e.add(r.div(t))}if(t.equals(n.MIN_VALUE))return n.ZERO;if(this.isNegative())return t.isNegative()?this.negate().div(t.negate()):this.negate().div(t).negate();if(t.isNegative())return this.div(t.negate()).negate();var i=n.ZERO;for(r=this;r.greaterThanOrEqual(t);){e=Math.max(1,Math.floor(r.toNumber()/t.toNumber()));for(var o=Math.ceil(Math.log(e)/Math.LN2),s=o<=48?1:Math.pow(2,o-48),a=n.fromNumber(e),u=a.multiply(t);u.isNegative()||u.greaterThan(r);)e-=s,u=(a=n.fromNumber(e)).multiply(t);a.isZero()&&(a=n.ONE),i=i.add(a),r=r.subtract(u)}return i},n.prototype.modulo=function(t){return this.subtract(this.div(t).multiply(t))},n.prototype.not=function(){return n.fromBits(~this.low_,~this.high_)},n.prototype.and=function(t){return n.fromBits(this.low_&t.low_,this.high_&t.high_)},n.prototype.or=function(t){return n.fromBits(this.low_|t.low_,this.high_|t.high_)},n.prototype.xor=function(t){return n.fromBits(this.low_^t.low_,this.high_^t.high_)},n.prototype.shiftLeft=function(t){if(0===(t&=63))return this;var e=this.low_;if(t<32){var r=this.high_;return n.fromBits(e<>>32-t)}return n.fromBits(0,e<>>t|e<<32-t,e>>t)}return n.fromBits(e>>t-32,e>=0?0:-1)},n.prototype.shiftRightUnsigned=function(t){if(0===(t&=63))return this;var e=this.high_;if(t<32){var r=this.low_;return n.fromBits(r>>>t|e<<32-t,e>>>t)}return 32===t?n.fromBits(e,0):n.fromBits(e>>>t-32,0)},n.fromInt=function(t){if(-128<=t&&t<128){var e=n.INT_CACHE_[t];if(e)return e}var r=new n(0|t,t<0?-1:0);return-128<=t&&t<128&&(n.INT_CACHE_[t]=r),r},n.fromNumber=function(t){return isNaN(t)||!isFinite(t)?n.ZERO:t<=-n.TWO_PWR_63_DBL_?n.MIN_VALUE:t+1>=n.TWO_PWR_63_DBL_?n.MAX_VALUE:t<0?n.fromNumber(-t).negate():new n(t%n.TWO_PWR_32_DBL_|0,t/n.TWO_PWR_32_DBL_|0)},n.fromBits=function(t,e){return new n(t,e)},n.fromString=function(t,e){if(0===t.length)throw Error("number format error: empty string");var r=e||10;if(r<2||36=0)throw Error('number format error: interior "-" character: '+t);for(var i=n.fromNumber(Math.pow(r,8)),o=n.ZERO,s=0;s>8&255,i[1]=t>>16&255,i[0]=t>>24&255,i[6]=255&s,i[5]=s>>8&255,i[4]=s>>16&255,i[8]=255&e,i[7]=e>>8&255,i[11]=255&r,i[10]=r>>8&255,i[9]=r>>16&255,i},c.prototype.toString=function(t){return this.id&&this.id.copy?this.id.toString("string"==typeof t?t:"hex"):this.toHexString()},c.prototype[i]=c.prototype.toString,c.prototype.toJSON=function(){return this.toHexString()},c.prototype.equals=function(t){return t instanceof c?this.toString()===t.toString():"string"==typeof t&&c.isValid(t)&&12===t.length&&this.id instanceof p?t===this.id.toString("binary"):"string"==typeof t&&c.isValid(t)&&24===t.length?t.toLowerCase()===this.toHexString():"string"==typeof t&&c.isValid(t)&&12===t.length?t===this.id:!(null==t||!(t instanceof c||t.toHexString))&&t.toHexString()===this.toHexString()},c.prototype.getTimestamp=function(){var t=new Date,e=this.id[3]|this.id[2]<<8|this.id[1]<<16|this.id[0]<<24;return t.setTime(1e3*Math.floor(e)),t},c.index=~~(16777215*Math.random()),c.createPk=function(){return new c},c.createFromTime=function(t){var e=o.toBuffer([0,0,0,0,0,0,0,0,0,0,0,0]);return e[3]=255&t,e[2]=t>>8&255,e[1]=t>>16&255,e[0]=t>>24&255,new c(e)};var h=[];for(f=0;f<10;)h[48+f]=f++;for(;f<16;)h[55+f]=h[87+f]=f++;var p=e,d=function(t){return t.toString("hex")};c.createFromHexString=function(t){if(void 0===t||null!=t&&24!==t.length)throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");if(u)return new c(o.toBuffer(t,"hex"));for(var e=new p(12),r=0,n=0;n<24;)e[r++]=h[t.charCodeAt(n++)]<<4|h[t.charCodeAt(n++)];return new c(e)},c.isValid=function(t){return null!=t&&("number"==typeof t||("string"==typeof t?12===t.length||24===t.length&&a.test(t):t instanceof c||(t instanceof p||!!t.toHexString&&(12===t.id.length||24===t.id.length&&a.test(t.id)))))},Object.defineProperty(c.prototype,"generationTime",{enumerable:!0,get:function(){return this.id[3]|this.id[2]<<8|this.id[1]<<16|this.id[0]<<24},set:function(t){this.id[3]=255&t,this.id[2]=t>>8&255,this.id[1]=t>>16&255,this.id[0]=t>>24&255}}),t.exports=c,t.exports.ObjectID=c,t.exports.ObjectId=c}).call(this,r(1).Buffer,r(8))},function(t,e,r){"use strict";function n(t,e){if(!(this instanceof n))return new n;this._bsontype="BSONRegExp",this.pattern=t||"",this.options=e||"";for(var r=0;r=7e3)throw new Error(t+" not a valid Decimal128 string");var T=t.match(i),B=t.match(o),C=t.match(s);if(!T&&!B&&!C||0===t.length)throw new Error(t+" not a valid Decimal128 string");if(T&&T[4]&&void 0===T[2])throw new Error(t+" not a valid Decimal128 string");if("+"!==t[k]&&"-"!==t[k]||(r="-"===t[k++]),!p(t[k])&&"."!==t[k]){if("i"===t[k]||"I"===t[k])return new y(h.toBuffer(r?c:l));if("N"===t[k])return new y(h.toBuffer(u))}for(;p(t[k])||"."===t[k];)if("."!==t[k])S<34&&("0"!==t[k]||v)&&(v||(w=m),v=!0,O[E++]=parseInt(t[k],10),S+=1),v&&(g+=1),d&&(b+=1),m+=1,k+=1;else{if(d)return new y(h.toBuffer(u));d=!0,k+=1}if(d&&!m)throw new Error(t+" not a valid Decimal128 string");if("e"===t[k]||"E"===t[k]){var D=t.substr(++k).match(f);if(!D||!D[2])return new y(h.toBuffer(u));j=parseInt(D[0],10),k+=D[0].length}if(t[k])return new y(h.toBuffer(u));if(A=0,S){if($=S-1,_=g,0!==j&&1!==_)for(;"0"===t[w+_-1];)_-=1}else A=0,$=0,O[0]=0,g=1,S=1,_=0;for(j<=b&&b-j>16384?j=-6176:j-=b;j>6111;){if(($+=1)-A>34){var M=O.join("");if(M.match(/^0+$/)){j=6111;break}return new y(h.toBuffer(r?c:l))}j-=1}for(;j<-6176||S=5&&(I=1,5===F))for(I=O[$]%2==1,x=w+$+2;x=0&&++O[L]>9;L--)if(O[L]=0,0===L){if(!(j<6111))return new y(h.toBuffer(r?c:l));j+=1,O[L]=1}}if(N=n.fromNumber(0),P=n.fromNumber(0),0===_)N=n.fromNumber(0),P=n.fromNumber(0);else if($-A<17)for(L=A,P=n.fromNumber(O[L++]),N=new n(0,0);L<=$;L++)P=(P=P.multiply(n.fromNumber(10))).add(n.fromNumber(O[L]));else{for(L=A,N=n.fromNumber(O[L++]);L<=$-17;L++)N=(N=N.multiply(n.fromNumber(10))).add(n.fromNumber(O[L]));for(P=n.fromNumber(O[L++]);L<=$;L++)P=(P=P.multiply(n.fromNumber(10))).add(n.fromNumber(O[L]))}var U=function(t,e){if(!t&&!e)return{high:n.fromNumber(0),low:n.fromNumber(0)};var r=t.shiftRightUnsigned(32),i=new n(t.getLowBits(),0),o=e.shiftRightUnsigned(32),s=new n(e.getLowBits(),0),a=r.multiply(o),u=r.multiply(s),c=i.multiply(o),l=i.multiply(s);return a=a.add(u.shiftRightUnsigned(32)),u=new n(u.getLowBits(),0).add(c).add(l.shiftRightUnsigned(32)),{high:a=a.add(u.shiftRightUnsigned(32)),low:l=u.shiftLeft(32).add(new n(l.getLowBits(),0))}}(N,n.fromString("100000000000000000"));U.low=U.low.add(P),function(t,e){var r=t.high_>>>0,n=e.high_>>>0;return r>>0>>0}(U.low,P)&&(U.high=U.high.add(n.fromNumber(1))),e=j+a;var V={low:n.fromNumber(0),high:n.fromNumber(0)};U.high.shiftRightUnsigned(49).and(n.fromNumber(1)).equals(n.fromNumber)?(V.high=V.high.or(n.fromNumber(3).shiftLeft(61)),V.high=V.high.or(n.fromNumber(e).and(n.fromNumber(16383).shiftLeft(47))),V.high=V.high.or(U.high.and(n.fromNumber(0x7fffffffffff)))):(V.high=V.high.or(n.fromNumber(16383&e).shiftLeft(49)),V.high=V.high.or(U.high.and(n.fromNumber(562949953421311)))),V.low=U.low,r&&(V.high=V.high.or(n.fromString("9223372036854775808")));var q=h.allocBuffer(16);return k=0,q[k++]=255&V.low.low_,q[k++]=V.low.low_>>8&255,q[k++]=V.low.low_>>16&255,q[k++]=V.low.low_>>24&255,q[k++]=255&V.low.high_,q[k++]=V.low.high_>>8&255,q[k++]=V.low.high_>>16&255,q[k++]=V.low.high_>>24&255,q[k++]=255&V.high.low_,q[k++]=V.high.low_>>8&255,q[k++]=V.high.low_>>16&255,q[k++]=V.high.low_>>24&255,q[k++]=255&V.high.high_,q[k++]=V.high.high_>>8&255,q[k++]=V.high.high_>>16&255,q[k++]=V.high.high_>>24&255,new y(q)};a=6176,y.prototype.toString=function(){for(var t,e,r,i,o,s,u=0,c=new Array(36),l=0;l>26&31)>>3==3){if(30===o)return b.join("")+"Infinity";if(31===o)return"NaN";s=t>>15&16383,p=8+(t>>14&1)}else p=t>>14&7,s=t>>17&16383;if(f=s-a,g.parts[0]=(16383&t)+((15&p)<<14),g.parts[1]=e,g.parts[2]=r,g.parts[3]=i,0===g.parts[0]&&0===g.parts[1]&&0===g.parts[2]&&0===g.parts[3])m=!0;else for(v=3;v>=0;v--){var O=0,S=d(g);if(g=S.quotient,O=S.rem.low_)for(y=8;y>=0;y--)c[9*v+y]=O%10,O=Math.floor(O/10)}if(m)u=1,c[_]=0;else for(u=36,l=0;!c[_];)l++,u-=1,_+=1;if((h=u-1+f)>=34||h<=-7||f>0){for(b.push(c[_++]),(u-=1)&&b.push("."),l=0;l0?b.push("+"+h):b.push(h)}else if(f>=0)for(l=0;l0)for(l=0;l0&&!A.hasUserDefinedProperty(e.of,this.options.typeKey)?new T(e.of):e.of;this.paths[f]=this.interpretAsType(f,h,this.options),l.$__schemaType=this.paths[f]}if(l.$isSingleNested){for(var p in l.schema.paths)this.singleNestedPaths[t+"."+p]=l.schema.paths[p];for(var d in l.schema.singleNestedPaths)this.singleNestedPaths[t+"."+d]=l.schema.singleNestedPaths[d];for(var y in l.schema.subpaths)this.singleNestedPaths[t+"."+y]=l.schema.subpaths[y];Object.defineProperty(l.schema,"base",{configurable:!0,enumerable:!1,writable:!1,value:this.base}),l.caster.base=this.base,this.childSchemas.push({schema:l.schema,model:l.caster})}else l.$isMongooseDocumentArray&&(Object.defineProperty(l.schema,"base",{configurable:!0,enumerable:!1,writable:!1,value:this.base}),l.casterConstructor.base=this.base,this.childSchemas.push({schema:l.schema,model:l.casterConstructor}));if(l.$isMongooseArray&&l.caster instanceof c){for(var v=t,_=l,m=[];_.$isMongooseArray;)v+=".$",(_=_.$isMongooseDocumentArray?_.$embeddedSchemaType.clone():_.caster.clone()).path=v,m.push(_);var g=!0,b=!1,w=void 0;try{for(var O,S=m[Symbol.iterator]();!(g=(O=S.next()).done);g=!0){var E=O.value;this.subpaths[E.path]=E}}catch(t){b=!0,w=t}finally{try{!g&&S.return&&S.return()}finally{if(b)throw w}}}if(l.$isMongooseDocumentArray){var j=!0,x=!1,N=void 0;try{for(var P,k=Object.keys(l.schema.paths)[Symbol.iterator]();!(j=(P=k.next()).done);j=!0){var F=P.value;this.subpaths[t+"."+F]=l.schema.paths[F],l.schema.paths[F].$isUnderneathDocArray=!0}}catch(t){x=!0,N=t}finally{try{!j&&k.return&&k.return()}finally{if(x)throw N}}var I=!0,L=!1,U=void 0;try{for(var V,q=Object.keys(l.schema.subpaths)[Symbol.iterator]();!(I=(V=q.next()).done);I=!0){var W=V.value;this.subpaths[t+"."+W]=l.schema.subpaths[W],l.schema.subpaths[W].$isUnderneathDocArray=!0}}catch(t){L=!0,U=t}finally{try{!I&&q.return&&q.return()}finally{if(L)throw U}}var H=!0,Y=!1,z=void 0;try{for(var K,Q=Object.keys(l.schema.singleNestedPaths)[Symbol.iterator]();!(H=(K=Q.next()).done);H=!0){var J=K.value;this.subpaths[t+"."+J]=l.schema.singleNestedPaths[J],l.schema.singleNestedPaths[J].$isUnderneathDocArray=!0}}catch(t){Y=!0,z=t}finally{try{!H&&Q.return&&Q.return()}finally{if(Y)throw z}}}return this},Object.defineProperty(T.prototype,"base",{configurable:!0,enumerable:!1,writable:!0,value:null}),T.prototype.interpretAsType=function(t,e,r){if(e instanceof c)return e;var o=null!=this.base?this.base.Schema.Types:T.Types;if(!(A.isPOJO(e)||e instanceof l)&&"Object"!==A.getFunctionName(e.constructor)){var s=e;(e={})[r.typeKey]=s}var a=!e[r.typeKey]||"type"===r.typeKey&&e.type.type?{}:e[r.typeKey],u=void 0;if(A.isPOJO(a)||"mixed"===a)return new o.Mixed(t,e);if(Array.isArray(a)||Array===a||"array"===a){var f=Array===a||"array"===a?e.cast:a[0];if(f&&f.instanceOfSchema)return new o.DocumentArray(t,f,e);if(f&&f[r.typeKey]&&f[r.typeKey].instanceOfSchema)return new o.DocumentArray(t,f[r.typeKey],e,f);if(Array.isArray(f))return new o.Array(t,this.interpretAsType(t,f,r),e);if("string"==typeof f)f=o[f.charAt(0).toUpperCase()+f.substring(1)];else if(f&&(!f[r.typeKey]||"type"===r.typeKey&&f.type.type)&&A.isPOJO(f)){if(Object.keys(f).length){var h={minimize:r.minimize};r.typeKey&&(h.typeKey=r.typeKey),r.hasOwnProperty("strict")&&(h.strict=r.strict),r.hasOwnProperty("typePojoToMixed")&&(h.typePojoToMixed=r.typePojoToMixed);var p=new T(f,h);return p.$implicitlyCreated=!0,new o.DocumentArray(t,p,e)}return new o.Array(t,o.Mixed,e)}if(f&&(u="string"==typeof(a=!f[r.typeKey]||"type"===r.typeKey&&f.type.type?f:f[r.typeKey])?a:a.schemaName||A.getFunctionName(a),!o.hasOwnProperty(u)))throw new TypeError("Invalid schema configuration: `"+u+"` is not a valid type within the array `"+t+"`.See http://bit.ly/mongoose-schematypes for a list of valid schema types.");return new o.Array(t,f||o.Mixed,e,r)}if(a&&a.instanceOfSchema)return new o.Embedded(a,t,e);if((u=n.isBuffer(a)?"Buffer":"function"==typeof a||"object"===(void 0===a?"undefined":i(a))?a.schemaName||A.getFunctionName(a):null==a?""+a:a.toString())&&(u=u.charAt(0).toUpperCase()+u.substring(1)),"ObjectID"===u&&(u="ObjectId"),null==o[u])throw new TypeError("Invalid schema configuration: `"+u+"` is not a valid type at path `"+t+"`. See http://bit.ly/mongoose-schematypes for a list of valid schema types.");return new o[u](t,e)},T.prototype.eachPath=function(t){for(var e=Object.keys(this.paths),r=e.length,n=0;n0?t+"."+e[r]:e[r])in this.paths&&this.paths[t]instanceof j.Mixed)return this.paths[t];return null},T.prototype.setupTimestamp=function(t){var e=this.childSchemas.find(function(t){return!!t.schema.options.timestamps});if(t||e){var r=g(t,"createdAt"),n=g(t,"updatedAt"),i=null!=t&&t.hasOwnProperty("currentTime")?t.currentTime:null,o={};this.$timestamps={createdAt:r,updatedAt:n},n&&!this.paths[n]&&(o[n]=Date),r&&!this.paths[r]&&(o[r]=Date),this.add(o),this.pre("save",function(t){var e=_(this,"$__.saveOptions.timestamps");if(!1===e)return t();var o=null!=e&&!1===e.updatedAt,s=null!=e&&!1===e.createdAt,a=null!=i?i():(this.ownerDocument?this.ownerDocument():this).constructor.base.now(),u=this._id&&this._id.auto;if(!s&&r&&!this.get(r)&&this.isSelected(r)&&this.set(r,u?this._id.getTimestamp():a),!o&&n&&(this.isNew||this.isModified())){var c=a;this.isNew&&(null!=r?c=this.$__getValue(r):u&&(c=this._id.getTimestamp())),this.set(n,c)}t()}),this.methods.initializeTimestamps=function(){var t=null!=i?i():this.constructor.base.now();return r&&!this.get(r)&&this.set(r,t),n&&!this.get(n)&&this.set(n,t),this},a[S.builtInMiddleware]=!0;var s={query:!0,model:!1};this.pre("findOneAndUpdate",s,a),this.pre("replaceOne",s,a),this.pre("update",s,a),this.pre("updateOne",s,a),this.pre("updateMany",s,a)}function a(t){var e=null!=i?i():this.model.base.now();y(e,r,n,this.getUpdate(),this.options,this.schema),d(e,this.getUpdate(),this.model.schema),t()}},T.prototype.queue=function(t,e){return this.callQueue.push([t,e]),this},T.prototype.pre=function(t){if(t instanceof RegExp){var e=Array.prototype.slice.call(arguments,1),r=!0,n=!1,i=void 0;try{for(var o,s=P[Symbol.iterator]();!(r=(o=s.next()).done);r=!0){var a=o.value;t.test(a)&&this.pre.apply(this,[a].concat(e))}}catch(t){n=!0,i=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw i}}return this}if(Array.isArray(t)){var u=Array.prototype.slice.call(arguments,1),c=!0,l=!1,f=void 0;try{for(var h,p=t[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var d=h.value;this.pre.apply(this,[d].concat(u))}}catch(t){l=!0,f=t}finally{try{!c&&p.return&&p.return()}finally{if(l)throw f}}return this}return this.s.hooks.pre.apply(this.s.hooks,arguments),this},T.prototype.post=function(t){if(t instanceof RegExp){var e=Array.prototype.slice.call(arguments,1),r=!0,n=!1,i=void 0;try{for(var o,s=P[Symbol.iterator]();!(r=(o=s.next()).done);r=!0){var a=o.value;t.test(a)&&this.post.apply(this,[a].concat(e))}}catch(t){n=!0,i=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw i}}return this}if(Array.isArray(t)){var u=Array.prototype.slice.call(arguments,1),c=!0,l=!1,f=void 0;try{for(var h,p=t[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var d=h.value;this.post.apply(this,[d].concat(u))}}catch(t){l=!0,f=t}finally{try{!c&&p.return&&p.return()}finally{if(l)throw f}}return this}return this.s.hooks.post.apply(this.s.hooks,arguments),this},T.prototype.plugin=function(t,e){if("function"!=typeof t)throw new Error('First param to `schema.plugin()` must be a function, got "'+(void 0===t?"undefined":i(t))+'"');if(e&&e.deduplicate)for(var r=0;r0||this.setters.length>0)){var t="$"+this.path;this.getters.push(function(){return this[t]}),this.setters.push(function(e){this[t]=e})}},
+/*!
+ * ignore
+ */
+n.prototype.clone=function(){var t=new n(this.options,this.path);return t.getters=[].concat(this.getters),t.setters=[].concat(this.setters),t},n.prototype.get=function(t){return this.getters.push(t),this},n.prototype.set=function(t){return this.setters.push(t),this},n.prototype.applyGetters=function(t,e){for(var r=t,n=this.getters.length-1;n>=0;n--)r=this.getters[n].call(e,r,this,e);return r},n.prototype.applySetters=function(t,e){for(var r=t,n=this.setters.length-1;n>=0;n--)r=this.setters[n].call(e,r,this,e);return r},
+/*!
+ * exports
+ */
+t.exports=n},function(t,e,r){"use strict";
+/*!
+ * Module exports.
+ */e.String=r(143),e.Number=r(77),e.Boolean=r(147),e.DocumentArray=r(148),e.Embedded=r(154),e.Array=r(55),e.Buffer=r(156),e.Date=r(158),e.ObjectId=r(161),e.Mixed=r(31),e.Decimal128=e.Decimal=r(163),e.Map=r(165),e.Oid=e.ObjectId,e.Object=e.Mixed,e.Bool=e.Boolean,e.ObjectID=e.ObjectId},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(48),i=r(71),o=r(16),s=r(149),a=r(7),u=a.CastError,c=r(31),l=r(150),f=r(151),h=r(5),p=r(79),d=r(3),y=r(2),v=r(32).castToNumber,_=r(80),m=r(56),g=void 0,b=void 0,w=Symbol("mongoose#isNestedArray");function O(t,e,n,i){b||(b=r(57).Embedded);var o="type";if(i&&i.typeKey&&(o=i.typeKey),this.schemaOptions=i,e){var s={};y.isPOJO(e)&&(e[o]?(delete(s=y.clone(e))[o],e=e[o]):e=c),e===Object&&(e=c);var u="string"==typeof e?e:y.getFunctionName(e),l=r(54),f=l.hasOwnProperty(u)?l[u]:e;this.casterConstructor=f,this.casterConstructor instanceof O&&(this.casterConstructor[w]=!0),"function"!=typeof f||f.$isArraySubdocument||f.$isSchemaMap?this.caster=f:this.caster=new f(null,s),this.$embeddedSchemaType=this.caster,this.caster instanceof b||(this.caster.path=t)}this.$isMongooseArray=!0,a.call(this,t,n,"Array");var h=void 0,p=void 0;if(null!=this.defaultValue&&(h=this.defaultValue,p="function"==typeof h),!("defaultValue"in this)||void 0!==this.defaultValue){var d=function(){var t=[];return p?t=h.call(this):null!=h&&(t=t.concat(h)),t};d.$runBeforeSetters=!0,this.default(d)}}O.schemaName="Array",O.options={castNonArrays:!0},O.defaultOptions={},O.set=a.set,
+/*!
+ * Inherits from SchemaType.
+ */
+O.prototype=Object.create(a.prototype),O.prototype.constructor=O,O.prototype.OptionsConstructor=s,
+/*!
+ * ignore
+ */
+O._checkRequired=a.prototype.checkRequired,O.checkRequired=a.checkRequired,O.prototype.checkRequired=function(t,e){return a._isRef(this,t,e,!0)?!!t:("function"==typeof this.constructor.checkRequired?this.constructor.checkRequired():O.checkRequired())(t)},O.prototype.enum=function(){for(var t=this;;){var e=h(t,"caster.instance");if("Array"!==e){if("String"!==e&&"Number"!==e)throw new Error("`enum` can only be set on an array of strings or numbers , not "+e);break}t=t.caster}return t.caster.enum.apply(t.caster,arguments),this},O.prototype.applyGetters=function(t,e){return this.caster.options&&this.caster.options.ref?t:a.prototype.applyGetters.call(this,t,e)},O.prototype._applySetters=function(t,e,r,n){if(this.casterConstructor instanceof O&&O.options.castNonArrays&&!this[w]){for(var i=0,o=this;null!=o&&o instanceof O&&!o.$isMongooseDocumentArray;)++i,o=o.casterConstructor;if(null!=t&&t.length>0){var s=l(t);if(s.min===s.max&&s.maxo;)n[i-o]=t[i];return n}},function(t,e,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=Object.prototype.toString;t.exports=function(t){if(!function(t){return"object"==(void 0===t?"undefined":n(t))&&"[object RegExp]"==i.call(t)}(t))throw new TypeError("Not a RegExp");var e=[];t.global&&e.push("g"),t.multiline&&e.push("m"),t.ignoreCase&&e.push("i"),t.dotAll&&e.push("s"),t.unicode&&e.push("u"),t.sticky&&e.push("y");var r=new RegExp(t.source,e.join(""));return"number"==typeof t.lastIndex&&(r.lastIndex=t.lastIndex),r}},function(t,e,r){"use strict";t.exports=function(t){return t.name?t.name:(t.toString().trim().match(/^function\s*([^\s(]+)/)||[])[1]}},function(t,e,r){"use strict";var n=r(5);
+/*!
+ * Get the bson type, if it exists
+ */t.exports=function(t,e){return n(t,"_bsontype",void 0)===e}},function(t,e,r){"use strict";(function(e){
+/*!
+ * ignore
+ */
+var n=r(21),i=r(114),o={_promise:null,get:function(){return o._promise},set:function(t){n.ok("function"==typeof t,"mongoose.Promise must be a function, got "+t),o._promise=t,i.Promise=t}};
+/*!
+ * Use native promises by default
+ */
+o.set(e.Promise),t.exports=o}).call(this,r(11))},function(t,e,r){"use strict";(function(t,n){
+/*!
+ * Module dependencies.
+ */
+var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},o=r(45).Buffer,s=r(63),a=e.clone=function t(r,n){if(void 0===r||null===r)return r;if(Array.isArray(r))return e.cloneArray(r,n);if(r.constructor){if(/ObjectI[dD]$/.test(r.constructor.name))return"function"==typeof r.clone?r.clone():new r.constructor(r.id);if("ReadPreference"===r.constructor.name)return new r.constructor(r.mode,t(r.tags,n));if("Binary"==r._bsontype&&r.buffer&&r.value)return"function"==typeof r.clone?r.clone():new r.constructor(r.value(!0),r.sub_type);if("Date"===r.constructor.name||"Function"===r.constructor.name)return new r.constructor(+r);if("RegExp"===r.constructor.name)return s(r);if("Buffer"===r.constructor.name)return e.cloneBuffer(r)}return c(r)?e.cloneObject(r,n):r.valueOf?r.valueOf():void 0};
+/*!
+ * ignore
+ */
+e.cloneObject=function(t,e){var r,n,i,o=e&&e.minimize,s={};for(i in t)n=a(t[i],e),o&&void 0===n||(r||(r=!0),s[i]=n);return o?r&&s:s},e.cloneArray=function(t,e){for(var r=[],n=0,i=t.length;n1)throw new Error("Adding properties is not supported");function e(){}return e.prototype=t,new e},e.inherits=function(t,r){t.prototype=e.create(r.prototype),t.prototype.constructor=t};var l=e.soon="function"==typeof t?t:n.nextTick;e.cloneBuffer=function(t){var e=o.alloc(t.length);return t.copy(e,0,0,t.length),e},e.isArgumentsObject=function(t){return"[object Arguments]"===Object.prototype.toString.call(t)}}).call(this,r(68).setImmediate,r(8))},function(t,e,r){"use strict";(function(t){var n=void 0!==t&&t||"undefined"!=typeof self&&self||window,i=Function.prototype.apply;function o(t,e){this._id=t,this._clearFn=e}e.setTimeout=function(){return new o(i.call(setTimeout,n,arguments),clearTimeout)},e.setInterval=function(){return new o(i.call(setInterval,n,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t&&t.close()},o.prototype.unref=o.prototype.ref=function(){},o.prototype.close=function(){this._clearFn.call(n,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},r(115),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||void 0,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||void 0}).call(this,r(11))},function(t,e,r){"use strict";(function(t,r,n,i){var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};e.isNode=void 0!==t&&"object"==o(r)&&"object"==(void 0===n?"undefined":o(n))&&"function"==typeof i&&t.argv,e.isMongo=!e.isNode&&"function"==typeof printjson&&"function"==typeof ObjectId&&"function"==typeof rs&&"function"==typeof sh,e.isBrowser=!e.isNode&&!e.isMongo&&"undefined"!=typeof window,e.type=e.isNode?"node":e.isMongo?"mongo":e.isBrowser?"browser":"unknown"}).call(this,r(8),r(120)(t),r(11),r(1).Buffer)},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);function i(t){var e=t.message;e||(e=n.messages.general.default);var r=this.formatMessage(e,t);n.call(this,r),t=Object.assign({},t,{message:r}),this.name="ValidatorError",Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack,this.properties=t,this.kind=t.type,this.path=t.path,this.value=t.value,this.reason=t.reason}
+/*!
+ * Inherits from MongooseError
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * The object used to define this validator. Not enumerable to hide
+ * it from `require('util').inspect()` output re: gh-3925
+ */
+Object.defineProperty(i.prototype,"properties",{enumerable:!1,writable:!0,value:null}),
+/*!
+ * Formats error messages
+ */
+i.prototype.formatMessage=function(t,e){if("function"==typeof t)return t(e);for(var r=Object.keys(e),n=0;n=t},message:r,type:"min",min:t})}return this},h.prototype.max=function(t,e){if(this.maxValidator&&(this.validators=this.validators.filter(function(t){return t.validator!==this.maxValidator},this)),null!==t&&void 0!==t){var r=e||n.messages.Number.max;r=r.replace(/{MAX}/,t),this.validators.push({validator:this.maxValidator=function(e){return null==e||e<=t},message:r,type:"max",max:t})}return this},h.prototype.enum=function(t,e){return this.enumValidator&&(this.validators=this.validators.filter(function(t){return t.validator!==this.enumValidator},this)),Array.isArray(t)||(t=Array.prototype.slice.call(arguments),e=n.messages.Number.enum),e=null==e?n.messages.Number.enum:e,this.enumValidator=function(e){return null==e||-1!==t.indexOf(e)},this.validators.push({validator:this.enumValidator,message:e,type:"enum",enumValues:t}),this},h.prototype.cast=function(t,n,i){if(o._isRef(this,t,n,i)){if(null===t||void 0===t)return t;if(f||(f=r(6)),t instanceof f)return t.$__.wasPopulated=!0,t;if("number"==typeof t)return t;if(e.isBuffer(t)||!u.isObject(t))throw new l("number",t,this.path,null,this);var s=n.$__fullPath(this.path),a=new((n.ownerDocument?n.ownerDocument():n).populated(s,!0).options[c])(t);return a.$__.wasPopulated=!0,a}var p=t&&void 0!==t._id?t._id:t,d="function"==typeof this.constructor.cast?this.constructor.cast():h.cast();try{return d(p)}catch(t){throw new l("number",p,this.path,t,this)}},h.prototype.$conditionalHandlers=u.options(o.prototype.$conditionalHandlers,{$bitsAllClear:a,$bitsAnyClear:a,$bitsAllSet:a,$bitsAnySet:a,$gt:p,$gte:p,$lt:p,$lte:p,$mod:function(t){var e=this;return Array.isArray(t)?t.map(function(t){return e.cast(t)}):[this.cast(t)]}}),h.prototype.castForQuery=function(t,e){var r=void 0;if(2===arguments.length){if(!(r=this.$conditionalHandlers[t]))throw new l("number",e,this.path,null,this);return r.call(this,e)}return e=this._castForQuery(t)},
+/*!
+ * Module exports.
+ */
+t.exports=h}).call(this,r(1).Buffer)},function(t,e,r){"use strict";(function(e){
+/*!
+ * Module requirements.
+ */
+var n=r(13);
+/*!
+ * ignore
+ */
+/*!
+ * ignore
+ */
+function i(t,e){var r=Number(e);if(isNaN(r))throw new n("number",e,t);return r}t.exports=function(t){var r=this;return Array.isArray(t)?t.map(function(t){return i(r.path,t)}):e.isBuffer(t)?t:i(r.path,t)}}).call(this,r(1).Buffer)},function(t,e,r){"use strict";var n=new Set(["$ref","$id","$db"]);t.exports=function(t){return t.startsWith("$")&&!n.has(t)}},function(t,e,r){"use strict";
+/*!
+ * Module requirements.
+ */var n=r(32).castArraysOfNumbers,i=r(32).castToNumber;function o(t,e){switch(t.$geometry.type){case"Polygon":case"LineString":case"Point":n(t.$geometry.coordinates,e)}return s(e,t),t}function s(t,e){e.$maxDistance&&(e.$maxDistance=i.call(t,e.$maxDistance)),e.$minDistance&&(e.$minDistance=i.call(t,e.$minDistance))}
+/*!
+ * ignore
+ */
+e.cast$geoIntersects=function(t){if(!t.$geometry)return;return o(t,this),t},e.cast$near=function(t){var e=r(55);if(Array.isArray(t))return n(t,this),t;if(s(this,t),t&&t.$geometry)return o(t,this);return e.prototype.castForQuery.call(this,t)},e.cast$within=function(t){var e=this;if(s(this,t),t.$box||t.$polygon){var r=t.$box?"$box":"$polygon";t[r].forEach(function(t){if(!Array.isArray(t)){var r="Invalid $within $box argument. Expected an array, received "+t;throw new TypeError(r)}t.forEach(function(r,n){t[n]=i.call(e,r)})})}else if(t.$center||t.$centerSphere){var n=t.$center?"$center":"$centerSphere";t[n].forEach(function(r,o){Array.isArray(r)?r.forEach(function(t,n){r[n]=i.call(e,t)}):t[n][o]=i.call(e,r)})}else t.$geometry&&o(t,this);return t}},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(82),i=r(6),o=r(0).arrayAtomicsSymbol,s=r(0).arrayParentSymbol,a=r(0).arrayPathSymbol,u=r(0).arraySchemaSymbol,c=Array.prototype.push;
+/*!
+ * Module exports.
+ */
+t.exports=function(t,e,r){var l=new n;if(l[o]={},Array.isArray(t)){for(var f=t.length,h=0;h0?t:r)}return this}},{key:"_registerAtomic",value:function(t,e){if("$set"===t)return this[p]={$set:e},u(this[d],this[y]),this._markModified(),this;var r=this[p];if("$pop"===t&&!("$pop"in r)){var n=this;this[d].once("save",function(){n._popped=n._shifted=null})}if(this[p].$set||Object.keys(r).length&&!(t in r))return this[p]={$set:this},this;var i=void 0;if("$pullAll"===t||"$addToSet"===t)r[t]||(r[t]=[]),r[t]=r[t].concat(e);else if("$pullDocs"===t){var s=r.$pull||(r.$pull={});e[0]instanceof o?(i=s.$or||(s.$or=[]),Array.prototype.push.apply(i,e.map(function(t){return t.toObject({transform:!1,virtuals:!1})}))):(i=s._id||(s._id={$in:[]})).$in=i.$in.concat(e)}else"$push"===t?(r.$push=r.$push||{$each:[]},null!=e&&f.hasUserDefinedProperty(e,"$each")?r.$push=e:r.$push.$each=r.$push.$each.concat(e)):r[t]=e;return this}},{key:"addToSet",value:function(){w(this,arguments);var t=[].map.call(arguments,this._mapCast,this),e=[],r="";return(t=this[v].applySetters(t,this[d]))[0]instanceof o?r="doc":t[0]instanceof Date&&(r="date"),t.forEach(function(t){var n=void 0,i=+t;switch(r){case"doc":n=this.some(function(e){return e.equals(t)});break;case"date":n=this.some(function(t){return+t===i});break;default:n=~this.indexOf(t)}n||([].push.call(this,t),this._registerAtomic("$addToSet",t),this._markModified(),[].push.call(e,t))},this),e}},{key:"hasAtomics",value:function(){return f.isPOJO(this[p])?Object.keys(this[p]).length:0}},{key:"includes",value:function(t,e){return-1!==this.indexOf(t,e)}},{key:"indexOf",value:function(t,e){t instanceof a&&(t=t.toString()),e=null==e?0:e;for(var r=this.length,n=e;n0&&this._registerAtomic("$set",this),this}},{key:"push",value:function(){var t=arguments,e=t,r=null!=t[0]&&f.hasUserDefinedProperty(t[0],"$each");if(r&&(e=t[0],t=t[0].$each),null==this[v])return m.apply(this,t);w(this,t);var n=this[d];t=[].map.call(t,this._mapCast,this),t=this[v].applySetters(t,n,void 0,void 0,{skipDocumentArrayCast:!0});var i=void 0,o=this[p];if(r){if(e.$each=t,c(o,"$push.$each.length",0)>0&&o.$push.$position!=o.$position)throw new s("Cannot call `Array#push()` multiple times with different `$position`");null!=e.$position?([].splice.apply(this,[e.$position,0].concat(t)),i=this.length):i=[].push.apply(this,t)}else{if(c(o,"$push.$each.length",0)>0&&null!=o.$push.$position)throw new s("Cannot call `Array#push()` multiple times with different `$position`");e=t,i=[].push.apply(this,t)}return this._registerAtomic("$push",e),this._markModified(),i}},{key:"remove",value:function(){return this.pull.apply(this,arguments)}},{key:"set",value:function(t,e){var r=this._cast(e,t);return this[t]=r,this._markModified(t),this}},{key:"shift",value:function(){var t=[].shift.call(this);return this._registerAtomic("$set",this),this._markModified(),t}},{key:"sort",value:function(){var t=[].sort.apply(this,arguments);return this._registerAtomic("$set",this),t}},{key:"splice",value:function(){var t=void 0;if(w(this,Array.prototype.slice.call(arguments,2)),arguments.length){var e=void 0;if(null==this[v])e=arguments;else{e=[];for(var r=0;r0&&
+/*!
+ * ignore
+ */
+function(t,e){if(!e)return!1;for(var r=0;r0&&this._markModified(),t},copy:function(t){var e=s.copy.apply(this,arguments);return t&&t.isMongooseBuffer&&t._markModified(),e}},
+/*!
+ * Compile other Buffer methods marking this buffer as modified.
+ */
+"writeUInt8 writeUInt16 writeUInt32 writeInt8 writeInt16 writeInt32 writeFloat writeDouble fill utf8Write binaryWrite asciiWrite set writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE writeInt16LE writeInt16BE writeInt32LE writeInt32BE writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE".split(" ").forEach(function(t){s[t]&&(a.mixin[t]=function(){var e=s[t].apply(this,arguments);return this._markModified(),e})}),a.mixin.toObject=function(t){var e="number"==typeof t?t:this._subtype||0;return new n(o.from(this),e)},a.mixin.toBSON=function(){return new n(this,this._subtype||0)},a.mixin.equals=function(t){if(!o.isBuffer(t))return!1;if(this.length!==t.length)return!1;for(var e=0;e0?s-4:s;for(r=0;r>16&255,u[l++]=e>>8&255,u[l++]=255&e;2===a&&(e=i[t.charCodeAt(r)]<<2|i[t.charCodeAt(r+1)]>>4,u[l++]=255&e);1===a&&(e=i[t.charCodeAt(r)]<<10|i[t.charCodeAt(r+1)]<<4|i[t.charCodeAt(r+2)]>>2,u[l++]=e>>8&255,u[l++]=255&e);return u},e.fromByteArray=function(t){for(var e,r=t.length,i=r%3,o=[],s=0,a=r-i;sa?a:s+16383));1===i?(e=t[r-1],o.push(n[e>>2]+n[e<<4&63]+"==")):2===i&&(e=(t[r-2]<<8)+t[r-1],o.push(n[e>>10]+n[e>>4&63]+n[e<<2&63]+"="));return o.join("")};for(var n=[],i=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,u=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");return-1===r&&(r=e),[r,r===e?0:4-r%4]}function l(t){return n[t>>18&63]+n[t>>12&63]+n[t>>6&63]+n[63&t]}function f(t,e,r){for(var n,i=[],o=e;o>1,l=-7,f=r?i-1:0,h=r?-1:1,p=t[e+f];for(f+=h,o=p&(1<<-l)-1,p>>=-l,l+=a;l>0;o=256*o+t[e+f],f+=h,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=n;l>0;s=256*s+t[e+f],f+=h,l-=8);if(0===o)o=1-c;else{if(o===u)return s?NaN:1/0*(p?-1:1);s+=Math.pow(2,n),o-=c}return(p?-1:1)*s*Math.pow(2,o-n)},e.write=function(t,e,r,n,i,o){var s,a,u,c=8*o-i-1,l=(1<>1,h=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:o-1,d=n?1:-1,y=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=l):(s=Math.floor(Math.log(e)/Math.LN2),e*(u=Math.pow(2,-s))<1&&(s--,u*=2),(e+=s+f>=1?h/u:h*Math.pow(2,1-f))*u>=2&&(s++,u/=2),s+f>=l?(a=0,s=l):s+f>=1?(a=(e*u-1)*Math.pow(2,i),s+=f):(a=e*Math.pow(2,f-1)*Math.pow(2,i),s=0));i>=8;t[r+p]=255&a,p+=d,a/=256,i-=8);for(s=s<0;t[r+p]=255&s,p+=d,s/=256,c-=8);t[r+p-d]|=128*y}},function(t,e,r){"use strict";var n={}.toString;t.exports=Array.isArray||function(t){return"[object Array]"==n.call(t)}},function(t,e,r){"use strict";
+/*!
+ * Module exports.
+ */e.Binary=r(98),e.Collection=function(){throw new Error("Cannot create a collection from browser library")},e.Decimal128=r(105),e.ObjectId=r(106),e.ReadPreference=r(107)},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(33).Binary;
+/*!
+ * Module exports.
+ */t.exports=n},function(t,e,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};t.exports=function(t){return t&&"object"===(void 0===t?"undefined":n(t))&&"function"==typeof t.copy&&"function"==typeof t.fill&&"function"==typeof t.readUInt8}},function(t,e,r){"use strict";"function"==typeof Object.create?t.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}},function(module,exports,__webpack_require__){"use strict";var Long=__webpack_require__(23).Long,Double=__webpack_require__(34).Double,Timestamp=__webpack_require__(35).Timestamp,ObjectID=__webpack_require__(36).ObjectID,_Symbol=__webpack_require__(38).Symbol,Code=__webpack_require__(39).Code,MinKey=__webpack_require__(41).MinKey,MaxKey=__webpack_require__(42).MaxKey,Decimal128=__webpack_require__(40),Int32=__webpack_require__(60),DBRef=__webpack_require__(43).DBRef,BSONRegExp=__webpack_require__(37).BSONRegExp,Binary=__webpack_require__(26).Binary,utils=__webpack_require__(15),deserialize=function(t,e,r){var n=(e=null==e?{}:e)&&e.index?e.index:0,i=t[n]|t[n+1]<<8|t[n+2]<<16|t[n+3]<<24;if(i<5||t.lengtht.length)throw new Error("corrupt bson message");if(0!==t[n+i-1])throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");return deserializeObject(t,n,e,r)},deserializeObject=function t(e,r,n,i){var o=null!=n.evalFunctions&&n.evalFunctions,s=null!=n.cacheFunctions&&n.cacheFunctions,a=null!=n.cacheFunctionsCrc32&&n.cacheFunctionsCrc32;if(!a)var u=null;var c=null==n.fieldsAsRaw?null:n.fieldsAsRaw,l=null!=n.raw&&n.raw,f="boolean"==typeof n.bsonRegExp&&n.bsonRegExp,h=null!=n.promoteBuffers&&n.promoteBuffers,p=null==n.promoteLongs||n.promoteLongs,d=null==n.promoteValues||n.promoteValues,y=r;if(e.length<5)throw new Error("corrupt bson message < 5 bytes long");var v=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;if(v<5||v>e.length)throw new Error("corrupt bson message");for(var _=i?[]:{},m=0;;){var g=e[r++];if(0===g)break;for(var b=r;0!==e[b]&&b=e.length)throw new Error("Bad BSON Document: illegal CString");var w=i?m++:e.toString("utf8",r,b);if(r=b+1,g===BSON.BSON_DATA_STRING){var O=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;if(O<=0||O>e.length-r||0!==e[r+O-1])throw new Error("bad string length in bson");_[w]=e.toString("utf8",r,r+O-1),r+=O}else if(g===BSON.BSON_DATA_OID){var S=utils.allocBuffer(12);e.copy(S,0,r,r+12),_[w]=new ObjectID(S),r+=12}else if(g===BSON.BSON_DATA_INT&&!1===d)_[w]=new Int32(e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24);else if(g===BSON.BSON_DATA_INT)_[w]=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;else if(g===BSON.BSON_DATA_NUMBER&&!1===d)_[w]=new Double(e.readDoubleLE(r)),r+=8;else if(g===BSON.BSON_DATA_NUMBER)_[w]=e.readDoubleLE(r),r+=8;else if(g===BSON.BSON_DATA_DATE){var E=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24,A=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;_[w]=new Date(new Long(E,A).toNumber())}else if(g===BSON.BSON_DATA_BOOLEAN){if(0!==e[r]&&1!==e[r])throw new Error("illegal boolean type value");_[w]=1===e[r++]}else if(g===BSON.BSON_DATA_OBJECT){var $=r,j=e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24;if(j<=0||j>e.length-r)throw new Error("bad embedded document length in bson");_[w]=l?e.slice(r,r+j):t(e,$,n,!1),r+=j}else if(g===BSON.BSON_DATA_ARRAY){$=r;var x=n,N=r+(j=e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24);if(c&&c[w]){for(var P in x={},n)x[P]=n[P];x.raw=!0}if(_[w]=t(e,$,x,!0),0!==e[(r+=j)-1])throw new Error("invalid array terminator byte");if(r!==N)throw new Error("corrupted array bson")}else if(g===BSON.BSON_DATA_UNDEFINED)_[w]=void 0;else if(g===BSON.BSON_DATA_NULL)_[w]=null;else if(g===BSON.BSON_DATA_LONG){E=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24,A=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;var k=new Long(E,A);_[w]=p&&!0===d&&k.lessThanOrEqual(JS_INT_MAX_LONG)&&k.greaterThanOrEqual(JS_INT_MIN_LONG)?k.toNumber():k}else if(g===BSON.BSON_DATA_DECIMAL128){var T=utils.allocBuffer(16);e.copy(T,0,r,r+16),r+=16;var B=new Decimal128(T);_[w]=B.toObject?B.toObject():B}else if(g===BSON.BSON_DATA_BINARY){var C=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24,D=C,M=e[r++];if(C<0)throw new Error("Negative binary type element size found");if(C>e.length)throw new Error("Binary type size larger than document size");if(null!=e.slice){if(M===Binary.SUBTYPE_BYTE_ARRAY){if((C=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24)<0)throw new Error("Negative binary type element size found for subtype 0x02");if(C>D-4)throw new Error("Binary type with subtype 0x02 contains to long binary size");if(CD-4)throw new Error("Binary type with subtype 0x02 contains to long binary size");if(C=e.length)throw new Error("Bad BSON Document: illegal CString");var F=e.toString("utf8",r,b);for(b=r=b+1;0!==e[b]&&b=e.length)throw new Error("Bad BSON Document: illegal CString");var I=e.toString("utf8",r,b);r=b+1;var L=new Array(I.length);for(b=0;b=e.length)throw new Error("Bad BSON Document: illegal CString");for(F=e.toString("utf8",r,b),b=r=b+1;0!==e[b]&&b=e.length)throw new Error("Bad BSON Document: illegal CString");I=e.toString("utf8",r,b),r=b+1,_[w]=new BSONRegExp(F,I)}else if(g===BSON.BSON_DATA_SYMBOL){if((O=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24)<=0||O>e.length-r||0!==e[r+O-1])throw new Error("bad string length in bson");_[w]=new _Symbol(e.toString("utf8",r,r+O-1)),r+=O}else if(g===BSON.BSON_DATA_TIMESTAMP)E=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24,A=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24,_[w]=new Timestamp(E,A);else if(g===BSON.BSON_DATA_MIN_KEY)_[w]=new MinKey;else if(g===BSON.BSON_DATA_MAX_KEY)_[w]=new MaxKey;else if(g===BSON.BSON_DATA_CODE){if((O=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24)<=0||O>e.length-r||0!==e[r+O-1])throw new Error("bad string length in bson");var U=e.toString("utf8",r,r+O-1);if(o)if(s){var V=a?u(U):U;_[w]=isolateEvalWithHash(functionCache,V,U,_)}else _[w]=isolateEval(U);else _[w]=new Code(U);r+=O}else if(g===BSON.BSON_DATA_CODE_W_SCOPE){var q=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24;if(q<13)throw new Error("code_w_scope total size shorter minimum expected length");if((O=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24)<=0||O>e.length-r||0!==e[r+O-1])throw new Error("bad string length in bson");U=e.toString("utf8",r,r+O-1),$=r+=O,j=e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24;var W=t(e,$,n,!1);if(r+=j,q<8+j+O)throw new Error("code_w_scope total size is to short, truncating scope");if(q>8+j+O)throw new Error("code_w_scope total size is to long, clips outer document");o?(s?(V=a?u(U):U,_[w]=isolateEvalWithHash(functionCache,V,U,_)):_[w]=isolateEval(U),_[w].scope=W):_[w]=new Code(U,W)}else{if(g!==BSON.BSON_DATA_DBPOINTER)throw new Error("Detected unknown BSON type "+g.toString(16)+' for fieldname "'+w+'", are you using the latest BSON parser');if((O=e[r++]|e[r++]<<8|e[r++]<<16|e[r++]<<24)<=0||O>e.length-r||0!==e[r+O-1])throw new Error("bad string length in bson");var H=e.toString("utf8",r,r+O-1);r+=O;var Y=utils.allocBuffer(12);e.copy(Y,0,r,r+12),S=new ObjectID(Y),r+=12;var z=H.split("."),K=z.shift(),Q=z.join(".");_[w]=new DBRef(Q,S,K)}}if(v!==r-y){if(i)throw new Error("corrupt array bson");throw new Error("corrupt object bson")}return null!=_.$id&&(_=new DBRef(_.$ref,_.$id,_.$db)),_},isolateEvalWithHash=function isolateEvalWithHash(functionCache,hash,functionString,object){var value=null;return null==functionCache[hash]&&(eval("value = "+functionString),functionCache[hash]=value),functionCache[hash].bind(object)},isolateEval=function isolateEval(functionString){var value=null;return eval("value = "+functionString),value},BSON={},functionCache=BSON.functionCache={};BSON.BSON_DATA_NUMBER=1,BSON.BSON_DATA_STRING=2,BSON.BSON_DATA_OBJECT=3,BSON.BSON_DATA_ARRAY=4,BSON.BSON_DATA_BINARY=5,BSON.BSON_DATA_UNDEFINED=6,BSON.BSON_DATA_OID=7,BSON.BSON_DATA_BOOLEAN=8,BSON.BSON_DATA_DATE=9,BSON.BSON_DATA_NULL=10,BSON.BSON_DATA_REGEXP=11,BSON.BSON_DATA_DBPOINTER=12,BSON.BSON_DATA_CODE=13,BSON.BSON_DATA_SYMBOL=14,BSON.BSON_DATA_CODE_W_SCOPE=15,BSON.BSON_DATA_INT=16,BSON.BSON_DATA_TIMESTAMP=17,BSON.BSON_DATA_LONG=18,BSON.BSON_DATA_DECIMAL128=19,BSON.BSON_DATA_MIN_KEY=255,BSON.BSON_DATA_MAX_KEY=127,BSON.BSON_BINARY_SUBTYPE_DEFAULT=0,BSON.BSON_BINARY_SUBTYPE_FUNCTION=1,BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY=2,BSON.BSON_BINARY_SUBTYPE_UUID=3,BSON.BSON_BINARY_SUBTYPE_MD5=4,BSON.BSON_BINARY_SUBTYPE_USER_DEFINED=128,BSON.BSON_INT32_MAX=2147483647,BSON.BSON_INT32_MIN=-2147483648,BSON.BSON_INT64_MAX=Math.pow(2,63)-1,BSON.BSON_INT64_MIN=-Math.pow(2,63),BSON.JS_INT_MAX=9007199254740992,BSON.JS_INT_MIN=-9007199254740992;var JS_INT_MAX_LONG=Long.fromNumber(9007199254740992),JS_INT_MIN_LONG=Long.fromNumber(-9007199254740992);module.exports=deserialize},function(t,e,r){"use strict";(function(e){var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(103).writeIEEE754,o=r(23).Long,s=r(59),a=r(26).Binary,u=r(15).normalizedFunctionString,c=/\x00/,l=["$db","$ref","$id","$clusterTime"],f=function(t){return"object"===(void 0===t?"undefined":n(t))&&"[object Date]"===Object.prototype.toString.call(t)},h=function(t){return"[object RegExp]"===Object.prototype.toString.call(t)},p=function(t,e,r,n,i){t[n++]=C.BSON_DATA_STRING,t[(n=n+(i?t.write(e,n,"ascii"):t.write(e,n,"utf8"))+1)-1]=0;var o=t.write(r,n+4,"utf8");return t[n+3]=o+1>>24&255,t[n+2]=o+1>>16&255,t[n+1]=o+1>>8&255,t[n]=o+1&255,n=n+4+o,t[n++]=0,n},d=function(t,e,r,n,s){if(Math.floor(r)===r&&r>=C.JS_INT_MIN&&r<=C.JS_INT_MAX)if(r>=C.BSON_INT32_MIN&&r<=C.BSON_INT32_MAX){t[n++]=C.BSON_DATA_INT;var a=s?t.write(e,n,"ascii"):t.write(e,n,"utf8");n+=a,t[n++]=0,t[n++]=255&r,t[n++]=r>>8&255,t[n++]=r>>16&255,t[n++]=r>>24&255}else if(r>=C.JS_INT_MIN&&r<=C.JS_INT_MAX)t[n++]=C.BSON_DATA_NUMBER,n+=a=s?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,i(t,r,n,"little",52,8),n+=8;else{t[n++]=C.BSON_DATA_LONG,n+=a=s?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var u=o.fromNumber(r),c=u.getLowBits(),l=u.getHighBits();t[n++]=255&c,t[n++]=c>>8&255,t[n++]=c>>16&255,t[n++]=c>>24&255,t[n++]=255&l,t[n++]=l>>8&255,t[n++]=l>>16&255,t[n++]=l>>24&255}else t[n++]=C.BSON_DATA_NUMBER,n+=a=s?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,i(t,r,n,"little",52,8),n+=8;return n},y=function(t,e,r,n,i){return t[n++]=C.BSON_DATA_NULL,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,n},v=function(t,e,r,n,i){return t[n++]=C.BSON_DATA_BOOLEAN,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,t[n++]=r?1:0,n},_=function(t,e,r,n,i){t[n++]=C.BSON_DATA_DATE,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var s=o.fromNumber(r.getTime()),a=s.getLowBits(),u=s.getHighBits();return t[n++]=255&a,t[n++]=a>>8&255,t[n++]=a>>16&255,t[n++]=a>>24&255,t[n++]=255&u,t[n++]=u>>8&255,t[n++]=u>>16&255,t[n++]=u>>24&255,n},m=function(t,e,r,n,i){if(t[n++]=C.BSON_DATA_REGEXP,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,r.source&&null!=r.source.match(c))throw Error("value "+r.source+" must not contain null bytes");return n+=t.write(r.source,n,"utf8"),t[n++]=0,r.global&&(t[n++]=115),r.ignoreCase&&(t[n++]=105),r.multiline&&(t[n++]=109),t[n++]=0,n},g=function(t,e,r,n,i){if(t[n++]=C.BSON_DATA_REGEXP,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,null!=r.pattern.match(c))throw Error("pattern "+r.pattern+" must not contain null bytes");return n+=t.write(r.pattern,n,"utf8"),t[n++]=0,n+=t.write(r.options.split("").sort().join(""),n,"utf8"),t[n++]=0,n},b=function(t,e,r,n,i){return null===r?t[n++]=C.BSON_DATA_NULL:"MinKey"===r._bsontype?t[n++]=C.BSON_DATA_MIN_KEY:t[n++]=C.BSON_DATA_MAX_KEY,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,n},w=function(t,e,r,n,i){if(t[n++]=C.BSON_DATA_OID,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,"string"==typeof r.id)t.write(r.id,n,"binary");else{if(!r.id||!r.id.copy)throw new Error("object ["+JSON.stringify(r)+"] is not a valid ObjectId");r.id.copy(t,n,0,12)}return n+12},O=function(t,e,r,n,i){t[n++]=C.BSON_DATA_BINARY,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var o=r.length;return t[n++]=255&o,t[n++]=o>>8&255,t[n++]=o>>16&255,t[n++]=o>>24&255,t[n++]=C.BSON_BINARY_SUBTYPE_DEFAULT,r.copy(t,n,0,o),n+=o},S=function(t,e,r,n,i,o,s,a,u,c){for(var l=0;l>8&255,t[n++]=o>>16&255,t[n++]=o>>24&255,t[n++]=255&s,t[n++]=s>>8&255,t[n++]=s>>16&255,t[n++]=s>>24&255,n},$=function(t,e,r,n,i){return t[n++]=C.BSON_DATA_INT,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,t[n++]=255&r,t[n++]=r>>8&255,t[n++]=r>>16&255,t[n++]=r>>24&255,n},j=function(t,e,r,n,o){return t[n++]=C.BSON_DATA_NUMBER,n+=o?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0,i(t,r,n,"little",52,8),n+=8},x=function(t,e,r,n,i,o,s){t[n++]=C.BSON_DATA_CODE,n+=s?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var a=u(r),c=t.write(a,n+4,"utf8")+1;return t[n]=255&c,t[n+1]=c>>8&255,t[n+2]=c>>16&255,t[n+3]=c>>24&255,n=n+4+c-1,t[n++]=0,n},N=function(t,e,r,i,o,s,a,u,c){if(r.scope&&"object"===n(r.scope)){t[i++]=C.BSON_DATA_CODE_W_SCOPE;var l=c?t.write(e,i,"ascii"):t.write(e,i,"utf8");i+=l,t[i++]=0;var f=i,h="string"==typeof r.code?r.code:r.code.toString();i+=4;var p=t.write(h,i+4,"utf8")+1;t[i]=255&p,t[i+1]=p>>8&255,t[i+2]=p>>16&255,t[i+3]=p>>24&255,t[i+4+p-1]=0,i=i+p+4;var d=B(t,r.scope,o,i,s+1,a,u);i=d-1;var y=d-f;t[f++]=255&y,t[f++]=y>>8&255,t[f++]=y>>16&255,t[f++]=y>>24&255,t[i++]=0}else{t[i++]=C.BSON_DATA_CODE,i+=l=c?t.write(e,i,"ascii"):t.write(e,i,"utf8"),t[i++]=0,h=r.code.toString();var v=t.write(h,i+4,"utf8")+1;t[i]=255&v,t[i+1]=v>>8&255,t[i+2]=v>>16&255,t[i+3]=v>>24&255,i=i+4+v-1,t[i++]=0}return i},P=function(t,e,r,n,i){t[n++]=C.BSON_DATA_BINARY,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var o=r.value(!0),s=r.position;return r.sub_type===a.SUBTYPE_BYTE_ARRAY&&(s+=4),t[n++]=255&s,t[n++]=s>>8&255,t[n++]=s>>16&255,t[n++]=s>>24&255,t[n++]=r.sub_type,r.sub_type===a.SUBTYPE_BYTE_ARRAY&&(s-=4,t[n++]=255&s,t[n++]=s>>8&255,t[n++]=s>>16&255,t[n++]=s>>24&255),o.copy(t,n,0,r.position),n+=r.position},k=function(t,e,r,n,i){t[n++]=C.BSON_DATA_SYMBOL,n+=i?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var o=t.write(r.value,n+4,"utf8")+1;return t[n]=255&o,t[n+1]=o>>8&255,t[n+2]=o>>16&255,t[n+3]=o>>24&255,n=n+4+o-1,t[n++]=0,n},T=function(t,e,r,n,i,o,s){t[n++]=C.BSON_DATA_OBJECT,n+=s?t.write(e,n,"ascii"):t.write(e,n,"utf8"),t[n++]=0;var a,u=n,c=(a=null!=r.db?B(t,{$ref:r.namespace,$id:r.oid,$db:r.db},!1,n,i+1,o):B(t,{$ref:r.namespace,$id:r.oid},!1,n,i+1,o))-u;return t[u++]=255&c,t[u++]=c>>8&255,t[u++]=c>>16&255,t[u++]=c>>24&255,a},B=function(t,r,i,o,a,u,B,C){o=o||0,(C=C||[]).push(r);var D=o+4;if(Array.isArray(r))for(var M=0;M>8&255,t[o++]=q>>16&255,t[o++]=q>>24&255,D},C={BSON_DATA_NUMBER:1,BSON_DATA_STRING:2,BSON_DATA_OBJECT:3,BSON_DATA_ARRAY:4,BSON_DATA_BINARY:5,BSON_DATA_UNDEFINED:6,BSON_DATA_OID:7,BSON_DATA_BOOLEAN:8,BSON_DATA_DATE:9,BSON_DATA_NULL:10,BSON_DATA_REGEXP:11,BSON_DATA_CODE:13,BSON_DATA_SYMBOL:14,BSON_DATA_CODE_W_SCOPE:15,BSON_DATA_INT:16,BSON_DATA_TIMESTAMP:17,BSON_DATA_LONG:18,BSON_DATA_DECIMAL128:19,BSON_DATA_MIN_KEY:255,BSON_DATA_MAX_KEY:127,BSON_BINARY_SUBTYPE_DEFAULT:0,BSON_BINARY_SUBTYPE_FUNCTION:1,BSON_BINARY_SUBTYPE_BYTE_ARRAY:2,BSON_BINARY_SUBTYPE_UUID:3,BSON_BINARY_SUBTYPE_MD5:4,BSON_BINARY_SUBTYPE_USER_DEFINED:128,BSON_INT32_MAX:2147483647,BSON_INT32_MIN:-2147483648};C.BSON_INT64_MAX=Math.pow(2,63)-1,C.BSON_INT64_MIN=-Math.pow(2,63),C.JS_INT_MAX=9007199254740992,C.JS_INT_MIN=-9007199254740992,t.exports=B}).call(this,r(1).Buffer)},function(t,e,r){"use strict";e.readIEEE754=function(t,e,r,n,i){var o,s,a="big"===r,u=8*i-n-1,c=(1<>1,f=-7,h=a?0:i-1,p=a?1:-1,d=t[e+h];for(h+=p,o=d&(1<<-f)-1,d>>=-f,f+=u;f>0;o=256*o+t[e+h],h+=p,f-=8);for(s=o&(1<<-f)-1,o>>=-f,f+=n;f>0;s=256*s+t[e+h],h+=p,f-=8);if(0===o)o=1-l;else{if(o===c)return s?NaN:1/0*(d?-1:1);s+=Math.pow(2,n),o-=l}return(d?-1:1)*s*Math.pow(2,o-n)},e.writeIEEE754=function(t,e,r,n,i,o){var s,a,u,c="big"===n,l=8*o-i-1,f=(1<>1,p=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,d=c?o-1:0,y=c?-1:1,v=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=f):(s=Math.floor(Math.log(e)/Math.LN2),e*(u=Math.pow(2,-s))<1&&(s--,u*=2),(e+=s+h>=1?p/u:p*Math.pow(2,1-h))*u>=2&&(s++,u/=2),s+h>=f?(a=0,s=f):s+h>=1?(a=(e*u-1)*Math.pow(2,i),s+=h):(a=e*Math.pow(2,h-1)*Math.pow(2,i),s=0));i>=8;t[r+d]=255&a,d+=y,a/=256,i-=8);for(s=s<0;t[r+d]=255&s,d+=y,s/=256,l-=8);t[r+d-y]|=128*v}},function(t,e,r){"use strict";(function(e){var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(23).Long,o=r(34).Double,s=r(35).Timestamp,a=r(36).ObjectID,u=r(38).Symbol,c=r(37).BSONRegExp,l=r(39).Code,f=r(40),h=r(41).MinKey,p=r(42).MaxKey,d=r(43).DBRef,y=r(26).Binary,v=r(15).normalizedFunctionString,_=function(t){return"object"===(void 0===t?"undefined":n(t))&&"[object Date]"===Object.prototype.toString.call(t)},m=function(t,e,r){var n=5;if(Array.isArray(t))for(var i=0;i=b.JS_INT_MIN&&r<=b.JS_INT_MAX&&r>=b.BSON_INT32_MIN&&r<=b.BSON_INT32_MAX?(null!=t?e.byteLength(t,"utf8")+1:0)+5:(null!=t?e.byteLength(t,"utf8")+1:0)+9;case"undefined":return w||!O?(null!=t?e.byteLength(t,"utf8")+1:0)+1:0;case"boolean":return(null!=t?e.byteLength(t,"utf8")+1:0)+2;case"object":if(null==r||r instanceof h||r instanceof p||"MinKey"===r._bsontype||"MaxKey"===r._bsontype)return(null!=t?e.byteLength(t,"utf8")+1:0)+1;if(r instanceof a||"ObjectID"===r._bsontype||"ObjectId"===r._bsontype)return(null!=t?e.byteLength(t,"utf8")+1:0)+13;if(r instanceof Date||_(r))return(null!=t?e.byteLength(t,"utf8")+1:0)+9;if(void 0!==e&&e.isBuffer(r))return(null!=t?e.byteLength(t,"utf8")+1:0)+6+r.length;if(r instanceof i||r instanceof o||r instanceof s||"Long"===r._bsontype||"Double"===r._bsontype||"Timestamp"===r._bsontype)return(null!=t?e.byteLength(t,"utf8")+1:0)+9;if(r instanceof f||"Decimal128"===r._bsontype)return(null!=t?e.byteLength(t,"utf8")+1:0)+17;if(r instanceof l||"Code"===r._bsontype)return null!=r.scope&&Object.keys(r.scope).length>0?(null!=t?e.byteLength(t,"utf8")+1:0)+1+4+4+e.byteLength(r.code.toString(),"utf8")+1+m(r.scope,g,O):(null!=t?e.byteLength(t,"utf8")+1:0)+1+4+e.byteLength(r.code.toString(),"utf8")+1;if(r instanceof y||"Binary"===r._bsontype)return r.sub_type===y.SUBTYPE_BYTE_ARRAY?(null!=t?e.byteLength(t,"utf8")+1:0)+(r.position+1+4+1+4):(null!=t?e.byteLength(t,"utf8")+1:0)+(r.position+1+4+1);if(r instanceof u||"Symbol"===r._bsontype)return(null!=t?e.byteLength(t,"utf8")+1:0)+e.byteLength(r.value,"utf8")+4+1+1;if(r instanceof d||"DBRef"===r._bsontype){var S={$ref:r.namespace,$id:r.oid};return null!=r.db&&(S.$db=r.db),(null!=t?e.byteLength(t,"utf8")+1:0)+1+m(S,g,O)}return r instanceof RegExp||"[object RegExp]"===Object.prototype.toString.call(r)?(null!=t?e.byteLength(t,"utf8")+1:0)+1+e.byteLength(r.source,"utf8")+1+(r.global?1:0)+(r.ignoreCase?1:0)+(r.multiline?1:0)+1:r instanceof c||"BSONRegExp"===r._bsontype?(null!=t?e.byteLength(t,"utf8")+1:0)+1+e.byteLength(r.pattern,"utf8")+1+e.byteLength(r.options,"utf8")+1:(null!=t?e.byteLength(t,"utf8")+1:0)+m(r,g,O)+1;case"function":if(r instanceof RegExp||"[object RegExp]"===Object.prototype.toString.call(r)||"[object RegExp]"===String.call(r))return(null!=t?e.byteLength(t,"utf8")+1:0)+1+e.byteLength(r.source,"utf8")+1+(r.global?1:0)+(r.ignoreCase?1:0)+(r.multiline?1:0)+1;if(g&&null!=r.scope&&Object.keys(r.scope).length>0)return(null!=t?e.byteLength(t,"utf8")+1:0)+1+4+4+e.byteLength(v(r),"utf8")+1+m(r.scope,g,O);if(g)return(null!=t?e.byteLength(t,"utf8")+1:0)+1+4+e.byteLength(v(r),"utf8")+1}return 0}var b={BSON_INT32_MAX:2147483647,BSON_INT32_MIN:-2147483648,JS_INT_MAX:9007199254740992,JS_INT_MIN:-9007199254740992};t.exports=m}).call(this,r(1).Buffer)},function(t,e,r){"use strict";
+/*!
+ * ignore
+ */t.exports=r(33).Decimal128},function(t,e,r){"use strict";
+/*!
+ * [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
+ * @constructor NodeMongoDbObjectId
+ * @see ObjectId
+ */var n=r(33).ObjectID;
+/*!
+ * Getter for convenience with populate, see gh-6115
+ */Object.defineProperty(n.prototype,"_id",{enumerable:!1,configurable:!0,get:function(){return this}}),
+/*!
+ * ignore
+ */
+t.exports=n},function(t,e,r){"use strict";
+/*!
+ * ignore
+ */t.exports=function(){}},function(t,e,r){"use strict";
+/*!
+ * Dependencies
+ */var n=r(109).ctor("require","modify","init","default","ignore");t.exports=function(){this.strictMode=void 0,this.selected=void 0,this.shardval=void 0,this.saveError=void 0,this.validationError=void 0,this.adhocPaths=void 0,this.removing=void 0,this.inserting=void 0,this.saving=void 0,this.version=void 0,this.getters={},this._id=void 0,this.populate=void 0,this.populated=void 0,this.wasPopulated=!1,this.scope=void 0,this.activePaths=new n,this.pathsToScopes={},this.cachedRequired={},this.session=null,this.$setCalled=new Set,this.ownerDocument=void 0,this.fullPath=void 0}},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(2),i=t.exports=function(){};
+/*!
+ * StateMachine represents a minimal `interface` for the
+ * constructors it builds via StateMachine.ctor(...).
+ *
+ * @api private
+ */
+/*!
+ * StateMachine.ctor('state1', 'state2', ...)
+ * A factory method for subclassing StateMachine.
+ * The arguments are a list of states. For each state,
+ * the constructor's prototype gets state transition
+ * methods named after each state. These transition methods
+ * place their path argument into the given state.
+ *
+ * @param {String} state
+ * @param {String} [state]
+ * @return {Function} subclass constructor
+ * @private
+ */
+i.ctor=function(){var t=n.args(arguments),e=function(){i.apply(this,arguments),this.paths={},this.states={},this.stateNames=t;for(var e=t.length,r=void 0;e--;)r=t[e],this.states[r]={}};return e.prototype=new i,t.forEach(function(t){e.prototype[t]=function(e){this._changeState(e,t)}}),e},
+/*!
+ * This function is wrapped by the state change functions:
+ *
+ * - `require(path)`
+ * - `modify(path)`
+ * - `init(path)`
+ *
+ * @api private
+ */
+i.prototype._changeState=function(t,e){var r=this.states[this.paths[t]];r&&delete r[t],this.paths[t]=e,this.states[e][t]=!0},
+/*!
+ * ignore
+ */
+i.prototype.clear=function(t){for(var e=Object.keys(this.states[t]),r=e.length,n=void 0;r--;)n=e[r],delete this.states[t][n],delete this.paths[n]},
+/*!
+ * Checks to see if at least one path is in the states passed in via `arguments`
+ * e.g., this.some('required', 'inited')
+ *
+ * @param {String} state that we want to check for.
+ * @private
+ */
+i.prototype.some=function(){var t=this,e=arguments.length?arguments:this.stateNames;return Array.prototype.some.call(e,function(e){return Object.keys(t.states[e]).length})},
+/*!
+ * This function builds the functions that get assigned to `forEach` and `map`,
+ * since both of those methods share a lot of the same logic.
+ *
+ * @param {String} iterMethod is either 'forEach' or 'map'
+ * @return {Function}
+ * @api private
+ */
+i.prototype._iter=function(t){return function(){var e=arguments.length,r=n.args(arguments,0,e-1),i=arguments[e-1];r.length||(r=this.stateNames);var o=this;return r.reduce(function(t,e){return t.concat(Object.keys(o.states[e]))},[])[t](function(t,e,r){return i(t,e,r)})}},
+/*!
+ * Iterates over the paths that belong to one of the parameter states.
+ *
+ * The function profile can look like:
+ * this.forEach(state1, fn); // iterates over all paths in state1
+ * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
+ * this.forEach(fn); // iterates over all paths in all states
+ *
+ * @param {String} [state]
+ * @param {String} [state]
+ * @param {Function} callback
+ * @private
+ */
+i.prototype.forEach=function(){return this.forEach=this._iter("forEach"),this.forEach.apply(this,arguments)},
+/*!
+ * Maps over the paths that belong to one of the parameter states.
+ *
+ * The function profile can look like:
+ * this.forEach(state1, fn); // iterates over all paths in state1
+ * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
+ * this.forEach(fn); // iterates over all paths in all states
+ *
+ * @param {String} [state]
+ * @param {String} [state]
+ * @param {Function} callback
+ * @return {Array}
+ * @private
+ */
+i.prototype.map=function(){return this.map=this._iter("map"),this.map.apply(this,arguments)}},function(t,e,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=1e3,o=60*i,s=60*o,a=24*s,u=7*a,c=365.25*a;function l(t,e,r,n){var i=e>=1.5*r;return Math.round(t/r)+" "+n+(i?"s":"")}t.exports=function(t,e){e=e||{};var r=void 0===t?"undefined":n(t);if("string"===r&&t.length>0)return function(t){if((t=String(t)).length>100)return;var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(!e)return;var r=parseFloat(e[1]);switch((e[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return r*c;case"weeks":case"week":case"w":return r*u;case"days":case"day":case"d":return r*a;case"hours":case"hour":case"hrs":case"hr":case"h":return r*s;case"minutes":case"minute":case"mins":case"min":case"m":return r*o;case"seconds":case"second":case"secs":case"sec":case"s":return r*i;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(t);if("number"===r&&isFinite(t))return e.long?function(t){var e=Math.abs(t);if(e>=a)return l(t,e,a,"day");if(e>=s)return l(t,e,s,"hour");if(e>=o)return l(t,e,o,"minute");if(e>=i)return l(t,e,i,"second");return t+" ms"}(t):function(t){var e=Math.abs(t);if(e>=a)return Math.round(t/a)+"d";if(e>=s)return Math.round(t/s)+"h";if(e>=o)return Math.round(t/o)+"m";if(e>=i)return Math.round(t/i)+"s";return t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=["__proto__","constructor","prototype"];
+/*!
+ * Returns the value passed to it.
+ */
+function o(t){return t}e.get=function(t,r,n,i){var s;"function"==typeof n&&(n.length<2?(i=n,n=void 0):(s=n,n=void 0)),i||(i=o);var a="string"==typeof t?t.split("."):t;if(!Array.isArray(a))throw new TypeError("Invalid `path`. Must be either string or array");for(var u,c=r,l=0;l");t.sort.set(r,n)})}
+/*!
+ * limit, skip, maxScan, batchSize, comment
+ *
+ * Sets these associated options.
+ *
+ * query.comment('feed query');
+ */(this.options,t),this;throw new TypeError("Invalid sort() argument. Must be a string, object, or array.")};
+/*!
+ * @ignore
+ */
+var f={1:1,"-1":-1,asc:1,ascending:1,desc:-1,descending:-1};function h(t,e,r){if(Array.isArray(t.sort))throw new TypeError("Can't mix sort syntaxes. Use either array or object:\n- `.sort([['field', 1], ['test', -1]])`\n- `.sort({ field: 1, test: -1 })`");var n;if(r&&r.$meta)(n=t.sort||(t.sort={}))[e]={$meta:r.$meta};else{n=t.sort||(t.sort={});var i=String(r||1).toLowerCase();if(!(i=f[i]))throw new TypeError("Invalid sort value: { "+e+": "+r+" }");n[e]=i}}function p(t,e,r){if(t.sort=t.sort||[],!Array.isArray(t.sort))throw new TypeError("Can't mix sort syntaxes. Use either array or object:\n- `.sort([['field', 1], ['test', -1]])`\n- `.sort({ field: 1, test: -1 })`");var n=String(r||1).toLowerCase();if(!(n=f[n]))throw new TypeError("Invalid sort value: [ "+e+", "+r+" ]");t.sort.push([e,n])}
+/*!
+ * Internal helper for update, updateMany, updateOne
+ */
+function d(t,e,r,n,i,o,s){return t.op=e,c.canMerge(r)&&t.merge(r),n&&t._mergeUpdate(n),a.isObject(i)&&t.setOptions(i),o||s?!t._update||!t.options.overwrite&&0===a.keys(t._update).length?(s&&a.soon(s.bind(null,null,0)),t):(i=t._optionsForExec(),s||(i.safe=!1),r=t._conditions,n=t._updateForExec(),u("update",t._collection.collectionName,r,n,i),s=t._wrapCallback(e,s,{conditions:r,doc:n,options:i}),t._collection[e](r,n,i,a.tick(s)),t):t}["limit","skip","maxScan","batchSize","comment"].forEach(function(t){c.prototype[t]=function(e){return this._validate(t),this.options[t]=e,this}}),c.prototype.maxTime=c.prototype.maxTimeMS=function(t){return this._validate("maxTime"),this.options.maxTimeMS=t,this},c.prototype.snapshot=function(){return this._validate("snapshot"),this.options.snapshot=!arguments.length||!!arguments[0],this},c.prototype.hint=function(){if(0===arguments.length)return this;this._validate("hint");var t=arguments[0];if(a.isObject(t)){var e=this.options.hint||(this.options.hint={});for(var r in t)e[r]=t[r];return this}if("string"==typeof t)return this.options.hint=t,this;throw new TypeError("Invalid hint. "+t)},c.prototype.j=function(t){return this.options.j=t,this},c.prototype.slaveOk=function(t){return this.options.slaveOk=!arguments.length||!!t,this},c.prototype.read=c.prototype.setReadPreference=function(t){return arguments.length>1&&!c.prototype.read.deprecationWarningIssued&&(console.error("Deprecation warning: 'tags' argument is not supported anymore in Query.read() method. Please use mongodb.ReadPreference object instead."),c.prototype.read.deprecationWarningIssued=!0),this.options.readPreference=a.readPref(t),this},c.prototype.readConcern=c.prototype.r=function(t){return this.options.readConcern=a.readConcern(t),this},c.prototype.tailable=function(){return this._validate("tailable"),this.options.tailable=!arguments.length||!!arguments[0],this},c.prototype.writeConcern=c.prototype.w=function(t){return"object"===(void 0===t?"undefined":n(t))?(void 0!==t.j&&(this.options.j=t.j),void 0!==t.w&&(this.options.w=t.w),void 0!==t.wtimeout&&(this.options.wtimeout=t.wtimeout)):this.options.w="m"===t?"majority":t,this},c.prototype.wtimeout=c.prototype.wTimeout=function(t){return this.options.wtimeout=t,this},c.prototype.merge=function(t){if(!t)return this;if(!c.canMerge(t))throw new TypeError("Invalid argument. Expected instanceof mquery or plain object");return t instanceof c?(t._conditions&&a.merge(this._conditions,t._conditions),t._fields&&(this._fields||(this._fields={}),a.merge(this._fields,t._fields)),t.options&&(this.options||(this.options={}),a.merge(this.options,t.options)),t._update&&(this._update||(this._update={}),a.mergeClone(this._update,t._update)),t._distinct&&(this._distinct=t._distinct),this):(a.merge(this._conditions,t),this)},c.prototype.find=function(t,e){if(this.op="find","function"==typeof t?(e=t,t=void 0):c.canMerge(t)&&this.merge(t),!e)return this;var r=this._conditions,n=this._optionsForExec();return this.$useProjection?n.projection=this._fieldsForExec():n.fields=this._fieldsForExec(),u("find",this._collection.collectionName,r,n),e=this._wrapCallback("find",e,{conditions:r,options:n}),this._collection.find(r,n,a.tick(e)),this},c.prototype.cursor=function(t){if(this.op){if("find"!==this.op)throw new TypeError(".cursor only support .find method")}else this.find(t);var e=this._conditions,r=this._optionsForExec();return this.$useProjection?r.projection=this._fieldsForExec():r.fields=this._fieldsForExec(),u("findCursor",this._collection.collectionName,e,r),this._collection.findCursor(e,r)},c.prototype.findOne=function(t,e){if(this.op="findOne","function"==typeof t?(e=t,t=void 0):c.canMerge(t)&&this.merge(t),!e)return this;var r=this._conditions,n=this._optionsForExec();return this.$useProjection?n.projection=this._fieldsForExec():n.fields=this._fieldsForExec(),u("findOne",this._collection.collectionName,r,n),e=this._wrapCallback("findOne",e,{conditions:r,options:n}),this._collection.findOne(r,n,a.tick(e)),this},c.prototype.count=function(t,e){if(this.op="count",this._validate(),"function"==typeof t?(e=t,t=void 0):c.canMerge(t)&&this.merge(t),!e)return this;var r=this._conditions,n=this._optionsForExec();return u("count",this._collection.collectionName,r,n),e=this._wrapCallback("count",e,{conditions:r,options:n}),this._collection.count(r,n,a.tick(e)),this},c.prototype.distinct=function(t,e,r){if(this.op="distinct",this._validate(),!r){switch(void 0===e?"undefined":n(e)){case"function":r=e,"string"==typeof t&&(e=t,t=void 0);break;case"undefined":case"string":break;default:throw new TypeError("Invalid `field` argument. Must be string or function")}switch(void 0===t?"undefined":n(t)){case"function":r=t,t=e=void 0;break;case"string":e=t,t=void 0}}if("string"==typeof e&&(this._distinct=e),c.canMerge(t)&&this.merge(t),!r)return this;if(!this._distinct)throw new Error("No value for `distinct` has been declared");var i=this._conditions,o=this._optionsForExec();return u("distinct",this._collection.collectionName,i,o),r=this._wrapCallback("distinct",r,{conditions:i,options:o}),this._collection.distinct(this._distinct,i,o,a.tick(r)),this},c.prototype.update=function(t,e,r,i){var o;switch(arguments.length){case 3:"function"==typeof r&&(i=r,r=void 0);break;case 2:"function"==typeof e&&(i=e,e=t,t=void 0);break;case 1:switch(void 0===t?"undefined":n(t)){case"function":i=t,t=r=e=void 0;break;case"boolean":o=t,t=void 0;break;default:e=t,t=r=void 0}}return d(this,"update",t,e,r,o,i)},c.prototype.updateMany=function(t,e,r,i){var o;switch(arguments.length){case 3:"function"==typeof r&&(i=r,r=void 0);break;case 2:"function"==typeof e&&(i=e,e=t,t=void 0);break;case 1:switch(void 0===t?"undefined":n(t)){case"function":i=t,t=r=e=void 0;break;case"boolean":o=t,t=void 0;break;default:e=t,t=r=void 0}}return d(this,"updateMany",t,e,r,o,i)},c.prototype.updateOne=function(t,e,r,i){var o;switch(arguments.length){case 3:"function"==typeof r&&(i=r,r=void 0);break;case 2:"function"==typeof e&&(i=e,e=t,t=void 0);break;case 1:switch(void 0===t?"undefined":n(t)){case"function":i=t,t=r=e=void 0;break;case"boolean":o=t,t=void 0;break;default:e=t,t=r=void 0}}return d(this,"updateOne",t,e,r,o,i)},c.prototype.replaceOne=function(t,e,r,i){var o;switch(arguments.length){case 3:"function"==typeof r&&(i=r,r=void 0);break;case 2:"function"==typeof e&&(i=e,e=t,t=void 0);break;case 1:switch(void 0===t?"undefined":n(t)){case"function":i=t,t=r=e=void 0;break;case"boolean":o=t,t=void 0;break;default:e=t,t=r=void 0}}return this.setOptions({overwrite:!0}),d(this,"replaceOne",t,e,r,o,i)},c.prototype.remove=function(t,e){var r;if(this.op="remove","function"==typeof t?(e=t,t=void 0):c.canMerge(t)?this.merge(t):!0===t&&(r=t,t=void 0),!r&&!e)return this;var n=this._optionsForExec();e||(n.safe=!1);var i=this._conditions;return u("remove",this._collection.collectionName,i,n),e=this._wrapCallback("remove",e,{conditions:i,options:n}),this._collection.remove(i,n,a.tick(e)),this},c.prototype.deleteOne=function(t,e){var r;if(this.op="deleteOne","function"==typeof t?(e=t,t=void 0):c.canMerge(t)?this.merge(t):!0===t&&(r=t,t=void 0),!r&&!e)return this;var n=this._optionsForExec();e||(n.safe=!1),delete n.justOne;var i=this._conditions;return u("deleteOne",this._collection.collectionName,i,n),e=this._wrapCallback("deleteOne",e,{conditions:i,options:n}),this._collection.deleteOne(i,n,a.tick(e)),this},c.prototype.deleteMany=function(t,e){var r;if(this.op="deleteMany","function"==typeof t?(e=t,t=void 0):c.canMerge(t)?this.merge(t):!0===t&&(r=t,t=void 0),!r&&!e)return this;var n=this._optionsForExec();e||(n.safe=!1),delete n.justOne;var i=this._conditions;return u("deleteOne",this._collection.collectionName,i,n),e=this._wrapCallback("deleteOne",e,{conditions:i,options:n}),this._collection.deleteMany(i,n,a.tick(e)),this},c.prototype.findOneAndUpdate=function(t,e,r,n){switch(this.op="findOneAndUpdate",this._validate(),arguments.length){case 3:"function"==typeof r&&(n=r,r={});break;case 2:"function"==typeof e&&(n=e,e=t,t=void 0),r=void 0;break;case 1:"function"==typeof t?(n=t,t=r=e=void 0):(e=t,t=r=void 0)}return c.canMerge(t)&&this.merge(t),e&&this._mergeUpdate(e),r&&this.setOptions(r),n?this._findAndModify("update",n):this},c.prototype.findOneAndRemove=c.prototype.findOneAndDelete=function(t,e,r){return this.op="findOneAndRemove",this._validate(),"function"==typeof e?(r=e,e=void 0):"function"==typeof t&&(r=t,t=void 0),c.canMerge(t)&&this.merge(t),e&&this.setOptions(e),r?this._findAndModify("remove",r):this},c.prototype._findAndModify=function(t,e){o.equal("function",void 0===e?"undefined":n(e));var r,i=this._optionsForExec();if("remove"==t)i.remove=!0;else if("new"in i||(i.new=!0),"upsert"in i||(i.upsert=!1),!(r=this._updateForExec())){if(!i.upsert)return this.findOne(e);r={$set:{}}}null!=this._fieldsForExec()&&(this.$useProjection?i.projection=this._fieldsForExec():i.fields=this._fieldsForExec());var s=this._conditions;return u("findAndModify",this._collection.collectionName,s,r,i),e=this._wrapCallback("findAndModify",e,{conditions:s,doc:r,options:i}),this._collection.findAndModify(s,r,i,a.tick(e)),this},c.prototype._wrapCallback=function(t,e,r){var n=this._traceFunction||c.traceFunction;if(n){r.collectionName=this._collection.collectionName;var i=n&&n.call(null,t,r,this),o=(new Date).getTime();return function(t,r){if(i){var n=(new Date).getTime()-o;i.call(null,t,r,n)}e&&e.apply(null,arguments)}}return e},c.prototype.setTraceFunction=function(t){return this._traceFunction=t,this},c.prototype.exec=function(t,e){switch(void 0===t?"undefined":n(t)){case"function":e=t,t=null;break;case"string":this.op=t}o.ok(this.op,"Missing query type: (find, update, etc)"),"update"!=this.op&&"remove"!=this.op||e||(e=!0);var r=this;if("function"!=typeof e)return new c.Promise(function(t,e){r[r.op](function(r,n){r?e(r):t(n),t=e=null})});this[this.op](e)},c.prototype.thunk=function(){var t=this;return function(e){t.exec(e)}},c.prototype.then=function(t,e){var r=this;return new c.Promise(function(t,e){r.exec(function(r,n){r?e(r):t(n),t=e=null})}).then(t,e)},c.prototype.stream=function(t){if("find"!=this.op)throw new Error("stream() is only available for find");var e=this._conditions,r=this._optionsForExec();return this.$useProjection?r.projection=this._fieldsForExec():r.fields=this._fieldsForExec(),u("stream",this._collection.collectionName,e,r,t),this._collection.findStream(e,r,t)},c.prototype.selected=function(){return!!(this._fields&&Object.keys(this._fields).length>0)},c.prototype.selectedInclusively=function(){if(!this._fields)return!1;var t=Object.keys(this._fields);if(0===t.length)return!1;for(var e=0;e=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},e.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(t){}}(),e.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},e.enable(o())}).call(this,r(8))},function(t,e,r){"use strict";function n(t){var r;function n(){if(n.enabled){var t=n,i=+new Date,o=i-(r||i);t.diff=o,t.prev=r,t.curr=i,r=i;for(var s=new Array(arguments.length),a=0;a0)return function(t){if((t=String(t)).length>100)return;var e=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(t);if(!e)return;var r=parseFloat(e[1]);switch((e[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return r*u;case"days":case"day":case"d":return r*a;case"hours":case"hour":case"hrs":case"hr":case"h":return r*s;case"minutes":case"minute":case"mins":case"min":case"m":return r*o;case"seconds":case"second":case"secs":case"sec":case"s":return r*i;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(t);if("number"===r&&!1===isNaN(t))return e.long?function(t){return c(t,a,"day")||c(t,s,"hour")||c(t,o,"minute")||c(t,i,"second")||t+" ms"}(t):function(t){if(t>=a)return Math.round(t/a)+"d";if(t>=s)return Math.round(t/s)+"h";if(t>=o)return Math.round(t/o)+"m";if(t>=i)return Math.round(t/i)+"s";return t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,r){"use strict";var n=e;n.distinct=function(t){return t._fields&&Object.keys(t._fields).length>0?"field selection and slice":(Object.keys(n.distinct).every(function(r){return!t.options[r]||(e=r,!1)}),e);var e},n.distinct.select=n.distinct.slice=n.distinct.sort=n.distinct.limit=n.distinct.skip=n.distinct.batchSize=n.distinct.comment=n.distinct.maxScan=n.distinct.snapshot=n.distinct.hint=n.distinct.tailable=!0,n.findOneAndUpdate=n.findOneAndRemove=function(t){var e;return Object.keys(n.findOneAndUpdate).every(function(r){return!t.options[r]||(e=r,!1)}),e},n.findOneAndUpdate.limit=n.findOneAndUpdate.skip=n.findOneAndUpdate.batchSize=n.findOneAndUpdate.maxScan=n.findOneAndUpdate.snapshot=n.findOneAndUpdate.hint=n.findOneAndUpdate.tailable=n.findOneAndUpdate.comment=!0,n.count=function(t){return t._fields&&Object.keys(t._fields).length>0?"field selection and slice":(Object.keys(n.count).every(function(r){return!t.options[r]||(e=r,!1)}),e);var e},n.count.slice=n.count.batchSize=n.count.comment=n.count.maxScan=n.count.snapshot=n.count.tailable=!0},function(t,e,r){"use strict";t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,e,r){"use strict";var n=r(69);if("unknown"==n.type)throw new Error("Unknown environment");t.exports=n.isNode?r(122):(n.isMongo,r(28))},function(t,e,r){"use strict";var n=r(28);function i(t){this.collection=t,this.collectionName=t.collectionName}r(67).inherits(i,n),i.prototype.find=function(t,e,r){this.collection.find(t,e,function(t,e){if(t)return r(t);try{e.toArray(r)}catch(t){r(t)}})},i.prototype.findOne=function(t,e,r){this.collection.findOne(t,e,r)},i.prototype.count=function(t,e,r){this.collection.count(t,e,r)},i.prototype.distinct=function(t,e,r,n){this.collection.distinct(t,e,r,n)},i.prototype.update=function(t,e,r,n){this.collection.update(t,e,r,n)},i.prototype.updateMany=function(t,e,r,n){this.collection.updateMany(t,e,r,n)},i.prototype.updateOne=function(t,e,r,n){this.collection.updateOne(t,e,r,n)},i.prototype.replaceOne=function(t,e,r,n){this.collection.replaceOne(t,e,r,n)},i.prototype.deleteOne=function(t,e,r){this.collection.deleteOne(t,e,r)},i.prototype.deleteMany=function(t,e,r){this.collection.deleteMany(t,e,r)},i.prototype.remove=function(t,e,r){this.collection.remove(t,e,r)},i.prototype.findAndModify=function(t,e,r,n){var i=Array.isArray(r.sort)?r.sort:[];this.collection.findAndModify(t,i,e,r,n)},i.prototype.findStream=function(t,e,r){return this.collection.find(t,e).stream(r)},i.prototype.findCursor=function(t,e){return this.collection.find(t,e)},t.exports=i},function(t,e,r){"use strict";(function(r,n,i){var o,s,a,u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};!function(r){"object"==u(e)&&void 0!==t?t.exports=r():(s=[],void 0===(a="function"==typeof(o=r)?o.apply(e,s):o)||(t.exports=a))}(function(){var t,e,o;return function t(e,r,n){function i(s,a){if(!r[s]){if(!e[s]){var u="function"==typeof _dereq_&&_dereq_;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=r[s]={exports:{}};e[s][0].call(l.exports,function(t){var r=e[s][1][t];return i(r||t)},l,l.exports,t,e,r,n)}return r[s].exports}for(var o="function"==typeof _dereq_&&_dereq_,s=0;s0;){var e=t.shift();if("function"==typeof e){var r=t.shift(),n=t.shift();e.call(r,n)}else e._settlePromises()}},u.prototype._drainQueues=function(){this._drainQueue(this._normalQueue),this._reset(),this._haveDrainedQueues=!0,this._drainQueue(this._lateQueue)},u.prototype._queueTick=function(){this._isTickUsed||(this._isTickUsed=!0,this._schedule(this.drainQueues))},u.prototype._reset=function(){this._isTickUsed=!1},e.exports=u,e.exports.firstLineError=i},{"./queue":26,"./schedule":29,"./util":36}],3:[function(t,e,r){e.exports=function(t,e,r,n){var i=!1,o=function(t,e){this._reject(e)},s=function(t,e){e.promiseRejectionQueued=!0,e.bindingPromise._then(o,o,null,this,t)},a=function(t,e){0==(50397184&this._bitField)&&this._resolveCallback(e.target)},u=function(t,e){e.promiseRejectionQueued||this._reject(t)};t.prototype.bind=function(o){i||(i=!0,t.prototype._propagateFrom=n.propagateFromFunction(),t.prototype._boundValue=n.boundValueFunction());var c=r(o),l=new t(e);l._propagateFrom(this,1);var f=this._target();if(l._setBoundTo(c),c instanceof t){var h={promiseRejectionQueued:!1,promise:l,target:f,bindingPromise:c};f._then(e,s,void 0,l,h),c._then(a,u,void 0,l,h),l._setOnCancel(c)}else l._resolveCallback(f);return l},t.prototype._setBoundTo=function(t){void 0!==t?(this._bitField=2097152|this._bitField,this._boundTo=t):this._bitField=-2097153&this._bitField},t.prototype._isBound=function(){return 2097152==(2097152&this._bitField)},t.bind=function(e,r){return t.resolve(r).bind(e)}}},{}],4:[function(t,e,r){var n;"undefined"!=typeof Promise&&(n=Promise);var i=t("./promise")();i.noConflict=function(){try{Promise===i&&(Promise=n)}catch(t){}return i},e.exports=i},{"./promise":22}],5:[function(t,e,r){var n=Object.create;if(n){var i=n(null),o=n(null);i[" size"]=o[" size"]=0}e.exports=function(e){var r=t("./util"),n=r.canEvaluate;r.isIdentifier;function i(t){return function(t,n){var i;if(null!=t&&(i=t[n]),"function"!=typeof i){var o="Object "+r.classString(t)+" has no method '"+r.toString(n)+"'";throw new e.TypeError(o)}return i}(t,this.pop()).apply(t,this)}function o(t){return t[this]}function s(t){var e=+this;return e<0&&(e=Math.max(0,e+t.length)),t[e]}e.prototype.call=function(t){var e=[].slice.call(arguments,1);return e.push(t),this._then(i,void 0,void 0,e,void 0)},e.prototype.get=function(t){var e;if("number"==typeof t)e=s;else if(n){var r=(void 0)(t);e=null!==r?r:o}else e=o;return this._then(e,void 0,void 0,t,void 0)}}},{"./util":36}],6:[function(t,e,r){e.exports=function(e,r,n,i){var o=t("./util"),s=o.tryCatch,a=o.errorObj,u=e._async;e.prototype.break=e.prototype.cancel=function(){if(!i.cancellation())return this._warn("cancellation is disabled");for(var t=this,e=t;t._isCancellable();){if(!t._cancelBy(e)){e._isFollowing()?e._followee().cancel():e._cancelBranched();break}var r=t._cancellationParent;if(null==r||!r._isCancellable()){t._isFollowing()?t._followee().cancel():t._cancelBranched();break}t._isFollowing()&&t._followee().cancel(),t._setWillBeCancelled(),e=t,t=r}},e.prototype._branchHasCancelled=function(){this._branchesRemainingToCancel--},e.prototype._enoughBranchesHaveCancelled=function(){return void 0===this._branchesRemainingToCancel||this._branchesRemainingToCancel<=0},e.prototype._cancelBy=function(t){return t===this?(this._branchesRemainingToCancel=0,this._invokeOnCancel(),!0):(this._branchHasCancelled(),!!this._enoughBranchesHaveCancelled()&&(this._invokeOnCancel(),!0))},e.prototype._cancelBranched=function(){this._enoughBranchesHaveCancelled()&&this._cancel()},e.prototype._cancel=function(){this._isCancellable()&&(this._setCancelled(),u.invoke(this._cancelPromises,this,void 0))},e.prototype._cancelPromises=function(){this._length()>0&&this._settlePromises()},e.prototype._unsetOnCancel=function(){this._onCancelField=void 0},e.prototype._isCancellable=function(){return this.isPending()&&!this._isCancelled()},e.prototype.isCancellable=function(){return this.isPending()&&!this.isCancelled()},e.prototype._doInvokeOnCancel=function(t,e){if(o.isArray(t))for(var r=0;r=0)return r[t]}return t.prototype._promiseCreated=function(){},t.prototype._pushContext=function(){},t.prototype._popContext=function(){return null},t._peekContext=t.prototype._peekContext=function(){},n.prototype._pushContext=function(){void 0!==this._trace&&(this._trace._promiseCreated=null,r.push(this._trace))},n.prototype._popContext=function(){if(void 0!==this._trace){var t=r.pop(),e=t._promiseCreated;return t._promiseCreated=null,e}return null},n.CapturedTrace=null,n.create=function(){if(e)return new n},n.deactivateLongStackTraces=function(){},n.activateLongStackTraces=function(){var r=t.prototype._pushContext,o=t.prototype._popContext,s=t._peekContext,a=t.prototype._peekContext,u=t.prototype._promiseCreated;n.deactivateLongStackTraces=function(){t.prototype._pushContext=r,t.prototype._popContext=o,t._peekContext=s,t.prototype._peekContext=a,t.prototype._promiseCreated=u,e=!1},e=!0,t.prototype._pushContext=n.prototype._pushContext,t.prototype._popContext=n.prototype._popContext,t._peekContext=t.prototype._peekContext=i,t.prototype._promiseCreated=function(){var t=this._peekContext();t&&null==t._promiseCreated&&(t._promiseCreated=this)}},n}},{}],9:[function(t,e,n){e.exports=function(e,n){var i,o,s,a=e._getDomain,c=e._async,l=t("./errors").Warning,f=t("./util"),h=f.canAttachTrace,p=/[\\\/]bluebird[\\\/]js[\\\/](release|debug|instrumented)/,d=/\((?:timers\.js):\d+:\d+\)/,y=/[\/<\(](.+?):(\d+):(\d+)\)?\s*$/,v=null,_=null,m=!1,g=!(0==f.env("BLUEBIRD_DEBUG")),b=!(0==f.env("BLUEBIRD_WARNINGS")||!g&&!f.env("BLUEBIRD_WARNINGS")),w=!(0==f.env("BLUEBIRD_LONG_STACK_TRACES")||!g&&!f.env("BLUEBIRD_LONG_STACK_TRACES")),O=0!=f.env("BLUEBIRD_W_FORGOTTEN_RETURN")&&(b||!!f.env("BLUEBIRD_W_FORGOTTEN_RETURN"));e.prototype.suppressUnhandledRejections=function(){var t=this._target();t._bitField=-1048577&t._bitField|524288},e.prototype._ensurePossibleRejectionHandled=function(){if(0==(524288&this._bitField)){this._setRejectionIsUnhandled();var t=this;setTimeout(function(){t._notifyUnhandledRejection()},1)}},e.prototype._notifyUnhandledRejectionIsHandled=function(){W("rejectionHandled",i,void 0,this)},e.prototype._setReturnedNonUndefined=function(){this._bitField=268435456|this._bitField},e.prototype._returnedNonUndefined=function(){return 0!=(268435456&this._bitField)},e.prototype._notifyUnhandledRejection=function(){if(this._isRejectionUnhandled()){var t=this._settledValue();this._setUnhandledRejectionIsNotified(),W("unhandledRejection",o,t,this)}},e.prototype._setUnhandledRejectionIsNotified=function(){this._bitField=262144|this._bitField},e.prototype._unsetUnhandledRejectionIsNotified=function(){this._bitField=-262145&this._bitField},e.prototype._isUnhandledRejectionNotified=function(){return(262144&this._bitField)>0},e.prototype._setRejectionIsUnhandled=function(){this._bitField=1048576|this._bitField},e.prototype._unsetRejectionIsUnhandled=function(){this._bitField=-1048577&this._bitField,this._isUnhandledRejectionNotified()&&(this._unsetUnhandledRejectionIsNotified(),this._notifyUnhandledRejectionIsHandled())},e.prototype._isRejectionUnhandled=function(){return(1048576&this._bitField)>0},e.prototype._warn=function(t,e,r){return L(t,e,r||this)},e.onPossiblyUnhandledRejection=function(t){var e=a();o="function"==typeof t?null===e?t:f.domainBind(e,t):void 0},e.onUnhandledRejectionHandled=function(t){var e=a();i="function"==typeof t?null===e?t:f.domainBind(e,t):void 0};var S=function(){};e.longStackTraces=function(){if(c.haveItemsQueued()&&!X.longStackTraces)throw new Error("cannot enable long stack traces after promises have been created\n\n See http://goo.gl/MqrFmX\n");if(!X.longStackTraces&&Y()){var t=e.prototype._captureStackTrace,r=e.prototype._attachExtraTrace;X.longStackTraces=!0,S=function(){if(c.haveItemsQueued()&&!X.longStackTraces)throw new Error("cannot enable long stack traces after promises have been created\n\n See http://goo.gl/MqrFmX\n");e.prototype._captureStackTrace=t,e.prototype._attachExtraTrace=r,n.deactivateLongStackTraces(),c.enableTrampoline(),X.longStackTraces=!1},e.prototype._captureStackTrace=F,e.prototype._attachExtraTrace=I,n.activateLongStackTraces(),c.disableTrampolineIfNecessary()}},e.hasLongStackTraces=function(){return X.longStackTraces&&Y()};var E=function(){try{if("function"==typeof CustomEvent){var t=new CustomEvent("CustomEvent");return f.global.dispatchEvent(t),function(t,e){var r=new CustomEvent(t.toLowerCase(),{detail:e,cancelable:!0});return!f.global.dispatchEvent(r)}}if("function"==typeof Event){t=new Event("CustomEvent");return f.global.dispatchEvent(t),function(t,e){var r=new Event(t.toLowerCase(),{cancelable:!0});return r.detail=e,!f.global.dispatchEvent(r)}}return(t=document.createEvent("CustomEvent")).initCustomEvent("testingtheevent",!1,!0,{}),f.global.dispatchEvent(t),function(t,e){var r=document.createEvent("CustomEvent");return r.initCustomEvent(t.toLowerCase(),!1,!0,e),!f.global.dispatchEvent(r)}}catch(t){}return function(){return!1}}(),A=f.isNode?function(){return r.emit.apply(r,arguments)}:f.global?function(t){var e="on"+t.toLowerCase(),r=f.global[e];return!!r&&(r.apply(f.global,[].slice.call(arguments,1)),!0)}:function(){return!1};function $(t,e){return{promise:e}}var j={promiseCreated:$,promiseFulfilled:$,promiseRejected:$,promiseResolved:$,promiseCancelled:$,promiseChained:function(t,e,r){return{promise:e,child:r}},warning:function(t,e){return{warning:e}},unhandledRejection:function(t,e,r){return{reason:e,promise:r}},rejectionHandled:$},x=function(t){var e=!1;try{e=A.apply(null,arguments)}catch(t){c.throwLater(t),e=!0}var r=!1;try{r=E(t,j[t].apply(null,arguments))}catch(t){c.throwLater(t),r=!0}return r||e};function N(){return!1}function P(t,e,r){var n=this;try{t(e,r,function(t){if("function"!=typeof t)throw new TypeError("onCancel must be a function, got: "+f.toString(t));n._attachCancellationCallback(t)})}catch(t){return t}}function k(t){if(!this._isCancellable())return this;var e=this._onCancel();void 0!==e?f.isArray(e)?e.push(t):this._setOnCancel([e,t]):this._setOnCancel(t)}function T(){return this._onCancelField}function B(t){this._onCancelField=t}function C(){this._cancellationParent=void 0,this._onCancelField=void 0}function D(t,e){if(0!=(1&e)){this._cancellationParent=t;var r=t._branchesRemainingToCancel;void 0===r&&(r=0),t._branchesRemainingToCancel=r+1}0!=(2&e)&&t._isBound()&&this._setBoundTo(t._boundTo)}e.config=function(t){if("longStackTraces"in(t=Object(t))&&(t.longStackTraces?e.longStackTraces():!t.longStackTraces&&e.hasLongStackTraces()&&S()),"warnings"in t){var r=t.warnings;X.warnings=!!r,O=X.warnings,f.isObject(r)&&"wForgottenReturn"in r&&(O=!!r.wForgottenReturn)}if("cancellation"in t&&t.cancellation&&!X.cancellation){if(c.haveItemsQueued())throw new Error("cannot enable cancellation after promises are in use");e.prototype._clearCancellationData=C,e.prototype._propagateFrom=D,e.prototype._onCancel=T,e.prototype._setOnCancel=B,e.prototype._attachCancellationCallback=k,e.prototype._execute=P,M=D,X.cancellation=!0}return"monitoring"in t&&(t.monitoring&&!X.monitoring?(X.monitoring=!0,e.prototype._fireEvent=x):!t.monitoring&&X.monitoring&&(X.monitoring=!1,e.prototype._fireEvent=N)),e},e.prototype._fireEvent=N,e.prototype._execute=function(t,e,r){try{t(e,r)}catch(t){return t}},e.prototype._onCancel=function(){},e.prototype._setOnCancel=function(t){},e.prototype._attachCancellationCallback=function(t){},e.prototype._captureStackTrace=function(){},e.prototype._attachExtraTrace=function(){},e.prototype._clearCancellationData=function(){},e.prototype._propagateFrom=function(t,e){};var M=function(t,e){0!=(2&e)&&t._isBound()&&this._setBoundTo(t._boundTo)};function R(){var t=this._boundTo;return void 0!==t&&t instanceof e?t.isFulfilled()?t.value():void 0:t}function F(){this._trace=new J(this._peekContext())}function I(t,e){if(h(t)){var r=this._trace;if(void 0!==r&&e&&(r=r._parent),void 0!==r)r.attachExtraTrace(t);else if(!t.__stackCleaned__){var n=V(t);f.notEnumerableProp(t,"stack",n.message+"\n"+n.stack.join("\n")),f.notEnumerableProp(t,"__stackCleaned__",!0)}}}function L(t,r,n){if(X.warnings){var i,o=new l(t);if(r)n._attachExtraTrace(o);else if(X.longStackTraces&&(i=e._peekContext()))i.attachExtraTrace(o);else{var s=V(o);o.stack=s.message+"\n"+s.stack.join("\n")}x("warning",o)||q(o,"",!0)}}function U(t){for(var e=[],r=0;r0?function(t){for(var e=t.stack.replace(/\s+$/g,"").split("\n"),r=0;r0&&"SyntaxError"!=t.name&&(e=e.slice(r)),e}(t):[" (No stack trace)"],{message:r,stack:"SyntaxError"==t.name?e:U(e)}}function q(t,e,r){if("undefined"!=typeof console){var n;if(f.isObject(t)){var i=t.stack;n=e+_(i,t)}else n=e+String(t);"function"==typeof s?s(n,r):"function"!=typeof console.log&&"object"!==u(console.log)||console.log(n)}}function W(t,e,r,n){var i=!1;try{"function"==typeof e&&(i=!0,"rejectionHandled"===t?e(n):e(r,n))}catch(t){c.throwLater(t)}"unhandledRejection"===t?x(t,r,n)||i||q(r,"Unhandled rejection "):x(t,n)}function H(t){var e;if("function"==typeof t)e="[function "+(t.name||"anonymous")+"]";else{e=t&&"function"==typeof t.toString?t.toString():f.toString(t);if(/\[object [a-zA-Z0-9$_]+\]/.test(e))try{e=JSON.stringify(t)}catch(t){}0===e.length&&(e="(empty array)")}return"(<"+function(t){if(t.length<41)return t;return t.substr(0,38)+"..."}(e)+">, no stack trace)"}function Y(){return"function"==typeof G}var z=function(){return!1},K=/[\/<\(]([^:\/]+):(\d+):(?:\d+)\)?\s*$/;function Q(t){var e=t.match(K);if(e)return{fileName:e[1],line:parseInt(e[2],10)}}function J(t){this._parent=t,this._promisesCreated=0;var e=this._length=1+(void 0===t?0:t._length);G(this,J),e>32&&this.uncycle()}f.inherits(J,Error),n.CapturedTrace=J,J.prototype.uncycle=function(){var t=this._length;if(!(t<2)){for(var e=[],r={},n=0,i=this;void 0!==i;++n)e.push(i),i=i._parent;for(n=(t=this._length=n)-1;n>=0;--n){var o=e[n].stack;void 0===r[o]&&(r[o]=n)}for(n=0;n0&&(e[s-1]._parent=void 0,e[s-1]._length=1),e[n]._parent=void 0,e[n]._length=1;var a=n>0?e[n-1]:this;s=0;--c)e[c]._length=u,u++;return}}}},J.prototype.attachExtraTrace=function(t){if(!t.__stackCleaned__){this.uncycle();for(var e=V(t),r=e.message,n=[e.stack],i=this;void 0!==i;)n.push(U(i.stack.split("\n"))),i=i._parent;!function(t){for(var e=t[0],r=1;r=0;--a)if(n[a]===o){s=a;break}for(a=s;a>=0;--a){var u=n[a];if(e[i]!==u)break;e.pop(),i--}e=n}}(n),function(t){for(var e=0;e=0)return v=/@/,_=e,m=!0,function(t){t.stack=(new Error).stack};try{throw new Error}catch(t){n="stack"in t}return"stack"in i||!n||"number"!=typeof Error.stackTraceLimit?(_=function(t,e){return"string"==typeof t?t:"object"!==(void 0===e?"undefined":u(e))&&"function"!=typeof e||void 0===e.name||void 0===e.message?H(e):e.toString()},null):(v=t,_=e,function(t){Error.stackTraceLimit+=6;try{throw new Error}catch(e){t.stack=e.stack}Error.stackTraceLimit-=6})}();"undefined"!=typeof console&&void 0!==console.warn&&(s=function(t){console.warn(t)},f.isNode&&r.stderr.isTTY?s=function(t,e){var r=e?"[33m":"[31m";console.warn(r+t+"[0m\n")}:f.isNode||"string"!=typeof(new Error).stack||(s=function(t,e){console.warn("%c"+t,e?"color: darkorange":"color: red")}));var X={warnings:b,longStackTraces:!1,cancellation:!1,monitoring:!1};return w&&e.longStackTraces(),{longStackTraces:function(){return X.longStackTraces},warnings:function(){return X.warnings},cancellation:function(){return X.cancellation},monitoring:function(){return X.monitoring},propagateFromFunction:function(){return M},boundValueFunction:function(){return R},checkForgottenReturns:function(t,e,r,n,i){if(void 0===t&&null!==e&&O){if(void 0!==i&&i._returnedNonUndefined())return;if(0==(65535&n._bitField))return;r&&(r+=" ");var o="",s="";if(e._trace){for(var a=e._trace.stack.split("\n"),u=U(a),c=u.length-1;c>=0;--c){var l=u[c];if(!d.test(l)){var f=l.match(y);f&&(o="at "+f[1]+":"+f[2]+":"+f[3]+" ");break}}if(u.length>0){var h=u[0];for(c=0;c0&&(s="\n"+a[c-1]);break}}}var p="a promise was created in a "+r+"handler "+o+"but was not returned from it, see http://goo.gl/rRqMUw"+s;n._warn(p,!0,e)}},setBounds:function(t,e){if(Y()){for(var r,n,i=t.stack.split("\n"),o=e.stack.split("\n"),s=-1,a=-1,u=0;u=a||(z=function(t){if(p.test(t))return!0;var e=Q(t);return!!(e&&e.fileName===r&&s<=e.line&&e.line<=a)})}},warn:L,deprecated:function(t,e){var r=t+" is deprecated and will be removed in a future version.";return e&&(r+=" Use "+e+" instead."),L(r)},CapturedTrace:J,fireDomEvent:E,fireGlobalEvent:A}}},{"./errors":12,"./util":36}],10:[function(t,e,r){e.exports=function(t){function e(){return this.value}function r(){throw this.reason}t.prototype.return=t.prototype.thenReturn=function(r){return r instanceof t&&r.suppressUnhandledRejections(),this._then(e,void 0,void 0,{value:r},void 0)},t.prototype.throw=t.prototype.thenThrow=function(t){return this._then(r,void 0,void 0,{reason:t},void 0)},t.prototype.catchThrow=function(t){if(arguments.length<=1)return this._then(void 0,r,void 0,{reason:t},void 0);var e=arguments[1];return this.caught(t,function(){throw e})},t.prototype.catchReturn=function(r){if(arguments.length<=1)return r instanceof t&&r.suppressUnhandledRejections(),this._then(void 0,e,void 0,{value:r},void 0);var n=arguments[1];n instanceof t&&n.suppressUnhandledRejections();return this.caught(r,function(){return n})}}},{}],11:[function(t,e,r){e.exports=function(t,e){var r=t.reduce,n=t.all;function i(){return n(this)}t.prototype.each=function(t){return r(this,t,e,0)._then(i,void 0,void 0,this,void 0)},t.prototype.mapSeries=function(t){return r(this,t,e,e)},t.each=function(t,n){return r(t,n,e,0)._then(i,void 0,void 0,t,void 0)},t.mapSeries=function(t,n){return r(t,n,e,e)}}},{}],12:[function(t,e,r){var n,i,o=t("./es5"),s=o.freeze,a=t("./util"),u=a.inherits,c=a.notEnumerableProp;function l(t,e){function r(n){if(!(this instanceof r))return new r(n);c(this,"message","string"==typeof n?n:e),c(this,"name",t),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):Error.call(this)}return u(r,Error),r}var f=l("Warning","warning"),h=l("CancellationError","cancellation error"),p=l("TimeoutError","timeout error"),d=l("AggregateError","aggregate error");try{n=TypeError,i=RangeError}catch(t){n=l("TypeError","type error"),i=l("RangeError","range error")}for(var y="join pop push shift unshift slice filter forEach some every map indexOf lastIndexOf reduce reduceRight sort reverse".split(" "),v=0;v1?t.cancelPromise._reject(e):t.cancelPromise._cancel(),t.cancelPromise=null,!0)}function f(){return p.call(this,this.promise._target()._settledValue())}function h(t){if(!l(this,t))return s.e=t,s}function p(t){var i=this.promise,a=this.handler;if(!this.called){this.called=!0;var u=this.isFinallyHandler()?a.call(i._boundValue()):a.call(i._boundValue(),t);if(u===n)return u;if(void 0!==u){i._setReturnedNonUndefined();var p=r(u,i);if(p instanceof e){if(null!=this.cancelPromise){if(p._isCancelled()){var d=new o("late cancellation observer");return i._attachExtraTrace(d),s.e=d,s}p.isPending()&&p._attachCancellationCallback(new c(this))}return p._then(f,h,void 0,this,void 0)}}}return i.isRejected()?(l(this),s.e=t,s):(l(this),t)}return u.prototype.isFinallyHandler=function(){return 0===this.type},c.prototype._resultCancelled=function(){l(this.finallyHandler)},e.prototype._passThrough=function(t,e,r,n){return"function"!=typeof t?this.then():this._then(r,n,void 0,new u(this,e,t),void 0)},e.prototype.lastly=e.prototype.finally=function(t){return this._passThrough(t,0,p,p)},e.prototype.tap=function(t){return this._passThrough(t,1,p)},e.prototype.tapCatch=function(t){var r=arguments.length;if(1===r)return this._passThrough(t,1,void 0,p);var n,o=new Array(r-1),s=0;for(n=0;n0&&"function"==typeof arguments[e]&&(t=arguments[e]);var n=[].slice.call(arguments);t&&n.pop();var i=new r(n).promise();return void 0!==t?i.spread(t):i}}},{"./util":36}],18:[function(t,e,r){e.exports=function(e,r,n,i,o,s){var a=e._getDomain,c=t("./util"),l=c.tryCatch,f=c.errorObj,h=e._async;function p(t,e,r,n){this.constructor$(t),this._promise._captureStackTrace();var i=a();this._callback=null===i?e:c.domainBind(i,e),this._preservedValues=n===o?new Array(this.length()):null,this._limit=r,this._inFlight=0,this._queue=[],h.invoke(this._asyncInit,this,void 0)}function d(t,r,i,o){if("function"!=typeof r)return n("expecting a function but got "+c.classString(r));var s=0;if(void 0!==i){if("object"!==(void 0===i?"undefined":u(i))||null===i)return e.reject(new TypeError("options argument must be an object but it is "+c.classString(i)));if("number"!=typeof i.concurrency)return e.reject(new TypeError("'concurrency' must be a number but it is "+c.classString(i.concurrency)));s=i.concurrency}return new p(t,r,s="number"==typeof s&&isFinite(s)&&s>=1?s:0,o).promise()}c.inherits(p,r),p.prototype._asyncInit=function(){this._init$(void 0,-2)},p.prototype._init=function(){},p.prototype._promiseFulfilled=function(t,r){var n=this._values,o=this.length(),a=this._preservedValues,u=this._limit;if(r<0){if(n[r=-1*r-1]=t,u>=1&&(this._inFlight--,this._drainQueue(),this._isResolved()))return!0}else{if(u>=1&&this._inFlight>=u)return n[r]=t,this._queue.push(r),!1;null!==a&&(a[r]=t);var c=this._promise,h=this._callback,p=c._boundValue();c._pushContext();var d=l(h).call(p,t,r,o),y=c._popContext();if(s.checkForgottenReturns(d,y,null!==a?"Promise.filter":"Promise.map",c),d===f)return this._reject(d.e),!0;var v=i(d,this._promise);if(v instanceof e){var _=(v=v._target())._bitField;if(0==(50397184&_))return u>=1&&this._inFlight++,n[r]=v,v._proxy(this,-1*(r+1)),!1;if(0==(33554432&_))return 0!=(16777216&_)?(this._reject(v._reason()),!0):(this._cancel(),!0);d=v._value()}n[r]=d}return++this._totalResolved>=o&&(null!==a?this._filter(n,a):this._resolve(n),!0)},p.prototype._drainQueue=function(){for(var t=this._queue,e=this._limit,r=this._values;t.length>0&&this._inFlight1){o.deprecated("calling Promise.try with more than 1 argument");var c=arguments[1],l=arguments[2];n=s.isArray(c)?a(t).apply(l,c):a(t).call(l,c)}else n=a(t)();var f=u._popContext();return o.checkForgottenReturns(n,f,"Promise.try",u),u._resolveFromSyncValue(n),u},e.prototype._resolveFromSyncValue=function(t){t===s.errorObj?this._rejectCallback(t.e,!1):this._resolveCallback(t,!0)}}},{"./util":36}],20:[function(t,e,r){var n=t("./util"),i=n.maybeWrapAsError,o=t("./errors").OperationalError,s=t("./es5");var a=/^(?:name|message|stack|cause)$/;function u(t){var e;if(function(t){return t instanceof Error&&s.getPrototypeOf(t)===Error.prototype}(t)){(e=new o(t)).name=t.name,e.message=t.message,e.stack=t.stack;for(var r=s.keys(t),i=0;i1){var r,n=new Array(e-1),i=0;for(r=0;r0&&"function"!=typeof t&&"function"!=typeof e){var r=".then() only accepts functions but was passed: "+c.classString(t);arguments.length>1&&(r+=", "+c.classString(e)),this._warn(r)}return this._then(t,e,void 0,void 0,void 0)},N.prototype.done=function(t,e){this._then(t,e,void 0,void 0,void 0)._setIsFinal()},N.prototype.spread=function(t){return"function"!=typeof t?o("expecting a function but got "+c.classString(t)):this.all()._then(t,void 0,void 0,_,void 0)},N.prototype.toJSON=function(){var t={isFulfilled:!1,isRejected:!1,fulfillmentValue:void 0,rejectionReason:void 0};return this.isFulfilled()?(t.fulfillmentValue=this.value(),t.isFulfilled=!0):this.isRejected()&&(t.rejectionReason=this.reason(),t.isRejected=!0),t},N.prototype.all=function(){return arguments.length>0&&this._warn(".all() was passed arguments but it does not take any"),new b(this).promise()},N.prototype.error=function(t){return this.caught(c.originatesFromRejection,t)},N.getNewLibraryCopy=e.exports,N.is=function(t){return t instanceof N},N.fromNode=N.fromCallback=function(t){var e=new N(v);e._captureStackTrace();var r=arguments.length>1&&!!Object(arguments[1]).multiArgs,n=x(t)($(e,r));return n===j&&e._rejectCallback(n.e,!0),e._isFateSealed()||e._setAsyncGuaranteed(),e},N.all=function(t){return new b(t).promise()},N.cast=function(t){var e=g(t);return e instanceof N||((e=new N(v))._captureStackTrace(),e._setFulfilled(),e._rejectionHandler0=t),e},N.resolve=N.fulfilled=N.cast,N.reject=N.rejected=function(t){var e=new N(v);return e._captureStackTrace(),e._rejectCallback(t,!0),e},N.setScheduler=function(t){if("function"!=typeof t)throw new d("expecting a function but got "+c.classString(t));return h.setScheduler(t)},N.prototype._then=function(t,e,r,n,i){var o=void 0!==i,s=o?i:new N(v),u=this._target(),l=u._bitField;o||(s._propagateFrom(this,3),s._captureStackTrace(),void 0===n&&0!=(2097152&this._bitField)&&(n=0!=(50397184&l)?this._boundValue():u===this?void 0:this._boundTo),this._fireEvent("promiseChained",this,s));var f=a();if(0!=(50397184&l)){var p,d,_=u._settlePromiseCtx;0!=(33554432&l)?(d=u._rejectionHandler0,p=t):0!=(16777216&l)?(d=u._fulfillmentHandler0,p=e,u._unsetRejectionIsUnhandled()):(_=u._settlePromiseLateCancellationObserver,d=new y("late cancellation observer"),u._attachExtraTrace(d),p=e),h.invoke(_,u,{handler:null===f?p:"function"==typeof p&&c.domainBind(f,p),promise:s,receiver:n,value:d})}else u._addCallbacks(t,e,s,n,f);return s},N.prototype._length=function(){return 65535&this._bitField},N.prototype._isFateSealed=function(){return 0!=(117506048&this._bitField)},N.prototype._isFollowing=function(){return 67108864==(67108864&this._bitField)},N.prototype._setLength=function(t){this._bitField=-65536&this._bitField|65535&t},N.prototype._setFulfilled=function(){this._bitField=33554432|this._bitField,this._fireEvent("promiseFulfilled",this)},N.prototype._setRejected=function(){this._bitField=16777216|this._bitField,this._fireEvent("promiseRejected",this)},N.prototype._setFollowing=function(){this._bitField=67108864|this._bitField,this._fireEvent("promiseResolved",this)},N.prototype._setIsFinal=function(){this._bitField=4194304|this._bitField},N.prototype._isFinal=function(){return(4194304&this._bitField)>0},N.prototype._unsetCancelled=function(){this._bitField=-65537&this._bitField},N.prototype._setCancelled=function(){this._bitField=65536|this._bitField,this._fireEvent("promiseCancelled",this)},N.prototype._setWillBeCancelled=function(){this._bitField=8388608|this._bitField},N.prototype._setAsyncGuaranteed=function(){h.hasCustomScheduler()||(this._bitField=134217728|this._bitField)},N.prototype._receiverAt=function(t){var e=0===t?this._receiver0:this[4*t-4+3];if(e!==u)return void 0===e&&this._isBound()?this._boundValue():e},N.prototype._promiseAt=function(t){return this[4*t-4+2]},N.prototype._fulfillmentHandlerAt=function(t){return this[4*t-4+0]},N.prototype._rejectionHandlerAt=function(t){return this[4*t-4+1]},N.prototype._boundValue=function(){},N.prototype._migrateCallback0=function(t){t._bitField;var e=t._fulfillmentHandler0,r=t._rejectionHandler0,n=t._promise0,i=t._receiverAt(0);void 0===i&&(i=u),this._addCallbacks(e,r,n,i,null)},N.prototype._migrateCallbackAt=function(t,e){var r=t._fulfillmentHandlerAt(e),n=t._rejectionHandlerAt(e),i=t._promiseAt(e),o=t._receiverAt(e);void 0===o&&(o=u),this._addCallbacks(r,n,i,o,null)},N.prototype._addCallbacks=function(t,e,r,n,i){var o=this._length();if(o>=65531&&(o=0,this._setLength(0)),0===o)this._promise0=r,this._receiver0=n,"function"==typeof t&&(this._fulfillmentHandler0=null===i?t:c.domainBind(i,t)),"function"==typeof e&&(this._rejectionHandler0=null===i?e:c.domainBind(i,e));else{var s=4*o-4;this[s+2]=r,this[s+3]=n,"function"==typeof t&&(this[s+0]=null===i?t:c.domainBind(i,t)),"function"==typeof e&&(this[s+1]=null===i?e:c.domainBind(i,e))}return this._setLength(o+1),o},N.prototype._proxy=function(t,e){this._addCallbacks(void 0,void 0,e,t,null)},N.prototype._resolveCallback=function(t,e){if(0==(117506048&this._bitField)){if(t===this)return this._rejectCallback(n(),!1);var r=g(t,this);if(!(r instanceof N))return this._fulfill(t);e&&this._propagateFrom(r,2);var i=r._target();if(i!==this){var o=i._bitField;if(0==(50397184&o)){var s=this._length();s>0&&i._migrateCallback0(this);for(var a=1;a>>16)){if(t===this){var r=n();return this._attachExtraTrace(r),this._reject(r)}this._setFulfilled(),this._rejectionHandler0=t,(65535&e)>0&&(0!=(134217728&e)?this._settlePromises():h.settlePromises(this))}},N.prototype._reject=function(t){var e=this._bitField;if(!((117506048&e)>>>16)){if(this._setRejected(),this._fulfillmentHandler0=t,this._isFinal())return h.fatalError(t,c.isNode);(65535&e)>0?h.settlePromises(this):this._ensurePossibleRejectionHandled()}},N.prototype._fulfillPromises=function(t,e){for(var r=1;r0){if(0!=(16842752&t)){var r=this._fulfillmentHandler0;this._settlePromise0(this._rejectionHandler0,r,t),this._rejectPromises(e,r)}else{var n=this._rejectionHandler0;this._settlePromise0(this._fulfillmentHandler0,n,t),this._fulfillPromises(e,n)}this._setLength(0)}this._clearCancellationData()},N.prototype._settledValue=function(){var t=this._bitField;return 0!=(33554432&t)?this._rejectionHandler0:0!=(16777216&t)?this._fulfillmentHandler0:void 0},N.defer=N.pending=function(){return S.deprecated("Promise.defer","new Promise"),{promise:new N(v),resolve:P,reject:k}},c.notEnumerableProp(N,"_makeSelfResolutionError",n),t("./method")(N,v,g,o,S),t("./bind")(N,v,g,S),t("./cancel")(N,b,o,S),t("./direct_resolve")(N),t("./synchronous_inspection")(N),t("./join")(N,b,g,v,h,a),N.Promise=N,N.version="3.5.1",t("./map.js")(N,b,o,g,v,S),t("./call_get.js")(N),t("./using.js")(N,o,g,O,v,S),t("./timers.js")(N,v,S),t("./generators.js")(N,o,v,g,s,S),t("./nodeify.js")(N),t("./promisify.js")(N,v),t("./props.js")(N,b,g,o),t("./race.js")(N,v,g,o),t("./reduce.js")(N,b,o,g,v,S),t("./settle.js")(N,b,S),t("./some.js")(N,b,o),t("./filter.js")(N,v),t("./each.js")(N,v),t("./any.js")(N),c.toFastProperties(N),c.toFastProperties(N.prototype),T({a:1}),T({b:2}),T({c:3}),T(1),T(function(){}),T(void 0),T(!1),T(new N(v)),S.setBounds(f.firstLineError,c.lastLineError),N}},{"./any.js":1,"./async":2,"./bind":3,"./call_get.js":5,"./cancel":6,"./catch_filter":7,"./context":8,"./debuggability":9,"./direct_resolve":10,"./each.js":11,"./errors":12,"./es5":13,"./filter.js":14,"./finally":15,"./generators.js":16,"./join":17,"./map.js":18,"./method":19,"./nodeback":20,"./nodeify.js":21,"./promise_array":23,"./promisify.js":24,"./props.js":25,"./race.js":27,"./reduce.js":28,"./settle.js":30,"./some.js":31,"./synchronous_inspection":32,"./thenables":33,"./timers.js":34,"./using.js":35,"./util":36}],23:[function(t,e,r){e.exports=function(e,r,n,i,o){var s=t("./util");s.isArray;function a(t){var n=this._promise=new e(r);t instanceof e&&n._propagateFrom(t,3),n._setOnCancel(this),this._values=t,this._length=0,this._totalResolved=0,this._init(void 0,-2)}return s.inherits(a,o),a.prototype.length=function(){return this._length},a.prototype.promise=function(){return this._promise},a.prototype._init=function t(r,o){var a=n(this._values,this._promise);if(a instanceof e){var u=(a=a._target())._bitField;if(this._values=a,0==(50397184&u))return this._promise._setAsyncGuaranteed(),a._then(t,this._reject,void 0,this,o);if(0==(33554432&u))return 0!=(16777216&u)?this._reject(a._reason()):this._cancel();a=a._value()}if(null!==(a=s.asArray(a)))0!==a.length?this._iterate(a):-5===o?this._resolveEmptyArray():this._resolve(function(t){switch(t){case-2:return[];case-3:return{};case-6:return new Map}}(o));else{var c=i("expecting an array or an iterable object but got "+s.classString(a)).reason();this._promise._rejectCallback(c,!1)}},a.prototype._iterate=function(t){var r=this.getActualLength(t.length);this._length=r,this._values=this.shouldCopyValues()?new Array(r):this._values;for(var i=this._promise,o=!1,s=null,a=0;a=this._length&&(this._resolve(this._values),!0)},a.prototype._promiseCancelled=function(){return this._cancel(),!0},a.prototype._promiseRejected=function(t){return this._totalResolved++,this._reject(t),!0},a.prototype._resultCancelled=function(){if(!this._isResolved()){var t=this._values;if(this._cancel(),t instanceof e)t.cancel();else for(var r=0;r=this._length){var r;if(this._isMap)r=function(t){for(var e=new o,r=t.length/2|0,n=0;n>1},e.prototype.props=function(){return f(this)},e.props=function(t){return f(t)}}},{"./es5":13,"./util":36}],26:[function(t,e,r){function n(t){this._capacity=t,this._length=0,this._front=0}n.prototype._willBeOverCapacity=function(t){return this._capacity=this._length&&(this._resolve(this._values),!0)},o.prototype._promiseFulfilled=function(t,e){var r=new i;return r._bitField=33554432,r._settledValueField=t,this._promiseResolved(e,r)},o.prototype._promiseRejected=function(t,e){var r=new i;return r._bitField=16777216,r._settledValueField=t,this._promiseResolved(e,r)},e.settle=function(t){return n.deprecated(".settle()",".reflect()"),new o(t).promise()},e.prototype.settle=function(){return e.settle(this)}}},{"./util":36}],31:[function(t,e,r){e.exports=function(e,r,n){var i=t("./util"),o=t("./errors").RangeError,s=t("./errors").AggregateError,a=i.isArray,u={};function c(t){this.constructor$(t),this._howMany=0,this._unwrap=!1,this._initialized=!1}function l(t,e){if((0|e)!==e||e<0)return n("expecting a positive integer\n\n See http://goo.gl/MqrFmX\n");var r=new c(t),i=r.promise();return r.setHowMany(e),r.init(),i}i.inherits(c,r),c.prototype._init=function(){if(this._initialized)if(0!==this._howMany){this._init$(void 0,-5);var t=a(this._values);!this._isResolved()&&t&&this._howMany>this._canPossiblyFulfill()&&this._reject(this._getRangeError(this.length()))}else this._resolve([])},c.prototype.init=function(){this._initialized=!0,this._init()},c.prototype.setUnwrap=function(){this._unwrap=!0},c.prototype.howMany=function(){return this._howMany},c.prototype.setHowMany=function(t){this._howMany=t},c.prototype._promiseFulfilled=function(t){return this._addFulfilled(t),this._fulfilled()===this.howMany()&&(this._values.length=this.howMany(),1===this.howMany()&&this._unwrap?this._resolve(this._values[0]):this._resolve(this._values),!0)},c.prototype._promiseRejected=function(t){return this._addRejected(t),this._checkOutcome()},c.prototype._promiseCancelled=function(){return this._values instanceof e||null==this._values?this._cancel():(this._addRejected(u),this._checkOutcome())},c.prototype._checkOutcome=function(){if(this.howMany()>this._canPossiblyFulfill()){for(var t=new s,e=this.length();e0?this._reject(t):this._cancel(),!0}return!1},c.prototype._fulfilled=function(){return this._totalResolved},c.prototype._rejected=function(){return this._values.length-this.length()},c.prototype._addRejected=function(t){this._values.push(t)},c.prototype._addFulfilled=function(t){this._values[this._totalResolved++]=t},c.prototype._canPossiblyFulfill=function(){return this.length()-this._rejected()},c.prototype._getRangeError=function(t){var e="Input array must contain at least "+this._howMany+" items but contains only "+t+" items";return new o(e)},c.prototype._resolveEmptyArray=function(){this._reject(this._getRangeError(0))},e.some=function(t,e){return l(t,e)},e.prototype.some=function(t){return l(this,t)},e._SomePromiseArray=c}},{"./errors":12,"./util":36}],32:[function(t,e,r){e.exports=function(t){function e(t){void 0!==t?(t=t._target(),this._bitField=t._bitField,this._settledValueField=t._isFateSealed()?t._settledValue():void 0):(this._bitField=0,this._settledValueField=void 0)}e.prototype._settledValue=function(){return this._settledValueField};var r=e.prototype.value=function(){if(!this.isFulfilled())throw new TypeError("cannot get fulfillment value of a non-fulfilled promise\n\n See http://goo.gl/MqrFmX\n");return this._settledValue()},n=e.prototype.error=e.prototype.reason=function(){if(!this.isRejected())throw new TypeError("cannot get rejection reason of a non-rejected promise\n\n See http://goo.gl/MqrFmX\n");return this._settledValue()},i=e.prototype.isFulfilled=function(){return 0!=(33554432&this._bitField)},o=e.prototype.isRejected=function(){return 0!=(16777216&this._bitField)},s=e.prototype.isPending=function(){return 0==(50397184&this._bitField)},a=e.prototype.isResolved=function(){return 0!=(50331648&this._bitField)};e.prototype.isCancelled=function(){return 0!=(8454144&this._bitField)},t.prototype.__isCancelled=function(){return 65536==(65536&this._bitField)},t.prototype._isCancelled=function(){return this._target().__isCancelled()},t.prototype.isCancelled=function(){return 0!=(8454144&this._target()._bitField)},t.prototype.isPending=function(){return s.call(this._target())},t.prototype.isRejected=function(){return o.call(this._target())},t.prototype.isFulfilled=function(){return i.call(this._target())},t.prototype.isResolved=function(){return a.call(this._target())},t.prototype.value=function(){return r.call(this._target())},t.prototype.reason=function(){var t=this._target();return t._unsetRejectionIsUnhandled(),n.call(t)},t.prototype._value=function(){return this._settledValue()},t.prototype._reason=function(){return this._unsetRejectionIsUnhandled(),this._settledValue()},t.PromiseInspection=e}},{}],33:[function(t,e,r){e.exports=function(e,r){var n=t("./util"),i=n.errorObj,o=n.isObject;var s={}.hasOwnProperty;return function(t,a){if(o(t)){if(t instanceof e)return t;var u=function(t){try{return function(t){return t.then}(t)}catch(t){return i.e=t,i}}(t);if(u===i){a&&a._pushContext();var c=e.reject(u.e);return a&&a._popContext(),c}if("function"==typeof u)return function(t){try{return s.call(t,"_promise0")}catch(t){return!1}}(t)?(c=new e(r),t._then(c._fulfill,c._reject,void 0,c,null),c):function(t,o,s){var a=new e(r),u=a;s&&s._pushContext(),a._captureStackTrace(),s&&s._popContext();var c=!0,l=n.tryCatch(o).call(t,function(t){a&&(a._resolveCallback(t),a=null)},function(t){a&&(a._rejectCallback(t,c,!0),a=null)});return c=!1,a&&l===i&&(a._rejectCallback(l.e,!0,!0),a=null),u}(t,u,a)}return t}}},{"./util":36}],34:[function(t,e,r){e.exports=function(e,r,n){var i=t("./util"),o=e.TimeoutError;function s(t){this.handle=t}s.prototype._resultCancelled=function(){clearTimeout(this.handle)};var a=function(t){return u(+this).thenReturn(t)},u=e.delay=function(t,i){var o,u;return void 0!==i?(o=e.resolve(i)._then(a,null,null,t,void 0),n.cancellation()&&i instanceof e&&o._setOnCancel(i)):(o=new e(r),u=setTimeout(function(){o._fulfill()},+t),n.cancellation()&&o._setOnCancel(new s(u)),o._captureStackTrace()),o._setAsyncGuaranteed(),o};e.prototype.delay=function(t){return u(t,this)};function c(t){return clearTimeout(this.handle),t}function l(t){throw clearTimeout(this.handle),t}e.prototype.timeout=function(t,e){var r,a;t=+t;var u=new s(setTimeout(function(){r.isPending()&&function(t,e,r){var n;n="string"!=typeof e?e instanceof Error?e:new o("operation timed out"):new o(e),i.markAsOriginatingFromRejection(n),t._attachExtraTrace(n),t._reject(n),null!=r&&r.cancel()}(r,e,a)},t));return n.cancellation()?(a=this.then(),(r=a._then(c,l,void 0,u,void 0))._setOnCancel(u)):r=this._then(c,l,void 0,u,void 0),r}}},{"./util":36}],35:[function(t,e,r){e.exports=function(e,r,n,i,o,s){var a=t("./util"),u=t("./errors").TypeError,c=t("./util").inherits,l=a.errorObj,f=a.tryCatch,h={};function p(t){setTimeout(function(){throw t},0)}function d(t,r){var i=0,s=t.length,a=new e(o);return function o(){if(i>=s)return a._fulfill();var u=function(t){var e=n(t);return e!==t&&"function"==typeof t._isDisposable&&"function"==typeof t._getDisposer&&t._isDisposable()&&e._setDisposable(t._getDisposer()),e}(t[i++]);if(u instanceof e&&u._isDisposable()){try{u=n(u._getDisposer().tryDispose(r),t.promise)}catch(t){return p(t)}if(u instanceof e)return u._then(o,p,null,null,null)}o()}(),a}function y(t,e,r){this._data=t,this._promise=e,this._context=r}function v(t,e,r){this.constructor$(t,e,r)}function _(t){return y.isDisposer(t)?(this.resources[this.index]._setDisposable(t),t.promise()):t}function m(t){this.length=t,this.promise=null,this[t-1]=null}y.prototype.data=function(){return this._data},y.prototype.promise=function(){return this._promise},y.prototype.resource=function(){return this.promise().isFulfilled()?this.promise().value():h},y.prototype.tryDispose=function(t){var e=this.resource(),r=this._context;void 0!==r&&r._pushContext();var n=e!==h?this.doDispose(e,t):null;return void 0!==r&&r._popContext(),this._promise._unsetDisposable(),this._data=null,n},y.isDisposer=function(t){return null!=t&&"function"==typeof t.resource&&"function"==typeof t.tryDispose},c(v,y),v.prototype.doDispose=function(t,e){return this.data().call(t,t,e)},m.prototype._resultCancelled=function(){for(var t=this.length,r=0;r0},e.prototype._getDisposer=function(){return this._disposer},e.prototype._unsetDisposable=function(){this._bitField=-131073&this._bitField,this._disposer=void 0},e.prototype.disposer=function(t){if("function"==typeof t)return new v(t,this,i());throw new u}}},{"./errors":12,"./util":36}],36:[function(t,e,i){var o=t("./es5"),s="undefined"==typeof navigator,a={e:{}},c,l="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n?n:void 0!==this?this:null;function f(){try{var t=c;return c=null,t.apply(this,arguments)}catch(t){return a.e=t,a}}function h(t){return c=t,f}var p=function(t,e){var r={}.hasOwnProperty;function n(){for(var n in this.constructor=t,this.constructor$=e,e.prototype)r.call(e.prototype,n)&&"$"!==n.charAt(n.length-1)&&(this[n+"$"]=e.prototype[n])}return n.prototype=e.prototype,t.prototype=new n,t.prototype};function d(t){return null==t||!0===t||!1===t||"string"==typeof t||"number"==typeof t}function y(t){return"function"==typeof t||"object"===(void 0===t?"undefined":u(t))&&null!==t}function v(t){return d(t)?new Error(x(t)):t}function _(t,e){var r,n=t.length,i=new Array(n+1);for(r=0;r1,n=e.length>0&&!(1===e.length&&"constructor"===e[0]),i=O.test(t+"")&&o.names(t).length>0;if(r||n||i)return!0}return!1}catch(t){return!1}}function E(t){function e(){}e.prototype=t;for(var r=8;r--;)new e;return t}var A=/^[a-z$_][a-z$_0-9]*$/i;function $(t){return A.test(t)}function j(t,e,r){for(var n=new Array(t),i=0;i10||t[0]>0}(),q.isNode&&q.toFastProperties(r);try{throw new Error}catch(t){q.lastLineError=t}e.exports=q},{"./es5":13}]},{},[4])(4)}),"undefined"!=typeof window&&null!==window?window.P=window.Promise:"undefined"!=typeof self&&null!==self&&(self.P=self.Promise)}).call(this,r(8),r(11),r(68).setImmediate)},function(t,e,r){"use strict";var n=t.exports={};n.DocumentNotFoundError=null,n.general={},n.general.default="Validator failed for path `{PATH}` with value `{VALUE}`",n.general.required="Path `{PATH}` is required.",n.Number={},n.Number.min="Path `{PATH}` ({VALUE}) is less than minimum allowed value ({MIN}).",n.Number.max="Path `{PATH}` ({VALUE}) is more than maximum allowed value ({MAX}).",n.Number.enum="`{VALUE}` is not a valid enum value for path `{PATH}`.",n.Date={},n.Date.min="Path `{PATH}` ({VALUE}) is before minimum allowed value ({MIN}).",n.Date.max="Path `{PATH}` ({VALUE}) is after maximum allowed value ({MAX}).",n.String={},n.String.enum="`{VALUE}` is not a valid enum value for path `{PATH}`.",n.String.match="Path `{PATH}` is invalid ({VALUE}).",n.String.minlength="Path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).",n.String.maxlength="Path `{PATH}` (`{VALUE}`) is longer than the maximum allowed length ({MAXLENGTH})."},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4),i=r(3);
+/*!
+ * OverwriteModel Error constructor.
+ *
+ * @inherits MongooseError
+ */
+function o(t,e,r,o){var s=void 0,a=n.messages;s=null!=a.DocumentNotFoundError?"function"==typeof a.DocumentNotFoundError?a.DocumentNotFoundError(t,e):a.DocumentNotFoundError:'No document found for query "'+i.inspect(t)+'" on model "'+e+'"',n.call(this,s),this.name="DocumentNotFoundError",this.result=o,this.numAffected=r,Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack,this.filter=t,this.query=t}
+/*!
+ * Inherits from MongooseError.
+ */o.prototype=Object.create(n.prototype),o.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=o},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);function i(t,e,r){var i=r.join(", ");n.call(this,'No matching document found for id "'+t._id+'" version '+e+' modifiedPaths "'+i+'"'),this.name="VersionError",this.version=e,this.modifiedPaths=r}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);function i(t){n.call(this,"Can't save() the same doc multiple times in parallel. Document: "+t._id),this.name="ParallelSaveError"}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);
+/*!
+ * OverwriteModel Error constructor.
+ *
+ * @inherits MongooseError
+ */function i(t){n.call(this,"Cannot overwrite `"+t+"` model once compiled."),this.name="OverwriteModelError",Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);
+/*!
+ * MissingSchema Error constructor.
+ *
+ * @inherits MongooseError
+ */function i(t){var e="Schema hasn't been registered for model \""+t+'".\nUse mongoose.model(name, schema)';n.call(this,e),this.name="MissingSchemaError",Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);
+/*!
+ * DivergentArrayError constructor.
+ *
+ * @inherits MongooseError
+ */function i(t){var e="For your own good, using `document.save()` to update an array which was selected using an $elemMatch projection OR populated using skip, limit, query conditions, or exclusion of the _id field when the operation results in a $pop or $set of the entire array is not supported. The following path(s) would have been modified unsafely:\n "+t.join("\n ")+"\nUse Model.update() to update these arrays instead.";n.call(this,e),this.name="DivergentArrayError",Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";var n=r(30);
+/*!
+ * ignore
+ */t.exports=function(t){t.$immutable?(t.$immutableSetter=function(t,e){return function(r){if(null==this||null==this.$__)return r;if(this.isNew)return r;var i="function"==typeof e?e.call(this,this):e;if(!i)return r;if("throw"===this.$__.strictMode&&r!==this[t])throw new n(t,"Path `"+t+"` is immutable and strict mode is set to throw.",!0);return this[t]}}(t.path,t.options.immutable),t.set(t.$immutableSetter)):t.$immutableSetter&&(t.setters=t.setters.filter(function(e){return e!==t.$immutableSetter}),delete t.$immutableSetter)}},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(4);function i(t,e,r){n.call(this,'Parameter "'+e+'" to '+r+"() must be an object, got "+t.toString()),this.name="ObjectParameterError",Error.captureStackTrace?Error.captureStackTrace(this):this.stack=(new Error).stack}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,t.exports=i},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(16);function i(t){n.call(this,"Can't validate() the same doc multiple times in parallel. Document: "+t._id),this.name="ParallelValidateError"}
+/*!
+ * Inherits from MongooseError.
+ */i.prototype=Object.create(n.prototype),i.prototype.constructor=n,
+/*!
+ * exports
+ */
+t.exports=i},function(t,e,r){"use strict";(function(e){var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};function n(){this._pres=new Map,this._posts=new Map}function i(t,e,r,n,i,o,s){if(o.useErrorHandlers){var a={error:e};return t.execPost(r,n,i,a,function(t){return"function"==typeof s&&s(t)})}return"function"==typeof s?s(e):void 0}function o(t,e,r){return t.has(e)?t.get(e):r}function s(t,e,r,n){var i=void 0;try{i=t.apply(e,r)}catch(t){return n(t)}a(i)&&i.then(function(){return n()},function(t){return n(t)})}function a(t){return null!=t&&"function"==typeof t.then}function u(t){var r=!1,n=this;return function(){var i=arguments;if(!r)return r=!0,e.nextTick(function(){return t.apply(n,i)})}}n.prototype.execPre=function(t,r,n,i){3===arguments.length&&(i=n,n=[]);var c=o(this._pres,t,[]),l=c.length,f=0,h=c.numAsync||0,p=!1,d=n;if(!l)return e.nextTick(function(){i(null)});var y=function t(){if(!(f>=l)){var n=c[f];if(n.isAsync){var o=[u(v),u(function(t){if(t){if(p)return;return p=!0,i(t)}if(0==--h&&f>=l)return i(null)})];s(n.fn,r,o,o[0])}else if(n.fn.length>0){o=[u(v)];for(var y=arguments.length>=2?arguments:[null].concat(d),_=1;_=l)return h>0?void 0:e.nextTick(function(){i(m)});t(m)}}}};function v(t){if(t){if(p)return;return p=!0,i(t)}if(++f>=l)return h>0?void 0:i(null);y.apply(r,arguments)}y.apply(null,[null].concat(n))},n.prototype.execPreSync=function(t,e,r){for(var n=o(this._pres,t,[]),i=n.length,s=0;s=f)return c.call(null,p);t()});s(e,r,[p].concat(d).concat([v]),v)}else{if(++h>=f)return c.call(null,p);t()}else{var _=u(function(e){return e?(p=e,t()):++h>=f?c.apply(null,[null].concat(n)):void t()});if(e.length===i+2)return++h>=f?c.apply(null,[null].concat(n)):t();if(e.length===i+1)s(e,r,d.concat([_]),_);else{var m=void 0,g=void 0;try{g=e.apply(r,d)}catch(t){m=t,p=t}if(a(g))return g.then(function(){return _()},function(t){return _(t)});if(++h>=f)return c.apply(null,[m].concat(n));t()}}}()},n.prototype.execPostSync=function(t,e,r){for(var n=o(this._posts,t,[]),i=n.length,s=0;s0?n[n.length-1]:null,a=("function"==typeof s&&n.slice(0,n.length-1),this),u=(o=o||{}).checkForPromise;this.execPre(t,r,n,function(c){if(c){for(var l=o.numCallbackParams||0,f=o.contextParameter?[r]:[],h=f.length;h0;--S){var E=r.path(O.slice(0,S).join("."));if(null!=E&&(E.$isMongooseDocumentArray||E.$isSingleNested)){w=E;break}}if(Array.isArray(e.$set[u])&&h.$isMongooseDocumentArray)o(e.$set[u],h,t);else if(e.$set[u]&&h.$isSingleNested)s(e.$set[u],h,t);else if(null!=w){if(f=w.schema.options.timestamps,c=i(f,"createdAt"),l=i(f,"updatedAt"),!f||null==l)continue;if(w.$isSingleNested){e.$set[w.path+"."+l]=t;continue}var A=u.substr(w.path.length+1);if(/^\d+$/.test(A)){e.$set[w.path+"."+A][l]=t;continue}var $=A.indexOf(".");A=-1!==$?A.substr(0,$):A,e.$set[w.path+"."+A+"."+l]=t}else if(null!=h.schema&&h.schema!=r&&e.$set[u]){if(f=h.schema.options.timestamps,c=i(f,"createdAt"),l=i(f,"updatedAt"),!f)continue;null!=l&&(e.$set[u][l]=t),null!=c&&(e.$set[u][c]=t)}}}}catch(t){v=!0,_=t}finally{try{!y&&g.return&&g.return()}finally{if(v)throw _}}}}else{var j=Object.keys(e).filter(function(t){return!t.startsWith("$")}),x=!0,N=!1,P=void 0;try{for(var k,T=j[Symbol.iterator]();!(x=(k=T.next()).done);x=!0){u=k.value;var B=n(u);(h=r.path(B))&&(Array.isArray(e[u])&&h.$isMongooseDocumentArray?o(e[u],h,t):null!=e[u]&&h.$isSingleNested&&s(e[u],h,t))}}catch(t){N=!0,P=t}finally{try{!x&&T.return&&T.return()}finally{if(N)throw P}}}}},function(t,e,r){"use strict";t.exports=function(t){return t.replace(/\.\$(\[[^\]]*\])?\./g,".0.").replace(/\.(\[[^\]]*\])?\$$/g,".0")}},function(t,e,r){"use strict";
+/*!
+ * ignore
+ */var n=r(5);t.exports=
+/*!
+ * ignore
+ */
+function(t,e,r,i,o){var s=i,a=s,u=n(o,"overwrite",!1),c=n(o,"timestamps",!0);if(!c||null==s)return i;var l=null!=c&&!1===c.createdAt,f=null!=c&&!1===c.updatedAt;if(u)return i&&i.$set&&(i=i.$set,s.$set={},a=s.$set),f||!r||i[r]||(a[r]=t),l||!e||i[e]||(a[e]=t),s;if(i=i||{},Array.isArray(s))return s.push({$set:{updatedAt:t}}),s;s.$set=s.$set||{},f||!r||i.$currentDate&&i.$currentDate[r]||(s.$set[r]=t,s.hasOwnProperty(r)&&delete s[r]);!l&&e&&(i[e]&&delete i[e],i.$set&&i.$set[e]&&delete i.$set[e],s.$setOnInsert=s.$setOnInsert||{},s.$setOnInsert[e]=t);0===Object.keys(s.$set).length&&delete s.$set;return s}},function(t,e,r){"use strict";var n=r(5),i=r(20);
+/*!
+ * Gather all indexes defined in the schema, including single nested,
+ * document arrays, and embedded discriminators.
+ */
+t.exports=function(t){var e=[],r=new WeakMap,o=t.constructor.indexTypes,s=new Map;return function t(a,u,c){if(!r.has(a)){r.set(a,!0),u=u||"";for(var l=Object.keys(a.paths),f=l.length,h=0;h0&&!t?this:this.set(function(t,e){return"string"!=typeof t&&(t=e.cast(t)),t?t.toLowerCase():t})},f.prototype.uppercase=function(t){return arguments.length>0&&!t?this:this.set(function(t,e){return"string"!=typeof t&&(t=e.cast(t)),t?t.toUpperCase():t})},f.prototype.trim=function(t){return arguments.length>0&&!t?this:this.set(function(t,e){return"string"!=typeof t&&(t=e.cast(t)),t?t.trim():t})},f.prototype.minlength=function(t,e){if(this.minlengthValidator&&(this.validators=this.validators.filter(function(t){return t.validator!==this.minlengthValidator},this)),null!==t&&void 0!==t){var r=e||i.messages.String.minlength;r=r.replace(/{MINLENGTH}/,t),this.validators.push({validator:this.minlengthValidator=function(e){return null===e||e.length>=t},message:r,type:"minlength",minlength:t})}return this},f.prototype.maxlength=function(t,e){if(this.maxlengthValidator&&(this.validators=this.validators.filter(function(t){return t.validator!==this.maxlengthValidator},this)),null!==t&&void 0!==t){var r=e||i.messages.String.maxlength;r=r.replace(/{MAXLENGTH}/,t),this.validators.push({validator:this.maxlengthValidator=function(e){return null===e||e.length<=t},message:r,type:"maxlength",maxlength:t})}return this},f.prototype.match=function(t,e){var r=e||i.messages.String.match;return this.validators.push({validator:function(e){return!!t&&(null==e||""===e||t.test(e))},message:r,type:"regexp",regexp:t}),this},f.prototype.checkRequired=function(t,e){return n._isRef(this,t,e,!0)?!!t:("function"==typeof this.constructor.checkRequired?this.constructor.checkRequired():f.checkRequired())(t)},f.prototype.cast=function(t,i,o){if(n._isRef(this,t,i,o)){if(null===t||void 0===t)return t;if(l||(l=r(6)),t instanceof l)return t.$__.wasPopulated=!0,t;if("string"==typeof t)return t;if(e.isBuffer(t)||!a.isObject(t))throw new c("string",t,this.path,null,this);var s=i.$__fullPath(this.path),h=new((i.ownerDocument?i.ownerDocument():i).populated(s,!0).options[u])(t);return h.$__.wasPopulated=!0,h}var p="function"==typeof this.constructor.cast?this.constructor.cast():f.cast();try{return p(t)}catch(e){throw new c("string",t,this.path,null,this)}};var p=a.options(n.prototype.$conditionalHandlers,{$all:function(t){var e=this;return Array.isArray(t)?t.map(function(t){return e.castForQuery(t)}):[this.castForQuery(t)]},$gt:h,$gte:h,$lt:h,$lte:h,$options:String,$regex:h,$not:h});Object.defineProperty(f.prototype,"$conditionalHandlers",{configurable:!1,enumerable:!1,writable:!1,value:Object.freeze(p)}),f.prototype.castForQuery=function(t,e){var r=void 0;if(2===arguments.length){if(!(r=this.$conditionalHandlers[t]))throw new Error("Can't use "+t+" with String.");return r.call(this,e)}return e=t,"[object RegExp]"===Object.prototype.toString.call(e)?e:this._castForQuery(e)},
+/*!
+ * Module exports.
+ */
+t.exports=f}).call(this,r(1).Buffer)},function(t,e,r){"use strict";var n=r(9),i=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,n),e}(),o=r(10);Object.defineProperty(i.prototype,"enum",o),Object.defineProperty(i.prototype,"match",o),Object.defineProperty(i.prototype,"lowercase",o),Object.defineProperty(i.prototype,"trim",o),Object.defineProperty(i.prototype,"uppercase",o),Object.defineProperty(i.prototype,"minlength",o),Object.defineProperty(i.prototype,"maxlength",o),
+/*!
+ * ignore
+ */
+t.exports=i},function(t,e,r){"use strict";var n=r(9),i=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,n),e}(),o=r(10);Object.defineProperty(i.prototype,"min",o),Object.defineProperty(i.prototype,"max",o),Object.defineProperty(i.prototype,"enum",o),
+/*!
+ * ignore
+ */
+t.exports=i},function(t,e,r){"use strict";var n=r(21);
+/*!
+ * Given a value, cast it to a number, or throw a `CastError` if the value
+ * cannot be casted. `null` and `undefined` are considered valid.
+ *
+ * @param {Any} value
+ * @param {String} [path] optional the path to set on the CastError
+ * @return {Boolean|null|undefined}
+ * @throws {Error} if `value` is not one of the allowed values
+ * @api private
+ */t.exports=function(t){return n.ok(!isNaN(t)),null==t?t:""===t?null:("string"!=typeof t&&"boolean"!=typeof t||(t=Number(t)),n.ok(!isNaN(t)),t instanceof Number?t.valueOf():"number"==typeof t?t:Array.isArray(t)||"function"!=typeof t.valueOf?t.toString&&!Array.isArray(t)&&t.toString()==Number(t)?Number(t):void n.ok(!1):Number(t.valueOf()))}},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(13),i=r(7),o=r(49),s=r(2);function a(t,e){i.call(this,t,e,"Boolean")}a.schemaName="Boolean",a.defaultOptions={},
+/*!
+ * Inherits from SchemaType.
+ */
+a.prototype=Object.create(i.prototype),a.prototype.constructor=a,
+/*!
+ * ignore
+ */
+a._cast=o,a.set=i.set,a.cast=function(t){return 0===arguments.length?this._cast:(!1===t&&(t=function(t){if(null!=t&&"boolean"!=typeof t)throw new Error;return t}),this._cast=t,this._cast)},
+/*!
+ * ignore
+ */
+a._checkRequired=function(t){return!0===t||!1===t},a.checkRequired=i.checkRequired,a.prototype.checkRequired=function(t){return this.constructor._checkRequired(t)},Object.defineProperty(a,"convertToTrue",{get:function(){return o.convertToTrue},set:function(t){o.convertToTrue=t}}),Object.defineProperty(a,"convertToFalse",{get:function(){return o.convertToFalse},set:function(t){o.convertToFalse=t}}),a.prototype.cast=function(t){var e="function"==typeof this.constructor.cast?this.constructor.cast():a.cast();try{return e(t)}catch(e){throw new n("Boolean",t,this.path,e,this)}},a.$conditionalHandlers=s.options(i.prototype.$conditionalHandlers,{}),a.prototype.castForQuery=function(t,e){var r=void 0;return 2===arguments.length?(r=a.$conditionalHandlers[t])?r.call(this,e):this._castForQuery(e):this._castForQuery(t)},
+/*!
+ * Module exports.
+ */
+t.exports=a},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n=r(55),i=r(13),o=r(18).EventEmitter,s=r(153),a=r(7),u=r(29),c=r(88),l=r(5),f=r(89),h=r(3),p=r(2),d=r(90),y=r(0).arrayPathSymbol,v=r(0).documentArrayParent,_=void 0,m=void 0;function g(t,e,r,i){null!=i&&null!=i._id?e=f(e,i):null!=r&&null!=r._id&&(e=f(e,r));var o=b(e,r);o.prototype.$basePath=t,n.call(this,t,o,r),this.schema=e,this.schemaOptions=i||{},this.$isMongooseDocumentArray=!0,this.Constructor=o,o.base=e.base;var s=this.defaultValue;"defaultValue"in this&&void 0===s||this.default(function(){var t=s.call(this);return Array.isArray(t)||(t=[t]),t});var u=this;this.$embeddedSchemaType=new a(t+".$",{required:l(this,"schemaOptions.required",!1)}),this.$embeddedSchemaType.cast=function(t,e,r){return u.cast(t,e,r)[0]},this.$embeddedSchemaType.$isMongooseDocumentArrayElement=!0,this.$embeddedSchemaType.caster=this.Constructor,this.$embeddedSchemaType.schema=this.schema}
+/*!
+ * Ignore
+ */
+function b(t,e,n){function i(){m.apply(this,arguments),this.$session(this.ownerDocument().$session())}m||(m=r(25));var s=null!=n?n.prototype:m.prototype;for(var a in i.prototype=Object.create(s),i.prototype.$__setSchema(t),i.schema=t,i.prototype.constructor=i,i.$isArraySubdocument=!0,i.events=new o,t.methods)i.prototype[a]=t.methods[a];for(var u in t.statics)i[u]=t.statics[u];for(var c in o.prototype)i[c]=o.prototype[c];return i.options=e,i}
+/*!
+ * Scopes paths selected in a query to this array.
+ * Necessary for proper default application of subdocument values.
+ *
+ * @param {DocumentArrayPath} array - the array to scope `fields` paths
+ * @param {Object|undefined} fields - the root fields selected in the query
+ * @param {Boolean|undefined} init - if we are being created part of a query result
+ */
+function w(t,e,r){if(r&&e){for(var n=t.path+".",i=Object.keys(e),o=i.length,s={},a=void 0,u=void 0,c=void 0;o--;)if((u=i[o]).startsWith(n)){if("$"===(c=u.substring(n.length)))continue;c.startsWith("$.")&&(c=c.substr(2)),a||(a=!0),s[c]=e[u]}return a&&s||void 0}}
+/*!
+ * Module exports.
+ */g.schemaName="DocumentArray",g.options={castNonArrays:!0},
+/*!
+ * Inherits from ArrayType.
+ */
+g.prototype=Object.create(n.prototype),g.prototype.constructor=g,g.prototype.OptionsConstructor=s,g.prototype.discriminator=function(t,e,r){"function"==typeof t&&(t=p.getFunctionName(t));var n=b(e=c(this.casterConstructor,t,e,r),null,this.casterConstructor);n.baseCasterConstructor=this.casterConstructor;try{Object.defineProperty(n,"name",{value:t})}catch(t){}return this.casterConstructor.discriminators[t]=n,this.casterConstructor.discriminators[t]},g.prototype.doValidate=function(t,e,n,i){_||(_=r(17));var o=this;try{a.prototype.doValidate.call(this,t,function(r){if(r)return r.$isArrayValidatorError=!0,e(r);var s=t&&t.length,a=void 0;if(!s)return e();if(i&&i.updateValidator)return e();t.isMongooseDocumentArray||(t=new _(t,o.path,n));function c(t){null!=t&&((a=t)instanceof u||(a.$isArrayValidatorError=!0)),--s||e(a)}for(var l=0,f=s;lr.max&&(r.max=i.max)}r.min=r.min+1;r.max=r.max+1;return r}},function(t,e,r){"use strict";
+/*!
+ * Module dependencies.
+ */var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(30),o=r(54),s=r(152),a=r(5),u=r(79),c=r(3),l=r(20),f=r(27),h=["Polygon","MultiPolygon"];function p(t,e,r){if(Array.isArray(t))t.forEach(function(n,i){if(Array.isArray(n)||l(n))return p(n,e,r);t[i]=e.castForQueryWrapper({val:n,context:r})});else for(var n=Object.keys(t),i=n.length;i--;){var o=n[i],s=t[o];Array.isArray(s)||l(s)?(p(s,e,r),t[o]=s):t[o]=e.castForQuery({val:s,context:r})}}t.exports=function t(e,r,d,y){if(Array.isArray(r))throw new Error("Query filter must be an object, got an array ",c.inspect(r));r.hasOwnProperty("_bsontype")&&"ObjectID"!==r._bsontype&&delete r._bsontype;var v=Object.keys(r),_=v.length,m=void 0,g=void 0,b=void 0,w=void 0,O=void 0,S=void 0;for(d=d||{};_--;)if(S=r[w=v[_]],"$or"===w||"$nor"===w||"$and"===w)for(var E=S.length;E--;)S[E]=t(e,S[E],d,y);else{if("$where"===w){if("string"!==(O=void 0===S?"undefined":n(S))&&"function"!==O)throw new Error("Must have a string or function for $where");"function"===O&&(r[w]=S.toString());continue}if("$elemMatch"===w)S=t(e,S,d,y);else if("$text"===w)S=s(S,w);else{if(!e)continue;if(!(g=e.path(w)))for(var A=w.split("."),$=A.length;$--;){var j=A.slice(0,$).join("."),x=A.slice($).join("."),N=e.path(j),P=a(N,"schema.options.discriminatorKey");if(null!=N&&null!=a(N,"schema.discriminators")&&null!=P&&x!==P){var k=a(r,j+"."+P);null!=k&&(g=N.schema.discriminators[k].path(x))}}if(g){if(null==S)continue;if("Object"===S.constructor.name)if(Object.keys(S).some(u))for(var T=Object.keys(S),B=void 0,C=T.length;C--;)if(b=S[B=T[C]],"$not"===B){if(b&&g&&!g.caster){if((m=Object.keys(b)).length&&u(m[0]))for(var D in b)b[D]=g.castForQueryWrapper({$conditional:D,val:b[D],context:y});else S[B]=g.castForQueryWrapper({$conditional:B,val:b,context:y});continue}t(g.caster?g.caster.schema:e,b,d,y)}else S[B]=g.castForQueryWrapper({$conditional:B,val:b,context:y});else r[w]=g.castForQueryWrapper({val:S,context:y});else if(Array.isArray(S)&&-1===["Buffer","Array"].indexOf(g.instance)){for(var M=[],R=0;R=n.valueOf()},message:r,type:"min",min:t})}return this},c.prototype.max=function(t,e){if(this.maxValidator&&(this.validators=this.validators.filter(function(t){return t.validator!==this.maxValidator},this)),t){var r=e||n.messages.Date.max;"string"==typeof r&&(r=r.replace(/{MAX}/,t===Date.now?"Date.now()":t.toString()));var i=this;this.validators.push({validator:this.maxValidator=function(e){var r=t;"function"==typeof r&&r!==Date.now&&(r=r.call(this));var n=r===Date.now?r():i.cast(r);return null===e||e.valueOf()<=n.valueOf()},message:r,type:"max",max:t})}return this},c.prototype.cast=function(t){var e="function"==typeof this.constructor.cast?this.constructor.cast():c.cast();try{return e(t)}catch(e){throw new u("date",t,this.path,e,this)}},c.prototype.$conditionalHandlers=a.options(o.prototype.$conditionalHandlers,{$gt:l,$gte:l,$lt:l,$lte:l}),c.prototype.castForQuery=function(t,e){if(2!==arguments.length)return this._castForQuery(t);var r=this.$conditionalHandlers[t];if(!r)throw new Error("Can't use "+t+" with Date.");return r.call(this,e)},
+/*!
+ * Module exports.
+ */
+t.exports=c},function(t,e,r){"use strict";var n=r(9),i=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,n),e}(),o=r(10);Object.defineProperty(i.prototype,"min",o),Object.defineProperty(i.prototype,"max",o),Object.defineProperty(i.prototype,"expires",o),
+/*!
+ * ignore
+ */
+t.exports=i},function(t,e,r){"use strict";var n=r(21);t.exports=function(t){if(null==t||""===t)return null;if(t instanceof Date)return n.ok(!isNaN(t.valueOf())),t;var e=void 0;if(n.ok("boolean"!=typeof t),e=t instanceof Number||"number"==typeof t?new Date(t):"string"==typeof t&&!isNaN(Number(t))&&(Number(t)>=275761||Number(t)<-271820)?new Date(Number(t)):"function"==typeof t.valueOf?new Date(t.valueOf()):new Date(t),!isNaN(e.valueOf()))return e;n.ok(!1)}},function(t,e,r){"use strict";(function(e){
+/*!
+ * Module dependencies.
+ */
+var n=r(162),i=r(7),o=r(85),s=r(12),a=r(2),u=r(0).populateModelSymbol,c=i.CastError,l=void 0;function f(t,e){var r="string"==typeof t&&24===t.length&&/^[a-f0-9]+$/i.test(t),n=e&&e.suppressWarning;!r&&void 0!==t||n||(console.warn("mongoose: To create a new ObjectId please try `Mongoose.Types.ObjectId` instead of using `Mongoose.Schema.ObjectId`. Set the `suppressWarning` option if you're trying to create a hex char path in your schema."),console.trace()),i.call(this,t,e,"ObjectID")}
+/*!
+ * ignore
+ */
+function h(t){return this.cast(t)}
+/*!
+ * ignore
+ */
+function p(){return new s}function d(t){if(l||(l=r(6)),this instanceof l){if(void 0===t){var e=new s;return this.$__._id=e,e}this.$__._id=t}return t}
+/*!
+ * Module exports.
+ */f.schemaName="ObjectId",f.defaultOptions={},
+/*!
+ * Inherits from SchemaType.
+ */
+f.prototype=Object.create(i.prototype),f.prototype.constructor=f,f.prototype.OptionsConstructor=n,f.get=i.get,f.set=i.set,f.prototype.auto=function(t){return t&&(this.default(p),this.set(d)),this},
+/*!
+ * ignore
+ */
+f._checkRequired=function(t){return t instanceof s},
+/*!
+ * ignore
+ */
+f._cast=o,f.cast=function(t){return 0===arguments.length?this._cast:(!1===t&&(t=function(t){if(!(t instanceof s))throw new Error;return t}),this._cast=t,this._cast)},f.checkRequired=i.checkRequired,f.prototype.checkRequired=function(t,e){return i._isRef(this,t,e,!0)?!!t:("function"==typeof this.constructor.checkRequired?this.constructor.checkRequired():f.checkRequired())(t)},f.prototype.cast=function(t,n,o){if(i._isRef(this,t,n,o)){if(null===t||void 0===t)return t;if(l||(l=r(6)),t instanceof l)return t.$__.wasPopulated=!0,t;if(t instanceof s)return t;if("objectid"===(t.constructor.name||"").toLowerCase())return new s(t.toHexString());if(e.isBuffer(t)||!a.isObject(t))throw new c("ObjectId",t,this.path,null,this);var h=n.$__fullPath(this.path),p=(n.ownerDocument?n.ownerDocument():n).populated(h,!0),d=t;return n.$__.populated&&n.$__.populated[h]&&n.$__.populated[h].options&&n.$__.populated[h].options.options&&n.$__.populated[h].options.options.lean||((d=new p.options[u](t)).$__.wasPopulated=!0),d}var y="function"==typeof this.constructor.cast?this.constructor.cast():f.cast();try{return y(t)}catch(e){throw new c("ObjectId",t,this.path,e,this)}},f.prototype.$conditionalHandlers=a.options(i.prototype.$conditionalHandlers,{$gt:h,$gte:h,$lt:h,$lte:h}),p.$runBeforeSetters=!0,t.exports=f}).call(this,r(1).Buffer)},function(t,e,r){"use strict";var n=r(9),i=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,n),e}(),o=r(10);Object.defineProperty(i.prototype,"auto",o),
+/*!
+ * ignore
+ */
+t.exports=i},function(t,e,r){"use strict";(function(e){
+/*!
+ * Module dependencies.
+ */
+var n=r(7),i=n.CastError,o=r(19),s=r(164),a=r(2),u=r(0).populateModelSymbol,c=void 0;function l(t,e){n.call(this,t,e,"Decimal128")}
+/*!
+ * ignore
+ */
+function f(t){return this.cast(t)}l.schemaName="Decimal128",l.defaultOptions={},
+/*!
+ * Inherits from SchemaType.
+ */
+l.prototype=Object.create(n.prototype),l.prototype.constructor=l,
+/*!
+ * ignore
+ */
+l._cast=s,l.set=n.set,l.cast=function(t){return 0===arguments.length?this._cast:(!1===t&&(t=function(t){if(null!=t&&!(t instanceof o))throw new Error;return t}),this._cast=t,this._cast)},
+/*!
+ * ignore
+ */
+l._checkRequired=function(t){return t instanceof o},l.checkRequired=n.checkRequired,l.prototype.checkRequired=function(t,e){return n._isRef(this,t,e,!0)?!!t:("function"==typeof this.constructor.checkRequired?this.constructor.checkRequired():l.checkRequired())(t)},l.prototype.cast=function(t,s,f){if(n._isRef(this,t,s,f)){if(null===t||void 0===t)return t;if(c||(c=r(6)),t instanceof c)return t.$__.wasPopulated=!0,t;if(t instanceof o)return t;if(e.isBuffer(t)||!a.isObject(t))throw new i("Decimal128",t,this.path,null,this);var h=s.$__fullPath(this.path),p=(s.ownerDocument?s.ownerDocument():s).populated(h,!0),d=t;return s.$__.populated&&s.$__.populated[h]&&s.$__.populated[h].options&&s.$__.populated[h].options.options&&s.$__.populated[h].options.options.lean||((d=new p.options[u](t)).$__.wasPopulated=!0),d}var y="function"==typeof this.constructor.cast?this.constructor.cast():l.cast();try{return y(t)}catch(e){throw new i("Decimal128",t,this.path,e,this)}},l.prototype.$conditionalHandlers=a.options(n.prototype.$conditionalHandlers,{$gt:f,$gte:f,$lt:f,$lte:f}),
+/*!
+ * Module exports.
+ */
+t.exports=l}).call(this,r(1).Buffer)},function(t,e,r){"use strict";(function(e){var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=r(19),o=r(21);t.exports=function(t){return null==t?t:"object"===(void 0===t?"undefined":n(t))&&"string"==typeof t.$numberDecimal?i.fromString(t.$numberDecimal):t instanceof i?t:"string"==typeof t?i.fromString(t):e.isBuffer(t)?new i(t):"number"==typeof t?i.fromString(String(t)):"function"==typeof t.valueOf&&"string"==typeof t.valueOf()?i.fromString(t.valueOf()):void o.ok(!1)}}).call(this,r(1).Buffer)},function(t,e,r){"use strict";(function(e){
+/*!
+ * ignore
+ */
+var n=function(){function t(t,e){for(var r=0;r0)&&!(e instanceof t)&&!(e instanceof o)&&!(e instanceof i)}e.flatten=
+/*!
+ * ignore
+ */
+function e(r,n,i,o){var s=void 0;s=r&&a(r)&&!t.isBuffer(r)?Object.keys(r.toObject({transform:!1,virtuals:!1})):Object.keys(r||{});var c=s.length;var l={};n=n?n+".":"";for(var f=0;f {
+ if (!this._pipeline.length) {
+ const err = new Error('Aggregate has empty pipeline');
+ return cb(err);
+ }
+
+ prepareDiscriminatorPipeline(this);
+
+ model.hooks.execPre('aggregate', this, error => {
+ if (error) {
+ const _opts = { error: error };
+ return model.hooks.execPost('aggregate', this, [null], _opts, error => {
+ cb(error);
+ });
+ }
+
+ this.options.explain = true;
+
+ model.collection.
+ aggregate(this._pipeline, this.options || {}).
+ explain((error, result) => {
+ const _opts = { error: error };
+ return model.hooks.execPost('aggregate', this, [result], _opts, error => {
+ if (error) {
+ return cb(error);
+ }
+ return cb(null, result);
+ });
+ });
+ });
+ }, model.events);
+};
+
+/**
+ * Sets the allowDiskUse option for the aggregation query (ignored for < 2.6.0)
+ *
+ * ####Example:
+ *
+ * await Model.aggregate([{ $match: { foo: 'bar' } }]).allowDiskUse(true);
+ *
+ * @param {Boolean} value Should tell server it can use hard drive to store data during aggregation.
+ * @param {Array} [tags] optional tags for this query
+ * @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
+ */
+
+Aggregate.prototype.allowDiskUse = function(value) {
+ this.options.allowDiskUse = value;
+ return this;
+};
+
+/**
+ * Sets the hint option for the aggregation query (ignored for < 3.6.0)
+ *
+ * ####Example:
+ *
+ * Model.aggregate(..).hint({ qty: 1, category: 1 }).exec(callback)
+ *
+ * @param {Object|String} value a hint object or the index name
+ * @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
+ */
+
+Aggregate.prototype.hint = function(value) {
+ this.options.hint = value;
+ return this;
+};
+
+/**
+ * Sets the session for this aggregation. Useful for [transactions](/docs/transactions.html).
+ *
+ * ####Example:
+ *
+ * const session = await Model.startSession();
+ * await Model.aggregate(..).session(session);
+ *
+ * @param {ClientSession} session
+ * @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
+ */
+
+Aggregate.prototype.session = function(session) {
+ if (session == null) {
+ delete this.options.session;
+ } else {
+ this.options.session = session;
+ }
+ return this;
+};
+
+/**
+ * Lets you set arbitrary options, for middleware or plugins.
+ *
+ * ####Example:
+ *
+ * var agg = Model.aggregate(..).option({ allowDiskUse: true }); // Set the `allowDiskUse` option
+ * agg.options; // `{ allowDiskUse: true }`
+ *
+ * @param {Object} options keys to merge into current options
+ * @param [options.maxTimeMS] number limits the time this aggregation will run, see [MongoDB docs on `maxTimeMS`](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/)
+ * @param [options.allowDiskUse] boolean if true, the MongoDB server will use the hard drive to store data during this aggregation
+ * @param [options.collation] object see [`Aggregate.prototype.collation()`](./docs/api.html#aggregate_Aggregate-collation)
+ * @param [options.session] ClientSession see [`Aggregate.prototype.session()`](./docs/api.html#aggregate_Aggregate-session)
+ * @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
+ * @return {Aggregate} this
+ * @api public
+ */
+
+Aggregate.prototype.option = function(value) {
+ for (const key in value) {
+ this.options[key] = value[key];
+ }
+ return this;
+};
+
+/**
+ * Sets the cursor option option for the aggregation query (ignored for < 2.6.0).
+ * Note the different syntax below: .exec() returns a cursor object, and no callback
+ * is necessary.
+ *
+ * ####Example:
+ *
+ * var cursor = Model.aggregate(..).cursor({ batchSize: 1000 }).exec();
+ * cursor.eachAsync(function(error, doc) {
+ * // use doc
+ * });
+ *
+ * @param {Object} options
+ * @param {Number} options.batchSize set the cursor batch size
+ * @param {Boolean} [options.useMongooseAggCursor] use experimental mongoose-specific aggregation cursor (for `eachAsync()` and other query cursor semantics)
+ * @return {Aggregate} this
+ * @api public
+ * @see mongodb http://mongodb.github.io/node-mongodb-native/2.0/api/AggregationCursor.html
+ */
+
+Aggregate.prototype.cursor = function(options) {
+ if (!this.options) {
+ this.options = {};
+ }
+ this.options.cursor = options || {};
+ return this;
+};
+
+/**
+ * Sets an option on this aggregation. This function will be deprecated in a
+ * future release. Use the [`cursor()`](./api.html#aggregate_Aggregate-cursor),
+ * [`collation()`](./api.html#aggregate_Aggregate-collation), etc. helpers to
+ * set individual options, or access `agg.options` directly.
+ *
+ * Note that MongoDB aggregations [do **not** support the `noCursorTimeout` flag](https://jira.mongodb.org/browse/SERVER-6036),
+ * if you try setting that flag with this function you will get a "unrecognized field 'noCursorTimeout'" error.
+ *
+ * @param {String} flag
+ * @param {Boolean} value
+ * @return {Aggregate} this
+ * @api public
+ * @deprecated Use [`.option()`](api.html#aggregate_Aggregate-option) instead. Note that MongoDB aggregations do **not** support a `noCursorTimeout` option.
+ */
+
+Aggregate.prototype.addCursorFlag = util.deprecate(function(flag, value) {
+ if (!this.options) {
+ this.options = {};
+ }
+ this.options[flag] = value;
+ return this;
+}, 'Mongoose: `Aggregate#addCursorFlag()` is deprecated, use `option()` instead');
+
+/**
+ * Adds a collation
+ *
+ * ####Example:
+ *
+ * Model.aggregate(..).collation({ locale: 'en_US', strength: 1 }).exec();
+ *
+ * @param {Object} collation options
+ * @return {Aggregate} this
+ * @api public
+ * @see mongodb http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#aggregate
+ */
+
+Aggregate.prototype.collation = function(collation) {
+ if (!this.options) {
+ this.options = {};
+ }
+ this.options.collation = collation;
+ return this;
+};
+
+/**
+ * Combines multiple aggregation pipelines.
+ *
+ * ####Example:
+ *
+ * Model.aggregate(...)
+ * .facet({
+ * books: [{ groupBy: '$author' }],
+ * price: [{ $bucketAuto: { groupBy: '$price', buckets: 2 } }]
+ * })
+ * .exec();
+ *
+ * // Output: { books: [...], price: [{...}, {...}] }
+ *
+ * @param {Object} facet options
+ * @return {Aggregate} this
+ * @see $facet https://docs.mongodb.com/v3.4/reference/operator/aggregation/facet/
+ * @api public
+ */
+
+Aggregate.prototype.facet = function(options) {
+ return this.append({ $facet: options });
+};
+
+/**
+ * Returns the current pipeline
+ *
+ * ####Example:
+ *
+ * MyModel.aggregate().match({ test: 1 }).pipeline(); // [{ $match: { test: 1 } }]
+ *
+ * @return {Array}
+ * @api public
+ */
+
+
+Aggregate.prototype.pipeline = function() {
+ return this._pipeline;
+};
+
+/**
+ * Executes the aggregate pipeline on the currently bound Model.
+ *
+ * ####Example:
+ *
+ * aggregate.exec(callback);
+ *
+ * // Because a promise is returned, the `callback` is optional.
+ * var promise = aggregate.exec();
+ * promise.then(..);
+ *
+ * @see Promise #promise_Promise
+ * @param {Function} [callback]
+ * @return {Promise}
+ * @api public
+ */
+
+Aggregate.prototype.exec = function(callback) {
+ if (!this._model) {
+ throw new Error('Aggregate not bound to any Model');
+ }
+ const model = this._model;
+ const collection = this._model.collection;
+
+ applyGlobalMaxTimeMS(this.options, model);
+
+ if (this.options && this.options.cursor) {
+ return new AggregationCursor(this);
+ }
+
+ return promiseOrCallback(callback, cb => {
+
+ prepareDiscriminatorPipeline(this);
+
+ model.hooks.execPre('aggregate', this, error => {
+ if (error) {
+ const _opts = { error: error };
+ return model.hooks.execPost('aggregate', this, [null], _opts, error => {
+ cb(error);
+ });
+ }
+ if (!this._pipeline.length) {
+ return cb(new Error('Aggregate has empty pipeline'));
+ }
+
+ const options = utils.clone(this.options || {});
+ collection.aggregate(this._pipeline, options, (error, cursor) => {
+ if (error) {
+ const _opts = { error: error };
+ return model.hooks.execPost('aggregate', this, [null], _opts, error => {
+ if (error) {
+ return cb(error);
+ }
+ return cb(null);
+ });
+ }
+ cursor.toArray((error, result) => {
+ const _opts = { error: error };
+ model.hooks.execPost('aggregate', this, [result], _opts, (error, result) => {
+ if (error) {
+ return cb(error);
+ }
+
+ cb(null, result);
+ });
+ });
+ });
+ });
+ }, model.events);
+};
+
+/**
+ * Provides promise for aggregate.
+ *
+ * ####Example:
+ *
+ * Model.aggregate(..).then(successCallback, errorCallback);
+ *
+ * @see Promise #promise_Promise
+ * @param {Function} [resolve] successCallback
+ * @param {Function} [reject] errorCallback
+ * @return {Promise}
+ */
+Aggregate.prototype.then = function(resolve, reject) {
+ return this.exec().then(resolve, reject);
+};
+
+/**
+ * Executes the query returning a `Promise` which will be
+ * resolved with either the doc(s) or rejected with the error.
+ * Like [`.then()`](#query_Query-then), but only takes a rejection handler.
+ *
+ * @param {Function} [reject]
+ * @return {Promise}
+ * @api public
+ */
+
+Aggregate.prototype.catch = function(reject) {
+ return this.exec().then(null, reject);
+};
+
+/**
+ * Returns an asyncIterator for use with [`for/await/of` loops](http://bit.ly/async-iterators)
+ * You do not need to call this function explicitly, the JavaScript runtime
+ * will call it for you.
+ *
+ * ####Example
+ *
+ * const agg = Model.aggregate([{ $match: { age: { $gte: 25 } } }]);
+ * for await (const doc of agg) {
+ * console.log(doc.name);
+ * }
+ *
+ * Node.js 10.x supports async iterators natively without any flags. You can
+ * enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).
+ *
+ * **Note:** This function is not set if `Symbol.asyncIterator` is undefined. If
+ * `Symbol.asyncIterator` is undefined, that means your Node.js version does not
+ * support async iterators.
+ *
+ * @method Symbol.asyncIterator
+ * @memberOf Aggregate
+ * @instance
+ * @api public
+ */
+
+if (Symbol.asyncIterator != null) {
+ Aggregate.prototype[Symbol.asyncIterator] = function() {
+ return this.cursor({ useMongooseAggCursor: true }).
+ exec().
+ transformNull().
+ map(doc => {
+ return doc == null ? { done: true } : { value: doc, done: false };
+ });
+ };
+}
+
+/*!
+ * Helpers
+ */
+
+/**
+ * Checks whether an object is likely a pipeline operator
+ *
+ * @param {Object} obj object to check
+ * @return {Boolean}
+ * @api private
+ */
+
+function isOperator(obj) {
+ if (typeof obj !== 'object') {
+ return false;
+ }
+
+ const k = Object.keys(obj);
+
+ return k.length === 1 && k.some(key => { return key[0] === '$'; });
+}
+
+/*!
+ * Adds the appropriate `$match` pipeline step to the top of an aggregate's
+ * pipeline, should it's model is a non-root discriminator type. This is
+ * analogous to the `prepareDiscriminatorCriteria` function in `lib/query.js`.
+ *
+ * @param {Aggregate} aggregate Aggregate to prepare
+ */
+
+Aggregate._prepareDiscriminatorPipeline = prepareDiscriminatorPipeline;
+
+function prepareDiscriminatorPipeline(aggregate) {
+ const schema = aggregate._model.schema;
+ const discriminatorMapping = schema && schema.discriminatorMapping;
+
+ if (discriminatorMapping && !discriminatorMapping.isRoot) {
+ const originalPipeline = aggregate._pipeline;
+ const discriminatorKey = discriminatorMapping.key;
+ const discriminatorValue = discriminatorMapping.value;
+
+ // If the first pipeline stage is a match and it doesn't specify a `__t`
+ // key, add the discriminator key to it. This allows for potential
+ // aggregation query optimizations not to be disturbed by this feature.
+ if (originalPipeline[0] && originalPipeline[0].$match && !originalPipeline[0].$match[discriminatorKey]) {
+ originalPipeline[0].$match[discriminatorKey] = discriminatorValue;
+ // `originalPipeline` is a ref, so there's no need for
+ // aggregate._pipeline = originalPipeline
+ } else if (originalPipeline[0] && originalPipeline[0].$geoNear) {
+ originalPipeline[0].$geoNear.query =
+ originalPipeline[0].$geoNear.query || {};
+ originalPipeline[0].$geoNear.query[discriminatorKey] = discriminatorValue;
+ } else {
+ const match = {};
+ match[discriminatorKey] = discriminatorValue;
+ aggregate._pipeline.unshift({ $match: match });
+ }
+ }
+}
+
+/*!
+ * Exports
+ */
+
+module.exports = Aggregate;
diff --git a/node_modules/mongoose/lib/browser.js b/node_modules/mongoose/lib/browser.js
new file mode 100644
index 0000000..0a65dd7
--- /dev/null
+++ b/node_modules/mongoose/lib/browser.js
@@ -0,0 +1,155 @@
+/* eslint-env browser */
+
+'use strict';
+
+require('./driver').set(require('./drivers/browser'));
+
+const DocumentProvider = require('./document_provider.js');
+const PromiseProvider = require('./promise_provider');
+
+DocumentProvider.setBrowser(true);
+
+/**
+ * The Mongoose [Promise](#promise_Promise) constructor.
+ *
+ * @method Promise
+ * @api public
+ */
+
+Object.defineProperty(exports, 'Promise', {
+ get: function() {
+ return PromiseProvider.get();
+ },
+ set: function(lib) {
+ PromiseProvider.set(lib);
+ }
+});
+
+/**
+ * Storage layer for mongoose promises
+ *
+ * @method PromiseProvider
+ * @api public
+ */
+
+exports.PromiseProvider = PromiseProvider;
+
+/**
+ * The [MongooseError](#error_MongooseError) constructor.
+ *
+ * @method Error
+ * @api public
+ */
+
+exports.Error = require('./error/index');
+
+/**
+ * The Mongoose [Schema](#schema_Schema) constructor
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var Schema = mongoose.Schema;
+ * var CatSchema = new Schema(..);
+ *
+ * @method Schema
+ * @api public
+ */
+
+exports.Schema = require('./schema');
+
+/**
+ * The various Mongoose Types.
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var array = mongoose.Types.Array;
+ *
+ * ####Types:
+ *
+ * - [ObjectId](#types-objectid-js)
+ * - [Buffer](#types-buffer-js)
+ * - [SubDocument](#types-embedded-js)
+ * - [Array](#types-array-js)
+ * - [DocumentArray](#types-documentarray-js)
+ *
+ * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
+ *
+ * var ObjectId = mongoose.Types.ObjectId;
+ * var id1 = new ObjectId;
+ *
+ * @property Types
+ * @api public
+ */
+exports.Types = require('./types');
+
+/**
+ * The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
+ *
+ * @method VirtualType
+ * @api public
+ */
+exports.VirtualType = require('./virtualtype');
+
+/**
+ * The various Mongoose SchemaTypes.
+ *
+ * ####Note:
+ *
+ * _Alias of mongoose.Schema.Types for backwards compatibility._
+ *
+ * @property SchemaTypes
+ * @see Schema.SchemaTypes #schema_Schema.Types
+ * @api public
+ */
+
+exports.SchemaType = require('./schematype.js');
+
+/**
+ * Internal utils
+ *
+ * @property utils
+ * @api private
+ */
+
+exports.utils = require('./utils.js');
+
+/**
+ * The Mongoose browser [Document](#document-js) constructor.
+ *
+ * @method Document
+ * @api public
+ */
+exports.Document = DocumentProvider();
+
+/**
+ * Return a new browser model. In the browser, a model is just
+ * a simplified document with a schema - it does **not** have
+ * functions like `findOne()`, etc.
+ *
+ * @method model
+ * @api public
+ * @param {String} name
+ * @param {Schema} schema
+ * @return Class
+ */
+exports.model = function(name, schema) {
+ class Model extends exports.Document {
+ constructor(obj, fields) {
+ super(obj, schema, fields);
+ }
+ }
+ Model.modelName = name;
+
+ return Model;
+};
+
+/*!
+ * Module exports.
+ */
+
+if (typeof window !== 'undefined') {
+ window.mongoose = module.exports;
+ window.Buffer = Buffer;
+}
diff --git a/node_modules/mongoose/lib/browserDocument.js b/node_modules/mongoose/lib/browserDocument.js
new file mode 100644
index 0000000..a44f307
--- /dev/null
+++ b/node_modules/mongoose/lib/browserDocument.js
@@ -0,0 +1,100 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const NodeJSDocument = require('./document');
+const EventEmitter = require('events').EventEmitter;
+const MongooseError = require('./error/index');
+const Schema = require('./schema');
+const ObjectId = require('./types/objectid');
+const ValidationError = MongooseError.ValidationError;
+const applyHooks = require('./helpers/model/applyHooks');
+const isObject = require('./helpers/isObject');
+
+/**
+ * Document constructor.
+ *
+ * @param {Object} obj the values to set
+ * @param {Object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
+ * @param {Boolean} [skipId] bool, should we auto create an ObjectId _id
+ * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
+ * @event `init`: Emitted on a document after it has was retrieved from the db and fully hydrated by Mongoose.
+ * @event `save`: Emitted when the document is successfully saved
+ * @api private
+ */
+
+function Document(obj, schema, fields, skipId, skipInit) {
+ if (!(this instanceof Document)) {
+ return new Document(obj, schema, fields, skipId, skipInit);
+ }
+
+ if (isObject(schema) && !schema.instanceOfSchema) {
+ schema = new Schema(schema);
+ }
+
+ // When creating EmbeddedDocument, it already has the schema and he doesn't need the _id
+ schema = this.schema || schema;
+
+ // Generate ObjectId if it is missing, but it requires a scheme
+ if (!this.schema && schema.options._id) {
+ obj = obj || {};
+
+ if (obj._id === undefined) {
+ obj._id = new ObjectId();
+ }
+ }
+
+ if (!schema) {
+ throw new MongooseError.MissingSchemaError();
+ }
+
+ this.$__setSchema(schema);
+
+ NodeJSDocument.call(this, obj, fields, skipId, skipInit);
+
+ applyHooks(this, schema, { decorateDoc: true });
+
+ // apply methods
+ for (const m in schema.methods) {
+ this[m] = schema.methods[m];
+ }
+ // apply statics
+ for (const s in schema.statics) {
+ this[s] = schema.statics[s];
+ }
+}
+
+/*!
+ * Inherit from the NodeJS document
+ */
+
+Document.prototype = Object.create(NodeJSDocument.prototype);
+Document.prototype.constructor = Document;
+
+/*!
+ * ignore
+ */
+
+Document.events = new EventEmitter();
+
+/*!
+ * Browser doc exposes the event emitter API
+ */
+
+Document.$emitter = new EventEmitter();
+
+['on', 'once', 'emit', 'listeners', 'removeListener', 'setMaxListeners',
+ 'removeAllListeners', 'addListener'].forEach(function(emitterFn) {
+ Document[emitterFn] = function() {
+ return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
+ };
+});
+
+/*!
+ * Module exports.
+ */
+
+Document.ValidationError = ValidationError;
+module.exports = exports = Document;
diff --git a/node_modules/mongoose/lib/cast.js b/node_modules/mongoose/lib/cast.js
new file mode 100644
index 0000000..9fe01ba
--- /dev/null
+++ b/node_modules/mongoose/lib/cast.js
@@ -0,0 +1,348 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const StrictModeError = require('./error/strict');
+const Types = require('./schema/index');
+const castTextSearch = require('./schema/operators/text');
+const get = require('./helpers/get');
+const isOperator = require('./helpers/query/isOperator');
+const util = require('util');
+const isObject = require('./helpers/isObject');
+const isMongooseObject = require('./helpers/isMongooseObject');
+
+const ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];
+
+/**
+ * Handles internal casting for query filters.
+ *
+ * @param {Schema} schema
+ * @param {Object} obj Object to cast
+ * @param {Object} options the query options
+ * @param {Query} context passed to setters
+ * @api private
+ */
+module.exports = function cast(schema, obj, options, context) {
+ if (Array.isArray(obj)) {
+ throw new Error('Query filter must be an object, got an array ', util.inspect(obj));
+ }
+
+ // bson 1.x has the unfortunate tendency to remove filters that have a top-level
+ // `_bsontype` property. But we should still allow ObjectIds because
+ // `Collection#find()` has a special case to support `find(objectid)`.
+ // Should remove this when we upgrade to bson 4.x. See gh-8222, gh-8268
+ if (obj.hasOwnProperty('_bsontype') && obj._bsontype !== 'ObjectID') {
+ delete obj._bsontype;
+ }
+
+ const paths = Object.keys(obj);
+ let i = paths.length;
+ let _keys;
+ let any$conditionals;
+ let schematype;
+ let nested;
+ let path;
+ let type;
+ let val;
+
+ options = options || {};
+
+ while (i--) {
+ path = paths[i];
+ val = obj[path];
+
+ if (path === '$or' || path === '$nor' || path === '$and') {
+ let k = val.length;
+
+ while (k--) {
+ val[k] = cast(schema, val[k], options, context);
+ }
+ } else if (path === '$where') {
+ type = typeof val;
+
+ if (type !== 'string' && type !== 'function') {
+ throw new Error('Must have a string or function for $where');
+ }
+
+ if (type === 'function') {
+ obj[path] = val.toString();
+ }
+
+ continue;
+ } else if (path === '$elemMatch') {
+ val = cast(schema, val, options, context);
+ } else if (path === '$text') {
+ val = castTextSearch(val, path);
+ } else {
+ if (!schema) {
+ // no casting for Mixed types
+ continue;
+ }
+
+ schematype = schema.path(path);
+
+ // Check for embedded discriminator paths
+ if (!schematype) {
+ const split = path.split('.');
+ let j = split.length;
+ while (j--) {
+ const pathFirstHalf = split.slice(0, j).join('.');
+ const pathLastHalf = split.slice(j).join('.');
+ const _schematype = schema.path(pathFirstHalf);
+ const discriminatorKey = get(_schematype, 'schema.options.discriminatorKey');
+
+ // gh-6027: if we haven't found the schematype but this path is
+ // underneath an embedded discriminator and the embedded discriminator
+ // key is in the query, use the embedded discriminator schema
+ if (_schematype != null &&
+ get(_schematype, 'schema.discriminators') != null &&
+ discriminatorKey != null &&
+ pathLastHalf !== discriminatorKey) {
+ const discriminatorVal = get(obj, pathFirstHalf + '.' + discriminatorKey);
+ if (discriminatorVal != null) {
+ schematype = _schematype.schema.discriminators[discriminatorVal].
+ path(pathLastHalf);
+ }
+ }
+ }
+ }
+
+ if (!schematype) {
+ // Handle potential embedded array queries
+ const split = path.split('.');
+ let j = split.length;
+ let pathFirstHalf;
+ let pathLastHalf;
+ let remainingConds;
+
+ // Find the part of the var path that is a path of the Schema
+ while (j--) {
+ pathFirstHalf = split.slice(0, j).join('.');
+ schematype = schema.path(pathFirstHalf);
+ if (schematype) {
+ break;
+ }
+ }
+
+ // If a substring of the input path resolves to an actual real path...
+ if (schematype) {
+ // Apply the casting; similar code for $elemMatch in schema/array.js
+ if (schematype.caster && schematype.caster.schema) {
+ remainingConds = {};
+ pathLastHalf = split.slice(j).join('.');
+ remainingConds[pathLastHalf] = val;
+ obj[path] = cast(schematype.caster.schema, remainingConds, options, context)[pathLastHalf];
+ } else {
+ obj[path] = val;
+ }
+ continue;
+ }
+
+ if (isObject(val)) {
+ // handle geo schemas that use object notation
+ // { loc: { long: Number, lat: Number }
+
+ let geo = '';
+ if (val.$near) {
+ geo = '$near';
+ } else if (val.$nearSphere) {
+ geo = '$nearSphere';
+ } else if (val.$within) {
+ geo = '$within';
+ } else if (val.$geoIntersects) {
+ geo = '$geoIntersects';
+ } else if (val.$geoWithin) {
+ geo = '$geoWithin';
+ }
+
+ if (geo) {
+ const numbertype = new Types.Number('__QueryCasting__');
+ let value = val[geo];
+
+ if (val.$maxDistance != null) {
+ val.$maxDistance = numbertype.castForQueryWrapper({
+ val: val.$maxDistance,
+ context: context
+ });
+ }
+ if (val.$minDistance != null) {
+ val.$minDistance = numbertype.castForQueryWrapper({
+ val: val.$minDistance,
+ context: context
+ });
+ }
+
+ if (geo === '$within') {
+ const withinType = value.$center
+ || value.$centerSphere
+ || value.$box
+ || value.$polygon;
+
+ if (!withinType) {
+ throw new Error('Bad $within parameter: ' + JSON.stringify(val));
+ }
+
+ value = withinType;
+ } else if (geo === '$near' &&
+ typeof value.type === 'string' && Array.isArray(value.coordinates)) {
+ // geojson; cast the coordinates
+ value = value.coordinates;
+ } else if ((geo === '$near' || geo === '$nearSphere' || geo === '$geoIntersects') &&
+ value.$geometry && typeof value.$geometry.type === 'string' &&
+ Array.isArray(value.$geometry.coordinates)) {
+ if (value.$maxDistance != null) {
+ value.$maxDistance = numbertype.castForQueryWrapper({
+ val: value.$maxDistance,
+ context: context
+ });
+ }
+ if (value.$minDistance != null) {
+ value.$minDistance = numbertype.castForQueryWrapper({
+ val: value.$minDistance,
+ context: context
+ });
+ }
+ if (isMongooseObject(value.$geometry)) {
+ value.$geometry = value.$geometry.toObject({
+ transform: false,
+ virtuals: false
+ });
+ }
+ value = value.$geometry.coordinates;
+ } else if (geo === '$geoWithin') {
+ if (value.$geometry) {
+ if (isMongooseObject(value.$geometry)) {
+ value.$geometry = value.$geometry.toObject({ virtuals: false });
+ }
+ const geoWithinType = value.$geometry.type;
+ if (ALLOWED_GEOWITHIN_GEOJSON_TYPES.indexOf(geoWithinType) === -1) {
+ throw new Error('Invalid geoJSON type for $geoWithin "' +
+ geoWithinType + '", must be "Polygon" or "MultiPolygon"');
+ }
+ value = value.$geometry.coordinates;
+ } else {
+ value = value.$box || value.$polygon || value.$center ||
+ value.$centerSphere;
+ if (isMongooseObject(value)) {
+ value = value.toObject({ virtuals: false });
+ }
+ }
+ }
+
+ _cast(value, numbertype, context);
+ continue;
+ }
+ }
+
+ if (schema.nested[path]) {
+ continue;
+ }
+ if (options.upsert && options.strict) {
+ if (options.strict === 'throw') {
+ throw new StrictModeError(path);
+ }
+ throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
+ 'schema, strict mode is `true`, and upsert is `true`.');
+ } else if (options.strictQuery === 'throw') {
+ throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
+ 'schema and strictQuery is \'throw\'.');
+ } else if (options.strictQuery) {
+ delete obj[path];
+ }
+ } else if (val == null) {
+ continue;
+ } else if (val.constructor.name === 'Object') {
+ any$conditionals = Object.keys(val).some(isOperator);
+
+ if (!any$conditionals) {
+ obj[path] = schematype.castForQueryWrapper({
+ val: val,
+ context: context
+ });
+ } else {
+ const ks = Object.keys(val);
+ let $cond;
+
+ let k = ks.length;
+
+ while (k--) {
+ $cond = ks[k];
+ nested = val[$cond];
+
+ if ($cond === '$not') {
+ if (nested && schematype && !schematype.caster) {
+ _keys = Object.keys(nested);
+ if (_keys.length && isOperator(_keys[0])) {
+ for (const key in nested) {
+ nested[key] = schematype.castForQueryWrapper({
+ $conditional: key,
+ val: nested[key],
+ context: context
+ });
+ }
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: context
+ });
+ }
+ continue;
+ }
+ cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: context
+ });
+ }
+ }
+ }
+ } else if (Array.isArray(val) && ['Buffer', 'Array'].indexOf(schematype.instance) === -1) {
+ const casted = [];
+ for (let valIndex = 0; valIndex < val.length; valIndex++) {
+ casted.push(schematype.castForQueryWrapper({
+ val: val[valIndex],
+ context: context
+ }));
+ }
+
+ obj[path] = { $in: casted };
+ } else {
+ obj[path] = schematype.castForQueryWrapper({
+ val: val,
+ context: context
+ });
+ }
+ }
+ }
+
+ return obj;
+};
+
+function _cast(val, numbertype, context) {
+ if (Array.isArray(val)) {
+ val.forEach(function(item, i) {
+ if (Array.isArray(item) || isObject(item)) {
+ return _cast(item, numbertype, context);
+ }
+ val[i] = numbertype.castForQueryWrapper({ val: item, context: context });
+ });
+ } else {
+ const nearKeys = Object.keys(val);
+ let nearLen = nearKeys.length;
+ while (nearLen--) {
+ const nkey = nearKeys[nearLen];
+ const item = val[nkey];
+ if (Array.isArray(item) || isObject(item)) {
+ _cast(item, numbertype, context);
+ val[nkey] = item;
+ } else {
+ val[nkey] = numbertype.castForQuery({ val: item, context: context });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/cast/boolean.js b/node_modules/mongoose/lib/cast/boolean.js
new file mode 100644
index 0000000..4843e1f
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/boolean.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const CastError = require('../error/cast');
+
+/*!
+ * Given a value, cast it to a boolean, or throw a `CastError` if the value
+ * cannot be casted. `null` and `undefined` are considered valid.
+ *
+ * @param {Any} value
+ * @param {String} [path] optional the path to set on the CastError
+ * @return {Boolean|null|undefined}
+ * @throws {CastError} if `value` is not one of the allowed values
+ * @api private
+ */
+
+module.exports = function castBoolean(value, path) {
+ if (value == null) {
+ return value;
+ }
+
+ if (module.exports.convertToTrue.has(value)) {
+ return true;
+ }
+ if (module.exports.convertToFalse.has(value)) {
+ return false;
+ }
+ throw new CastError('boolean', value, path);
+};
+
+module.exports.convertToTrue = new Set([true, 'true', 1, '1', 'yes']);
+module.exports.convertToFalse = new Set([false, 'false', 0, '0', 'no']);
diff --git a/node_modules/mongoose/lib/cast/date.js b/node_modules/mongoose/lib/cast/date.js
new file mode 100644
index 0000000..ac17006
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/date.js
@@ -0,0 +1,41 @@
+'use strict';
+
+const assert = require('assert');
+
+module.exports = function castDate(value) {
+ // Support empty string because of empty form values. Originally introduced
+ // in https://github.com/Automattic/mongoose/commit/efc72a1898fc3c33a319d915b8c5463a22938dfe
+ if (value == null || value === '') {
+ return null;
+ }
+
+ if (value instanceof Date) {
+ assert.ok(!isNaN(value.valueOf()));
+
+ return value;
+ }
+
+ let date;
+
+ assert.ok(typeof value !== 'boolean');
+
+ if (value instanceof Number || typeof value === 'number') {
+ date = new Date(value);
+ } else if (typeof value === 'string' && !isNaN(Number(value)) && (Number(value) >= 275761 || Number(value) < -271820)) {
+ // string representation of milliseconds take this path
+ date = new Date(Number(value));
+ } else if (typeof value.valueOf === 'function') {
+ // support for moment.js. This is also the path strings will take because
+ // strings have a `valueOf()`
+ date = new Date(value.valueOf());
+ } else {
+ // fallback
+ date = new Date(value);
+ }
+
+ if (!isNaN(date.valueOf())) {
+ return date;
+ }
+
+ assert.ok(false);
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/cast/decimal128.js b/node_modules/mongoose/lib/cast/decimal128.js
new file mode 100644
index 0000000..bfb1578
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/decimal128.js
@@ -0,0 +1,36 @@
+'use strict';
+
+const Decimal128Type = require('../types/decimal128');
+const assert = require('assert');
+
+module.exports = function castDecimal128(value) {
+ if (value == null) {
+ return value;
+ }
+
+ if (typeof value === 'object' && typeof value.$numberDecimal === 'string') {
+ return Decimal128Type.fromString(value.$numberDecimal);
+ }
+
+ if (value instanceof Decimal128Type) {
+ return value;
+ }
+
+ if (typeof value === 'string') {
+ return Decimal128Type.fromString(value);
+ }
+
+ if (Buffer.isBuffer(value)) {
+ return new Decimal128Type(value);
+ }
+
+ if (typeof value === 'number') {
+ return Decimal128Type.fromString(String(value));
+ }
+
+ if (typeof value.valueOf === 'function' && typeof value.valueOf() === 'string') {
+ return Decimal128Type.fromString(value.valueOf());
+ }
+
+ assert.ok(false);
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/cast/number.js b/node_modules/mongoose/lib/cast/number.js
new file mode 100644
index 0000000..18d2eeb
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/number.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const assert = require('assert');
+
+/*!
+ * Given a value, cast it to a number, or throw a `CastError` if the value
+ * cannot be casted. `null` and `undefined` are considered valid.
+ *
+ * @param {Any} value
+ * @param {String} [path] optional the path to set on the CastError
+ * @return {Boolean|null|undefined}
+ * @throws {Error} if `value` is not one of the allowed values
+ * @api private
+ */
+
+module.exports = function castNumber(val) {
+ assert.ok(!isNaN(val));
+
+ if (val == null) {
+ return val;
+ }
+ if (val === '') {
+ return null;
+ }
+
+ if (typeof val === 'string' || typeof val === 'boolean') {
+ val = Number(val);
+ }
+
+ assert.ok(!isNaN(val));
+ if (val instanceof Number) {
+ return val.valueOf();
+ }
+ if (typeof val === 'number') {
+ return val;
+ }
+ if (!Array.isArray(val) && typeof val.valueOf === 'function') {
+ return Number(val.valueOf());
+ }
+ if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {
+ return Number(val);
+ }
+
+ assert.ok(false);
+};
diff --git a/node_modules/mongoose/lib/cast/objectid.js b/node_modules/mongoose/lib/cast/objectid.js
new file mode 100644
index 0000000..67cffb5
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/objectid.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const ObjectId = require('../driver').get().ObjectId;
+const assert = require('assert');
+
+module.exports = function castObjectId(value) {
+ if (value == null) {
+ return value;
+ }
+
+ if (value instanceof ObjectId) {
+ return value;
+ }
+
+ if (value._id) {
+ if (value._id instanceof ObjectId) {
+ return value._id;
+ }
+ if (value._id.toString instanceof Function) {
+ return new ObjectId(value._id.toString());
+ }
+ }
+
+ if (value.toString instanceof Function) {
+ return new ObjectId(value.toString());
+ }
+
+ assert.ok(false);
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/cast/string.js b/node_modules/mongoose/lib/cast/string.js
new file mode 100644
index 0000000..4d89f8e
--- /dev/null
+++ b/node_modules/mongoose/lib/cast/string.js
@@ -0,0 +1,37 @@
+'use strict';
+
+const CastError = require('../error/cast');
+
+/*!
+ * Given a value, cast it to a string, or throw a `CastError` if the value
+ * cannot be casted. `null` and `undefined` are considered valid.
+ *
+ * @param {Any} value
+ * @param {String} [path] optional the path to set on the CastError
+ * @return {string|null|undefined}
+ * @throws {CastError}
+ * @api private
+ */
+
+module.exports = function castString(value, path) {
+ // If null or undefined
+ if (value == null) {
+ return value;
+ }
+
+ // handle documents being passed
+ if (value._id && typeof value._id === 'string') {
+ return value._id;
+ }
+
+ // Re: gh-647 and gh-3030, we're ok with casting using `toString()`
+ // **unless** its the default Object.toString, because "[object Object]"
+ // doesn't really qualify as useful data
+ if (value.toString &&
+ value.toString !== Object.prototype.toString &&
+ !Array.isArray(value)) {
+ return value.toString();
+ }
+
+ throw new CastError('string', value, path);
+};
diff --git a/node_modules/mongoose/lib/collection.js b/node_modules/mongoose/lib/collection.js
new file mode 100644
index 0000000..ff02426
--- /dev/null
+++ b/node_modules/mongoose/lib/collection.js
@@ -0,0 +1,269 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const EventEmitter = require('events').EventEmitter;
+const STATES = require('./connectionstate');
+const immediate = require('./helpers/immediate');
+
+/**
+ * Abstract Collection constructor
+ *
+ * This is the base class that drivers inherit from and implement.
+ *
+ * @param {String} name name of the collection
+ * @param {Connection} conn A MongooseConnection instance
+ * @param {Object} opts optional collection options
+ * @api public
+ */
+
+function Collection(name, conn, opts) {
+ if (opts === void 0) {
+ opts = {};
+ }
+ if (opts.capped === void 0) {
+ opts.capped = {};
+ }
+
+ opts.bufferCommands = undefined === opts.bufferCommands
+ ? true
+ : opts.bufferCommands;
+
+ if (typeof opts.capped === 'number') {
+ opts.capped = { size: opts.capped };
+ }
+
+ this.opts = opts;
+ this.name = name;
+ this.collectionName = name;
+ this.conn = conn;
+ this.queue = [];
+ this.buffer = this.opts.bufferCommands;
+ this.emitter = new EventEmitter();
+
+ if (STATES.connected === this.conn.readyState) {
+ this.onOpen();
+ }
+}
+
+/**
+ * The collection name
+ *
+ * @api public
+ * @property name
+ */
+
+Collection.prototype.name;
+
+/**
+ * The collection name
+ *
+ * @api public
+ * @property collectionName
+ */
+
+Collection.prototype.collectionName;
+
+/**
+ * The Connection instance
+ *
+ * @api public
+ * @property conn
+ */
+
+Collection.prototype.conn;
+
+/**
+ * Called when the database connects
+ *
+ * @api private
+ */
+
+Collection.prototype.onOpen = function() {
+ this.buffer = false;
+ immediate(() => this.doQueue());
+};
+
+/**
+ * Called when the database disconnects
+ *
+ * @api private
+ */
+
+Collection.prototype.onClose = function(force) {
+ if (this.opts.bufferCommands && !force) {
+ this.buffer = true;
+ }
+};
+
+/**
+ * Queues a method for later execution when its
+ * database connection opens.
+ *
+ * @param {String} name name of the method to queue
+ * @param {Array} args arguments to pass to the method when executed
+ * @api private
+ */
+
+Collection.prototype.addQueue = function(name, args) {
+ this.queue.push([name, args]);
+ return this;
+};
+
+/**
+ * Executes all queued methods and clears the queue.
+ *
+ * @api private
+ */
+
+Collection.prototype.doQueue = function() {
+ for (let i = 0, l = this.queue.length; i < l; i++) {
+ if (typeof this.queue[i][0] === 'function') {
+ this.queue[i][0].apply(this, this.queue[i][1]);
+ } else {
+ this[this.queue[i][0]].apply(this, this.queue[i][1]);
+ }
+ }
+ this.queue = [];
+ const _this = this;
+ process.nextTick(function() {
+ _this.emitter.emit('queue');
+ });
+ return this;
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.ensureIndex = function() {
+ throw new Error('Collection#ensureIndex unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.createIndex = function() {
+ throw new Error('Collection#ensureIndex unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.findAndModify = function() {
+ throw new Error('Collection#findAndModify unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.findOneAndUpdate = function() {
+ throw new Error('Collection#findOneAndUpdate unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.findOneAndDelete = function() {
+ throw new Error('Collection#findOneAndDelete unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.findOneAndReplace = function() {
+ throw new Error('Collection#findOneAndReplace unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.findOne = function() {
+ throw new Error('Collection#findOne unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.find = function() {
+ throw new Error('Collection#find unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.insert = function() {
+ throw new Error('Collection#insert unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.insertOne = function() {
+ throw new Error('Collection#insertOne unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.insertMany = function() {
+ throw new Error('Collection#insertMany unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.save = function() {
+ throw new Error('Collection#save unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.update = function() {
+ throw new Error('Collection#update unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.getIndexes = function() {
+ throw new Error('Collection#getIndexes unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.mapReduce = function() {
+ throw new Error('Collection#mapReduce unimplemented by driver');
+};
+
+/**
+ * Abstract method that drivers must implement.
+ */
+
+Collection.prototype.watch = function() {
+ throw new Error('Collection#watch unimplemented by driver');
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = Collection;
diff --git a/node_modules/mongoose/lib/connection.js b/node_modules/mongoose/lib/connection.js
new file mode 100644
index 0000000..2bdfa69
--- /dev/null
+++ b/node_modules/mongoose/lib/connection.js
@@ -0,0 +1,1285 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const ChangeStream = require('./cursor/ChangeStream');
+const EventEmitter = require('events').EventEmitter;
+const Schema = require('./schema');
+const Collection = require('./driver').get().Collection;
+const STATES = require('./connectionstate');
+const MongooseError = require('./error/index');
+const PromiseProvider = require('./promise_provider');
+const ServerSelectionError = require('./error/serverSelection');
+const applyPlugins = require('./helpers/schema/applyPlugins');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const get = require('./helpers/get');
+const immediate = require('./helpers/immediate');
+const mongodb = require('mongodb');
+const pkg = require('../package.json');
+const utils = require('./utils');
+
+const parseConnectionString = require('mongodb/lib/core').parseConnectionString;
+
+let id = 0;
+
+/*!
+ * A list of authentication mechanisms that don't require a password for authentication.
+ * This is used by the authMechanismDoesNotRequirePassword method.
+ *
+ * @api private
+ */
+const noPasswordAuthMechanisms = [
+ 'MONGODB-X509'
+];
+
+/**
+ * Connection constructor
+ *
+ * For practical reasons, a Connection equals a Db.
+ *
+ * @param {Mongoose} base a mongoose instance
+ * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
+ * @event `connecting`: Emitted when `connection.openUri()` is executed on this connection.
+ * @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected` scenarios.
+ * @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
+ * @event `disconnecting`: Emitted when `connection.close()` was executed.
+ * @event `disconnected`: Emitted after getting disconnected from the db.
+ * @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
+ * @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successful connection.
+ * @event `error`: Emitted when an error occurs on this connection.
+ * @event `fullsetup`: Emitted after the driver has connected to primary and all secondaries if specified in the connection string.
+ * @api public
+ */
+
+function Connection(base) {
+ this.base = base;
+ this.collections = {};
+ this.models = {};
+ this.config = { autoIndex: true };
+ this.replica = false;
+ this.options = null;
+ this.otherDbs = []; // FIXME: To be replaced with relatedDbs
+ this.relatedDbs = {}; // Hashmap of other dbs that share underlying connection
+ this.states = STATES;
+ this._readyState = STATES.disconnected;
+ this._closeCalled = false;
+ this._hasOpened = false;
+ this.plugins = [];
+ this.id = id++;
+}
+
+/*!
+ * Inherit from EventEmitter
+ */
+
+Connection.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Connection ready state
+ *
+ * - 0 = disconnected
+ * - 1 = connected
+ * - 2 = connecting
+ * - 3 = disconnecting
+ *
+ * Each state change emits its associated event name.
+ *
+ * ####Example
+ *
+ * conn.on('connected', callback);
+ * conn.on('disconnected', callback);
+ *
+ * @property readyState
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'readyState', {
+ get: function() {
+ return this._readyState;
+ },
+ set: function(val) {
+ if (!(val in STATES)) {
+ throw new Error('Invalid connection state: ' + val);
+ }
+
+ if (this._readyState !== val) {
+ this._readyState = val;
+ // [legacy] loop over the otherDbs on this connection and change their state
+ for (let i = 0; i < this.otherDbs.length; i++) {
+ this.otherDbs[i].readyState = val;
+ }
+
+ // loop over relatedDbs on this connection and change their state
+ for (const k in this.relatedDbs) {
+ this.relatedDbs[k].readyState = val;
+ }
+
+ if (STATES.connected === val) {
+ this._hasOpened = true;
+ }
+
+ this.emit(STATES[val]);
+ }
+ }
+});
+
+/**
+ * Gets the value of the option `key`. Equivalent to `conn.options[key]`
+ *
+ * ####Example:
+ *
+ * conn.get('test'); // returns the 'test' value
+ *
+ * @param {String} key
+ * @method get
+ * @api public
+ */
+
+Connection.prototype.get = function(key) {
+ return get(this.options, key);
+};
+
+/**
+ * Sets the value of the option `key`. Equivalent to `conn.options[key] = val`
+ *
+ * Supported options include:
+ *
+ * - `maxTimeMS`: Set [`maxTimeMS`](/docs/api.html#query_Query-maxTimeMS) for all queries on this connection.
+ * - `useFindAndModify`: Set to `false` to work around the [`findAndModify()` deprecation warning](/docs/deprecations.html#findandmodify)
+ *
+ * ####Example:
+ *
+ * conn.set('test', 'foo');
+ * conn.get('test'); // 'foo'
+ * conn.options.test; // 'foo'
+ *
+ * @param {String} key
+ * @param {Any} val
+ * @method set
+ * @api public
+ */
+
+Connection.prototype.set = function(key, val) {
+ this.options = this.options || {};
+ this.options[key] = val;
+ return val;
+};
+
+/**
+ * A hash of the collections associated with this connection
+ *
+ * @property collections
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.collections;
+
+/**
+ * The name of the database this connection points to.
+ *
+ * ####Example
+ *
+ * mongoose.createConnection('mongodb://localhost:27017/mydb').name; // "mydb"
+ *
+ * @property name
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.name;
+
+/**
+ * A [POJO](https://masteringjs.io/tutorials/fundamentals/pojo) containing
+ * a map from model names to models. Contains all models that have been
+ * added to this connection using [`Connection#model()`](/docs/api/connection.html#connection_Connection-model).
+ *
+ * ####Example
+ *
+ * const conn = mongoose.createConnection();
+ * const Test = conn.model('Test', mongoose.Schema({ name: String }));
+ *
+ * Object.keys(conn.models).length; // 1
+ * conn.models.Test === Test; // true
+ *
+ * @property models
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.models;
+
+/**
+ * A number identifier for this connection. Used for debugging when
+ * you have [multiple connections](/docs/connections.html#multiple_connections).
+ *
+ * ####Example
+ *
+ * // The default connection has `id = 0`
+ * mongoose.connection.id; // 0
+ *
+ * // If you create a new connection, Mongoose increments id
+ * const conn = mongoose.createConnection();
+ * conn.id; // 1
+ *
+ * @property id
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.id;
+
+/**
+ * The plugins that will be applied to all models created on this connection.
+ *
+ * ####Example:
+ *
+ * const db = mongoose.createConnection('mongodb://localhost:27017/mydb');
+ * db.plugin(() => console.log('Applied'));
+ * db.plugins.length; // 1
+ *
+ * db.model('Test', new Schema({})); // Prints "Applied"
+ *
+ * @property plugins
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'plugins', {
+ configurable: false,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The host name portion of the URI. If multiple hosts, such as a replica set,
+ * this will contain the first host name in the URI
+ *
+ * ####Example
+ *
+ * mongoose.createConnection('mongodb://localhost:27017/mydb').host; // "localhost"
+ *
+ * @property host
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'host', {
+ configurable: true,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The port portion of the URI. If multiple hosts, such as a replica set,
+ * this will contain the port from the first host name in the URI.
+ *
+ * ####Example
+ *
+ * mongoose.createConnection('mongodb://localhost:27017/mydb').port; // 27017
+ *
+ * @property port
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'port', {
+ configurable: true,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The username specified in the URI
+ *
+ * ####Example
+ *
+ * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').user; // "val"
+ *
+ * @property user
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'user', {
+ configurable: true,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The password specified in the URI
+ *
+ * ####Example
+ *
+ * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').pass; // "psw"
+ *
+ * @property pass
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Object.defineProperty(Connection.prototype, 'pass', {
+ configurable: true,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The mongodb.Db instance, set when the connection is opened
+ *
+ * @property db
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.db;
+
+/**
+ * A hash of the global options that are associated with this connection
+ *
+ * @property config
+ * @memberOf Connection
+ * @instance
+ * @api public
+ */
+
+Connection.prototype.config;
+
+/**
+ * Helper for `createCollection()`. Will explicitly create the given collection
+ * with specified options. Used to create [capped collections](https://docs.mongodb.com/manual/core/capped-collections/)
+ * and [views](https://docs.mongodb.com/manual/core/views/) from mongoose.
+ *
+ * Options are passed down without modification to the [MongoDB driver's `createCollection()` function](http://mongodb.github.io/node-mongodb-native/2.2/api/Db.html#createCollection)
+ *
+ * @method createCollection
+ * @param {string} collection The collection to create
+ * @param {Object} [options] see [MongoDB driver docs](http://mongodb.github.io/node-mongodb-native/2.2/api/Db.html#createCollection)
+ * @param {Function} [callback]
+ * @return {Promise}
+ * @api public
+ */
+
+Connection.prototype.createCollection = _wrapConnHelper(function createCollection(collection, options, cb) {
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+ this.db.createCollection(collection, options, cb);
+});
+
+/**
+ * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions)
+ * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/),
+ * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).
+ *
+ * ####Example:
+ *
+ * const session = await conn.startSession();
+ * let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
+ * await doc.remove();
+ * // `doc` will always be null, even if reading from a replica set
+ * // secondary. Without causal consistency, it is possible to
+ * // get a doc back from the below query if the query reads from a
+ * // secondary that is experiencing replication lag.
+ * doc = await Person.findOne({ name: 'Ned Stark' }, null, { session, readPreference: 'secondary' });
+ *
+ *
+ * @method startSession
+ * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#startSession)
+ * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
+ * @param {Function} [callback]
+ * @return {Promise} promise that resolves to a MongoDB driver `ClientSession`
+ * @api public
+ */
+
+Connection.prototype.startSession = _wrapConnHelper(function startSession(options, cb) {
+ if (typeof options === 'function') {
+ cb = options;
+ options = null;
+ }
+ const session = this.client.startSession(options);
+ cb(null, session);
+});
+
+/**
+ * Helper for `dropCollection()`. Will delete the given collection, including
+ * all documents and indexes.
+ *
+ * @method dropCollection
+ * @param {string} collection The collection to delete
+ * @param {Function} [callback]
+ * @return {Promise}
+ * @api public
+ */
+
+Connection.prototype.dropCollection = _wrapConnHelper(function dropCollection(collection, cb) {
+ this.db.dropCollection(collection, cb);
+});
+
+/**
+ * Helper for `dropDatabase()`. Deletes the given database, including all
+ * collections, documents, and indexes.
+ *
+ * ####Example:
+ *
+ * const conn = mongoose.createConnection('mongodb://localhost:27017/mydb');
+ * // Deletes the entire 'mydb' database
+ * await conn.dropDatabase();
+ *
+ * @method dropDatabase
+ * @param {Function} [callback]
+ * @return {Promise}
+ * @api public
+ */
+
+Connection.prototype.dropDatabase = _wrapConnHelper(function dropDatabase(cb) {
+ // If `dropDatabase()` is called, this model's collection will not be
+ // init-ed. It is sufficiently common to call `dropDatabase()` after
+ // `mongoose.connect()` but before creating models that we want to
+ // support this. See gh-6967
+ for (const name of Object.keys(this.models)) {
+ delete this.models[name].$init;
+ }
+ this.db.dropDatabase(cb);
+});
+
+/*!
+ * ignore
+ */
+
+function _wrapConnHelper(fn) {
+ return function() {
+ const cb = arguments.length > 0 ? arguments[arguments.length - 1] : null;
+ const argsWithoutCb = typeof cb === 'function' ?
+ Array.prototype.slice.call(arguments, 0, arguments.length - 1) :
+ Array.prototype.slice.call(arguments);
+ const disconnectedError = new MongooseError('Connection ' + this.id +
+ ' was disconnected when calling `' + fn.name + '`');
+ return promiseOrCallback(cb, cb => {
+ // Make it ok to call collection helpers before `mongoose.connect()`
+ // as long as `mongoose.connect()` is called on the same tick.
+ // Re: gh-8534
+ immediate(() => {
+ if (this.readyState === STATES.connecting) {
+ this.once('open', function() {
+ fn.apply(this, argsWithoutCb.concat([cb]));
+ });
+ } else if (this.readyState === STATES.disconnected && this.db == null) {
+ cb(disconnectedError);
+ } else {
+ fn.apply(this, argsWithoutCb.concat([cb]));
+ }
+ });
+ });
+ };
+}
+
+/**
+ * error
+ *
+ * Graceful error handling, passes error to callback
+ * if available, else emits error on the connection.
+ *
+ * @param {Error} err
+ * @param {Function} callback optional
+ * @api private
+ */
+
+Connection.prototype.error = function(err, callback) {
+ if (callback) {
+ callback(err);
+ return null;
+ }
+ if (this.listeners('error').length > 0) {
+ this.emit('error', err);
+ }
+ return Promise.reject(err);
+};
+
+/**
+ * Called when the connection is opened
+ *
+ * @api private
+ */
+
+Connection.prototype.onOpen = function() {
+ this.readyState = STATES.connected;
+
+ // avoid having the collection subscribe to our event emitter
+ // to prevent 0.3 warning
+ for (const i in this.collections) {
+ if (utils.object.hasOwnProperty(this.collections, i)) {
+ this.collections[i].onOpen();
+ }
+ }
+
+ this.emit('open');
+};
+
+/**
+ * Opens the connection with a URI using `MongoClient.connect()`.
+ *
+ * @param {String} uri The URI to connect with.
+ * @param {Object} [options] Passed on to http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect
+ * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
+ * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ * @param {Boolean} [options.useNewUrlParser=false] False by default. Set to `true` to opt in to the MongoDB driver's new URL parser logic.
+ * @param {Boolean} [options.useUnifiedTopology=false] False by default. Set to `true` to opt in to the MongoDB driver's replica set and sharded cluster monitoring engine.
+ * @param {Boolean} [options.useCreateIndex=true] Mongoose-specific option. If `true`, this connection will use [`createIndex()` instead of `ensureIndex()`](/docs/deprecations.html#ensureindex) for automatic index builds via [`Model.init()`](/docs/api.html#model_Model.init).
+ * @param {Boolean} [options.useFindAndModify=true] True by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
+ * @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
+ * @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
+ * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
+ * @param {Number} [options.poolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ * @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
+ * @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
+ * @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
+ * @param {Function} [callback]
+ * @returns {Connection} this
+ * @api public
+ */
+
+Connection.prototype.openUri = function(uri, options, callback) {
+ this.readyState = STATES.connecting;
+ this._closeCalled = false;
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ if (['string', 'number'].indexOf(typeof options) !== -1) {
+ throw new MongooseError('Mongoose 5.x no longer supports ' +
+ '`mongoose.connect(host, dbname, port)` or ' +
+ '`mongoose.createConnection(host, dbname, port)`. See ' +
+ 'http://mongoosejs.com/docs/connections.html for supported connection syntax');
+ }
+
+ if (typeof uri !== 'string') {
+ throw new MongooseError('The `uri` parameter to `openUri()` must be a ' +
+ `string, got "${typeof uri}". Make sure the first parameter to ` +
+ '`mongoose.connect()` or `mongoose.createConnection()` is a string.');
+ }
+
+ if (callback != null && typeof callback !== 'function') {
+ throw new MongooseError('3rd parameter to `mongoose.connect()` or ' +
+ '`mongoose.createConnection()` must be a function, got "' +
+ typeof callback + '"');
+ }
+
+ const Promise = PromiseProvider.get();
+ const _this = this;
+
+ if (options) {
+ options = utils.clone(options);
+ const autoIndex = options.config && options.config.autoIndex != null ?
+ options.config.autoIndex :
+ options.autoIndex;
+ if (autoIndex != null) {
+ this.config.autoIndex = autoIndex !== false;
+ delete options.config;
+ delete options.autoIndex;
+ }
+
+ if ('autoCreate' in options) {
+ this.config.autoCreate = !!options.autoCreate;
+ delete options.autoCreate;
+ }
+ if ('useCreateIndex' in options) {
+ this.config.useCreateIndex = !!options.useCreateIndex;
+ delete options.useCreateIndex;
+ }
+
+ if ('useFindAndModify' in options) {
+ this.config.useFindAndModify = !!options.useFindAndModify;
+ delete options.useFindAndModify;
+ }
+
+ // Backwards compat
+ if (options.user || options.pass) {
+ options.auth = options.auth || {};
+ options.auth.user = options.user;
+ options.auth.password = options.pass;
+
+ this.user = options.user;
+ this.pass = options.pass;
+ }
+ delete options.user;
+ delete options.pass;
+
+ if (options.bufferCommands != null) {
+ options.bufferMaxEntries = 0;
+ this.config.bufferCommands = options.bufferCommands;
+ delete options.bufferCommands;
+ }
+
+ if (options.useMongoClient != null) {
+ handleUseMongoClient(options);
+ }
+ } else {
+ options = {};
+ }
+
+ this._connectionOptions = options;
+ const dbName = options.dbName;
+ if (dbName != null) {
+ this.$dbName = dbName;
+ }
+ delete options.dbName;
+
+ if (!('promiseLibrary' in options)) {
+ options.promiseLibrary = PromiseProvider.get();
+ }
+ if (!('useNewUrlParser' in options)) {
+ if ('useNewUrlParser' in this.base.options) {
+ options.useNewUrlParser = this.base.options.useNewUrlParser;
+ } else {
+ options.useNewUrlParser = false;
+ }
+ }
+ if (!utils.hasUserDefinedProperty(options, 'useUnifiedTopology')) {
+ if (utils.hasUserDefinedProperty(this.base.options, 'useUnifiedTopology')) {
+ options.useUnifiedTopology = this.base.options.useUnifiedTopology;
+ } else {
+ options.useUnifiedTopology = false;
+ }
+ }
+ if (!utils.hasUserDefinedProperty(options, 'driverInfo')) {
+ options.driverInfo = {
+ name: 'Mongoose',
+ version: pkg.version
+ };
+ }
+
+ const parsePromise = new Promise((resolve, reject) => {
+ parseConnectionString(uri, options, (err, parsed) => {
+ if (err) {
+ return reject(err);
+ }
+ if (dbName) {
+ this.name = dbName;
+ } else if (parsed.defaultDatabase) {
+ this.name = parsed.defaultDatabase;
+ } else {
+ this.name = get(parsed, 'auth.db', null);
+ }
+ this.host = get(parsed, 'hosts.0.host', 'localhost');
+ this.port = get(parsed, 'hosts.0.port', 27017);
+ this.user = this.user || get(parsed, 'auth.username');
+ this.pass = this.pass || get(parsed, 'auth.password');
+ resolve();
+ });
+ });
+
+ const _handleReconnect = () => {
+ // If we aren't disconnected, we assume this reconnect is due to a
+ // socket timeout. If there's no activity on a socket for
+ // `socketTimeoutMS`, the driver will attempt to reconnect and emit
+ // this event.
+ if (_this.readyState !== STATES.connected) {
+ _this.readyState = STATES.connected;
+ _this.emit('reconnect');
+ _this.emit('reconnected');
+ }
+ };
+
+ const promise = new Promise((resolve, reject) => {
+ const client = new mongodb.MongoClient(uri, options);
+ _this.client = client;
+ client.connect(function(error) {
+ if (error) {
+ _this.readyState = STATES.disconnected;
+ return reject(error);
+ }
+
+ const db = dbName != null ? client.db(dbName) : client.db();
+ _this.db = db;
+
+ // `useUnifiedTopology` events
+ const type = get(db, 's.topology.s.description.type', '');
+ if (options.useUnifiedTopology) {
+ if (type === 'Single') {
+ const server = Array.from(db.s.topology.s.servers.values())[0];
+
+ server.s.topology.on('serverHeartbeatSucceeded', () => {
+ _handleReconnect();
+ });
+ server.s.pool.on('reconnect', () => {
+ _handleReconnect();
+ });
+ client.on('serverDescriptionChanged', ev => {
+ const newDescription = ev.newDescription;
+ if (newDescription.type === 'Standalone') {
+ _handleReconnect();
+ } else {
+ _this.readyState = STATES.disconnected;
+ }
+ });
+ } else if (type.startsWith('ReplicaSet')) {
+ client.on('topologyDescriptionChanged', ev => {
+ // Emit disconnected if we've lost connectivity to _all_ servers
+ // in the replica set.
+ const description = ev.newDescription;
+ const servers = Array.from(ev.newDescription.servers.values());
+ const allServersDisconnected = description.type === 'ReplicaSetNoPrimary' &&
+ servers.reduce((cur, d) => cur || d.type === 'Unknown', false);
+ if (_this.readyState === STATES.connected && allServersDisconnected) {
+ // Implicitly emits 'disconnected'
+ _this.readyState = STATES.disconnected;
+ } else if (_this.readyState === STATES.disconnected && !allServersDisconnected) {
+ _handleReconnect();
+ }
+ });
+
+ db.on('close', function() {
+ const type = get(db, 's.topology.s.description.type', '');
+ if (type !== 'ReplicaSetWithPrimary') {
+ // Implicitly emits 'disconnected'
+ _this.readyState = STATES.disconnected;
+ }
+ });
+ }
+ }
+
+ // Backwards compat for mongoose 4.x
+ db.on('reconnect', function() {
+ _handleReconnect();
+ });
+ db.s.topology.on('reconnectFailed', function() {
+ _this.emit('reconnectFailed');
+ });
+
+ if (!options.useUnifiedTopology) {
+ db.s.topology.on('left', function(data) {
+ _this.emit('left', data);
+ });
+ }
+ db.s.topology.on('joined', function(data) {
+ _this.emit('joined', data);
+ });
+ db.s.topology.on('fullsetup', function(data) {
+ _this.emit('fullsetup', data);
+ });
+ if (get(db, 's.topology.s.coreTopology.s.pool') != null) {
+ db.s.topology.s.coreTopology.s.pool.on('attemptReconnect', function() {
+ _this.emit('attemptReconnect');
+ });
+ }
+ if (!options.useUnifiedTopology || !type.startsWith('ReplicaSet')) {
+ db.on('close', function() {
+ // Implicitly emits 'disconnected'
+ _this.readyState = STATES.disconnected;
+ });
+ }
+
+ if (!options.useUnifiedTopology) {
+ client.on('left', function() {
+ if (_this.readyState === STATES.connected &&
+ get(db, 's.topology.s.coreTopology.s.replicaSetState.topologyType') === 'ReplicaSetNoPrimary') {
+ _this.readyState = STATES.disconnected;
+ }
+ });
+ }
+
+ db.on('timeout', function() {
+ _this.emit('timeout');
+ });
+
+ delete _this.then;
+ delete _this.catch;
+ _this.readyState = STATES.connected;
+
+ for (const i in _this.collections) {
+ if (utils.object.hasOwnProperty(_this.collections, i)) {
+ _this.collections[i].onOpen();
+ }
+ }
+
+ resolve(_this);
+ _this.emit('open');
+ });
+ });
+
+ const serverSelectionError = new ServerSelectionError();
+ this.$initialConnection = Promise.all([promise, parsePromise]).
+ then(res => res[0]).
+ catch(err => {
+ if (err != null && err.name === 'MongoServerSelectionError') {
+ err = serverSelectionError.assimilateError(err);
+ }
+
+ if (this.listeners('error').length > 0) {
+ process.nextTick(() => this.emit('error', err));
+ }
+ throw err;
+ });
+ this.then = function(resolve, reject) {
+ return this.$initialConnection.then(resolve, reject);
+ };
+ this.catch = function(reject) {
+ return this.$initialConnection.catch(reject);
+ };
+
+ if (callback != null) {
+ this.$initialConnection = this.$initialConnection.then(
+ () => callback(null, this),
+ err => callback(err)
+ );
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+const handleUseMongoClient = function handleUseMongoClient(options) {
+ console.warn('WARNING: The `useMongoClient` option is no longer ' +
+ 'necessary in mongoose 5.x, please remove it.');
+ const stack = new Error().stack;
+ console.warn(stack.substr(stack.indexOf('\n') + 1));
+ delete options.useMongoClient;
+};
+
+/**
+ * Closes the connection
+ *
+ * @param {Boolean} [force] optional
+ * @param {Function} [callback] optional
+ * @return {Promise}
+ * @api public
+ */
+
+Connection.prototype.close = function(force, callback) {
+ if (typeof force === 'function') {
+ callback = force;
+ force = false;
+ }
+
+ this.$wasForceClosed = !!force;
+
+ return promiseOrCallback(callback, cb => {
+ this._close(force, cb);
+ });
+};
+
+/**
+ * Handles closing the connection
+ *
+ * @param {Boolean} force
+ * @param {Function} callback
+ * @api private
+ */
+Connection.prototype._close = function(force, callback) {
+ const _this = this;
+ this._closeCalled = true;
+
+ switch (this.readyState) {
+ case STATES.disconnected:
+ callback();
+ break;
+
+ case STATES.connected:
+ this.readyState = STATES.disconnecting;
+ this.doClose(force, function(err) {
+ if (err) {
+ return callback(err);
+ }
+ _this.onClose(force);
+ callback(null);
+ });
+
+ break;
+ case STATES.connecting:
+ this.once('open', function() {
+ _this.close(callback);
+ });
+ break;
+
+ case STATES.disconnecting:
+ this.once('close', function() {
+ callback();
+ });
+ break;
+ }
+
+ return this;
+};
+
+/**
+ * Called when the connection closes
+ *
+ * @api private
+ */
+
+Connection.prototype.onClose = function(force) {
+ this.readyState = STATES.disconnected;
+
+ // avoid having the collection subscribe to our event emitter
+ // to prevent 0.3 warning
+ for (const i in this.collections) {
+ if (utils.object.hasOwnProperty(this.collections, i)) {
+ this.collections[i].onClose(force);
+ }
+ }
+
+ this.emit('close', force);
+};
+
+/**
+ * Retrieves a collection, creating it if not cached.
+ *
+ * Not typically needed by applications. Just talk to your collection through your model.
+ *
+ * @param {String} name of the collection
+ * @param {Object} [options] optional collection options
+ * @return {Collection} collection instance
+ * @api public
+ */
+
+Connection.prototype.collection = function(name, options) {
+ options = options ? utils.clone(options) : {};
+ options.$wasForceClosed = this.$wasForceClosed;
+ if (!(name in this.collections)) {
+ this.collections[name] = new Collection(name, this, options);
+ }
+ return this.collections[name];
+};
+
+/**
+ * Declares a plugin executed on all schemas you pass to `conn.model()`
+ *
+ * Equivalent to calling `.plugin(fn)` on each schema you create.
+ *
+ * ####Example:
+ * const db = mongoose.createConnection('mongodb://localhost:27017/mydb');
+ * db.plugin(() => console.log('Applied'));
+ * db.plugins.length; // 1
+ *
+ * db.model('Test', new Schema({})); // Prints "Applied"
+ *
+ * @param {Function} fn plugin callback
+ * @param {Object} [opts] optional options
+ * @return {Connection} this
+ * @see plugins ./plugins.html
+ * @api public
+ */
+
+Connection.prototype.plugin = function(fn, opts) {
+ this.plugins.push([fn, opts]);
+ return this;
+};
+
+/**
+ * Defines or retrieves a model.
+ *
+ * var mongoose = require('mongoose');
+ * var db = mongoose.createConnection(..);
+ * db.model('Venue', new Schema(..));
+ * var Ticket = db.model('Ticket', new Schema(..));
+ * var Venue = db.model('Venue');
+ *
+ * _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ name: String }, { collection: 'actor' });
+ *
+ * // or
+ *
+ * schema.set('collection', 'actor');
+ *
+ * // or
+ *
+ * var collectionName = 'actor'
+ * var M = conn.model('Actor', schema, collectionName)
+ *
+ * @param {String|Function} name the model name or class extending Model
+ * @param {Schema} [schema] a schema. necessary when defining a model
+ * @param {String} [collection] name of mongodb collection (optional) if not given it will be induced from model name
+ * @see Mongoose#model #index_Mongoose-model
+ * @return {Model} The compiled model
+ * @api public
+ */
+
+Connection.prototype.model = function(name, schema, collection) {
+ if (!(this instanceof Connection)) {
+ throw new MongooseError('`connection.model()` should not be run with ' +
+ '`new`. If you are doing `new db.model(foo)(bar)`, use ' +
+ '`db.model(foo)(bar)` instead');
+ }
+
+ let fn;
+ if (typeof name === 'function') {
+ fn = name;
+ name = fn.name;
+ }
+
+ // collection name discovery
+ if (typeof schema === 'string') {
+ collection = schema;
+ schema = false;
+ }
+
+ if (utils.isObject(schema) && !schema.instanceOfSchema) {
+ schema = new Schema(schema);
+ }
+ if (schema && !schema.instanceOfSchema) {
+ throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
+ 'schema or a POJO');
+ }
+
+ if (this.models[name] && !collection) {
+ // model exists but we are not subclassing with custom collection
+ if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
+ throw new MongooseError.OverwriteModelError(name);
+ }
+ return this.models[name];
+ }
+
+ const opts = { cache: false, connection: this };
+ let model;
+
+ if (schema && schema.instanceOfSchema) {
+ applyPlugins(schema, this.plugins, null, '$connectionPluginsApplied');
+
+ // compile a model
+ model = this.base.model(fn || name, schema, collection, opts);
+
+ // only the first model with this name is cached to allow
+ // for one-offs with custom collection names etc.
+ if (!this.models[name]) {
+ this.models[name] = model;
+ }
+
+ // Errors handled internally, so safe to ignore error
+ model.init(function $modelInitNoop() {});
+
+ return model;
+ }
+
+ if (this.models[name] && collection) {
+ // subclassing current model with alternate collection
+ model = this.models[name];
+ schema = model.prototype.schema;
+ const sub = model.__subclass(this, schema, collection);
+ // do not cache the sub model
+ return sub;
+ }
+
+ // lookup model in mongoose module
+ model = this.base.models[name];
+
+ if (!model) {
+ throw new MongooseError.MissingSchemaError(name);
+ }
+
+ if (this === model.prototype.db
+ && (!collection || collection === model.collection.name)) {
+ // model already uses this connection.
+
+ // only the first model with this name is cached to allow
+ // for one-offs with custom collection names etc.
+ if (!this.models[name]) {
+ this.models[name] = model;
+ }
+
+ return model;
+ }
+ this.models[name] = model.__subclass(this, schema, collection);
+ return this.models[name];
+};
+
+/**
+ * Removes the model named `name` from this connection, if it exists. You can
+ * use this function to clean up any models you created in your tests to
+ * prevent OverwriteModelErrors.
+ *
+ * ####Example:
+ *
+ * conn.model('User', new Schema({ name: String }));
+ * console.log(conn.model('User')); // Model object
+ * conn.deleteModel('User');
+ * console.log(conn.model('User')); // undefined
+ *
+ * // Usually useful in a Mocha `afterEach()` hook
+ * afterEach(function() {
+ * conn.deleteModel(/.+/); // Delete every model
+ * });
+ *
+ * @api public
+ * @param {String|RegExp} name if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.
+ * @return {Connection} this
+ */
+
+Connection.prototype.deleteModel = function(name) {
+ if (typeof name === 'string') {
+ const model = this.model(name);
+ if (model == null) {
+ return this;
+ }
+ delete this.models[name];
+ delete this.collections[model.collection.name];
+ delete this.base.modelSchemas[name];
+ } else if (name instanceof RegExp) {
+ const pattern = name;
+ const names = this.modelNames();
+ for (const name of names) {
+ if (pattern.test(name)) {
+ this.deleteModel(name);
+ }
+ }
+ } else {
+ throw new Error('First parameter to `deleteModel()` must be a string ' +
+ 'or regexp, got "' + name + '"');
+ }
+
+ return this;
+};
+
+/**
+ * Watches the entire underlying database for changes. Similar to
+ * [`Model.watch()`](/docs/api/model.html#model_Model.watch).
+ *
+ * This function does **not** trigger any middleware. In particular, it
+ * does **not** trigger aggregate middleware.
+ *
+ * The ChangeStream object is an event emitter that emits the following events:
+ *
+ * - 'change': A change occurred, see below example
+ * - 'error': An unrecoverable error occurred. In particular, change streams currently error out if they lose connection to the replica set primary. Follow [this GitHub issue](https://github.com/Automattic/mongoose/issues/6799) for updates.
+ * - 'end': Emitted if the underlying stream is closed
+ * - 'close': Emitted if the underlying stream is closed
+ *
+ * ####Example:
+ *
+ * const User = conn.model('User', new Schema({ name: String }));
+ *
+ * const changeStream = conn.watch().on('change', data => console.log(data));
+ *
+ * // Triggers a 'change' event on the change stream.
+ * await User.create({ name: 'test' });
+ *
+ * @api public
+ * @param {Array} [pipeline]
+ * @param {Object} [options] passed without changes to [the MongoDB driver's `Db#watch()` function](https://mongodb.github.io/node-mongodb-native/3.4/api/Db.html#watch)
+ * @return {ChangeStream} mongoose-specific change stream wrapper, inherits from EventEmitter
+ */
+
+Connection.prototype.watch = function(pipeline, options) {
+ const disconnectedError = new MongooseError('Connection ' + this.id +
+ ' was disconnected when calling `watch()`');
+
+ const changeStreamThunk = cb => {
+ immediate(() => {
+ if (this.readyState === STATES.connecting) {
+ this.once('open', function() {
+ const driverChangeStream = this.db.watch(pipeline, options);
+ cb(null, driverChangeStream);
+ });
+ } else if (this.readyState === STATES.disconnected && this.db == null) {
+ cb(disconnectedError);
+ } else {
+ const driverChangeStream = this.db.watch(pipeline, options);
+ cb(null, driverChangeStream);
+ }
+ });
+ };
+
+ const changeStream = new ChangeStream(changeStreamThunk, pipeline, options);
+ return changeStream;
+};
+
+/**
+ * Returns an array of model names created on this connection.
+ * @api public
+ * @return {Array}
+ */
+
+Connection.prototype.modelNames = function() {
+ return Object.keys(this.models);
+};
+
+/**
+ * @brief Returns if the connection requires authentication after it is opened. Generally if a
+ * username and password are both provided than authentication is needed, but in some cases a
+ * password is not required.
+ * @api private
+ * @return {Boolean} true if the connection should be authenticated after it is opened, otherwise false.
+ */
+Connection.prototype.shouldAuthenticate = function() {
+ return this.user != null &&
+ (this.pass != null || this.authMechanismDoesNotRequirePassword());
+};
+
+/**
+ * @brief Returns a boolean value that specifies if the current authentication mechanism needs a
+ * password to authenticate according to the auth objects passed into the openUri methods.
+ * @api private
+ * @return {Boolean} true if the authentication mechanism specified in the options object requires
+ * a password, otherwise false.
+ */
+Connection.prototype.authMechanismDoesNotRequirePassword = function() {
+ if (this.options && this.options.auth) {
+ return noPasswordAuthMechanisms.indexOf(this.options.auth.authMechanism) >= 0;
+ }
+ return true;
+};
+
+/**
+ * @brief Returns a boolean value that specifies if the provided objects object provides enough
+ * data to authenticate with. Generally this is true if the username and password are both specified
+ * but in some authentication methods, a password is not required for authentication so only a username
+ * is required.
+ * @param {Object} [options] the options object passed into the openUri methods.
+ * @api private
+ * @return {Boolean} true if the provided options object provides enough data to authenticate with,
+ * otherwise false.
+ */
+Connection.prototype.optionsProvideAuthenticationData = function(options) {
+ return (options) &&
+ (options.user) &&
+ ((options.pass) || this.authMechanismDoesNotRequirePassword());
+};
+
+/**
+ * Switches to a different database using the same connection pool.
+ *
+ * Returns a new connection object, with the new db.
+ *
+ * @method useDb
+ * @memberOf Connection
+ * @param {String} name The database name
+ * @param {Object} [options]
+ * @param {Boolean} [options.useCache=false] If true, cache results so calling `useDb()` multiple times with the same name only creates 1 connection object.
+ * @return {Connection} New Connection Object
+ * @api public
+ */
+
+/*!
+ * Module exports.
+ */
+
+Connection.STATES = STATES;
+module.exports = Connection;
diff --git a/node_modules/mongoose/lib/connectionstate.js b/node_modules/mongoose/lib/connectionstate.js
new file mode 100644
index 0000000..920f45b
--- /dev/null
+++ b/node_modules/mongoose/lib/connectionstate.js
@@ -0,0 +1,26 @@
+
+/*!
+ * Connection states
+ */
+
+'use strict';
+
+const STATES = module.exports = exports = Object.create(null);
+
+const disconnected = 'disconnected';
+const connected = 'connected';
+const connecting = 'connecting';
+const disconnecting = 'disconnecting';
+const uninitialized = 'uninitialized';
+
+STATES[0] = disconnected;
+STATES[1] = connected;
+STATES[2] = connecting;
+STATES[3] = disconnecting;
+STATES[99] = uninitialized;
+
+STATES[disconnected] = 0;
+STATES[connected] = 1;
+STATES[connecting] = 2;
+STATES[disconnecting] = 3;
+STATES[uninitialized] = 99;
diff --git a/node_modules/mongoose/lib/cursor/AggregationCursor.js b/node_modules/mongoose/lib/cursor/AggregationCursor.js
new file mode 100644
index 0000000..51dd519
--- /dev/null
+++ b/node_modules/mongoose/lib/cursor/AggregationCursor.js
@@ -0,0 +1,306 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('../error/mongooseError');
+const Readable = require('stream').Readable;
+const promiseOrCallback = require('../helpers/promiseOrCallback');
+const eachAsync = require('../helpers/cursor/eachAsync');
+const util = require('util');
+
+/**
+ * An AggregationCursor is a concurrency primitive for processing aggregation
+ * results one document at a time. It is analogous to QueryCursor.
+ *
+ * An AggregationCursor fulfills the Node.js streams3 API,
+ * in addition to several other mechanisms for loading documents from MongoDB
+ * one at a time.
+ *
+ * Creating an AggregationCursor executes the model's pre aggregate hooks,
+ * but **not** the model's post aggregate hooks.
+ *
+ * Unless you're an advanced user, do **not** instantiate this class directly.
+ * Use [`Aggregate#cursor()`](/docs/api.html#aggregate_Aggregate-cursor) instead.
+ *
+ * @param {Aggregate} agg
+ * @param {Object} options
+ * @inherits Readable
+ * @event `cursor`: Emitted when the cursor is created
+ * @event `error`: Emitted when an error occurred
+ * @event `data`: Emitted when the stream is flowing and the next doc is ready
+ * @event `end`: Emitted when the stream is exhausted
+ * @api public
+ */
+
+function AggregationCursor(agg) {
+ Readable.call(this, { objectMode: true });
+
+ this.cursor = null;
+ this.agg = agg;
+ this._transforms = [];
+ const model = agg._model;
+ delete agg.options.cursor.useMongooseAggCursor;
+ this._mongooseOptions = {};
+
+ _init(model, this, agg);
+}
+
+util.inherits(AggregationCursor, Readable);
+
+/*!
+ * ignore
+ */
+
+function _init(model, c, agg) {
+ if (!model.collection.buffer) {
+ model.hooks.execPre('aggregate', agg, function() {
+ c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
+ c.emit('cursor', c.cursor);
+ });
+ } else {
+ model.collection.emitter.once('queue', function() {
+ model.hooks.execPre('aggregate', agg, function() {
+ c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
+ c.emit('cursor', c.cursor);
+ });
+ });
+ }
+}
+
+/*!
+ * Necessary to satisfy the Readable API
+ */
+
+AggregationCursor.prototype._read = function() {
+ const _this = this;
+ _next(this, function(error, doc) {
+ if (error) {
+ return _this.emit('error', error);
+ }
+ if (!doc) {
+ _this.push(null);
+ _this.cursor.close(function(error) {
+ if (error) {
+ return _this.emit('error', error);
+ }
+ setTimeout(function() {
+ _this.emit('close');
+ }, 0);
+ });
+ return;
+ }
+ _this.push(doc);
+ });
+};
+
+if (Symbol.asyncIterator != null) {
+ const msg = 'Mongoose does not support using async iterators with an ' +
+ 'existing aggregation cursor. See http://bit.ly/mongoose-async-iterate-aggregation';
+
+ AggregationCursor.prototype[Symbol.asyncIterator] = function() {
+ throw new MongooseError(msg);
+ };
+}
+
+/**
+ * Registers a transform function which subsequently maps documents retrieved
+ * via the streams interface or `.next()`
+ *
+ * ####Example
+ *
+ * // Map documents returned by `data` events
+ * Thing.
+ * find({ name: /^hello/ }).
+ * cursor().
+ * map(function (doc) {
+ * doc.foo = "bar";
+ * return doc;
+ * })
+ * on('data', function(doc) { console.log(doc.foo); });
+ *
+ * // Or map documents returned by `.next()`
+ * var cursor = Thing.find({ name: /^hello/ }).
+ * cursor().
+ * map(function (doc) {
+ * doc.foo = "bar";
+ * return doc;
+ * });
+ * cursor.next(function(error, doc) {
+ * console.log(doc.foo);
+ * });
+ *
+ * @param {Function} fn
+ * @return {AggregationCursor}
+ * @api public
+ * @method map
+ */
+
+AggregationCursor.prototype.map = function(fn) {
+ this._transforms.push(fn);
+ return this;
+};
+
+/*!
+ * Marks this cursor as errored
+ */
+
+AggregationCursor.prototype._markError = function(error) {
+ this._error = error;
+ return this;
+};
+
+/**
+ * Marks this cursor as closed. Will stop streaming and subsequent calls to
+ * `next()` will error.
+ *
+ * @param {Function} callback
+ * @return {Promise}
+ * @api public
+ * @method close
+ * @emits close
+ * @see MongoDB driver cursor#close http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#close
+ */
+
+AggregationCursor.prototype.close = function(callback) {
+ return promiseOrCallback(callback, cb => {
+ this.cursor.close(error => {
+ if (error) {
+ cb(error);
+ return this.listeners('error').length > 0 && this.emit('error', error);
+ }
+ this.emit('close');
+ cb(null);
+ });
+ });
+};
+
+/**
+ * Get the next document from this cursor. Will return `null` when there are
+ * no documents left.
+ *
+ * @param {Function} callback
+ * @return {Promise}
+ * @api public
+ * @method next
+ */
+
+AggregationCursor.prototype.next = function(callback) {
+ return promiseOrCallback(callback, cb => {
+ _next(this, cb);
+ });
+};
+
+/**
+ * Execute `fn` for every document in the cursor. If `fn` returns a promise,
+ * will wait for the promise to resolve before iterating on to the next one.
+ * Returns a promise that resolves when done.
+ *
+ * @param {Function} fn
+ * @param {Object} [options]
+ * @param {Number} [options.parallel] the number of promises to execute in parallel. Defaults to 1.
+ * @param {Function} [callback] executed when all docs have been processed
+ * @return {Promise}
+ * @api public
+ * @method eachAsync
+ */
+
+AggregationCursor.prototype.eachAsync = function(fn, opts, callback) {
+ const _this = this;
+ if (typeof opts === 'function') {
+ callback = opts;
+ opts = {};
+ }
+ opts = opts || {};
+
+ return eachAsync(function(cb) { return _next(_this, cb); }, fn, opts, callback);
+};
+
+/*!
+ * ignore
+ */
+
+AggregationCursor.prototype.transformNull = function(val) {
+ if (arguments.length === 0) {
+ val = true;
+ }
+ this._mongooseOptions.transformNull = val;
+ return this;
+};
+
+/**
+ * Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag).
+ * Useful for setting the `noCursorTimeout` and `tailable` flags.
+ *
+ * @param {String} flag
+ * @param {Boolean} value
+ * @return {AggregationCursor} this
+ * @api public
+ * @method addCursorFlag
+ */
+
+AggregationCursor.prototype.addCursorFlag = function(flag, value) {
+ const _this = this;
+ _waitForCursor(this, function() {
+ _this.cursor.addCursorFlag(flag, value);
+ });
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+function _waitForCursor(ctx, cb) {
+ if (ctx.cursor) {
+ return cb();
+ }
+ ctx.once('cursor', function() {
+ cb();
+ });
+}
+
+/*!
+ * Get the next doc from the underlying cursor and mongooseify it
+ * (populate, etc.)
+ */
+
+function _next(ctx, cb) {
+ let callback = cb;
+ if (ctx._transforms.length) {
+ callback = function(err, doc) {
+ if (err || (doc === null && !ctx._mongooseOptions.transformNull)) {
+ return cb(err, doc);
+ }
+ cb(err, ctx._transforms.reduce(function(doc, fn) {
+ return fn(doc);
+ }, doc));
+ };
+ }
+
+ if (ctx._error) {
+ return process.nextTick(function() {
+ callback(ctx._error);
+ });
+ }
+
+ if (ctx.cursor) {
+ return ctx.cursor.next(function(error, doc) {
+ if (error) {
+ return callback(error);
+ }
+ if (!doc) {
+ return callback(null, null);
+ }
+
+ callback(null, doc);
+ });
+ } else {
+ ctx.once('cursor', function() {
+ _next(ctx, cb);
+ });
+ }
+}
+
+module.exports = AggregationCursor;
diff --git a/node_modules/mongoose/lib/cursor/ChangeStream.js b/node_modules/mongoose/lib/cursor/ChangeStream.js
new file mode 100644
index 0000000..b3445b0
--- /dev/null
+++ b/node_modules/mongoose/lib/cursor/ChangeStream.js
@@ -0,0 +1,61 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const EventEmitter = require('events').EventEmitter;
+
+/*!
+ * ignore
+ */
+
+class ChangeStream extends EventEmitter {
+ constructor(changeStreamThunk, pipeline, options) {
+ super();
+
+ this.driverChangeStream = null;
+ this.closed = false;
+ this.pipeline = pipeline;
+ this.options = options;
+
+ // This wrapper is necessary because of buffering.
+ changeStreamThunk((err, driverChangeStream) => {
+ if (err != null) {
+ this.emit('error', err);
+ return;
+ }
+
+ this.driverChangeStream = driverChangeStream;
+ this._bindEvents();
+ this.emit('ready');
+ });
+ }
+
+ _bindEvents() {
+ this.driverChangeStream.on('close', () => {
+ this.closed = true;
+ });
+
+ ['close', 'change', 'end', 'error'].forEach(ev => {
+ this.driverChangeStream.on(ev, data => this.emit(ev, data));
+ });
+ }
+
+ _queue(cb) {
+ this.once('ready', () => cb());
+ }
+
+ close() {
+ this.closed = true;
+ if (this.driverChangeStream) {
+ this.driverChangeStream.close();
+ }
+ }
+}
+
+/*!
+ * ignore
+ */
+
+module.exports = ChangeStream;
diff --git a/node_modules/mongoose/lib/cursor/QueryCursor.js b/node_modules/mongoose/lib/cursor/QueryCursor.js
new file mode 100644
index 0000000..de0108a
--- /dev/null
+++ b/node_modules/mongoose/lib/cursor/QueryCursor.js
@@ -0,0 +1,348 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const Readable = require('stream').Readable;
+const promiseOrCallback = require('../helpers/promiseOrCallback');
+const eachAsync = require('../helpers/cursor/eachAsync');
+const helpers = require('../queryhelpers');
+const util = require('util');
+
+/**
+ * A QueryCursor is a concurrency primitive for processing query results
+ * one document at a time. A QueryCursor fulfills the Node.js streams3 API,
+ * in addition to several other mechanisms for loading documents from MongoDB
+ * one at a time.
+ *
+ * QueryCursors execute the model's pre find hooks, but **not** the model's
+ * post find hooks.
+ *
+ * Unless you're an advanced user, do **not** instantiate this class directly.
+ * Use [`Query#cursor()`](/docs/api.html#query_Query-cursor) instead.
+ *
+ * @param {Query} query
+ * @param {Object} options query options passed to `.find()`
+ * @inherits Readable
+ * @event `cursor`: Emitted when the cursor is created
+ * @event `error`: Emitted when an error occurred
+ * @event `data`: Emitted when the stream is flowing and the next doc is ready
+ * @event `end`: Emitted when the stream is exhausted
+ * @api public
+ */
+
+function QueryCursor(query, options) {
+ Readable.call(this, { objectMode: true });
+
+ this.cursor = null;
+ this.query = query;
+ const _this = this;
+ const model = query.model;
+ this._mongooseOptions = {};
+ this._transforms = [];
+ this.model = model;
+ this.options = options || {};
+
+ model.hooks.execPre('find', query, () => {
+ this._transforms = this._transforms.concat(query._transforms.slice());
+ if (this.options.transform) {
+ this._transforms.push(options.transform);
+ }
+ // Re: gh-8039, you need to set the `cursor.batchSize` option, top-level
+ // `batchSize` option doesn't work.
+ if (this.options.batchSize) {
+ this.options.cursor = options.cursor || {};
+ this.options.cursor.batchSize = options.batchSize;
+ }
+ model.collection.find(query._conditions, this.options, function(err, cursor) {
+ if (_this._error) {
+ cursor.close(function() {});
+ _this.listeners('error').length > 0 && _this.emit('error', _this._error);
+ }
+ if (err) {
+ return _this.emit('error', err);
+ }
+ _this.cursor = cursor;
+ _this.emit('cursor', cursor);
+ });
+ });
+}
+
+util.inherits(QueryCursor, Readable);
+
+/*!
+ * Necessary to satisfy the Readable API
+ */
+
+QueryCursor.prototype._read = function() {
+ const _this = this;
+ _next(this, function(error, doc) {
+ if (error) {
+ return _this.emit('error', error);
+ }
+ if (!doc) {
+ _this.push(null);
+ _this.cursor.close(function(error) {
+ if (error) {
+ return _this.emit('error', error);
+ }
+ setTimeout(function() {
+ _this.emit('close');
+ }, 0);
+ });
+ return;
+ }
+ _this.push(doc);
+ });
+};
+
+/**
+ * Registers a transform function which subsequently maps documents retrieved
+ * via the streams interface or `.next()`
+ *
+ * ####Example
+ *
+ * // Map documents returned by `data` events
+ * Thing.
+ * find({ name: /^hello/ }).
+ * cursor().
+ * map(function (doc) {
+ * doc.foo = "bar";
+ * return doc;
+ * })
+ * on('data', function(doc) { console.log(doc.foo); });
+ *
+ * // Or map documents returned by `.next()`
+ * var cursor = Thing.find({ name: /^hello/ }).
+ * cursor().
+ * map(function (doc) {
+ * doc.foo = "bar";
+ * return doc;
+ * });
+ * cursor.next(function(error, doc) {
+ * console.log(doc.foo);
+ * });
+ *
+ * @param {Function} fn
+ * @return {QueryCursor}
+ * @api public
+ * @method map
+ */
+
+QueryCursor.prototype.map = function(fn) {
+ this._transforms.push(fn);
+ return this;
+};
+
+/*!
+ * Marks this cursor as errored
+ */
+
+QueryCursor.prototype._markError = function(error) {
+ this._error = error;
+ return this;
+};
+
+/**
+ * Marks this cursor as closed. Will stop streaming and subsequent calls to
+ * `next()` will error.
+ *
+ * @param {Function} callback
+ * @return {Promise}
+ * @api public
+ * @method close
+ * @emits close
+ * @see MongoDB driver cursor#close http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#close
+ */
+
+QueryCursor.prototype.close = function(callback) {
+ return promiseOrCallback(callback, cb => {
+ this.cursor.close(error => {
+ if (error) {
+ cb(error);
+ return this.listeners('error').length > 0 && this.emit('error', error);
+ }
+ this.emit('close');
+ cb(null);
+ });
+ }, this.model.events);
+};
+
+/**
+ * Get the next document from this cursor. Will return `null` when there are
+ * no documents left.
+ *
+ * @param {Function} callback
+ * @return {Promise}
+ * @api public
+ * @method next
+ */
+
+QueryCursor.prototype.next = function(callback) {
+ return promiseOrCallback(callback, cb => {
+ _next(this, function(error, doc) {
+ if (error) {
+ return cb(error);
+ }
+ cb(null, doc);
+ });
+ }, this.model.events);
+};
+
+/**
+ * Execute `fn` for every document in the cursor. If `fn` returns a promise,
+ * will wait for the promise to resolve before iterating on to the next one.
+ * Returns a promise that resolves when done.
+ *
+ * @param {Function} fn
+ * @param {Object} [options]
+ * @param {Number} [options.parallel] the number of promises to execute in parallel. Defaults to 1.
+ * @param {Function} [callback] executed when all docs have been processed
+ * @return {Promise}
+ * @api public
+ * @method eachAsync
+ */
+
+QueryCursor.prototype.eachAsync = function(fn, opts, callback) {
+ const _this = this;
+ if (typeof opts === 'function') {
+ callback = opts;
+ opts = {};
+ }
+ opts = opts || {};
+
+ return eachAsync(function(cb) { return _next(_this, cb); }, fn, opts, callback);
+};
+
+/**
+ * The `options` passed in to the `QueryCursor` constructor.
+ *
+ * @api public
+ * @property options
+ */
+
+QueryCursor.prototype.options;
+
+/**
+ * Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag).
+ * Useful for setting the `noCursorTimeout` and `tailable` flags.
+ *
+ * @param {String} flag
+ * @param {Boolean} value
+ * @return {AggregationCursor} this
+ * @api public
+ * @method addCursorFlag
+ */
+
+QueryCursor.prototype.addCursorFlag = function(flag, value) {
+ const _this = this;
+ _waitForCursor(this, function() {
+ _this.cursor.addCursorFlag(flag, value);
+ });
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+QueryCursor.prototype.transformNull = function(val) {
+ if (arguments.length === 0) {
+ val = true;
+ }
+ this._mongooseOptions.transformNull = val;
+ return this;
+};
+
+/*!
+ * Get the next doc from the underlying cursor and mongooseify it
+ * (populate, etc.)
+ */
+
+function _next(ctx, cb) {
+ let callback = cb;
+ if (ctx._transforms.length) {
+ callback = function(err, doc) {
+ if (err || (doc === null && !ctx._mongooseOptions.transformNull)) {
+ return cb(err, doc);
+ }
+ cb(err, ctx._transforms.reduce(function(doc, fn) {
+ return fn.call(ctx, doc);
+ }, doc));
+ };
+ }
+
+ if (ctx._error) {
+ return process.nextTick(function() {
+ callback(ctx._error);
+ });
+ }
+
+ if (ctx.cursor) {
+ return ctx.cursor.next(function(error, doc) {
+ if (error) {
+ return callback(error);
+ }
+ if (!doc) {
+ return callback(null, null);
+ }
+
+ const opts = ctx.query._mongooseOptions;
+ if (!opts.populate) {
+ return opts.lean ?
+ callback(null, doc) :
+ _create(ctx, doc, null, callback);
+ }
+
+ const pop = helpers.preparePopulationOptionsMQ(ctx.query,
+ ctx.query._mongooseOptions);
+ pop.__noPromise = true;
+ ctx.query.model.populate(doc, pop, function(err, doc) {
+ if (err) {
+ return callback(err);
+ }
+ return opts.lean ?
+ callback(null, doc) :
+ _create(ctx, doc, pop, callback);
+ });
+ });
+ } else {
+ ctx.once('cursor', function() {
+ _next(ctx, cb);
+ });
+ }
+}
+
+/*!
+ * ignore
+ */
+
+function _waitForCursor(ctx, cb) {
+ if (ctx.cursor) {
+ return cb();
+ }
+ ctx.once('cursor', function() {
+ cb();
+ });
+}
+
+/*!
+ * Convert a raw doc into a full mongoose doc.
+ */
+
+function _create(ctx, doc, populatedIds, cb) {
+ const instance = helpers.createModel(ctx.query.model, doc, ctx.query._fields);
+ const opts = populatedIds ?
+ { populated: populatedIds } :
+ undefined;
+
+ instance.init(doc, opts, function(err) {
+ if (err) {
+ return cb(err);
+ }
+ cb(null, instance);
+ });
+}
+
+module.exports = QueryCursor;
diff --git a/node_modules/mongoose/lib/document.js b/node_modules/mongoose/lib/document.js
new file mode 100644
index 0000000..b81e45b
--- /dev/null
+++ b/node_modules/mongoose/lib/document.js
@@ -0,0 +1,3774 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const EventEmitter = require('events').EventEmitter;
+const InternalCache = require('./internal');
+const MongooseError = require('./error/index');
+const MixedSchema = require('./schema/mixed');
+const ObjectExpectedError = require('./error/objectExpected');
+const ObjectParameterError = require('./error/objectParameter');
+const ParallelValidateError = require('./error/parallelValidate');
+const Schema = require('./schema');
+const StrictModeError = require('./error/strict');
+const ValidationError = require('./error/validation');
+const ValidatorError = require('./error/validator');
+const VirtualType = require('./virtualtype');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const cleanModifiedSubpaths = require('./helpers/document/cleanModifiedSubpaths');
+const compile = require('./helpers/document/compile').compile;
+const defineKey = require('./helpers/document/compile').defineKey;
+const flatten = require('./helpers/common').flatten;
+const get = require('./helpers/get');
+const getEmbeddedDiscriminatorPath = require('./helpers/document/getEmbeddedDiscriminatorPath');
+const idGetter = require('./plugins/idGetter');
+const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
+const isExclusive = require('./helpers/projection/isExclusive');
+const inspect = require('util').inspect;
+const internalToObjectOptions = require('./options').internalToObjectOptions;
+const mpath = require('mpath');
+const utils = require('./utils');
+
+const clone = utils.clone;
+const deepEqual = utils.deepEqual;
+const isMongooseObject = utils.isMongooseObject;
+
+const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
+const documentArrayParent = require('./helpers/symbols').documentArrayParent;
+const documentSchemaSymbol = require('./helpers/symbols').documentSchemaSymbol;
+const getSymbol = require('./helpers/symbols').getSymbol;
+const populateModelSymbol = require('./helpers/symbols').populateModelSymbol;
+
+let DocumentArray;
+let MongooseArray;
+let Embedded;
+
+const specialProperties = utils.specialProperties;
+
+/**
+ * The core Mongoose document constructor. You should not call this directly,
+ * the Mongoose [Model constructor](./api.html#Model) calls this for you.
+ *
+ * @param {Object} obj the values to set
+ * @param {Object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
+ * @param {Boolean} [skipId] bool, should we auto create an ObjectId _id
+ * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
+ * @event `init`: Emitted on a document after it has been retrieved from the db and fully hydrated by Mongoose.
+ * @event `save`: Emitted when the document is successfully saved
+ * @api private
+ */
+
+function Document(obj, fields, skipId, options) {
+ if (typeof skipId === 'object' && skipId != null) {
+ options = skipId;
+ skipId = options.skipId;
+ }
+ options = options || {};
+
+ // Support `browserDocument.js` syntax
+ if (this.schema == null) {
+ const _schema = utils.isObject(fields) && !fields.instanceOfSchema ?
+ new Schema(fields) :
+ fields;
+ this.$__setSchema(_schema);
+ fields = skipId;
+ skipId = options;
+ options = arguments[4] || {};
+ }
+
+ this.$__ = new InternalCache;
+ this.$__.emitter = new EventEmitter();
+ this.isNew = 'isNew' in options ? options.isNew : true;
+ this.errors = undefined;
+ this.$__.$options = options || {};
+
+ if (obj != null && typeof obj !== 'object') {
+ throw new ObjectParameterError(obj, 'obj', 'Document');
+ }
+
+ const schema = this.schema;
+
+ if (typeof fields === 'boolean') {
+ this.$__.strictMode = fields;
+ fields = undefined;
+ } else {
+ this.$__.strictMode = schema.options.strict;
+ this.$__.selected = fields;
+ }
+
+ const required = schema.requiredPaths(true);
+ for (let i = 0; i < required.length; ++i) {
+ this.$__.activePaths.require(required[i]);
+ }
+
+ this.$__.emitter.setMaxListeners(0);
+
+ let exclude = null;
+
+ // determine if this doc is a result of a query with
+ // excluded fields
+ if (utils.isPOJO(fields)) {
+ exclude = isExclusive(fields);
+ }
+
+ const hasIncludedChildren = exclude === false && fields ?
+ $__hasIncludedChildren(fields) :
+ {};
+
+ if (this._doc == null) {
+ this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
+
+ // By default, defaults get applied **before** setting initial values
+ // Re: gh-6155
+ $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, true, {
+ isNew: this.isNew
+ });
+ }
+
+ if (obj) {
+ // Skip set hooks
+ if (this.$__original_set) {
+ this.$__original_set(obj, undefined, true);
+ } else {
+ this.$set(obj, undefined, true);
+ }
+
+ if (obj instanceof Document) {
+ this.isNew = obj.isNew;
+ }
+ }
+
+ // Function defaults get applied **after** setting initial values so they
+ // see the full doc rather than an empty one, unless they opt out.
+ // Re: gh-3781, gh-6155
+ if (options.willInit) {
+ EventEmitter.prototype.once.call(this, 'init', () => {
+ $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
+ isNew: this.isNew
+ });
+ });
+ } else {
+ $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
+ isNew: this.isNew
+ });
+ }
+
+ this.$__._id = this._id;
+ this.$locals = {};
+ this.$op = null;
+
+ if (!schema.options.strict && obj) {
+ const _this = this;
+ const keys = Object.keys(this._doc);
+
+ keys.forEach(function(key) {
+ if (!(key in schema.tree)) {
+ defineKey(key, null, _this);
+ }
+ });
+ }
+
+ applyQueue(this);
+}
+
+/*!
+ * Document exposes the NodeJS event emitter API, so you can use
+ * `on`, `once`, etc.
+ */
+utils.each(
+ ['on', 'once', 'emit', 'listeners', 'removeListener', 'setMaxListeners',
+ 'removeAllListeners', 'addListener'],
+ function(emitterFn) {
+ Document.prototype[emitterFn] = function() {
+ return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
+ };
+ });
+
+Document.prototype.constructor = Document;
+
+for (const i in EventEmitter.prototype) {
+ Document[i] = EventEmitter.prototype[i];
+}
+
+/**
+ * The documents schema.
+ *
+ * @api public
+ * @property schema
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.schema;
+
+/**
+ * Empty object that you can use for storing properties on the document. This
+ * is handy for passing data to middleware without conflicting with Mongoose
+ * internals.
+ *
+ * ####Example:
+ *
+ * schema.pre('save', function() {
+ * // Mongoose will set `isNew` to `false` if `save()` succeeds
+ * this.$locals.wasNew = this.isNew;
+ * });
+ *
+ * schema.post('save', function() {
+ * // Prints true if `isNew` was set before `save()`
+ * console.log(this.$locals.wasNew);
+ * });
+ *
+ * @api public
+ * @property $locals
+ * @memberOf Document
+ * @instance
+ */
+
+Object.defineProperty(Document.prototype, '$locals', {
+ configurable: false,
+ enumerable: false,
+ writable: true
+});
+
+/**
+ * Boolean flag specifying if the document is new.
+ *
+ * @api public
+ * @property isNew
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.isNew;
+
+/**
+ * The string version of this documents _id.
+ *
+ * ####Note:
+ *
+ * This getter exists on all documents by default. The getter can be disabled by setting the `id` [option](/docs/guide.html#id) of its `Schema` to false at construction time.
+ *
+ * new Schema({ name: String }, { id: false });
+ *
+ * @api public
+ * @see Schema options /docs/guide.html#options
+ * @property id
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.id;
+
+/**
+ * Hash containing current validation errors.
+ *
+ * @api public
+ * @property errors
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.errors;
+
+/**
+ * A string containing the current operation that Mongoose is executing
+ * on this document. May be `null`, `'save'`, `'validate'`, or `'remove'`.
+ *
+ * ####Example:
+ *
+ * const doc = new Model({ name: 'test' });
+ * doc.$op; // null
+ *
+ * const promise = doc.save();
+ * doc.$op; // 'save'
+ *
+ * await promise;
+ * doc.$op; // null
+ *
+ * @api public
+ * @property $op
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$op;
+
+/*!
+ * ignore
+ */
+
+function $__hasIncludedChildren(fields) {
+ const hasIncludedChildren = {};
+ const keys = Object.keys(fields);
+ for (let j = 0; j < keys.length; ++j) {
+ const parts = keys[j].split('.');
+ const c = [];
+ for (let k = 0; k < parts.length; ++k) {
+ c.push(parts[k]);
+ hasIncludedChildren[c.join('.')] = 1;
+ }
+ }
+
+ return hasIncludedChildren;
+}
+
+/*!
+ * ignore
+ */
+
+function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
+ const paths = Object.keys(doc.schema.paths);
+ const plen = paths.length;
+
+ for (let i = 0; i < plen; ++i) {
+ let def;
+ let curPath = '';
+ const p = paths[i];
+
+ if (p === '_id' && skipId) {
+ continue;
+ }
+
+ const type = doc.schema.paths[p];
+ const path = p.indexOf('.') === -1 ? [p] : p.split('.');
+ const len = path.length;
+ let included = false;
+ let doc_ = doc._doc;
+
+ for (let j = 0; j < len; ++j) {
+ if (doc_ == null) {
+ break;
+ }
+
+ const piece = path[j];
+ curPath += (!curPath.length ? '' : '.') + piece;
+
+ if (exclude === true) {
+ if (curPath in fields) {
+ break;
+ }
+ } else if (exclude === false && fields && !included) {
+ if (curPath in fields) {
+ included = true;
+ } else if (!hasIncludedChildren[curPath]) {
+ break;
+ }
+ }
+
+ if (j === len - 1) {
+ if (doc_[piece] !== void 0) {
+ break;
+ }
+
+ if (typeof type.defaultValue === 'function') {
+ if (!type.defaultValue.$runBeforeSetters && isBeforeSetters) {
+ break;
+ }
+ if (type.defaultValue.$runBeforeSetters && !isBeforeSetters) {
+ break;
+ }
+ } else if (!isBeforeSetters) {
+ // Non-function defaults should always run **before** setters
+ continue;
+ }
+
+ if (pathsToSkip && pathsToSkip[curPath]) {
+ break;
+ }
+
+ if (fields && exclude !== null) {
+ if (exclude === true) {
+ // apply defaults to all non-excluded fields
+ if (p in fields) {
+ continue;
+ }
+
+ def = type.getDefault(doc, false);
+ if (typeof def !== 'undefined') {
+ doc_[piece] = def;
+ doc.$__.activePaths.default(p);
+ }
+ } else if (included) {
+ // selected field
+ def = type.getDefault(doc, false);
+ if (typeof def !== 'undefined') {
+ doc_[piece] = def;
+ doc.$__.activePaths.default(p);
+ }
+ }
+ } else {
+ def = type.getDefault(doc, false);
+ if (typeof def !== 'undefined') {
+ doc_[piece] = def;
+ doc.$__.activePaths.default(p);
+ }
+ }
+ } else {
+ doc_ = doc_[piece];
+ }
+ }
+ }
+}
+
+/**
+ * Builds the default doc structure
+ *
+ * @param {Object} obj
+ * @param {Object} [fields]
+ * @param {Boolean} [skipId]
+ * @api private
+ * @method $__buildDoc
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) {
+ const doc = {};
+
+ const paths = Object.keys(this.schema.paths).
+ // Don't build up any paths that are underneath a map, we don't know
+ // what the keys will be
+ filter(p => !p.includes('$*'));
+ const plen = paths.length;
+ let ii = 0;
+
+ for (; ii < plen; ++ii) {
+ const p = paths[ii];
+
+ if (p === '_id') {
+ if (skipId) {
+ continue;
+ }
+ if (obj && '_id' in obj) {
+ continue;
+ }
+ }
+
+ const path = p.split('.');
+ const len = path.length;
+ const last = len - 1;
+ let curPath = '';
+ let doc_ = doc;
+ let included = false;
+
+ for (let i = 0; i < len; ++i) {
+ const piece = path[i];
+
+ curPath += (!curPath.length ? '' : '.') + piece;
+
+ // support excluding intermediary levels
+ if (exclude === true) {
+ if (curPath in fields) {
+ break;
+ }
+ } else if (exclude === false && fields && !included) {
+ if (curPath in fields) {
+ included = true;
+ } else if (!hasIncludedChildren[curPath]) {
+ break;
+ }
+ }
+
+ if (i < last) {
+ doc_ = doc_[piece] || (doc_[piece] = {});
+ }
+ }
+ }
+
+ this._doc = doc;
+};
+
+/*!
+ * Converts to POJO when you use the document for querying
+ */
+
+Document.prototype.toBSON = function() {
+ return this.toObject(internalToObjectOptions);
+};
+
+/**
+ * Initializes the document without setters or marking anything modified.
+ *
+ * Called internally after a document is returned from mongodb. Normally,
+ * you do **not** need to call this function on your own.
+ *
+ * This function triggers `init` [middleware](/docs/middleware.html).
+ * Note that `init` hooks are [synchronous](/docs/middleware.html#synchronous).
+ *
+ * @param {Object} doc document returned by mongo
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.init = function(doc, opts, fn) {
+ if (typeof opts === 'function') {
+ fn = opts;
+ opts = null;
+ }
+
+ this.$__init(doc, opts);
+
+ if (fn) {
+ fn(null, this);
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+Document.prototype.$__init = function(doc, opts) {
+ this.isNew = false;
+ this.$init = true;
+ opts = opts || {};
+
+ // handle docs with populated paths
+ // If doc._id is not null or undefined
+ if (doc._id != null && opts.populated && opts.populated.length) {
+ const id = String(doc._id);
+ for (let i = 0; i < opts.populated.length; ++i) {
+ const item = opts.populated[i];
+ if (item.isVirtual) {
+ this.populated(item.path, utils.getValue(item.path, doc), item);
+ } else {
+ this.populated(item.path, item._docs[id], item);
+ }
+ }
+ }
+
+ init(this, doc, this._doc, opts);
+
+ markArraySubdocsPopulated(this, opts.populated);
+
+ this.emit('init', this);
+ this.constructor.emit('init', this);
+
+ this.$__._id = this._id;
+
+ return this;
+};
+
+/*!
+ * If populating a path within a document array, make sure each
+ * subdoc within the array knows its subpaths are populated.
+ *
+ * ####Example:
+ * const doc = await Article.findOne().populate('comments.author');
+ * doc.comments[0].populated('author'); // Should be set
+ */
+
+function markArraySubdocsPopulated(doc, populated) {
+ if (doc._id == null || populated == null || populated.length === 0) {
+ return;
+ }
+
+ const id = String(doc._id);
+ for (const item of populated) {
+ if (item.isVirtual) {
+ continue;
+ }
+ const path = item.path;
+ const pieces = path.split('.');
+ for (let i = 0; i < pieces.length - 1; ++i) {
+ const subpath = pieces.slice(0, i + 1).join('.');
+ const rest = pieces.slice(i + 1).join('.');
+ const val = doc.get(subpath);
+ if (val == null) {
+ continue;
+ }
+ if (val.isMongooseDocumentArray) {
+ for (let j = 0; j < val.length; ++j) {
+ val[j].populated(rest, item._docs[id] == null ? [] : item._docs[id][j], item);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/*!
+ * Init helper.
+ *
+ * @param {Object} self document instance
+ * @param {Object} obj raw mongodb doc
+ * @param {Object} doc object we are initializing
+ * @api private
+ */
+
+function init(self, obj, doc, opts, prefix) {
+ prefix = prefix || '';
+
+ const keys = Object.keys(obj);
+ const len = keys.length;
+ let schema;
+ let path;
+ let i;
+ let index = 0;
+
+ while (index < len) {
+ _init(index++);
+ }
+
+ function _init(index) {
+ i = keys[index];
+ path = prefix + i;
+ schema = self.schema.path(path);
+
+ // Should still work if not a model-level discriminator, but should not be
+ // necessary. This is *only* to catch the case where we queried using the
+ // base model and the discriminated model has a projection
+ if (self.schema.$isRootDiscriminator && !self.isSelected(path)) {
+ return;
+ }
+
+ if (!schema && utils.isPOJO(obj[i])) {
+ // assume nested object
+ if (!doc[i]) {
+ doc[i] = {};
+ }
+ init(self, obj[i], doc[i], opts, path + '.');
+ } else if (!schema) {
+ doc[i] = obj[i];
+ } else {
+ if (obj[i] === null) {
+ doc[i] = null;
+ } else if (obj[i] !== undefined) {
+ const intCache = obj[i].$__ || {};
+ const wasPopulated = intCache.wasPopulated || null;
+
+ if (schema && !wasPopulated) {
+ try {
+ doc[i] = schema.cast(obj[i], self, true);
+ } catch (e) {
+ self.invalidate(e.path, new ValidatorError({
+ path: e.path,
+ message: e.message,
+ type: 'cast',
+ value: e.value
+ }));
+ }
+ } else {
+ doc[i] = obj[i];
+ }
+ }
+ // mark as hydrated
+ if (!self.isModified(path)) {
+ self.$__.activePaths.init(path);
+ }
+ }
+ }
+}
+
+/**
+ * Sends an update command with this document `_id` as the query selector.
+ *
+ * ####Example:
+ *
+ * weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
+ *
+ * ####Valid options:
+ *
+ * - same as in [Model.update](#model_Model.update)
+ *
+ * @see Model.update #model_Model.update
+ * @param {Object} doc
+ * @param {Object} options
+ * @param {Function} callback
+ * @return {Query}
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.update = function update() {
+ const args = utils.args(arguments);
+ args.unshift({ _id: this._id });
+ const query = this.constructor.update.apply(this.constructor, args);
+
+ if (this.$session() != null) {
+ if (!('session' in query.options)) {
+ query.options.session = this.$session();
+ }
+ }
+
+ return query;
+};
+
+/**
+ * Sends an updateOne command with this document `_id` as the query selector.
+ *
+ * ####Example:
+ *
+ * weirdCar.updateOne({$inc: {wheels:1}}, { w: 1 }, callback);
+ *
+ * ####Valid options:
+ *
+ * - same as in [Model.updateOne](#model_Model.updateOne)
+ *
+ * @see Model.updateOne #model_Model.updateOne
+ * @param {Object} doc
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and the [Mongoose lean tutorial](/docs/tutorials/lean.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} callback
+ * @return {Query}
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.updateOne = function updateOne(doc, options, callback) {
+ const query = this.constructor.updateOne({ _id: this._id }, doc, options);
+ query._pre(cb => {
+ this.constructor._middleware.execPre('updateOne', this, [this], cb);
+ });
+ query._post(cb => {
+ this.constructor._middleware.execPost('updateOne', this, [this], {}, cb);
+ });
+
+ if (this.$session() != null) {
+ if (!('session' in query.options)) {
+ query.options.session = this.$session();
+ }
+ }
+
+ if (callback != null) {
+ return query.exec(callback);
+ }
+
+ return query;
+};
+
+/**
+ * Sends a replaceOne command with this document `_id` as the query selector.
+ *
+ * ####Valid options:
+ *
+ * - same as in [Model.replaceOne](#model_Model.replaceOne)
+ *
+ * @see Model.replaceOne #model_Model.replaceOne
+ * @param {Object} doc
+ * @param {Object} options
+ * @param {Function} callback
+ * @return {Query}
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.replaceOne = function replaceOne() {
+ const args = utils.args(arguments);
+ args.unshift({ _id: this._id });
+ return this.constructor.replaceOne.apply(this.constructor, args);
+};
+
+/**
+ * Getter/setter around the session associated with this document. Used to
+ * automatically set `session` if you `save()` a doc that you got from a
+ * query with an associated session.
+ *
+ * ####Example:
+ *
+ * const session = MyModel.startSession();
+ * const doc = await MyModel.findOne().session(session);
+ * doc.$session() === session; // true
+ * doc.$session(null);
+ * doc.$session() === null; // true
+ *
+ * If this is a top-level document, setting the session propagates to all child
+ * docs.
+ *
+ * @param {ClientSession} [session] overwrite the current session
+ * @return {ClientSession}
+ * @method $session
+ * @api public
+ * @memberOf Document
+ */
+
+Document.prototype.$session = function $session(session) {
+ if (arguments.length === 0) {
+ return this.$__.session;
+ }
+ this.$__.session = session;
+
+ if (!this.ownerDocument) {
+ const subdocs = this.$__getAllSubdocs();
+ for (const child of subdocs) {
+ child.$session(session);
+ }
+ }
+
+ return session;
+};
+
+/**
+ * Overwrite all values in this document with the values of `obj`, except
+ * for immutable properties. Behaves similarly to `set()`, except for it
+ * unsets all properties that aren't in `obj`.
+ *
+ * @param {Object} obj the object to overwrite this document with
+ * @method overwrite
+ * @name overwrite
+ * @memberOf Document
+ * @instance
+ * @api public
+ */
+
+Document.prototype.overwrite = function overwrite(obj) {
+ const keys = Array.from(new Set(Object.keys(this._doc).concat(Object.keys(obj))));
+
+ for (const key of keys) {
+ if (key === '_id') {
+ continue;
+ }
+ // Explicitly skip version key
+ if (this.schema.options.versionKey && key === this.schema.options.versionKey) {
+ continue;
+ }
+ this.$set(key, obj[key]);
+ }
+
+ return this;
+};
+
+/**
+ * Alias for `set()`, used internally to avoid conflicts
+ *
+ * @param {String|Object} path path or object of key/vals to set
+ * @param {Any} val the value to set
+ * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
+ * @param {Object} [options] optionally specify options that modify the behavior of the set
+ * @method $set
+ * @name $set
+ * @memberOf Document
+ * @instance
+ * @api public
+ */
+
+Document.prototype.$set = function $set(path, val, type, options) {
+ if (utils.isPOJO(type)) {
+ options = type;
+ type = undefined;
+ }
+
+ options = options || {};
+ const merge = options.merge;
+ const adhoc = type && type !== true;
+ const constructing = type === true;
+ let adhocs;
+ let keys;
+ let i = 0;
+ let pathtype;
+ let key;
+ let prefix;
+
+ const strict = 'strict' in options
+ ? options.strict
+ : this.$__.strictMode;
+
+ if (adhoc) {
+ adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {});
+ adhocs[path] = this.schema.interpretAsType(path, type, this.schema.options);
+ }
+
+ if (typeof path !== 'string') {
+ // new Document({ key: val })
+ if (path instanceof Document) {
+ if (path.$__isNested) {
+ path = path.toObject();
+ } else {
+ path = path._doc;
+ }
+ }
+
+ if (path == null) {
+ const _ = path;
+ path = val;
+ val = _;
+ } else {
+ prefix = val ? val + '.' : '';
+
+ keys = Object.keys(path);
+ const len = keys.length;
+
+ // `_skipMinimizeTopLevel` is because we may have deleted the top-level
+ // nested key to ensure key order.
+ const _skipMinimizeTopLevel = get(options, '_skipMinimizeTopLevel', false);
+ if (len === 0 && (!this.schema.options.minimize || _skipMinimizeTopLevel)) {
+ delete options._skipMinimizeTopLevel;
+ if (val) {
+ this.$set(val, {});
+ }
+ return this;
+ }
+
+ while (i < len) {
+ _handleIndex.call(this, i++);
+ }
+
+ return this;
+ }
+ } else {
+ this.$__.$setCalled.add(path);
+ }
+
+ function _handleIndex(i) {
+ key = keys[i];
+ const pathName = prefix + key;
+ pathtype = this.schema.pathType(pathName);
+
+ // On initial set, delete any nested keys if we're going to overwrite
+ // them to ensure we keep the user's key order.
+ if (type === true &&
+ !prefix &&
+ path[key] != null &&
+ pathtype === 'nested' &&
+ this._doc[key] != null &&
+ Object.keys(this._doc[key]).length === 0) {
+ delete this._doc[key];
+ // Make sure we set `{}` back even if we minimize re: gh-8565
+ options = Object.assign({}, options, { _skipMinimizeTopLevel: true });
+ }
+
+ if (typeof path[key] === 'object' &&
+ !utils.isNativeObject(path[key]) &&
+ !utils.isMongooseType(path[key]) &&
+ path[key] != null &&
+ pathtype !== 'virtual' &&
+ pathtype !== 'real' &&
+ !(this.$__path(pathName) instanceof MixedSchema) &&
+ !(this.schema.paths[pathName] &&
+ this.schema.paths[pathName].options &&
+ this.schema.paths[pathName].options.ref)) {
+ this.$__.$setCalled.add(prefix + key);
+ this.$set(path[key], prefix + key, constructing, options);
+ } else if (strict) {
+ // Don't overwrite defaults with undefined keys (gh-3981)
+ if (constructing && path[key] === void 0 &&
+ this.get(key) !== void 0) {
+ return;
+ }
+
+ if (pathtype === 'adhocOrUndefined') {
+ pathtype = getEmbeddedDiscriminatorPath(this, pathName, { typeOnly: true });
+ }
+
+ if (pathtype === 'real' || pathtype === 'virtual') {
+ // Check for setting single embedded schema to document (gh-3535)
+ let p = path[key];
+ if (this.schema.paths[pathName] &&
+ this.schema.paths[pathName].$isSingleNested &&
+ path[key] instanceof Document) {
+ p = p.toObject({ virtuals: false, transform: false });
+ }
+ this.$set(prefix + key, p, constructing, options);
+ } else if (pathtype === 'nested' && path[key] instanceof Document) {
+ this.$set(prefix + key,
+ path[key].toObject({ transform: false }), constructing, options);
+ } else if (strict === 'throw') {
+ if (pathtype === 'nested') {
+ throw new ObjectExpectedError(key, path[key]);
+ } else {
+ throw new StrictModeError(key);
+ }
+ }
+ } else if (path[key] !== void 0) {
+ this.$set(prefix + key, path[key], constructing, options);
+ }
+ }
+
+ let pathType = this.schema.pathType(path);
+ if (pathType === 'adhocOrUndefined') {
+ pathType = getEmbeddedDiscriminatorPath(this, path, { typeOnly: true });
+ }
+
+ // Assume this is a Mongoose document that was copied into a POJO using
+ // `Object.assign()` or `{...doc}`
+ if (utils.isPOJO(val) && val.$__ != null && val._doc != null) {
+ val = val._doc;
+ }
+
+ if (pathType === 'nested' && val) {
+ if (typeof val === 'object' && val != null) {
+ if (!merge) {
+ this.$__setValue(path, null);
+ cleanModifiedSubpaths(this, path);
+ } else {
+ return this.$set(val, path, constructing);
+ }
+
+ const keys = Object.keys(val);
+ this.$__setValue(path, {});
+ for (const key of keys) {
+ this.$set(path + '.' + key, val[key], constructing);
+ }
+ this.markModified(path);
+ cleanModifiedSubpaths(this, path, { skipDocArrays: true });
+ return this;
+ }
+ this.invalidate(path, new MongooseError.CastError('Object', val, path));
+ return this;
+ }
+
+ let schema;
+ const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
+
+ // Might need to change path for top-level alias
+ if (typeof this.schema.aliases[parts[0]] == 'string') {
+ parts[0] = this.schema.aliases[parts[0]];
+ }
+
+ if (pathType === 'adhocOrUndefined' && strict) {
+ // check for roots that are Mixed types
+ let mixed;
+
+ for (i = 0; i < parts.length; ++i) {
+ const subpath = parts.slice(0, i + 1).join('.');
+
+ // If path is underneath a virtual, bypass everything and just set it.
+ if (i + 1 < parts.length && this.schema.pathType(subpath) === 'virtual') {
+ mpath.set(path, val, this);
+ return this;
+ }
+
+ schema = this.schema.path(subpath);
+ if (schema == null) {
+ continue;
+ }
+
+ if (schema instanceof MixedSchema) {
+ // allow changes to sub paths of mixed types
+ mixed = true;
+ break;
+ }
+ }
+
+ if (schema == null) {
+ // Check for embedded discriminators
+ schema = getEmbeddedDiscriminatorPath(this, path);
+ }
+
+ if (!mixed && !schema) {
+ if (strict === 'throw') {
+ throw new StrictModeError(path);
+ }
+ return this;
+ }
+ } else if (pathType === 'virtual') {
+ schema = this.schema.virtualpath(path);
+ schema.applySetters(val, this);
+ return this;
+ } else {
+ schema = this.$__path(path);
+ }
+
+ // gh-4578, if setting a deeply nested path that doesn't exist yet, create it
+ let cur = this._doc;
+ let curPath = '';
+ for (i = 0; i < parts.length - 1; ++i) {
+ cur = cur[parts[i]];
+ curPath += (curPath.length > 0 ? '.' : '') + parts[i];
+ if (!cur) {
+ this.$set(curPath, {});
+ // Hack re: gh-5800. If nested field is not selected, it probably exists
+ // so `MongoError: cannot use the part (nested of nested.num) to
+ // traverse the element ({nested: null})` is not likely. If user gets
+ // that error, its their fault for now. We should reconsider disallowing
+ // modifying not selected paths for 6.x
+ if (!this.isSelected(curPath)) {
+ this.unmarkModified(curPath);
+ }
+ cur = this.$__getValue(curPath);
+ }
+ }
+
+ let pathToMark;
+
+ // When using the $set operator the path to the field must already exist.
+ // Else mongodb throws: "LEFT_SUBFIELD only supports Object"
+
+ if (parts.length <= 1) {
+ pathToMark = path;
+ } else {
+ for (i = 0; i < parts.length; ++i) {
+ const subpath = parts.slice(0, i + 1).join('.');
+ if (this.get(subpath, null, { getters: false }) === null) {
+ pathToMark = subpath;
+ break;
+ }
+ }
+
+ if (!pathToMark) {
+ pathToMark = path;
+ }
+ }
+
+ // if this doc is being constructed we should not trigger getters
+ const priorVal = (() => {
+ if (this.$__.$options.priorDoc != null) {
+ return this.$__.$options.priorDoc.$__getValue(path);
+ }
+ if (constructing) {
+ return void 0;
+ }
+ return this.$__getValue(path);
+ })();
+
+ if (!schema) {
+ this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal);
+ return this;
+ }
+
+ if (schema.$isSingleNested && val != null && merge) {
+ if (val instanceof Document) {
+ val = val.toObject({ virtuals: false, transform: false });
+ }
+ const keys = Object.keys(val);
+ for (const key of keys) {
+ this.$set(path + '.' + key, val[key], constructing, options);
+ }
+
+ return this;
+ }
+
+ let shouldSet = true;
+ try {
+ // If the user is trying to set a ref path to a document with
+ // the correct model name, treat it as populated
+ const refMatches = (() => {
+ if (schema.options == null) {
+ return false;
+ }
+ if (!(val instanceof Document)) {
+ return false;
+ }
+ const model = val.constructor;
+
+ // Check ref
+ const ref = schema.options.ref;
+ if (ref != null && (ref === model.modelName || ref === model.baseModelName)) {
+ return true;
+ }
+
+ // Check refPath
+ const refPath = schema.options.refPath;
+ if (refPath == null) {
+ return false;
+ }
+ const modelName = val.get(refPath);
+ return modelName === model.modelName || modelName === model.baseModelName;
+ })();
+
+ let didPopulate = false;
+ if (refMatches && val instanceof Document) {
+ this.populated(path, val._id, { [populateModelSymbol]: val.constructor });
+ didPopulate = true;
+ }
+
+ let popOpts;
+ if (schema.options &&
+ Array.isArray(schema.options[this.schema.options.typeKey]) &&
+ schema.options[this.schema.options.typeKey].length &&
+ schema.options[this.schema.options.typeKey][0].ref &&
+ _isManuallyPopulatedArray(val, schema.options[this.schema.options.typeKey][0].ref)) {
+ if (this.ownerDocument) {
+ popOpts = { [populateModelSymbol]: val[0].constructor };
+ this.ownerDocument().populated(this.$__fullPath(path),
+ val.map(function(v) { return v._id; }), popOpts);
+ } else {
+ popOpts = { [populateModelSymbol]: val[0].constructor };
+ this.populated(path, val.map(function(v) { return v._id; }), popOpts);
+ }
+ didPopulate = true;
+ }
+
+ if (this.schema.singleNestedPaths[path] == null) {
+ // If this path is underneath a single nested schema, we'll call the setter
+ // later in `$__set()` because we don't take `_doc` when we iterate through
+ // a single nested doc. That's to make sure we get the correct context.
+ // Otherwise we would double-call the setter, see gh-7196.
+ val = schema.applySetters(val, this, false, priorVal);
+ }
+
+ if (schema.$isMongooseDocumentArray &&
+ Array.isArray(val) &&
+ val.length > 0 &&
+ val[0] != null &&
+ val[0].$__ != null &&
+ val[0].$__.populated != null) {
+ const populatedPaths = Object.keys(val[0].$__.populated);
+ for (const populatedPath of populatedPaths) {
+ this.populated(path + '.' + populatedPath,
+ val.map(v => v.populated(populatedPath)),
+ val[0].$__.populated[populatedPath].options);
+ }
+ didPopulate = true;
+ }
+
+ if (!didPopulate && this.$__.populated) {
+ // If this array partially contains populated documents, convert them
+ // all to ObjectIds re: #8443
+ if (Array.isArray(val) && this.$__.populated[path]) {
+ for (let i = 0; i < val.length; ++i) {
+ if (val[i] instanceof Document) {
+ val[i] = val[i]._id;
+ }
+ }
+ }
+ delete this.$__.populated[path];
+ }
+
+ this.$markValid(path);
+ } catch (e) {
+ if (e instanceof MongooseError.StrictModeError && e.isImmutableError) {
+ this.invalidate(path, e);
+ } else {
+ this.invalidate(path,
+ new MongooseError.CastError(schema.instance, val, path, e));
+ }
+ shouldSet = false;
+ }
+
+ if (shouldSet) {
+ this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal);
+ }
+
+ if (schema.$isSingleNested && (this.isDirectModified(path) || val == null)) {
+ cleanModifiedSubpaths(this, path);
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+function _isManuallyPopulatedArray(val, ref) {
+ if (!Array.isArray(val)) {
+ return false;
+ }
+ if (val.length === 0) {
+ return false;
+ }
+
+ for (const el of val) {
+ if (!(el instanceof Document)) {
+ return false;
+ }
+ const modelName = el.constructor.modelName;
+ if (modelName == null) {
+ return false;
+ }
+ if (el.constructor.modelName != ref && el.constructor.baseModelName != ref) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Sets the value of a path, or many paths.
+ *
+ * ####Example:
+ *
+ * // path, value
+ * doc.set(path, value)
+ *
+ * // object
+ * doc.set({
+ * path : value
+ * , path2 : {
+ * path : value
+ * }
+ * })
+ *
+ * // on-the-fly cast to number
+ * doc.set(path, value, Number)
+ *
+ * // on-the-fly cast to string
+ * doc.set(path, value, String)
+ *
+ * // changing strict mode behavior
+ * doc.set(path, value, { strict: false });
+ *
+ * @param {String|Object} path path or object of key/vals to set
+ * @param {Any} val the value to set
+ * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
+ * @param {Object} [options] optionally specify options that modify the behavior of the set
+ * @api public
+ * @method set
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.set = Document.prototype.$set;
+
+/**
+ * Determine if we should mark this change as modified.
+ *
+ * @return {Boolean}
+ * @api private
+ * @method $__shouldModify
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__shouldModify = function(pathToMark, path, constructing, parts, schema, val, priorVal) {
+ if (this.isNew) {
+ return true;
+ }
+
+ // Re: the note about gh-7196, `val` is the raw value without casting or
+ // setters if the full path is under a single nested subdoc because we don't
+ // want to double run setters. So don't set it as modified. See gh-7264.
+ if (this.schema.singleNestedPaths[path] != null) {
+ return false;
+ }
+
+ if (val === void 0 && !this.isSelected(path)) {
+ // when a path is not selected in a query, its initial
+ // value will be undefined.
+ return true;
+ }
+
+ if (val === void 0 && path in this.$__.activePaths.states.default) {
+ // we're just unsetting the default value which was never saved
+ return false;
+ }
+
+ // gh-3992: if setting a populated field to a doc, don't mark modified
+ // if they have the same _id
+ if (this.populated(path) &&
+ val instanceof Document &&
+ deepEqual(val._id, priorVal)) {
+ return false;
+ }
+
+ if (!deepEqual(val, priorVal || this.get(path))) {
+ return true;
+ }
+
+ if (!constructing &&
+ val !== null &&
+ val !== undefined &&
+ path in this.$__.activePaths.states.default &&
+ deepEqual(val, schema.getDefault(this, constructing))) {
+ // a path with a default was $unset on the server
+ // and the user is setting it to the same value again
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Handles the actual setting of the value and marking the path modified if appropriate.
+ *
+ * @api private
+ * @method $__set
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__set = function(pathToMark, path, constructing, parts, schema, val, priorVal) {
+ Embedded = Embedded || require('./types/embedded');
+
+ const shouldModify = this.$__shouldModify(pathToMark, path, constructing, parts,
+ schema, val, priorVal);
+ const _this = this;
+
+ if (shouldModify) {
+ this.markModified(pathToMark);
+
+ // handle directly setting arrays (gh-1126)
+ MongooseArray || (MongooseArray = require('./types/array'));
+ if (val && val.isMongooseArray) {
+ val._registerAtomic('$set', val);
+
+ // Update embedded document parent references (gh-5189)
+ if (val.isMongooseDocumentArray) {
+ val.forEach(function(item) {
+ item && item.__parentArray && (item.__parentArray = val);
+ });
+ }
+
+ // Small hack for gh-1638: if we're overwriting the entire array, ignore
+ // paths that were modified before the array overwrite
+ this.$__.activePaths.forEach(function(modifiedPath) {
+ if (modifiedPath.startsWith(path + '.')) {
+ _this.$__.activePaths.ignore(modifiedPath);
+ }
+ });
+ }
+ }
+
+ let obj = this._doc;
+ let i = 0;
+ const l = parts.length;
+ let cur = '';
+
+ for (; i < l; i++) {
+ const next = i + 1;
+ const last = next === l;
+ cur += (cur ? '.' + parts[i] : parts[i]);
+ if (specialProperties.has(parts[i])) {
+ return;
+ }
+
+ if (last) {
+ if (obj instanceof Map) {
+ obj.set(parts[i], val);
+ } else {
+ obj[parts[i]] = val;
+ }
+ } else {
+ if (utils.isPOJO(obj[parts[i]])) {
+ obj = obj[parts[i]];
+ } else if (obj[parts[i]] && obj[parts[i]] instanceof Embedded) {
+ obj = obj[parts[i]];
+ } else if (obj[parts[i]] && obj[parts[i]].$isSingleNested) {
+ obj = obj[parts[i]];
+ } else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) {
+ obj = obj[parts[i]];
+ } else {
+ obj[parts[i]] = obj[parts[i]] || {};
+ obj = obj[parts[i]];
+ }
+ }
+ }
+};
+
+/**
+ * Gets a raw value from a path (no getters)
+ *
+ * @param {String} path
+ * @api private
+ */
+
+Document.prototype.$__getValue = function(path) {
+ return utils.getValue(path, this._doc);
+};
+
+/**
+ * Sets a raw value for a path (no casting, setters, transformations)
+ *
+ * @param {String} path
+ * @param {Object} value
+ * @api private
+ */
+
+Document.prototype.$__setValue = function(path, val) {
+ utils.setValue(path, val, this._doc);
+ return this;
+};
+
+/**
+ * Returns the value of a path.
+ *
+ * ####Example
+ *
+ * // path
+ * doc.get('age') // 47
+ *
+ * // dynamic casting to a string
+ * doc.get('age', String) // "47"
+ *
+ * @param {String} path
+ * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for on-the-fly attributes
+ * @param {Object} [options]
+ * @param {Boolean} [options.virtuals=false] Apply virtuals before getting this path
+ * @param {Boolean} [options.getters=true] If false, skip applying getters and just get the raw value
+ * @api public
+ */
+
+Document.prototype.get = function(path, type, options) {
+ let adhoc;
+ options = options || {};
+ if (type) {
+ adhoc = this.schema.interpretAsType(path, type, this.schema.options);
+ }
+
+ let schema = this.$__path(path);
+ if (schema == null) {
+ schema = this.schema.virtualpath(path);
+ }
+ if (schema instanceof MixedSchema) {
+ const virtual = this.schema.virtualpath(path);
+ if (virtual != null) {
+ schema = virtual;
+ }
+ }
+ const pieces = path.split('.');
+ let obj = this._doc;
+
+ if (schema instanceof VirtualType) {
+ if (schema.getters.length === 0) {
+ return void 0;
+ }
+ return schema.applyGetters(null, this);
+ }
+
+ // Might need to change path for top-level alias
+ if (typeof this.schema.aliases[pieces[0]] == 'string') {
+ pieces[0] = this.schema.aliases[pieces[0]];
+ }
+
+ for (let i = 0, l = pieces.length; i < l; i++) {
+ if (obj && obj._doc) {
+ obj = obj._doc;
+ }
+
+ if (obj == null) {
+ obj = void 0;
+ } else if (obj instanceof Map) {
+ obj = obj.get(pieces[i]);
+ } else if (i === l - 1) {
+ obj = utils.getValue(pieces[i], obj);
+ } else {
+ obj = obj[pieces[i]];
+ }
+ }
+
+ if (adhoc) {
+ obj = adhoc.cast(obj);
+ }
+
+ if (schema != null && options.getters !== false) {
+ obj = schema.applyGetters(obj, this);
+ } else if (this.schema.nested[path] && options.virtuals) {
+ // Might need to apply virtuals if this is a nested path
+ return applyVirtuals(this, utils.clone(obj) || {}, { path: path });
+ }
+
+ return obj;
+};
+
+/*!
+ * ignore
+ */
+
+Document.prototype[getSymbol] = Document.prototype.get;
+
+/**
+ * Returns the schematype for the given `path`.
+ *
+ * @param {String} path
+ * @api private
+ * @method $__path
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__path = function(path) {
+ const adhocs = this.$__.adhocPaths;
+ const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
+
+ if (adhocType) {
+ return adhocType;
+ }
+ return this.schema.path(path);
+};
+
+/**
+ * Marks the path as having pending changes to write to the db.
+ *
+ * _Very helpful when using [Mixed](./schematypes.html#mixed) types._
+ *
+ * ####Example:
+ *
+ * doc.mixed.type = 'changed';
+ * doc.markModified('mixed.type');
+ * doc.save() // changes to mixed.type are now persisted
+ *
+ * @param {String} path the path to mark modified
+ * @param {Document} [scope] the scope to run validators with
+ * @api public
+ */
+
+Document.prototype.markModified = function(path, scope) {
+ this.$__.activePaths.modify(path);
+ if (scope != null && !this.ownerDocument) {
+ this.$__.pathsToScopes[path] = scope;
+ }
+};
+
+/**
+ * Clears the modified state on the specified path.
+ *
+ * ####Example:
+ *
+ * doc.foo = 'bar';
+ * doc.unmarkModified('foo');
+ * doc.save(); // changes to foo will not be persisted
+ *
+ * @param {String} path the path to unmark modified
+ * @api public
+ */
+
+Document.prototype.unmarkModified = function(path) {
+ this.$__.activePaths.init(path);
+ delete this.$__.pathsToScopes[path];
+};
+
+/**
+ * Don't run validation on this path or persist changes to this path.
+ *
+ * ####Example:
+ *
+ * doc.foo = null;
+ * doc.$ignore('foo');
+ * doc.save(); // changes to foo will not be persisted and validators won't be run
+ *
+ * @memberOf Document
+ * @instance
+ * @method $ignore
+ * @param {String} path the path to ignore
+ * @api public
+ */
+
+Document.prototype.$ignore = function(path) {
+ this.$__.activePaths.ignore(path);
+};
+
+/**
+ * Returns the list of paths that have been directly modified. A direct
+ * modified path is a path that you explicitly set, whether via `doc.foo = 'bar'`,
+ * `Object.assign(doc, { foo: 'bar' })`, or `doc.set('foo', 'bar')`.
+ *
+ * A path `a` may be in `modifiedPaths()` but not in `directModifiedPaths()`
+ * because a child of `a` was directly modified.
+ *
+ * ####Example
+ * const schema = new Schema({ foo: String, nested: { bar: String } });
+ * const Model = mongoose.model('Test', schema);
+ * await Model.create({ foo: 'original', nested: { bar: 'original' } });
+ *
+ * const doc = await Model.findOne();
+ * doc.nested.bar = 'modified';
+ * doc.directModifiedPaths(); // ['nested.bar']
+ * doc.modifiedPaths(); // ['nested', 'nested.bar']
+ *
+ * @return {Array}
+ * @api public
+ */
+
+Document.prototype.directModifiedPaths = function() {
+ return Object.keys(this.$__.activePaths.states.modify);
+};
+
+/**
+ * Returns true if the given path is nullish or only contains empty objects.
+ * Useful for determining whether this subdoc will get stripped out by the
+ * [minimize option](/docs/guide.html#minimize).
+ *
+ * ####Example:
+ * const schema = new Schema({ nested: { foo: String } });
+ * const Model = mongoose.model('Test', schema);
+ * const doc = new Model({});
+ * doc.$isEmpty('nested'); // true
+ * doc.nested.$isEmpty(); // true
+ *
+ * doc.nested.foo = 'bar';
+ * doc.$isEmpty('nested'); // false
+ * doc.nested.$isEmpty(); // false
+ *
+ * @memberOf Document
+ * @instance
+ * @api public
+ * @method $isEmpty
+ * @return {Boolean}
+ */
+
+Document.prototype.$isEmpty = function(path) {
+ const isEmptyOptions = {
+ minimize: true,
+ virtuals: false,
+ getters: false,
+ transform: false
+ };
+
+ if (arguments.length > 0) {
+ const v = this.get(path);
+ if (v == null) {
+ return true;
+ }
+ if (typeof v !== 'object') {
+ return false;
+ }
+ if (utils.isPOJO(v)) {
+ return _isEmpty(v);
+ }
+ return Object.keys(v.toObject(isEmptyOptions)).length === 0;
+ }
+
+ return Object.keys(this.toObject(isEmptyOptions)).length === 0;
+};
+
+function _isEmpty(v) {
+ if (v == null) {
+ return true;
+ }
+ if (typeof v !== 'object' || Array.isArray(v)) {
+ return false;
+ }
+ for (const key of Object.keys(v)) {
+ if (!_isEmpty(v[key])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Returns the list of paths that have been modified.
+ *
+ * @param {Object} [options]
+ * @param {Boolean} [options.includeChildren=false] if true, returns children of modified paths as well. For example, if false, the list of modified paths for `doc.colors = { primary: 'blue' };` will **not** contain `colors.primary`. If true, `modifiedPaths()` will return an array that contains `colors.primary`.
+ * @return {Array}
+ * @api public
+ */
+
+Document.prototype.modifiedPaths = function(options) {
+ options = options || {};
+ const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
+ const _this = this;
+ return directModifiedPaths.reduce(function(list, path) {
+ const parts = path.split('.');
+ list = list.concat(parts.reduce(function(chains, part, i) {
+ return chains.concat(parts.slice(0, i).concat(part).join('.'));
+ }, []).filter(function(chain) {
+ return (list.indexOf(chain) === -1);
+ }));
+
+ if (!options.includeChildren) {
+ return list;
+ }
+
+ let cur = _this.get(path);
+ if (cur != null && typeof cur === 'object') {
+ if (cur._doc) {
+ cur = cur._doc;
+ }
+ if (Array.isArray(cur)) {
+ const len = cur.length;
+ for (let i = 0; i < len; ++i) {
+ if (list.indexOf(path + '.' + i) === -1) {
+ list.push(path + '.' + i);
+ if (cur[i] != null && cur[i].$__) {
+ const modified = cur[i].modifiedPaths();
+ for (const childPath of modified) {
+ list.push(path + '.' + i + '.' + childPath);
+ }
+ }
+ }
+ }
+ } else {
+ Object.keys(cur).
+ filter(function(key) {
+ return list.indexOf(path + '.' + key) === -1;
+ }).
+ forEach(function(key) {
+ list.push(path + '.' + key);
+ });
+ }
+ }
+
+ return list;
+ }, []);
+};
+
+/**
+ * Returns true if this document was modified, else false.
+ *
+ * If `path` is given, checks if a path or any full path containing `path` as part of its path chain has been modified.
+ *
+ * ####Example
+ *
+ * doc.set('documents.0.title', 'changed');
+ * doc.isModified() // true
+ * doc.isModified('documents') // true
+ * doc.isModified('documents.0.title') // true
+ * doc.isModified('documents otherProp') // true
+ * doc.isDirectModified('documents') // false
+ *
+ * @param {String} [path] optional
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.isModified = function(paths, modifiedPaths) {
+ if (paths) {
+ if (!Array.isArray(paths)) {
+ paths = paths.split(' ');
+ }
+ const modified = modifiedPaths || this.modifiedPaths();
+ const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
+ const isModifiedChild = paths.some(function(path) {
+ return !!~modified.indexOf(path);
+ });
+ return isModifiedChild || paths.some(function(path) {
+ return directModifiedPaths.some(function(mod) {
+ return mod === path || path.startsWith(mod + '.');
+ });
+ });
+ }
+ return this.$__.activePaths.some('modify');
+};
+
+/**
+ * Checks if a path is set to its default.
+ *
+ * ####Example
+ *
+ * MyModel = mongoose.model('test', { name: { type: String, default: 'Val '} });
+ * var m = new MyModel();
+ * m.$isDefault('name'); // true
+ *
+ * @memberOf Document
+ * @instance
+ * @method $isDefault
+ * @param {String} [path]
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.$isDefault = function(path) {
+ return (path in this.$__.activePaths.states.default);
+};
+
+/**
+ * Getter/setter, determines whether the document was removed or not.
+ *
+ * ####Example:
+ * product.remove(function (err, product) {
+ * product.$isDeleted(); // true
+ * product.remove(); // no-op, doesn't send anything to the db
+ *
+ * product.$isDeleted(false);
+ * product.$isDeleted(); // false
+ * product.remove(); // will execute a remove against the db
+ * })
+ *
+ * @param {Boolean} [val] optional, overrides whether mongoose thinks the doc is deleted
+ * @return {Boolean} whether mongoose thinks this doc is deleted.
+ * @method $isDeleted
+ * @memberOf Document
+ * @instance
+ * @api public
+ */
+
+Document.prototype.$isDeleted = function(val) {
+ if (arguments.length === 0) {
+ return !!this.$__.isDeleted;
+ }
+
+ this.$__.isDeleted = !!val;
+ return this;
+};
+
+/**
+ * Returns true if `path` was directly set and modified, else false.
+ *
+ * ####Example
+ *
+ * doc.set('documents.0.title', 'changed');
+ * doc.isDirectModified('documents.0.title') // true
+ * doc.isDirectModified('documents') // false
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.isDirectModified = function(path) {
+ return (path in this.$__.activePaths.states.modify);
+};
+
+/**
+ * Checks if `path` was initialized.
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.isInit = function(path) {
+ return (path in this.$__.activePaths.states.init);
+};
+
+/**
+ * Checks if `path` was selected in the source query which initialized this document.
+ *
+ * ####Example
+ *
+ * Thing.findOne().select('name').exec(function (err, doc) {
+ * doc.isSelected('name') // true
+ * doc.isSelected('age') // false
+ * })
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.isSelected = function isSelected(path) {
+ if (this.$__.selected) {
+ if (path === '_id') {
+ return this.$__.selected._id !== 0;
+ }
+
+ const paths = Object.keys(this.$__.selected);
+ let i = paths.length;
+ let inclusive = null;
+ let cur;
+
+ if (i === 1 && paths[0] === '_id') {
+ // only _id was selected.
+ return this.$__.selected._id === 0;
+ }
+
+ while (i--) {
+ cur = paths[i];
+ if (cur === '_id') {
+ continue;
+ }
+ if (!isDefiningProjection(this.$__.selected[cur])) {
+ continue;
+ }
+ inclusive = !!this.$__.selected[cur];
+ break;
+ }
+
+ if (inclusive === null) {
+ return true;
+ }
+
+ if (path in this.$__.selected) {
+ return inclusive;
+ }
+
+ i = paths.length;
+ const pathDot = path + '.';
+
+ while (i--) {
+ cur = paths[i];
+ if (cur === '_id') {
+ continue;
+ }
+
+ if (cur.startsWith(pathDot)) {
+ return inclusive || cur !== pathDot;
+ }
+
+ if (pathDot.startsWith(cur + '.')) {
+ return inclusive;
+ }
+ }
+
+ return !inclusive;
+ }
+
+ return true;
+};
+
+/**
+ * Checks if `path` was explicitly selected. If no projection, always returns
+ * true.
+ *
+ * ####Example
+ *
+ * Thing.findOne().select('nested.name').exec(function (err, doc) {
+ * doc.isDirectSelected('nested.name') // true
+ * doc.isDirectSelected('nested.otherName') // false
+ * doc.isDirectSelected('nested') // false
+ * })
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api public
+ */
+
+Document.prototype.isDirectSelected = function isDirectSelected(path) {
+ if (this.$__.selected) {
+ if (path === '_id') {
+ return this.$__.selected._id !== 0;
+ }
+
+ const paths = Object.keys(this.$__.selected);
+ let i = paths.length;
+ let inclusive = null;
+ let cur;
+
+ if (i === 1 && paths[0] === '_id') {
+ // only _id was selected.
+ return this.$__.selected._id === 0;
+ }
+
+ while (i--) {
+ cur = paths[i];
+ if (cur === '_id') {
+ continue;
+ }
+ if (!isDefiningProjection(this.$__.selected[cur])) {
+ continue;
+ }
+ inclusive = !!this.$__.selected[cur];
+ break;
+ }
+
+ if (inclusive === null) {
+ return true;
+ }
+
+ if (path in this.$__.selected) {
+ return inclusive;
+ }
+
+ return !inclusive;
+ }
+
+ return true;
+};
+
+/**
+ * Executes registered validation rules for this document.
+ *
+ * ####Note:
+ *
+ * This method is called `pre` save and if a validation rule is violated, [save](#model_Model-save) is aborted and the error is returned to your `callback`.
+ *
+ * ####Example:
+ *
+ * doc.validate(function (err) {
+ * if (err) handleError(err);
+ * else // validation passed
+ * });
+ *
+ * @param {Array|String} [pathsToValidate] list of paths to validate. If set, Mongoose will validate only the modified paths that are in the given list.
+ * @param {Object} [options] internal options
+ * @param {Function} [callback] optional callback called after validation completes, passing an error if one occurred
+ * @return {Promise} Promise
+ * @api public
+ */
+
+Document.prototype.validate = function(pathsToValidate, options, callback) {
+ let parallelValidate;
+ this.$op = 'validate';
+
+ if (this.ownerDocument != null) {
+ // Skip parallel validate check for subdocuments
+ } else if (this.$__.validating) {
+ parallelValidate = new ParallelValidateError(this, {
+ parentStack: options && options.parentStack,
+ conflictStack: this.$__.validating.stack
+ });
+ } else {
+ this.$__.validating = new ParallelValidateError(this, { parentStack: options && options.parentStack });
+ }
+
+ if (typeof pathsToValidate === 'function') {
+ callback = pathsToValidate;
+ options = null;
+ pathsToValidate = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = pathsToValidate;
+ pathsToValidate = null;
+ }
+
+ return promiseOrCallback(callback, cb => {
+ if (parallelValidate != null) {
+ return cb(parallelValidate);
+ }
+
+ this.$__validate(pathsToValidate, options, (error) => {
+ this.$op = null;
+ cb(error);
+ });
+ }, this.constructor.events);
+};
+
+/*!
+ * ignore
+ */
+
+function _evaluateRequiredFunctions(doc) {
+ Object.keys(doc.$__.activePaths.states.require).forEach(path => {
+ const p = doc.schema.path(path);
+
+ if (p != null && typeof p.originalRequiredValue === 'function') {
+ doc.$__.cachedRequired[path] = p.originalRequiredValue.call(doc);
+ }
+ });
+}
+
+/*!
+ * ignore
+ */
+
+function _getPathsToValidate(doc) {
+ const skipSchemaValidators = {};
+
+ _evaluateRequiredFunctions(doc);
+
+ // only validate required fields when necessary
+ let paths = new Set(Object.keys(doc.$__.activePaths.states.require).filter(function(path) {
+ if (!doc.isSelected(path) && !doc.isModified(path)) {
+ return false;
+ }
+ if (path in doc.$__.cachedRequired) {
+ return doc.$__.cachedRequired[path];
+ }
+ return true;
+ }));
+
+
+ function addToPaths(p) { paths.add(p); }
+ Object.keys(doc.$__.activePaths.states.init).forEach(addToPaths);
+ Object.keys(doc.$__.activePaths.states.modify).forEach(addToPaths);
+ Object.keys(doc.$__.activePaths.states.default).forEach(addToPaths);
+
+ const subdocs = doc.$__getAllSubdocs();
+ const modifiedPaths = doc.modifiedPaths();
+ for (const subdoc of subdocs) {
+ if (subdoc.$basePath) {
+ // Remove child paths for now, because we'll be validating the whole
+ // subdoc
+ for (const p of paths) {
+ if (p === null || p.startsWith(subdoc.$basePath + '.')) {
+ paths.delete(p);
+ }
+ }
+
+ if (doc.isModified(subdoc.$basePath, modifiedPaths) &&
+ !doc.isDirectModified(subdoc.$basePath) &&
+ !doc.$isDefault(subdoc.$basePath)) {
+ paths.add(subdoc.$basePath);
+
+ skipSchemaValidators[subdoc.$basePath] = true;
+ }
+ }
+ }
+
+ // from here on we're not removing items from paths
+
+ // gh-661: if a whole array is modified, make sure to run validation on all
+ // the children as well
+ for (const path of paths) {
+ const _pathType = doc.schema.path(path);
+ if (!_pathType ||
+ !_pathType.$isMongooseArray ||
+ // To avoid potential performance issues, skip doc arrays whose children
+ // are not required. `getPositionalPathType()` may be slow, so avoid
+ // it unless we have a case of #6364
+ (_pathType.$isMongooseDocumentArray && !get(_pathType, 'schemaOptions.required'))) {
+ continue;
+ }
+
+ const val = doc.$__getValue(path);
+ _pushNestedArrayPaths(val, paths, path);
+ }
+
+ function _pushNestedArrayPaths(val, paths, path) {
+ if (val != null) {
+ const numElements = val.length;
+ for (let j = 0; j < numElements; ++j) {
+ if (Array.isArray(val[j])) {
+ _pushNestedArrayPaths(val[j], paths, path + '.' + j);
+ } else {
+ paths.add(path + '.' + j);
+ }
+ }
+ }
+ }
+
+ const flattenOptions = { skipArrays: true };
+ for (const pathToCheck of paths) {
+ if (doc.schema.nested[pathToCheck]) {
+ let _v = doc.$__getValue(pathToCheck);
+ if (isMongooseObject(_v)) {
+ _v = _v.toObject({ transform: false });
+ }
+ const flat = flatten(_v, pathToCheck, flattenOptions, doc.schema);
+ Object.keys(flat).forEach(addToPaths);
+ }
+ }
+
+
+ for (const path of paths) {
+ // Single nested paths (paths embedded under single nested subdocs) will
+ // be validated on their own when we call `validate()` on the subdoc itself.
+ // Re: gh-8468
+ if (doc.schema.singleNestedPaths.hasOwnProperty(path)) {
+ paths.delete(path);
+ continue;
+ }
+ const _pathType = doc.schema.path(path);
+ if (!_pathType || !_pathType.$isSchemaMap) {
+ continue;
+ }
+
+ const val = doc.$__getValue(path);
+ if (val == null) {
+ continue;
+ }
+ for (const key of val.keys()) {
+ paths.add(path + '.' + key);
+ }
+ }
+
+ paths = Array.from(paths);
+ return [paths, skipSchemaValidators];
+}
+
+/*!
+ * ignore
+ */
+
+Document.prototype.$__validate = function(pathsToValidate, options, callback) {
+ if (typeof pathsToValidate === 'function') {
+ callback = pathsToValidate;
+ options = null;
+ pathsToValidate = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const hasValidateModifiedOnlyOption = options &&
+ (typeof options === 'object') &&
+ ('validateModifiedOnly' in options);
+
+ let shouldValidateModifiedOnly;
+ if (hasValidateModifiedOnlyOption) {
+ shouldValidateModifiedOnly = !!options.validateModifiedOnly;
+ } else {
+ shouldValidateModifiedOnly = this.schema.options.validateModifiedOnly;
+ }
+
+ const _this = this;
+ const _complete = () => {
+ let validationError = this.$__.validationError;
+ this.$__.validationError = undefined;
+
+ if (shouldValidateModifiedOnly && validationError != null) {
+ // Remove any validation errors that aren't from modified paths
+ const errors = Object.keys(validationError.errors);
+ for (const errPath of errors) {
+ if (!this.isModified(errPath)) {
+ delete validationError.errors[errPath];
+ }
+ }
+ if (Object.keys(validationError.errors).length === 0) {
+ validationError = void 0;
+ }
+ }
+
+ this.$__.cachedRequired = {};
+ this.emit('validate', _this);
+ this.constructor.emit('validate', _this);
+
+ this.$__.validating = null;
+ if (validationError) {
+ for (const key in validationError.errors) {
+ // Make sure cast errors persist
+ if (!this[documentArrayParent] &&
+ validationError.errors[key] instanceof MongooseError.CastError) {
+ this.invalidate(key, validationError.errors[key]);
+ }
+ }
+
+ return validationError;
+ }
+ };
+
+ // only validate required fields when necessary
+ const pathDetails = _getPathsToValidate(this);
+ let paths = shouldValidateModifiedOnly ?
+ pathDetails[0].filter((path) => this.isModified(path)) :
+ pathDetails[0];
+ const skipSchemaValidators = pathDetails[1];
+
+ if (Array.isArray(pathsToValidate)) {
+ paths = _handlePathsToValidate(paths, pathsToValidate);
+ }
+
+ if (paths.length === 0) {
+ return process.nextTick(function() {
+ const error = _complete();
+ if (error) {
+ return _this.schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
+ callback(error);
+ });
+ }
+ callback(null, _this);
+ });
+ }
+
+ const validated = {};
+ let total = 0;
+
+ const complete = function() {
+ const error = _complete();
+ if (error) {
+ return _this.schema.s.hooks.execPost('validate:error', _this, [_this], { error: error }, function(error) {
+ callback(error);
+ });
+ }
+ callback(null, _this);
+ };
+
+ const validatePath = function(path) {
+ if (path == null || validated[path]) {
+ return;
+ }
+
+ validated[path] = true;
+ total++;
+
+ process.nextTick(function() {
+ const p = _this.schema.path(path);
+
+ if (!p) {
+ return --total || complete();
+ }
+
+ // If user marked as invalid or there was a cast error, don't validate
+ if (!_this.$isValid(path)) {
+ --total || complete();
+ return;
+ }
+
+ let val = _this.$__getValue(path);
+
+ // If you `populate()` and get back a null value, required validators
+ // shouldn't fail (gh-8018). We should always fall back to the populated
+ // value.
+ let pop;
+ if (val == null && (pop = _this.populated(path))) {
+ val = pop;
+ }
+ const scope = path in _this.$__.pathsToScopes ?
+ _this.$__.pathsToScopes[path] :
+ _this;
+
+ const doValidateOptions = {
+ skipSchemaValidators: skipSchemaValidators[path],
+ path: path
+ };
+ p.doValidate(val, function(err) {
+ if (err && (!p.$isMongooseDocumentArray || err.$isArrayValidatorError)) {
+ if (p.$isSingleNested &&
+ err instanceof ValidationError &&
+ p.schema.options.storeSubdocValidationError === false) {
+ return --total || complete();
+ }
+ _this.invalidate(path, err, undefined, true);
+ }
+ --total || complete();
+ }, scope, doValidateOptions);
+ });
+ };
+
+ const numPaths = paths.length;
+ for (let i = 0; i < numPaths; ++i) {
+ validatePath(paths[i]);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function _handlePathsToValidate(paths, pathsToValidate) {
+ const _pathsToValidate = new Set(pathsToValidate);
+ const parentPaths = new Map([]);
+ for (const path of pathsToValidate) {
+ if (path.indexOf('.') === -1) {
+ continue;
+ }
+ const pieces = path.split('.');
+ let cur = pieces[0];
+ for (let i = 1; i < pieces.length; ++i) {
+ // Since we skip subpaths under single nested subdocs to
+ // avoid double validation, we need to add back the
+ // single nested subpath if the user asked for it (gh-8626)
+ parentPaths.set(cur, path);
+ cur = cur + '.' + pieces[i];
+ }
+ }
+
+ const ret = [];
+ for (const path of paths) {
+ if (_pathsToValidate.has(path)) {
+ ret.push(path);
+ } else if (parentPaths.has(path)) {
+ ret.push(parentPaths.get(path));
+ }
+ }
+ return ret;
+}
+
+/**
+ * Executes registered validation rules (skipping asynchronous validators) for this document.
+ *
+ * ####Note:
+ *
+ * This method is useful if you need synchronous validation.
+ *
+ * ####Example:
+ *
+ * var err = doc.validateSync();
+ * if (err) {
+ * handleError(err);
+ * } else {
+ * // validation passed
+ * }
+ *
+ * @param {Array|string} pathsToValidate only validate the given paths
+ * @return {ValidationError|undefined} ValidationError if there are errors during validation, or undefined if there is no error.
+ * @api public
+ */
+
+Document.prototype.validateSync = function(pathsToValidate, options) {
+ const _this = this;
+
+ const hasValidateModifiedOnlyOption = options &&
+ (typeof options === 'object') &&
+ ('validateModifiedOnly' in options);
+
+ let shouldValidateModifiedOnly;
+ if (hasValidateModifiedOnlyOption) {
+ shouldValidateModifiedOnly = !!options.validateModifiedOnly;
+ } else {
+ shouldValidateModifiedOnly = this.schema.options.validateModifiedOnly;
+ }
+
+ if (typeof pathsToValidate === 'string') {
+ pathsToValidate = pathsToValidate.split(' ');
+ }
+
+ // only validate required fields when necessary
+ const pathDetails = _getPathsToValidate(this);
+ let paths = shouldValidateModifiedOnly ?
+ pathDetails[0].filter((path) => this.isModified(path)) :
+ pathDetails[0];
+ const skipSchemaValidators = pathDetails[1];
+
+ if (Array.isArray(pathsToValidate)) {
+ paths = _handlePathsToValidate(paths, pathsToValidate);
+ }
+
+ const validating = {};
+
+ paths.forEach(function(path) {
+ if (validating[path]) {
+ return;
+ }
+
+ validating[path] = true;
+
+ const p = _this.schema.path(path);
+ if (!p) {
+ return;
+ }
+ if (!_this.$isValid(path)) {
+ return;
+ }
+
+ const val = _this.$__getValue(path);
+ const err = p.doValidateSync(val, _this, {
+ skipSchemaValidators: skipSchemaValidators[path],
+ path: path
+ });
+ if (err && (!p.$isMongooseDocumentArray || err.$isArrayValidatorError)) {
+ if (p.$isSingleNested &&
+ err instanceof ValidationError &&
+ p.schema.options.storeSubdocValidationError === false) {
+ return;
+ }
+ _this.invalidate(path, err, undefined, true);
+ }
+ });
+
+ const err = _this.$__.validationError;
+ _this.$__.validationError = undefined;
+ _this.emit('validate', _this);
+ _this.constructor.emit('validate', _this);
+
+ if (err) {
+ for (const key in err.errors) {
+ // Make sure cast errors persist
+ if (err.errors[key] instanceof MongooseError.CastError) {
+ _this.invalidate(key, err.errors[key]);
+ }
+ }
+ }
+
+ return err;
+};
+
+/**
+ * Marks a path as invalid, causing validation to fail.
+ *
+ * The `errorMsg` argument will become the message of the `ValidationError`.
+ *
+ * The `value` argument (if passed) will be available through the `ValidationError.value` property.
+ *
+ * doc.invalidate('size', 'must be less than 20', 14);
+
+ * doc.validate(function (err) {
+ * console.log(err)
+ * // prints
+ * { message: 'Validation failed',
+ * name: 'ValidationError',
+ * errors:
+ * { size:
+ * { message: 'must be less than 20',
+ * name: 'ValidatorError',
+ * path: 'size',
+ * type: 'user defined',
+ * value: 14 } } }
+ * })
+ *
+ * @param {String} path the field to invalidate
+ * @param {String|Error} errorMsg the error which states the reason `path` was invalid
+ * @param {Object|String|Number|any} value optional invalid value
+ * @param {String} [kind] optional `kind` property for the error
+ * @return {ValidationError} the current ValidationError, with all currently invalidated paths
+ * @api public
+ */
+
+Document.prototype.invalidate = function(path, err, val, kind) {
+ if (!this.$__.validationError) {
+ this.$__.validationError = new ValidationError(this);
+ }
+
+ if (this.$__.validationError.errors[path]) {
+ return;
+ }
+
+ if (!err || typeof err === 'string') {
+ err = new ValidatorError({
+ path: path,
+ message: err,
+ type: kind || 'user defined',
+ value: val
+ });
+ }
+
+ if (this.$__.validationError === err) {
+ return this.$__.validationError;
+ }
+
+ this.$__.validationError.addError(path, err);
+ return this.$__.validationError;
+};
+
+/**
+ * Marks a path as valid, removing existing validation errors.
+ *
+ * @param {String} path the field to mark as valid
+ * @api public
+ * @memberOf Document
+ * @instance
+ * @method $markValid
+ */
+
+Document.prototype.$markValid = function(path) {
+ if (!this.$__.validationError || !this.$__.validationError.errors[path]) {
+ return;
+ }
+
+ delete this.$__.validationError.errors[path];
+ if (Object.keys(this.$__.validationError.errors).length === 0) {
+ this.$__.validationError = null;
+ }
+};
+
+/**
+ * Saves this document.
+ *
+ * ####Example:
+ *
+ * product.sold = Date.now();
+ * product.save(function (err, product) {
+ * if (err) ..
+ * })
+ *
+ * The callback will receive two parameters
+ *
+ * 1. `err` if an error occurred
+ * 2. `product` which is the saved `product`
+ *
+ * As an extra measure of flow control, save will return a Promise.
+ * ####Example:
+ * product.save().then(function(product) {
+ * ...
+ * });
+ *
+ * @param {Object} [options] options optional options
+ * @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](http://mongoosejs.com//docs/guide.html#safe)
+ * @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
+ * @param {Function} [fn] optional callback
+ * @method save
+ * @memberOf Document
+ * @instance
+ * @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
+ * @api public
+ * @see middleware http://mongoosejs.com/docs/middleware.html
+ */
+
+/**
+ * Checks if a path is invalid
+ *
+ * @param {String} path the field to check
+ * @method $isValid
+ * @memberOf Document
+ * @instance
+ * @api private
+ */
+
+Document.prototype.$isValid = function(path) {
+ return !this.$__.validationError || !this.$__.validationError.errors[path];
+};
+
+/**
+ * Resets the internal modified state of this document.
+ *
+ * @api private
+ * @return {Document}
+ * @method $__reset
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__reset = function reset() {
+ let _this = this;
+ DocumentArray || (DocumentArray = require('./types/documentarray'));
+
+ this.$__.activePaths
+ .map('init', 'modify', function(i) {
+ return _this.$__getValue(i);
+ })
+ .filter(function(val) {
+ return val && val instanceof Array && val.isMongooseDocumentArray && val.length;
+ })
+ .forEach(function(array) {
+ let i = array.length;
+ while (i--) {
+ const doc = array[i];
+ if (!doc) {
+ continue;
+ }
+ doc.$__reset();
+ }
+
+ _this.$__.activePaths.init(array.$path());
+
+ array[arrayAtomicsSymbol] = {};
+ });
+
+ this.$__.activePaths.
+ map('init', 'modify', function(i) {
+ return _this.$__getValue(i);
+ }).
+ filter(function(val) {
+ return val && val.$isSingleNested;
+ }).
+ forEach(function(doc) {
+ doc.$__reset();
+ _this.$__.activePaths.init(doc.$basePath);
+ });
+
+ // clear atomics
+ this.$__dirty().forEach(function(dirt) {
+ const type = dirt.value;
+
+ if (type && type[arrayAtomicsSymbol]) {
+ type[arrayAtomicsSymbol] = {};
+ }
+ });
+
+ // Clear 'dirty' cache
+ this.$__.activePaths.clear('modify');
+ this.$__.activePaths.clear('default');
+ this.$__.validationError = undefined;
+ this.errors = undefined;
+ _this = this;
+ this.schema.requiredPaths().forEach(function(path) {
+ _this.$__.activePaths.require(path);
+ });
+
+ return this;
+};
+
+/**
+ * Returns this documents dirty paths / vals.
+ *
+ * @api private
+ * @method $__dirty
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__dirty = function() {
+ const _this = this;
+
+ let all = this.$__.activePaths.map('modify', function(path) {
+ return {
+ path: path,
+ value: _this.$__getValue(path),
+ schema: _this.$__path(path)
+ };
+ });
+
+ // gh-2558: if we had to set a default and the value is not undefined,
+ // we have to save as well
+ all = all.concat(this.$__.activePaths.map('default', function(path) {
+ if (path === '_id' || _this.$__getValue(path) == null) {
+ return;
+ }
+ return {
+ path: path,
+ value: _this.$__getValue(path),
+ schema: _this.$__path(path)
+ };
+ }));
+
+ // Sort dirty paths in a flat hierarchy.
+ all.sort(function(a, b) {
+ return (a.path < b.path ? -1 : (a.path > b.path ? 1 : 0));
+ });
+
+ // Ignore "foo.a" if "foo" is dirty already.
+ const minimal = [];
+ let lastPath;
+ let top;
+
+ all.forEach(function(item) {
+ if (!item) {
+ return;
+ }
+ if (lastPath == null || item.path.indexOf(lastPath) !== 0) {
+ lastPath = item.path + '.';
+ minimal.push(item);
+ top = item;
+ } else if (top != null &&
+ top.value != null &&
+ top.value[arrayAtomicsSymbol] != null &&
+ top.value.hasAtomics()) {
+ // special case for top level MongooseArrays
+ // the `top` array itself and a sub path of `top` are being modified.
+ // the only way to honor all of both modifications is through a $set
+ // of entire array.
+ top.value[arrayAtomicsSymbol] = {};
+ top.value[arrayAtomicsSymbol].$set = top.value;
+ }
+ });
+
+ top = lastPath = null;
+ return minimal;
+};
+
+/**
+ * Assigns/compiles `schema` into this documents prototype.
+ *
+ * @param {Schema} schema
+ * @api private
+ * @method $__setSchema
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__setSchema = function(schema) {
+ schema.plugin(idGetter, { deduplicate: true });
+ compile(schema.tree, this, undefined, schema.options);
+
+ // Apply default getters if virtual doesn't have any (gh-6262)
+ for (const key of Object.keys(schema.virtuals)) {
+ schema.virtuals[key]._applyDefaultGetters();
+ }
+
+ this.schema = schema;
+ this[documentSchemaSymbol] = schema;
+};
+
+
+/**
+ * Get active path that were changed and are arrays
+ *
+ * @api private
+ * @method $__getArrayPathsToValidate
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__getArrayPathsToValidate = function() {
+ DocumentArray || (DocumentArray = require('./types/documentarray'));
+
+ // validate all document arrays.
+ return this.$__.activePaths
+ .map('init', 'modify', function(i) {
+ return this.$__getValue(i);
+ }.bind(this))
+ .filter(function(val) {
+ return val && val instanceof Array && val.isMongooseDocumentArray && val.length;
+ }).reduce(function(seed, array) {
+ return seed.concat(array);
+ }, [])
+ .filter(function(doc) {
+ return doc;
+ });
+};
+
+
+/**
+ * Get all subdocs (by bfs)
+ *
+ * @api private
+ * @method $__getAllSubdocs
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__getAllSubdocs = function() {
+ DocumentArray || (DocumentArray = require('./types/documentarray'));
+ Embedded = Embedded || require('./types/embedded');
+
+ function docReducer(doc, seed, path) {
+ let val = doc;
+ if (path) {
+ if (doc instanceof Document && doc[documentSchemaSymbol].paths[path]) {
+ val = doc._doc[path];
+ } else {
+ val = doc[path];
+ }
+ }
+ if (val instanceof Embedded) {
+ seed.push(val);
+ } else if (val instanceof Map) {
+ seed = Array.from(val.keys()).reduce(function(seed, path) {
+ return docReducer(val.get(path), seed, null);
+ }, seed);
+ } else if (val && val.$isSingleNested) {
+ seed = Object.keys(val._doc).reduce(function(seed, path) {
+ return docReducer(val._doc, seed, path);
+ }, seed);
+ seed.push(val);
+ } else if (val && val.isMongooseDocumentArray) {
+ val.forEach(function _docReduce(doc) {
+ if (!doc || !doc._doc) {
+ return;
+ }
+ seed = Object.keys(doc._doc).reduce(function(seed, path) {
+ return docReducer(doc._doc, seed, path);
+ }, seed);
+ if (doc instanceof Embedded) {
+ seed.push(doc);
+ }
+ });
+ } else if (val instanceof Document && val.$__isNested) {
+ seed = Object.keys(val).reduce(function(seed, path) {
+ return docReducer(val, seed, path);
+ }, seed);
+ }
+ return seed;
+ }
+
+ const _this = this;
+ const subDocs = Object.keys(this._doc).reduce(function(seed, path) {
+ return docReducer(_this, seed, path);
+ }, []);
+
+ return subDocs;
+};
+
+/*!
+ * Runs queued functions
+ */
+
+function applyQueue(doc) {
+ const q = doc.schema && doc.schema.callQueue;
+ if (!q.length) {
+ return;
+ }
+ let pair;
+
+ for (let i = 0; i < q.length; ++i) {
+ pair = q[i];
+ if (pair[0] !== 'pre' && pair[0] !== 'post' && pair[0] !== 'on') {
+ doc[pair[0]].apply(doc, pair[1]);
+ }
+ }
+}
+
+/*!
+ * ignore
+ */
+
+Document.prototype.$__handleReject = function handleReject(err) {
+ // emit on the Model if listening
+ if (this.listeners('error').length) {
+ this.emit('error', err);
+ } else if (this.constructor.listeners && this.constructor.listeners('error').length) {
+ this.constructor.emit('error', err);
+ } else if (this.listeners && this.listeners('error').length) {
+ this.emit('error', err);
+ }
+};
+
+/**
+ * Internal helper for toObject() and toJSON() that doesn't manipulate options
+ *
+ * @api private
+ * @method $toObject
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$toObject = function(options, json) {
+ let defaultOptions = {
+ transform: true,
+ flattenDecimals: true
+ };
+
+ const path = json ? 'toJSON' : 'toObject';
+ const baseOptions = get(this, 'constructor.base.options.' + path, {});
+ const schemaOptions = get(this, 'schema.options', {});
+ // merge base default options with Schema's set default options if available.
+ // `clone` is necessary here because `utils.options` directly modifies the second input.
+ defaultOptions = utils.options(defaultOptions, clone(baseOptions));
+ defaultOptions = utils.options(defaultOptions, clone(schemaOptions[path] || {}));
+
+ // If options do not exist or is not an object, set it to empty object
+ options = utils.isPOJO(options) ? clone(options) : {};
+
+ if (!('flattenMaps' in options)) {
+ options.flattenMaps = defaultOptions.flattenMaps;
+ }
+
+ let _minimize;
+ if (options.minimize != null) {
+ _minimize = options.minimize;
+ } else if (defaultOptions.minimize != null) {
+ _minimize = defaultOptions.minimize;
+ } else {
+ _minimize = schemaOptions.minimize;
+ }
+
+ // The original options that will be passed to `clone()`. Important because
+ // `clone()` will recursively call `$toObject()` on embedded docs, so we
+ // need the original options the user passed in, plus `_isNested` and
+ // `_parentOptions` for checking whether we need to depopulate.
+ const cloneOptions = Object.assign(utils.clone(options), {
+ _isNested: true,
+ json: json,
+ minimize: _minimize
+ });
+
+ if (utils.hasUserDefinedProperty(options, 'getters')) {
+ cloneOptions.getters = options.getters;
+ }
+ if (utils.hasUserDefinedProperty(options, 'virtuals')) {
+ cloneOptions.virtuals = options.virtuals;
+ }
+
+ const depopulate = options.depopulate ||
+ get(options, '_parentOptions.depopulate', false);
+ // _isNested will only be true if this is not the top level document, we
+ // should never depopulate
+ if (depopulate && options._isNested && this.$__.wasPopulated) {
+ // populated paths that we set to a document
+ return clone(this._id, cloneOptions);
+ }
+
+ // merge default options with input options.
+ options = utils.options(defaultOptions, options);
+ options._isNested = true;
+ options.json = json;
+ options.minimize = _minimize;
+
+ cloneOptions._parentOptions = options;
+ cloneOptions._skipSingleNestedGetters = true;
+
+ const gettersOptions = Object.assign({}, cloneOptions);
+ gettersOptions._skipSingleNestedGetters = false;
+
+ // remember the root transform function
+ // to save it from being overwritten by sub-transform functions
+ const originalTransform = options.transform;
+
+ let ret = clone(this._doc, cloneOptions) || {};
+
+ if (options.getters) {
+ applyGetters(this, ret, gettersOptions);
+
+ if (options.minimize) {
+ ret = minimize(ret) || {};
+ }
+ }
+
+ if (options.virtuals || (options.getters && options.virtuals !== false)) {
+ applyVirtuals(this, ret, gettersOptions, options);
+ }
+
+ if (options.versionKey === false && this.schema.options.versionKey) {
+ delete ret[this.schema.options.versionKey];
+ }
+
+ let transform = options.transform;
+
+ // In the case where a subdocument has its own transform function, we need to
+ // check and see if the parent has a transform (options.transform) and if the
+ // child schema has a transform (this.schema.options.toObject) In this case,
+ // we need to adjust options.transform to be the child schema's transform and
+ // not the parent schema's
+ if (transform) {
+ applySchemaTypeTransforms(this, ret, gettersOptions, options);
+ }
+
+ if (transform === true || (schemaOptions.toObject && transform)) {
+ const opts = options.json ? schemaOptions.toJSON : schemaOptions.toObject;
+
+ if (opts) {
+ transform = (typeof options.transform === 'function' ? options.transform : opts.transform);
+ }
+ } else {
+ options.transform = originalTransform;
+ }
+
+ if (typeof transform === 'function') {
+ const xformed = transform(this, ret, options);
+ if (typeof xformed !== 'undefined') {
+ ret = xformed;
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * Converts this document into a plain javascript object, ready for storage in MongoDB.
+ *
+ * Buffers are converted to instances of [mongodb.Binary](http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html) for proper storage.
+ *
+ * ####Options:
+ *
+ * - `getters` apply all getters (path and virtual getters), defaults to false
+ * - `virtuals` apply virtual getters (can override `getters` option), defaults to false
+ * - `minimize` remove empty objects (defaults to true)
+ * - `transform` a transform function to apply to the resulting document before returning
+ * - `depopulate` depopulate any populated paths, replacing them with their original refs (defaults to false)
+ * - `versionKey` whether to include the version key (defaults to true)
+ *
+ * ####Getters/Virtuals
+ *
+ * Example of only applying path getters
+ *
+ * doc.toObject({ getters: true, virtuals: false })
+ *
+ * Example of only applying virtual getters
+ *
+ * doc.toObject({ virtuals: true })
+ *
+ * Example of applying both path and virtual getters
+ *
+ * doc.toObject({ getters: true })
+ *
+ * To apply these options to every document of your schema by default, set your [schemas](#schema_Schema) `toObject` option to the same argument.
+ *
+ * schema.set('toObject', { virtuals: true })
+ *
+ * ####Transform
+ *
+ * We may need to perform a transformation of the resulting object based on some criteria, say to remove some sensitive information or return a custom object. In this case we set the optional `transform` function.
+ *
+ * Transform functions receive three arguments
+ *
+ * function (doc, ret, options) {}
+ *
+ * - `doc` The mongoose document which is being converted
+ * - `ret` The plain object representation which has been converted
+ * - `options` The options in use (either schema options or the options passed inline)
+ *
+ * ####Example
+ *
+ * // specify the transform schema option
+ * if (!schema.options.toObject) schema.options.toObject = {};
+ * schema.options.toObject.transform = function (doc, ret, options) {
+ * // remove the _id of every document before returning the result
+ * delete ret._id;
+ * return ret;
+ * }
+ *
+ * // without the transformation in the schema
+ * doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' }
+ *
+ * // with the transformation
+ * doc.toObject(); // { name: 'Wreck-it Ralph' }
+ *
+ * With transformations we can do a lot more than remove properties. We can even return completely new customized objects:
+ *
+ * if (!schema.options.toObject) schema.options.toObject = {};
+ * schema.options.toObject.transform = function (doc, ret, options) {
+ * return { movie: ret.name }
+ * }
+ *
+ * // without the transformation in the schema
+ * doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' }
+ *
+ * // with the transformation
+ * doc.toObject(); // { movie: 'Wreck-it Ralph' }
+ *
+ * _Note: if a transform function returns `undefined`, the return value will be ignored._
+ *
+ * Transformations may also be applied inline, overridding any transform set in the options:
+ *
+ * function xform (doc, ret, options) {
+ * return { inline: ret.name, custom: true }
+ * }
+ *
+ * // pass the transform as an inline option
+ * doc.toObject({ transform: xform }); // { inline: 'Wreck-it Ralph', custom: true }
+ *
+ * If you want to skip transformations, use `transform: false`:
+ *
+ * schema.options.toObject.hide = '_id';
+ * schema.options.toObject.transform = function (doc, ret, options) {
+ * if (options.hide) {
+ * options.hide.split(' ').forEach(function (prop) {
+ * delete ret[prop];
+ * });
+ * }
+ * return ret;
+ * }
+ *
+ * var doc = new Doc({ _id: 'anId', secret: 47, name: 'Wreck-it Ralph' });
+ * doc.toObject(); // { secret: 47, name: 'Wreck-it Ralph' }
+ * doc.toObject({ hide: 'secret _id', transform: false });// { _id: 'anId', secret: 47, name: 'Wreck-it Ralph' }
+ * doc.toObject({ hide: 'secret _id', transform: true }); // { name: 'Wreck-it Ralph' }
+ *
+ * If you pass a transform in `toObject()` options, Mongoose will apply the transform
+ * to [subdocuments](/docs/subdocs.html) in addition to the top-level document.
+ * Similarly, `transform: false` skips transforms for all subdocuments.
+ * Note that this is behavior is different for transforms defined in the schema:
+ * if you define a transform in `schema.options.toObject.transform`, that transform
+ * will **not** apply to subdocuments.
+ *
+ * const memberSchema = new Schema({ name: String, email: String });
+ * const groupSchema = new Schema({ members: [memberSchema], name: String, email });
+ * const Group = mongoose.model('Group', groupSchema);
+ *
+ * const doc = new Group({
+ * name: 'Engineering',
+ * email: 'dev@mongoosejs.io',
+ * members: [{ name: 'Val', email: 'val@mongoosejs.io' }]
+ * });
+ *
+ * // Removes `email` from both top-level document **and** array elements
+ * // { name: 'Engineering', members: [{ name: 'Val' }] }
+ * doc.toObject({ transform: (doc, ret) => { delete ret.email; return ret; } });
+ *
+ * Transforms, like all of these options, are also available for `toJSON`. See [this guide to `JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html) to learn why `toJSON()` and `toObject()` are separate functions.
+ *
+ * See [schema options](/docs/guide.html#toObject) for some more details.
+ *
+ * _During save, no custom options are applied to the document before being sent to the database._
+ *
+ * @param {Object} [options]
+ * @param {Boolean} [options.getters=false] if true, apply all getters, including virtuals
+ * @param {Boolean} [options.virtuals=false] if true, apply virtuals, including aliases. Use `{ getters: true, virtuals: false }` to just apply getters, not virtuals
+ * @param {Boolean} [options.aliases=true] if `options.virtuals = true`, you can set `options.aliases = false` to skip applying aliases. This option is a no-op if `options.virtuals = false`.
+ * @param {Boolean} [options.minimize=true] if true, omit any empty objects from the output
+ * @param {Function|null} [options.transform=null] if set, mongoose will call this function to allow you to transform the returned object
+ * @param {Boolean} [options.depopulate=false] if true, replace any conventionally populated paths with the original id in the output. Has no affect on virtual populated paths.
+ * @param {Boolean} [options.versionKey=true] if false, exclude the version key (`__v` by default) from the output
+ * @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
+ * @return {Object} js object
+ * @see mongodb.Binary http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.toObject = function(options) {
+ return this.$toObject(options);
+};
+
+/*!
+ * Minimizes an object, removing undefined values and empty objects
+ *
+ * @param {Object} object to minimize
+ * @return {Object}
+ */
+
+function minimize(obj) {
+ const keys = Object.keys(obj);
+ let i = keys.length;
+ let hasKeys;
+ let key;
+ let val;
+
+ while (i--) {
+ key = keys[i];
+ val = obj[key];
+
+ if (utils.isObject(val) && !Buffer.isBuffer(val)) {
+ obj[key] = minimize(val);
+ }
+
+ if (undefined === obj[key]) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ }
+
+ return hasKeys
+ ? obj
+ : undefined;
+}
+
+/*!
+ * Applies virtuals properties to `json`.
+ */
+
+function applyVirtuals(self, json, options, toObjectOptions) {
+ const schema = self.schema;
+ const paths = Object.keys(schema.virtuals);
+ let i = paths.length;
+ const numPaths = i;
+ let path;
+ let assignPath;
+ let cur = self._doc;
+ let v;
+ const aliases = get(toObjectOptions, 'aliases', true);
+
+ if (!cur) {
+ return json;
+ }
+
+ options = options || {};
+ for (i = 0; i < numPaths; ++i) {
+ path = paths[i];
+
+ // Allow skipping aliases with `toObject({ virtuals: true, aliases: false })`
+ if (!aliases && schema.aliases.hasOwnProperty(path)) {
+ continue;
+ }
+
+ // We may be applying virtuals to a nested object, for example if calling
+ // `doc.nestedProp.toJSON()`. If so, the path we assign to, `assignPath`,
+ // will be a trailing substring of the `path`.
+ assignPath = path;
+ if (options.path != null) {
+ if (!path.startsWith(options.path + '.')) {
+ continue;
+ }
+ assignPath = path.substr(options.path.length + 1);
+ }
+ const parts = assignPath.split('.');
+ v = clone(self.get(path), options);
+ if (v === void 0) {
+ continue;
+ }
+ const plen = parts.length;
+ cur = json;
+ for (let j = 0; j < plen - 1; ++j) {
+ cur[parts[j]] = cur[parts[j]] || {};
+ cur = cur[parts[j]];
+ }
+ cur[parts[plen - 1]] = v;
+ }
+
+ return json;
+}
+
+/*!
+ * Applies virtuals properties to `json`.
+ *
+ * @param {Document} self
+ * @param {Object} json
+ * @return {Object} `json`
+ */
+
+function applyGetters(self, json, options) {
+ const schema = self.schema;
+ const paths = Object.keys(schema.paths);
+ let i = paths.length;
+ let path;
+ let cur = self._doc;
+ let v;
+
+ if (!cur) {
+ return json;
+ }
+
+ while (i--) {
+ path = paths[i];
+
+ const parts = path.split('.');
+ const plen = parts.length;
+ const last = plen - 1;
+ let branch = json;
+ let part;
+ cur = self._doc;
+
+ if (!self.isSelected(path)) {
+ continue;
+ }
+
+ for (let ii = 0; ii < plen; ++ii) {
+ part = parts[ii];
+ v = cur[part];
+ if (ii === last) {
+ const val = self.get(path);
+ branch[part] = clone(val, options);
+ } else if (v == null) {
+ if (part in cur) {
+ branch[part] = v;
+ }
+ break;
+ } else {
+ branch = branch[part] || (branch[part] = {});
+ }
+ cur = v;
+ }
+ }
+
+ return json;
+}
+
+/*!
+ * Applies schema type transforms to `json`.
+ *
+ * @param {Document} self
+ * @param {Object} json
+ * @return {Object} `json`
+ */
+
+function applySchemaTypeTransforms(self, json) {
+ const schema = self.schema;
+ const paths = Object.keys(schema.paths || {});
+ const cur = self._doc;
+
+ if (!cur) {
+ return json;
+ }
+
+ for (const path of paths) {
+ const schematype = schema.paths[path];
+ if (typeof schematype.options.transform === 'function') {
+ const val = self.get(path);
+ json[path] = schematype.options.transform.call(self, val);
+ } else if (schematype.$embeddedSchemaType != null &&
+ typeof schematype.$embeddedSchemaType.options.transform === 'function') {
+ const vals = [].concat(self.get(path));
+ const transform = schematype.$embeddedSchemaType.options.transform;
+ for (let i = 0; i < vals.length; ++i) {
+ vals[i] = transform.call(self, vals[i]);
+ }
+
+ json[path] = vals;
+ }
+ }
+
+ return json;
+}
+
+/**
+ * The return value of this method is used in calls to JSON.stringify(doc).
+ *
+ * This method accepts the same options as [Document#toObject](#document_Document-toObject). To apply the options to every document of your schema by default, set your [schemas](#schema_Schema) `toJSON` option to the same argument.
+ *
+ * schema.set('toJSON', { virtuals: true })
+ *
+ * See [schema options](/docs/guide.html#toJSON) for details.
+ *
+ * @param {Object} options
+ * @return {Object}
+ * @see Document#toObject #document_Document-toObject
+ * @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.toJSON = function(options) {
+ return this.$toObject(options, true);
+};
+
+/**
+ * Helper for console.log
+ *
+ * @api public
+ * @method inspect
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.inspect = function(options) {
+ const isPOJO = utils.isPOJO(options);
+ let opts;
+ if (isPOJO) {
+ opts = options;
+ opts.minimize = false;
+ }
+ const ret = this.toObject(opts);
+
+ if (ret == null) {
+ // If `toObject()` returns null, `this` is still an object, so if `inspect()`
+ // prints out null this can cause some serious confusion. See gh-7942.
+ return 'MongooseDocument { ' + ret + ' }';
+ }
+
+ return ret;
+};
+
+if (inspect.custom) {
+ /*!
+ * Avoid Node deprecation warning DEP0079
+ */
+
+ Document.prototype[inspect.custom] = Document.prototype.inspect;
+}
+
+/**
+ * Helper for console.log
+ *
+ * @api public
+ * @method toString
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.toString = function() {
+ const ret = this.inspect();
+ if (typeof ret === 'string') {
+ return ret;
+ }
+ return inspect(ret);
+};
+
+/**
+ * Returns true if the Document stores the same data as doc.
+ *
+ * Documents are considered equal when they have matching `_id`s, unless neither
+ * document has an `_id`, in which case this function falls back to using
+ * `deepEqual()`.
+ *
+ * @param {Document} doc a document to compare
+ * @return {Boolean}
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.equals = function(doc) {
+ if (!doc) {
+ return false;
+ }
+
+ const tid = this.get('_id');
+ const docid = doc.get ? doc.get('_id') : doc;
+ if (!tid && !docid) {
+ return deepEqual(this, doc);
+ }
+ return tid && tid.equals
+ ? tid.equals(docid)
+ : tid === docid;
+};
+
+/**
+ * Populates document references, executing the `callback` when complete.
+ * If you want to use promises instead, use this function with
+ * [`execPopulate()`](#document_Document-execPopulate)
+ *
+ * ####Example:
+ *
+ * doc
+ * .populate('company')
+ * .populate({
+ * path: 'notes',
+ * match: /airline/,
+ * select: 'text',
+ * model: 'modelName'
+ * options: opts
+ * }, function (err, user) {
+ * assert(doc._id === user._id) // the document itself is passed
+ * })
+ *
+ * // summary
+ * doc.populate(path) // not executed
+ * doc.populate(options); // not executed
+ * doc.populate(path, callback) // executed
+ * doc.populate(options, callback); // executed
+ * doc.populate(callback); // executed
+ * doc.populate(options).execPopulate() // executed, returns promise
+ *
+ *
+ * ####NOTE:
+ *
+ * Population does not occur unless a `callback` is passed *or* you explicitly
+ * call `execPopulate()`.
+ * Passing the same path a second time will overwrite the previous path options.
+ * See [Model.populate()](#model_Model.populate) for explaination of options.
+ *
+ * @see Model.populate #model_Model.populate
+ * @see Document.execPopulate #document_Document-execPopulate
+ * @param {String|Object} [path] The path to populate or an options object
+ * @param {Function} [callback] When passed, population is invoked
+ * @api public
+ * @return {Document} this
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.populate = function populate() {
+ if (arguments.length === 0) {
+ return this;
+ }
+
+ const pop = this.$__.populate || (this.$__.populate = {});
+ const args = utils.args(arguments);
+ let fn;
+
+ if (typeof args[args.length - 1] === 'function') {
+ fn = args.pop();
+ }
+
+ // allow `doc.populate(callback)`
+ if (args.length) {
+ // use hash to remove duplicate paths
+ const res = utils.populate.apply(null, args);
+ for (let i = 0; i < res.length; ++i) {
+ pop[res[i].path] = res[i];
+ }
+ }
+
+ if (fn) {
+ const paths = utils.object.vals(pop);
+ this.$__.populate = undefined;
+ let topLevelModel = this.constructor;
+ if (this.$__isNested) {
+ topLevelModel = this.$__.scope.constructor;
+ const nestedPath = this.$__.nestedPath;
+ paths.forEach(function(populateOptions) {
+ populateOptions.path = nestedPath + '.' + populateOptions.path;
+ });
+ }
+
+ // Use `$session()` by default if the document has an associated session
+ // See gh-6754
+ if (this.$session() != null) {
+ const session = this.$session();
+ paths.forEach(path => {
+ if (path.options == null) {
+ path.options = { session: session };
+ return;
+ }
+ if (!('session' in path.options)) {
+ path.options.session = session;
+ }
+ });
+ }
+
+ topLevelModel.populate(this, paths, fn);
+ }
+
+ return this;
+};
+
+/**
+ * Explicitly executes population and returns a promise. Useful for ES2015
+ * integration.
+ *
+ * ####Example:
+ *
+ * var promise = doc.
+ * populate('company').
+ * populate({
+ * path: 'notes',
+ * match: /airline/,
+ * select: 'text',
+ * model: 'modelName'
+ * options: opts
+ * }).
+ * execPopulate();
+ *
+ * // summary
+ * doc.execPopulate().then(resolve, reject);
+ *
+ *
+ * @see Document.populate #document_Document-populate
+ * @api public
+ * @param {Function} [callback] optional callback. If specified, a promise will **not** be returned
+ * @return {Promise} promise that resolves to the document when population is done
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.execPopulate = function(callback) {
+ return promiseOrCallback(callback, cb => {
+ this.populate(cb);
+ }, this.constructor.events);
+};
+
+/**
+ * Gets _id(s) used during population of the given `path`.
+ *
+ * ####Example:
+ *
+ * Model.findOne().populate('author').exec(function (err, doc) {
+ * console.log(doc.author.name) // Dr.Seuss
+ * console.log(doc.populated('author')) // '5144cf8050f071d979c118a7'
+ * })
+ *
+ * If the path was not populated, undefined is returned.
+ *
+ * @param {String} path
+ * @return {Array|ObjectId|Number|Buffer|String|undefined}
+ * @memberOf Document
+ * @instance
+ * @api public
+ */
+
+Document.prototype.populated = function(path, val, options) {
+ // val and options are internal
+ if (val === null || val === void 0) {
+ if (!this.$__.populated) {
+ return undefined;
+ }
+ const v = this.$__.populated[path];
+ if (v) {
+ return v.value;
+ }
+ return undefined;
+ }
+
+ // internal
+ if (val === true) {
+ if (!this.$__.populated) {
+ return undefined;
+ }
+ return this.$__.populated[path];
+ }
+
+ this.$__.populated || (this.$__.populated = {});
+ this.$__.populated[path] = { value: val, options: options };
+
+ // If this was a nested populate, make sure each populated doc knows
+ // about its populated children (gh-7685)
+ const pieces = path.split('.');
+ for (let i = 0; i < pieces.length - 1; ++i) {
+ const subpath = pieces.slice(0, i + 1).join('.');
+ const subdoc = this.get(subpath);
+ if (subdoc != null && subdoc.$__ != null && this.populated(subpath)) {
+ const rest = pieces.slice(i + 1).join('.');
+ subdoc.populated(rest, val, options);
+ // No need to continue because the above recursion should take care of
+ // marking the rest of the docs as populated
+ break;
+ }
+ }
+
+ return val;
+};
+
+/**
+ * Takes a populated field and returns it to its unpopulated state.
+ *
+ * ####Example:
+ *
+ * Model.findOne().populate('author').exec(function (err, doc) {
+ * console.log(doc.author.name); // Dr.Seuss
+ * console.log(doc.depopulate('author'));
+ * console.log(doc.author); // '5144cf8050f071d979c118a7'
+ * })
+ *
+ * If the path was not populated, this is a no-op.
+ *
+ * @param {String} path
+ * @return {Document} this
+ * @see Document.populate #document_Document-populate
+ * @api public
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.depopulate = function(path) {
+ if (typeof path === 'string') {
+ path = path.split(' ');
+ }
+ let populatedIds;
+ const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
+ const populated = get(this, '$__.populated', {});
+
+ if (arguments.length === 0) {
+ // Depopulate all
+ for (let i = 0; i < virtualKeys.length; i++) {
+ delete this.$$populatedVirtuals[virtualKeys[i]];
+ delete this._doc[virtualKeys[i]];
+ delete populated[virtualKeys[i]];
+ }
+
+ const keys = Object.keys(populated);
+
+ for (let i = 0; i < keys.length; i++) {
+ populatedIds = this.populated(keys[i]);
+ if (!populatedIds) {
+ continue;
+ }
+ delete populated[keys[i]];
+ this.$set(keys[i], populatedIds);
+ }
+ return this;
+ }
+
+ for (let i = 0; i < path.length; i++) {
+ populatedIds = this.populated(path[i]);
+ delete populated[path[i]];
+
+ if (virtualKeys.indexOf(path[i]) !== -1) {
+ delete this.$$populatedVirtuals[path[i]];
+ delete this._doc[path[i]];
+ } else if (populatedIds) {
+ this.$set(path[i], populatedIds);
+ }
+ }
+ return this;
+};
+
+
+/**
+ * Returns the full path to this document.
+ *
+ * @param {String} [path]
+ * @return {String}
+ * @api private
+ * @method $__fullPath
+ * @memberOf Document
+ * @instance
+ */
+
+Document.prototype.$__fullPath = function(path) {
+ // overridden in SubDocuments
+ return path || '';
+};
+
+/*!
+ * Module exports.
+ */
+
+Document.ValidationError = ValidationError;
+module.exports = exports = Document;
diff --git a/node_modules/mongoose/lib/document_provider.js b/node_modules/mongoose/lib/document_provider.js
new file mode 100644
index 0000000..1ace61f
--- /dev/null
+++ b/node_modules/mongoose/lib/document_provider.js
@@ -0,0 +1,30 @@
+'use strict';
+
+/* eslint-env browser */
+
+/*!
+ * Module dependencies.
+ */
+const Document = require('./document.js');
+const BrowserDocument = require('./browserDocument.js');
+
+let isBrowser = false;
+
+/**
+ * Returns the Document constructor for the current context
+ *
+ * @api private
+ */
+module.exports = function() {
+ if (isBrowser) {
+ return BrowserDocument;
+ }
+ return Document;
+};
+
+/*!
+ * ignore
+ */
+module.exports.setBrowser = function(flag) {
+ isBrowser = flag;
+};
diff --git a/node_modules/mongoose/lib/driver.js b/node_modules/mongoose/lib/driver.js
new file mode 100644
index 0000000..cf7ca3d
--- /dev/null
+++ b/node_modules/mongoose/lib/driver.js
@@ -0,0 +1,15 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+let driver = null;
+
+module.exports.get = function() {
+ return driver;
+};
+
+module.exports.set = function(v) {
+ driver = v;
+};
diff --git a/node_modules/mongoose/lib/drivers/SPEC.md b/node_modules/mongoose/lib/drivers/SPEC.md
new file mode 100644
index 0000000..6464693
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/SPEC.md
@@ -0,0 +1,4 @@
+
+# Driver Spec
+
+TODO
diff --git a/node_modules/mongoose/lib/drivers/browser/ReadPreference.js b/node_modules/mongoose/lib/drivers/browser/ReadPreference.js
new file mode 100644
index 0000000..1363570
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/browser/ReadPreference.js
@@ -0,0 +1,7 @@
+/*!
+ * ignore
+ */
+
+'use strict';
+
+module.exports = function() {};
diff --git a/node_modules/mongoose/lib/drivers/browser/binary.js b/node_modules/mongoose/lib/drivers/browser/binary.js
new file mode 100644
index 0000000..4658f7b
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/browser/binary.js
@@ -0,0 +1,14 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const Binary = require('bson').Binary;
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = Binary;
diff --git a/node_modules/mongoose/lib/drivers/browser/decimal128.js b/node_modules/mongoose/lib/drivers/browser/decimal128.js
new file mode 100644
index 0000000..5668182
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/browser/decimal128.js
@@ -0,0 +1,7 @@
+/*!
+ * ignore
+ */
+
+'use strict';
+
+module.exports = require('bson').Decimal128;
diff --git a/node_modules/mongoose/lib/drivers/browser/index.js b/node_modules/mongoose/lib/drivers/browser/index.js
new file mode 100644
index 0000000..56d0b8a
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/browser/index.js
@@ -0,0 +1,13 @@
+/*!
+ * Module exports.
+ */
+
+'use strict';
+
+exports.Binary = require('./binary');
+exports.Collection = function() {
+ throw new Error('Cannot create a collection from browser library');
+};
+exports.Decimal128 = require('./decimal128');
+exports.ObjectId = require('./objectid');
+exports.ReadPreference = require('./ReadPreference');
diff --git a/node_modules/mongoose/lib/drivers/browser/objectid.js b/node_modules/mongoose/lib/drivers/browser/objectid.js
new file mode 100644
index 0000000..b1e603d
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/browser/objectid.js
@@ -0,0 +1,28 @@
+
+/*!
+ * [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
+ * @constructor NodeMongoDbObjectId
+ * @see ObjectId
+ */
+
+'use strict';
+
+const ObjectId = require('bson').ObjectID;
+
+/*!
+ * Getter for convenience with populate, see gh-6115
+ */
+
+Object.defineProperty(ObjectId.prototype, '_id', {
+ enumerable: false,
+ configurable: true,
+ get: function() {
+ return this;
+ }
+});
+
+/*!
+ * ignore
+ */
+
+module.exports = exports = ObjectId;
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/ReadPreference.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/ReadPreference.js
new file mode 100644
index 0000000..024ee18
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/ReadPreference.js
@@ -0,0 +1,47 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const mongodb = require('mongodb');
+const ReadPref = mongodb.ReadPreference;
+
+/*!
+ * Converts arguments to ReadPrefs the driver
+ * can understand.
+ *
+ * @param {String|Array} pref
+ * @param {Array} [tags]
+ */
+
+module.exports = function readPref(pref, tags) {
+ if (Array.isArray(pref)) {
+ tags = pref[1];
+ pref = pref[0];
+ }
+
+ if (pref instanceof ReadPref) {
+ return pref;
+ }
+
+ switch (pref) {
+ case 'p':
+ pref = 'primary';
+ break;
+ case 'pp':
+ pref = 'primaryPreferred';
+ break;
+ case 's':
+ pref = 'secondary';
+ break;
+ case 'sp':
+ pref = 'secondaryPreferred';
+ break;
+ case 'n':
+ pref = 'nearest';
+ break;
+ }
+
+ return new ReadPref(pref, tags);
+};
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js
new file mode 100644
index 0000000..4e3c86f
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js
@@ -0,0 +1,10 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const Binary = require('mongodb').Binary;
+
+module.exports = exports = Binary;
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js
new file mode 100644
index 0000000..7f0be87
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js
@@ -0,0 +1,359 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseCollection = require('../../collection');
+const MongooseError = require('../../error/mongooseError');
+const Collection = require('mongodb').Collection;
+const get = require('../../helpers/get');
+const sliced = require('sliced');
+const stream = require('stream');
+const util = require('util');
+
+/**
+ * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
+ *
+ * All methods methods from the [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver are copied and wrapped in queue management.
+ *
+ * @inherits Collection
+ * @api private
+ */
+
+function NativeCollection(name, options) {
+ this.collection = null;
+ this.Promise = options.Promise || Promise;
+ MongooseCollection.apply(this, arguments);
+}
+
+/*!
+ * Inherit from abstract Collection.
+ */
+
+NativeCollection.prototype.__proto__ = MongooseCollection.prototype;
+
+/**
+ * Called when the connection opens.
+ *
+ * @api private
+ */
+
+NativeCollection.prototype.onOpen = function() {
+ const _this = this;
+
+ // always get a new collection in case the user changed host:port
+ // of parent db instance when re-opening the connection.
+
+ if (!_this.opts.capped.size) {
+ // non-capped
+ callback(null, _this.conn.db.collection(_this.name));
+ return _this.collection;
+ }
+
+ if (_this.opts.autoCreate === false) {
+ _this.collection = _this.conn.db.collection(_this.name);
+ return _this.collection;
+ }
+
+ // capped
+ return _this.conn.db.collection(_this.name, function(err, c) {
+ if (err) return callback(err);
+
+ // discover if this collection exists and if it is capped
+ _this.conn.db.listCollections({ name: _this.name }).toArray(function(err, docs) {
+ if (err) {
+ return callback(err);
+ }
+ const doc = docs[0];
+ const exists = !!doc;
+
+ if (exists) {
+ if (doc.options && doc.options.capped) {
+ callback(null, c);
+ } else {
+ const msg = 'A non-capped collection exists with the name: ' + _this.name + '\n\n'
+ + ' To use this collection as a capped collection, please '
+ + 'first convert it.\n'
+ + ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped';
+ err = new Error(msg);
+ callback(err);
+ }
+ } else {
+ // create
+ const opts = Object.assign({}, _this.opts.capped);
+ opts.capped = true;
+ _this.conn.db.createCollection(_this.name, opts, callback);
+ }
+ });
+ });
+
+ function callback(err, collection) {
+ if (err) {
+ // likely a strict mode error
+ _this.conn.emit('error', err);
+ } else {
+ _this.collection = collection;
+ MongooseCollection.prototype.onOpen.call(_this);
+ }
+ }
+};
+
+/**
+ * Called when the connection closes
+ *
+ * @api private
+ */
+
+NativeCollection.prototype.onClose = function(force) {
+ MongooseCollection.prototype.onClose.call(this, force);
+};
+
+/*!
+ * ignore
+ */
+
+const syncCollectionMethods = { watch: true };
+
+/*!
+ * Copy the collection methods and make them subject to queues
+ */
+
+function iter(i) {
+ NativeCollection.prototype[i] = function() {
+ const collection = this.collection;
+ const args = Array.from(arguments);
+ const _this = this;
+ const debug = get(_this, 'conn.base.options.debug');
+ const lastArg = arguments[arguments.length - 1];
+
+ // If user force closed, queueing will hang forever. See #5664
+ if (this.conn.$wasForceClosed) {
+ const error = new MongooseError('Connection was force closed');
+ if (args.length > 0 &&
+ typeof args[args.length - 1] === 'function') {
+ args[args.length - 1](error);
+ return;
+ } else {
+ throw error;
+ }
+ }
+ if (this.buffer) {
+ if (syncCollectionMethods[i]) {
+ throw new Error('Collection method ' + i + ' is synchronous');
+ }
+ if (typeof lastArg === 'function') {
+ this.addQueue(i, args);
+ return;
+ }
+ return new this.Promise((resolve, reject) => {
+ this.addQueue(i, [].concat(args).concat([(err, res) => {
+ if (err != null) {
+ return reject(err);
+ }
+ resolve(res);
+ }]));
+ });
+ }
+
+ if (debug) {
+ if (typeof debug === 'function') {
+ debug.apply(_this,
+ [_this.name, i].concat(sliced(args, 0, args.length - 1)));
+ } else if (debug instanceof stream.Writable) {
+ this.$printToStream(_this.name, i, args, debug);
+ } else {
+ this.$print(_this.name, i, args, typeof debug.color === 'undefined' ? true : debug.color);
+ }
+ }
+
+ try {
+ return collection[i].apply(collection, args);
+ } catch (error) {
+ // Collection operation may throw because of max bson size, catch it here
+ // See gh-3906
+ if (args.length > 0 &&
+ typeof args[args.length - 1] === 'function') {
+ args[args.length - 1](error);
+ } else {
+ throw error;
+ }
+ }
+ };
+}
+
+for (const key of Object.keys(Collection.prototype)) {
+ // Janky hack to work around gh-3005 until we can get rid of the mongoose
+ // collection abstraction
+ const descriptor = Object.getOwnPropertyDescriptor(Collection.prototype, key);
+ // Skip properties with getters because they may throw errors (gh-8528)
+ if (descriptor.get !== undefined) {
+ continue;
+ }
+ if (typeof Collection.prototype[key] !== 'function') {
+ continue;
+ }
+
+ iter(key);
+}
+
+/**
+ * Debug print helper
+ *
+ * @api public
+ * @method $print
+ */
+
+NativeCollection.prototype.$print = function(name, i, args, color) {
+ const moduleName = color ? '\x1B[0;36mMongoose:\x1B[0m ' : 'Mongoose: ';
+ const functionCall = [name, i].join('.');
+ const _args = [];
+ for (let j = args.length - 1; j >= 0; --j) {
+ if (this.$format(args[j]) || _args.length) {
+ _args.unshift(this.$format(args[j], color));
+ }
+ }
+ const params = '(' + _args.join(', ') + ')';
+
+ console.info(moduleName + functionCall + params);
+};
+
+/**
+ * Debug print helper
+ *
+ * @api public
+ * @method $print
+ */
+
+NativeCollection.prototype.$printToStream = function(name, i, args, stream) {
+ const functionCall = [name, i].join('.');
+ const _args = [];
+ for (let j = args.length - 1; j >= 0; --j) {
+ if (this.$format(args[j]) || _args.length) {
+ _args.unshift(this.$format(args[j]));
+ }
+ }
+ const params = '(' + _args.join(', ') + ')';
+
+ stream.write(functionCall + params, 'utf8');
+};
+
+/**
+ * Formatter for debug print args
+ *
+ * @api public
+ * @method $format
+ */
+
+NativeCollection.prototype.$format = function(arg, color) {
+ const type = typeof arg;
+ if (type === 'function' || type === 'undefined') return '';
+ return format(arg, false, color);
+};
+
+/*!
+ * Debug print helper
+ */
+
+function inspectable(representation) {
+ const ret = {
+ inspect: function() { return representation; }
+ };
+ if (util.inspect.custom) {
+ ret[util.inspect.custom] = ret.inspect;
+ }
+ return ret;
+}
+function map(o) {
+ return format(o, true);
+}
+function formatObjectId(x, key) {
+ x[key] = inspectable('ObjectId("' + x[key].toHexString() + '")');
+}
+function formatDate(x, key) {
+ x[key] = inspectable('new Date("' + x[key].toUTCString() + '")');
+}
+function format(obj, sub, color) {
+ if (obj && typeof obj.toBSON === 'function') {
+ obj = obj.toBSON();
+ }
+ if (obj == null) {
+ return obj;
+ }
+
+ const clone = require('../../helpers/clone');
+ let x = clone(obj, { transform: false });
+
+ if (x.constructor.name === 'Binary') {
+ x = 'BinData(' + x.sub_type + ', "' + x.toString('base64') + '")';
+ } else if (x.constructor.name === 'ObjectID') {
+ x = inspectable('ObjectId("' + x.toHexString() + '")');
+ } else if (x.constructor.name === 'Date') {
+ x = inspectable('new Date("' + x.toUTCString() + '")');
+ } else if (x.constructor.name === 'Object') {
+ const keys = Object.keys(x);
+ const numKeys = keys.length;
+ let key;
+ for (let i = 0; i < numKeys; ++i) {
+ key = keys[i];
+ if (x[key]) {
+ let error;
+ if (typeof x[key].toBSON === 'function') {
+ try {
+ // `session.toBSON()` throws an error. This means we throw errors
+ // in debug mode when using transactions, see gh-6712. As a
+ // workaround, catch `toBSON()` errors, try to serialize without
+ // `toBSON()`, and rethrow if serialization still fails.
+ x[key] = x[key].toBSON();
+ } catch (_error) {
+ error = _error;
+ }
+ }
+ if (x[key].constructor.name === 'Binary') {
+ x[key] = 'BinData(' + x[key].sub_type + ', "' +
+ x[key].buffer.toString('base64') + '")';
+ } else if (x[key].constructor.name === 'Object') {
+ x[key] = format(x[key], true);
+ } else if (x[key].constructor.name === 'ObjectID') {
+ formatObjectId(x, key);
+ } else if (x[key].constructor.name === 'Date') {
+ formatDate(x, key);
+ } else if (x[key].constructor.name === 'ClientSession') {
+ x[key] = inspectable('ClientSession("' +
+ get(x[key], 'id.id.buffer', '').toString('hex') + '")');
+ } else if (Array.isArray(x[key])) {
+ x[key] = x[key].map(map);
+ } else if (error != null) {
+ // If there was an error with `toBSON()` and the object wasn't
+ // already converted to a string representation, rethrow it.
+ // Open to better ideas on how to handle this.
+ throw error;
+ }
+ }
+ }
+ }
+ if (sub) {
+ return x;
+ }
+
+ return util.
+ inspect(x, false, 10, color).
+ replace(/\n/g, '').
+ replace(/\s{2,}/g, ' ');
+}
+
+/**
+ * Retrieves information about this collections indexes.
+ *
+ * @param {Function} callback
+ * @method getIndexes
+ * @api public
+ */
+
+NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation;
+
+/*!
+ * Module exports.
+ */
+
+module.exports = NativeCollection;
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js
new file mode 100644
index 0000000..5fb8c8d
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js
@@ -0,0 +1,184 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseConnection = require('../../connection');
+const STATES = require('../../connectionstate');
+
+/**
+ * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
+ *
+ * @inherits Connection
+ * @api private
+ */
+
+function NativeConnection() {
+ MongooseConnection.apply(this, arguments);
+ this._listening = false;
+}
+
+/**
+ * Expose the possible connection states.
+ * @api public
+ */
+
+NativeConnection.STATES = STATES;
+
+/*!
+ * Inherits from Connection.
+ */
+
+NativeConnection.prototype.__proto__ = MongooseConnection.prototype;
+
+/**
+ * Switches to a different database using the same connection pool.
+ *
+ * Returns a new connection object, with the new db. If you set the `useCache`
+ * option, `useDb()` will cache connections by `name`.
+ *
+ * @param {String} name The database name
+ * @param {Object} [options]
+ * @param {Boolean} [options.useCache=false] If true, cache results so calling `useDb()` multiple times with the same name only creates 1 connection object.
+ * @return {Connection} New Connection Object
+ * @api public
+ */
+
+NativeConnection.prototype.useDb = function(name, options) {
+ // Return immediately if cached
+ if (options && options.useCache && this.relatedDbs[name]) {
+ return this.relatedDbs[name];
+ }
+
+ // we have to manually copy all of the attributes...
+ const newConn = new this.constructor();
+ newConn.name = name;
+ newConn.base = this.base;
+ newConn.collections = {};
+ newConn.models = {};
+ newConn.replica = this.replica;
+ newConn.name = this.name;
+ newConn.options = this.options;
+ newConn._readyState = this._readyState;
+ newConn._closeCalled = this._closeCalled;
+ newConn._hasOpened = this._hasOpened;
+ newConn._listening = false;
+
+ newConn.host = this.host;
+ newConn.port = this.port;
+ newConn.user = this.user;
+ newConn.pass = this.pass;
+
+ // First, when we create another db object, we are not guaranteed to have a
+ // db object to work with. So, in the case where we have a db object and it
+ // is connected, we can just proceed with setting everything up. However, if
+ // we do not have a db or the state is not connected, then we need to wait on
+ // the 'open' event of the connection before doing the rest of the setup
+ // the 'connected' event is the first time we'll have access to the db object
+
+ const _this = this;
+
+ newConn.client = _this.client;
+
+ if (this.db && this._readyState === STATES.connected) {
+ wireup();
+ } else {
+ this.once('connected', wireup);
+ }
+
+ function wireup() {
+ newConn.client = _this.client;
+ newConn.db = _this.client.db(name);
+ newConn.onOpen();
+ // setup the events appropriately
+ listen(newConn);
+ }
+
+ newConn.name = name;
+
+ // push onto the otherDbs stack, this is used when state changes
+ this.otherDbs.push(newConn);
+ newConn.otherDbs.push(this);
+
+ // push onto the relatedDbs cache, this is used when state changes
+ if (options && options.useCache) {
+ this.relatedDbs[newConn.name] = newConn;
+ newConn.relatedDbs = this.relatedDbs;
+ }
+
+ return newConn;
+};
+
+/*!
+ * Register listeners for important events and bubble appropriately.
+ */
+
+function listen(conn) {
+ if (conn.db._listening) {
+ return;
+ }
+ conn.db._listening = true;
+
+ conn.db.on('close', function(force) {
+ if (conn._closeCalled) return;
+
+ // the driver never emits an `open` event. auto_reconnect still
+ // emits a `close` event but since we never get another
+ // `open` we can't emit close
+ if (conn.db.serverConfig.autoReconnect) {
+ conn.readyState = STATES.disconnected;
+ conn.emit('close');
+ return;
+ }
+ conn.onClose(force);
+ });
+ conn.db.on('error', function(err) {
+ conn.emit('error', err);
+ });
+ conn.db.on('reconnect', function() {
+ conn.readyState = STATES.connected;
+ conn.emit('reconnect');
+ conn.emit('reconnected');
+ conn.onOpen();
+ });
+ conn.db.on('timeout', function(err) {
+ conn.emit('timeout', err);
+ });
+ conn.db.on('open', function(err, db) {
+ if (STATES.disconnected === conn.readyState && db && db.databaseName) {
+ conn.readyState = STATES.connected;
+ conn.emit('reconnect');
+ conn.emit('reconnected');
+ }
+ });
+ conn.db.on('parseError', function(err) {
+ conn.emit('parseError', err);
+ });
+}
+
+/**
+ * Closes the connection
+ *
+ * @param {Boolean} [force]
+ * @param {Function} [fn]
+ * @return {Connection} this
+ * @api private
+ */
+
+NativeConnection.prototype.doClose = function(force, fn) {
+ this.client.close(force, (err, res) => {
+ // Defer because the driver will wait at least 1ms before finishing closing
+ // the pool, see https://github.com/mongodb-js/mongodb-core/blob/a8f8e4ce41936babc3b9112bf42d609779f03b39/lib/connection/pool.js#L1026-L1030.
+ // If there's queued operations, you may still get some background work
+ // after the callback is called.
+ setTimeout(() => fn(err, res), 1);
+ });
+ return this;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = NativeConnection;
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/decimal128.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/decimal128.js
new file mode 100644
index 0000000..c895f17
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/decimal128.js
@@ -0,0 +1,7 @@
+/*!
+ * ignore
+ */
+
+'use strict';
+
+module.exports = require('mongodb').Decimal128;
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/index.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/index.js
new file mode 100644
index 0000000..2cd749e
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/index.js
@@ -0,0 +1,11 @@
+/*!
+ * Module exports.
+ */
+
+'use strict';
+
+exports.Binary = require('./binary');
+exports.Collection = require('./collection');
+exports.Decimal128 = require('./decimal128');
+exports.ObjectId = require('./objectid');
+exports.ReadPreference = require('./ReadPreference');
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js
new file mode 100644
index 0000000..6f432b7
--- /dev/null
+++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js
@@ -0,0 +1,16 @@
+
+/*!
+ * [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
+ * @constructor NodeMongoDbObjectId
+ * @see ObjectId
+ */
+
+'use strict';
+
+const ObjectId = require('mongodb').ObjectId;
+
+/*!
+ * ignore
+ */
+
+module.exports = exports = ObjectId;
diff --git a/node_modules/mongoose/lib/error/browserMissingSchema.js b/node_modules/mongoose/lib/error/browserMissingSchema.js
new file mode 100644
index 0000000..852f873
--- /dev/null
+++ b/node_modules/mongoose/lib/error/browserMissingSchema.js
@@ -0,0 +1,38 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/*!
+ * MissingSchema Error constructor.
+ *
+ * @inherits MongooseError
+ */
+
+function MissingSchemaError() {
+ const msg = 'Schema hasn\'t been registered for document.\n'
+ + 'Use mongoose.Document(name, schema)';
+ MongooseError.call(this, msg);
+ this.name = 'MissingSchemaError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+MissingSchemaError.prototype = Object.create(MongooseError.prototype);
+MissingSchemaError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = MissingSchemaError;
diff --git a/node_modules/mongoose/lib/error/cast.js b/node_modules/mongoose/lib/error/cast.js
new file mode 100644
index 0000000..87f1ce9
--- /dev/null
+++ b/node_modules/mongoose/lib/error/cast.js
@@ -0,0 +1,91 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./mongooseError');
+const get = require('../helpers/get');
+const util = require('util');
+
+/**
+ * Casting Error constructor.
+ *
+ * @param {String} type
+ * @param {String} value
+ * @inherits MongooseError
+ * @api private
+ */
+
+function CastError(type, value, path, reason, schemaType) {
+ let stringValue = util.inspect(value);
+ stringValue = stringValue.replace(/^'/, '"').replace(/'$/, '"');
+ if (!stringValue.startsWith('"')) {
+ stringValue = '"' + stringValue + '"';
+ }
+
+ const messageFormat = get(schemaType, 'options.cast', null);
+ if (typeof messageFormat === 'string') {
+ this.messageFormat = schemaType.options.cast;
+ }
+ this.stringValue = stringValue;
+ this.kind = type;
+ this.value = value;
+ this.path = path;
+ this.reason = reason;
+ MongooseError.call(this, this.formatMessage());
+ this.name = 'CastError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+CastError.prototype = Object.create(MongooseError.prototype);
+CastError.prototype.constructor = MongooseError;
+
+/*!
+ * ignore
+ */
+
+CastError.prototype.setModel = function(model) {
+ this.model = model;
+ this.message = this.formatMessage(model);
+};
+
+/*!
+ * ignore
+ */
+
+CastError.prototype.formatMessage = function(model) {
+ if (this.messageFormat != null) {
+ let ret = this.messageFormat.
+ replace('{KIND}', this.kind).
+ replace('{VALUE}', this.stringValue).
+ replace('{PATH}', this.path);
+ if (model != null) {
+ ret = ret.replace('{MODEL}', model.modelName);
+ }
+
+ return ret;
+ } else {
+ let ret = 'Cast to ' + this.kind + ' failed for value ' +
+ this.stringValue + ' at path "' + this.path + '"';
+ if (model != null) {
+ ret += ' for model "' + model.modelName + '"';
+ }
+
+ return ret;
+ }
+};
+
+/*!
+ * exports
+ */
+
+module.exports = CastError;
diff --git a/node_modules/mongoose/lib/error/disconnected.js b/node_modules/mongoose/lib/error/disconnected.js
new file mode 100644
index 0000000..3e36c1c
--- /dev/null
+++ b/node_modules/mongoose/lib/error/disconnected.js
@@ -0,0 +1,43 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/**
+ * The connection failed to reconnect and will never successfully reconnect to
+ * MongoDB without manual intervention.
+ *
+ * @param {String} type
+ * @param {String} value
+ * @inherits MongooseError
+ * @api private
+ */
+
+function DisconnectedError(connectionString) {
+ MongooseError.call(this, 'Ran out of retries trying to reconnect to "' +
+ connectionString + '". Try setting `server.reconnectTries` and ' +
+ '`server.reconnectInterval` to something higher.');
+ this.name = 'DisconnectedError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+DisconnectedError.prototype = Object.create(MongooseError.prototype);
+DisconnectedError.prototype.constructor = MongooseError;
+
+
+/*!
+ * exports
+ */
+
+module.exports = DisconnectedError;
diff --git a/node_modules/mongoose/lib/error/divergentArray.js b/node_modules/mongoose/lib/error/divergentArray.js
new file mode 100644
index 0000000..872fd2b
--- /dev/null
+++ b/node_modules/mongoose/lib/error/divergentArray.js
@@ -0,0 +1,48 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/*!
+ * DivergentArrayError constructor.
+ *
+ * @inherits MongooseError
+ */
+
+function DivergentArrayError(paths) {
+ const msg = 'For your own good, using `document.save()` to update an array '
+ + 'which was selected using an $elemMatch projection OR '
+ + 'populated using skip, limit, query conditions, or exclusion of '
+ + 'the _id field when the operation results in a $pop or $set of '
+ + 'the entire array is not supported. The following '
+ + 'path(s) would have been modified unsafely:\n'
+ + ' ' + paths.join('\n ') + '\n'
+ + 'Use Model.update() to update these arrays instead.';
+ // TODO write up a docs page (FAQ) and link to it
+
+ MongooseError.call(this, msg);
+ this.name = 'DivergentArrayError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+DivergentArrayError.prototype = Object.create(MongooseError.prototype);
+DivergentArrayError.prototype.constructor = MongooseError;
+
+
+/*!
+ * exports
+ */
+
+module.exports = DivergentArrayError;
diff --git a/node_modules/mongoose/lib/error/index.js b/node_modules/mongoose/lib/error/index.js
new file mode 100644
index 0000000..ec4188d
--- /dev/null
+++ b/node_modules/mongoose/lib/error/index.js
@@ -0,0 +1,205 @@
+'use strict';
+
+/**
+ * MongooseError constructor. MongooseError is the base class for all
+ * Mongoose-specific errors.
+ *
+ * ####Example:
+ * const Model = mongoose.model('Test', new Schema({ answer: Number }));
+ * const doc = new Model({ answer: 'not a number' });
+ * const err = doc.validateSync();
+ *
+ * err instanceof mongoose.Error; // true
+ *
+ * @constructor Error
+ * @param {String} msg Error message
+ * @inherits Error https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error
+ */
+
+const MongooseError = require('./mongooseError');
+
+/**
+ * The name of the error. The name uniquely identifies this Mongoose error. The
+ * possible values are:
+ *
+ * - `MongooseError`: general Mongoose error
+ * - `CastError`: Mongoose could not convert a value to the type defined in the schema path. May be in a `ValidationError` class' `errors` property.
+ * - `DisconnectedError`: This [connection](connections.html) timed out in trying to reconnect to MongoDB and will not successfully reconnect to MongoDB unless you explicitly reconnect.
+ * - `DivergentArrayError`: You attempted to `save()` an array that was modified after you loaded it with a `$elemMatch` or similar projection
+ * - `MissingSchemaError`: You tried to access a model with [`mongoose.model()`](api.html#mongoose_Mongoose-model) that was not defined
+ * - `DocumentNotFoundError`: The document you tried to [`save()`](api.html#document_Document-save) was not found
+ * - `ValidatorError`: error from an individual schema path's validator
+ * - `ValidationError`: error returned from [`validate()`](api.html#document_Document-validate) or [`validateSync()`](api.html#document_Document-validateSync). Contains zero or more `ValidatorError` instances in `.errors` property.
+ * - `MissingSchemaError`: You called `mongoose.Document()` without a schema
+ * - `ObjectExpectedError`: Thrown when you set a nested path to a non-object value with [strict mode set](guide.html#strict).
+ * - `ObjectParameterError`: Thrown when you pass a non-object value to a function which expects an object as a paramter
+ * - `OverwriteModelError`: Thrown when you call [`mongoose.model()`](api.html#mongoose_Mongoose-model) to re-define a model that was already defined.
+ * - `ParallelSaveError`: Thrown when you call [`save()`](api.html#model_Model-save) on a document when the same document instance is already saving.
+ * - `StrictModeError`: Thrown when you set a path that isn't the schema and [strict mode](guide.html#strict) is set to `throw`.
+ * - `VersionError`: Thrown when the [document is out of sync](guide.html#versionKey)
+ *
+ * @api public
+ * @property {String} name
+ * @memberOf Error
+ * @instance
+ */
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = MongooseError;
+
+/**
+ * The default built-in validator error messages.
+ *
+ * @see Error.messages #error_messages_MongooseError-messages
+ * @api public
+ * @memberOf Error
+ * @static messages
+ */
+
+MongooseError.messages = require('./messages');
+
+// backward compat
+MongooseError.Messages = MongooseError.messages;
+
+/**
+ * An instance of this error class will be returned when `save()` fails
+ * because the underlying
+ * document was not found. The constructor takes one parameter, the
+ * conditions that mongoose passed to `update()` when trying to update
+ * the document.
+ *
+ * @api public
+ * @memberOf Error
+ * @static DocumentNotFoundError
+ */
+
+MongooseError.DocumentNotFoundError = require('./notFound');
+
+/**
+ * An instance of this error class will be returned when mongoose failed to
+ * cast a value.
+ *
+ * @api public
+ * @memberOf Error
+ * @static CastError
+ */
+
+MongooseError.CastError = require('./cast');
+
+/**
+ * An instance of this error class will be returned when [validation](/docs/validation.html) failed.
+ * The `errors` property contains an object whose keys are the paths that failed and whose values are
+ * instances of CastError or ValidationError.
+ *
+ * @api public
+ * @memberOf Error
+ * @static ValidationError
+ */
+
+MongooseError.ValidationError = require('./validation');
+
+/**
+ * A `ValidationError` has a hash of `errors` that contain individual
+ * `ValidatorError` instances.
+ *
+ * ####Example:
+ *
+ * const schema = Schema({ name: { type: String, required: true } });
+ * const Model = mongoose.model('Test', schema);
+ * const doc = new Model({});
+ *
+ * // Top-level error is a ValidationError, **not** a ValidatorError
+ * const err = doc.validateSync();
+ * err instanceof mongoose.Error.ValidationError; // true
+ *
+ * // A ValidationError `err` has 0 or more ValidatorErrors keyed by the
+ * // path in the `err.errors` property.
+ * err.errors['name'] instanceof mongoose.Error.ValidatorError;
+ *
+ * err.errors['name'].kind; // 'required'
+ * err.errors['name'].path; // 'name'
+ * err.errors['name'].value; // undefined
+ *
+ * Instances of `ValidatorError` have the following properties:
+ *
+ * - `kind`: The validator's `type`, like `'required'` or `'regexp'`
+ * - `path`: The path that failed validation
+ * - `value`: The value that failed validation
+ *
+ * @api public
+ * @memberOf Error
+ * @static ValidatorError
+ */
+
+MongooseError.ValidatorError = require('./validator');
+
+/**
+ * An instance of this error class will be returned when you call `save()` after
+ * the document in the database was changed in a potentially unsafe way. See
+ * the [`versionKey` option](/docs/guide.html#versionKey) for more information.
+ *
+ * @api public
+ * @memberOf Error
+ * @static VersionError
+ */
+
+MongooseError.VersionError = require('./version');
+
+/**
+ * An instance of this error class will be returned when you call `save()` multiple
+ * times on the same document in parallel. See the [FAQ](/docs/faq.html) for more
+ * information.
+ *
+ * @api public
+ * @memberOf Error
+ * @static ParallelSaveError
+ */
+
+MongooseError.ParallelSaveError = require('./parallelSave');
+
+/**
+ * Thrown when a model with the given name was already registered on the connection.
+ * See [the FAQ about `OverwriteModelError`](/docs/faq.html#overwrite-model-error).
+ *
+ * @api public
+ * @memberOf Error
+ * @static OverwriteModelError
+ */
+
+MongooseError.OverwriteModelError = require('./overwriteModel');
+
+/**
+ * Thrown when you try to access a model that has not been registered yet
+ *
+ * @api public
+ * @memberOf Error
+ * @static MissingSchemaError
+ */
+
+MongooseError.MissingSchemaError = require('./missingSchema');
+
+/**
+ * An instance of this error will be returned if you used an array projection
+ * and then modified the array in an unsafe way.
+ *
+ * @api public
+ * @memberOf Error
+ * @static DivergentArrayError
+ */
+
+MongooseError.DivergentArrayError = require('./divergentArray');
+
+/**
+ * Thrown when your try to pass values to model contrtuctor that
+ * were not specified in schema or change immutable properties when
+ * `strict` mode is `"throw"`
+ *
+ * @api public
+ * @memberOf Error
+ * @static StrictModeError
+ */
+
+MongooseError.StrictModeError = require('./strict');
diff --git a/node_modules/mongoose/lib/error/messages.js b/node_modules/mongoose/lib/error/messages.js
new file mode 100644
index 0000000..78fb6d5
--- /dev/null
+++ b/node_modules/mongoose/lib/error/messages.js
@@ -0,0 +1,47 @@
+
+/**
+ * The default built-in validator error messages. These may be customized.
+ *
+ * // customize within each schema or globally like so
+ * var mongoose = require('mongoose');
+ * mongoose.Error.messages.String.enum = "Your custom message for {PATH}.";
+ *
+ * As you might have noticed, error messages support basic templating
+ *
+ * - `{PATH}` is replaced with the invalid document path
+ * - `{VALUE}` is replaced with the invalid value
+ * - `{TYPE}` is replaced with the validator type such as "regexp", "min", or "user defined"
+ * - `{MIN}` is replaced with the declared min value for the Number.min validator
+ * - `{MAX}` is replaced with the declared max value for the Number.max validator
+ *
+ * Click the "show code" link below to see all defaults.
+ *
+ * @static messages
+ * @receiver MongooseError
+ * @api public
+ */
+
+'use strict';
+
+const msg = module.exports = exports = {};
+
+msg.DocumentNotFoundError = null;
+
+msg.general = {};
+msg.general.default = 'Validator failed for path `{PATH}` with value `{VALUE}`';
+msg.general.required = 'Path `{PATH}` is required.';
+
+msg.Number = {};
+msg.Number.min = 'Path `{PATH}` ({VALUE}) is less than minimum allowed value ({MIN}).';
+msg.Number.max = 'Path `{PATH}` ({VALUE}) is more than maximum allowed value ({MAX}).';
+msg.Number.enum = '`{VALUE}` is not a valid enum value for path `{PATH}`.';
+
+msg.Date = {};
+msg.Date.min = 'Path `{PATH}` ({VALUE}) is before minimum allowed value ({MIN}).';
+msg.Date.max = 'Path `{PATH}` ({VALUE}) is after maximum allowed value ({MAX}).';
+
+msg.String = {};
+msg.String.enum = '`{VALUE}` is not a valid enum value for path `{PATH}`.';
+msg.String.match = 'Path `{PATH}` is invalid ({VALUE}).';
+msg.String.minlength = 'Path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).';
+msg.String.maxlength = 'Path `{PATH}` (`{VALUE}`) is longer than the maximum allowed length ({MAXLENGTH}).';
diff --git a/node_modules/mongoose/lib/error/missingSchema.js b/node_modules/mongoose/lib/error/missingSchema.js
new file mode 100644
index 0000000..3195158
--- /dev/null
+++ b/node_modules/mongoose/lib/error/missingSchema.js
@@ -0,0 +1,39 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/*!
+ * MissingSchema Error constructor.
+ *
+ * @inherits MongooseError
+ */
+
+function MissingSchemaError(name) {
+ const msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ + 'Use mongoose.model(name, schema)';
+ MongooseError.call(this, msg);
+ this.name = 'MissingSchemaError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+MissingSchemaError.prototype = Object.create(MongooseError.prototype);
+MissingSchemaError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = MissingSchemaError;
diff --git a/node_modules/mongoose/lib/error/mongooseError.js b/node_modules/mongoose/lib/error/mongooseError.js
new file mode 100644
index 0000000..2487dfe
--- /dev/null
+++ b/node_modules/mongoose/lib/error/mongooseError.js
@@ -0,0 +1,25 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+function MongooseError(msg) {
+ Error.call(this);
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+ this.message = msg;
+ this.name = 'MongooseError';
+}
+
+/*!
+ * Inherits from Error.
+ */
+
+MongooseError.prototype = Object.create(Error.prototype);
+MongooseError.prototype.constructor = Error;
+
+module.exports = MongooseError;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/error/notFound.js b/node_modules/mongoose/lib/error/notFound.js
new file mode 100644
index 0000000..a12bcb2
--- /dev/null
+++ b/node_modules/mongoose/lib/error/notFound.js
@@ -0,0 +1,55 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./');
+const util = require('util');
+
+/*!
+ * OverwriteModel Error constructor.
+ *
+ * @inherits MongooseError
+ */
+
+function DocumentNotFoundError(filter, model, numAffected, result) {
+ let msg;
+ const messages = MongooseError.messages;
+ if (messages.DocumentNotFoundError != null) {
+ msg = typeof messages.DocumentNotFoundError === 'function' ?
+ messages.DocumentNotFoundError(filter, model) :
+ messages.DocumentNotFoundError;
+ } else {
+ msg = 'No document found for query "' + util.inspect(filter) +
+ '" on model "' + model + '"';
+ }
+
+ MongooseError.call(this, msg);
+
+ this.name = 'DocumentNotFoundError';
+ this.result = result;
+ this.numAffected = numAffected;
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+
+ this.filter = filter;
+ // Backwards compat
+ this.query = filter;
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+DocumentNotFoundError.prototype = Object.create(MongooseError.prototype);
+DocumentNotFoundError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = DocumentNotFoundError;
diff --git a/node_modules/mongoose/lib/error/objectExpected.js b/node_modules/mongoose/lib/error/objectExpected.js
new file mode 100644
index 0000000..9f9fac7
--- /dev/null
+++ b/node_modules/mongoose/lib/error/objectExpected.js
@@ -0,0 +1,38 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/**
+ * Strict mode error constructor
+ *
+ * @param {String} type
+ * @param {String} value
+ * @inherits MongooseError
+ * @api private
+ */
+
+function ObjectExpectedError(path, val) {
+ const typeDescription = Array.isArray(val) ? 'array' : 'primitive value';
+ MongooseError.call(this, 'Tried to set nested object field `' + path +
+ `\` to ${typeDescription} \`` + val + '` and strict mode is set to throw.');
+ this.name = 'ObjectExpectedError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+ this.path = path;
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+ObjectExpectedError.prototype = Object.create(MongooseError.prototype);
+ObjectExpectedError.prototype.constructor = MongooseError;
+
+module.exports = ObjectExpectedError;
diff --git a/node_modules/mongoose/lib/error/objectParameter.js b/node_modules/mongoose/lib/error/objectParameter.js
new file mode 100644
index 0000000..3a7f284
--- /dev/null
+++ b/node_modules/mongoose/lib/error/objectParameter.js
@@ -0,0 +1,38 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/**
+ * Constructor for errors that happen when a parameter that's expected to be
+ * an object isn't an object
+ *
+ * @param {Any} value
+ * @param {String} paramName
+ * @param {String} fnName
+ * @inherits MongooseError
+ * @api private
+ */
+
+function ObjectParameterError(value, paramName, fnName) {
+ MongooseError.call(this, 'Parameter "' + paramName + '" to ' + fnName +
+ '() must be an object, got ' + value.toString());
+ this.name = 'ObjectParameterError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+ObjectParameterError.prototype = Object.create(MongooseError.prototype);
+ObjectParameterError.prototype.constructor = MongooseError;
+
+module.exports = ObjectParameterError;
diff --git a/node_modules/mongoose/lib/error/overwriteModel.js b/node_modules/mongoose/lib/error/overwriteModel.js
new file mode 100644
index 0000000..21013b6
--- /dev/null
+++ b/node_modules/mongoose/lib/error/overwriteModel.js
@@ -0,0 +1,37 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/*!
+ * OverwriteModel Error constructor.
+ *
+ * @inherits MongooseError
+ */
+
+function OverwriteModelError(name) {
+ MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
+ this.name = 'OverwriteModelError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+OverwriteModelError.prototype = Object.create(MongooseError.prototype);
+OverwriteModelError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = OverwriteModelError;
diff --git a/node_modules/mongoose/lib/error/parallelSave.js b/node_modules/mongoose/lib/error/parallelSave.js
new file mode 100644
index 0000000..1b54613
--- /dev/null
+++ b/node_modules/mongoose/lib/error/parallelSave.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./');
+
+/**
+ * ParallelSave Error constructor.
+ *
+ * @inherits MongooseError
+ * @api private
+ */
+
+function ParallelSaveError(doc) {
+ const msg = 'Can\'t save() the same doc multiple times in parallel. Document: ';
+ MongooseError.call(this, msg + doc._id);
+ this.name = 'ParallelSaveError';
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+ParallelSaveError.prototype = Object.create(MongooseError.prototype);
+ParallelSaveError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = ParallelSaveError;
diff --git a/node_modules/mongoose/lib/error/parallelValidate.js b/node_modules/mongoose/lib/error/parallelValidate.js
new file mode 100644
index 0000000..c5cc83b
--- /dev/null
+++ b/node_modules/mongoose/lib/error/parallelValidate.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./mongooseError');
+
+/**
+ * ParallelValidate Error constructor.
+ *
+ * @inherits MongooseError
+ * @api private
+ */
+
+function ParallelValidateError(doc) {
+ const msg = 'Can\'t validate() the same doc multiple times in parallel. Document: ';
+ MongooseError.call(this, msg + doc._id);
+ this.name = 'ParallelValidateError';
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+ParallelValidateError.prototype = Object.create(MongooseError.prototype);
+ParallelValidateError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = ParallelValidateError;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/error/serverSelection.js b/node_modules/mongoose/lib/error/serverSelection.js
new file mode 100644
index 0000000..7e6a128
--- /dev/null
+++ b/node_modules/mongoose/lib/error/serverSelection.js
@@ -0,0 +1,48 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./mongooseError');
+
+/**
+ * MongooseServerSelectionError constructor
+ *
+ * @param {String} type
+ * @param {String} value
+ * @inherits MongooseError
+ * @api private
+ */
+
+function MongooseServerSelectionError(message) {
+ MongooseError.call(this, message);
+ this.name = 'MongooseServerSelectionError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+MongooseServerSelectionError.prototype = Object.create(MongooseError.prototype);
+MongooseServerSelectionError.prototype.constructor = MongooseError;
+
+/*!
+ * ignore
+ */
+
+MongooseServerSelectionError.prototype.assimilateError = function(err) {
+ this.message = err.message;
+ Object.assign(this, err, {
+ name: 'MongooseServerSelectionError'
+ });
+
+ return this;
+};
+
+module.exports = MongooseServerSelectionError;
diff --git a/node_modules/mongoose/lib/error/strict.js b/node_modules/mongoose/lib/error/strict.js
new file mode 100644
index 0000000..7f32268
--- /dev/null
+++ b/node_modules/mongoose/lib/error/strict.js
@@ -0,0 +1,39 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/**
+ * Strict mode error constructor
+ *
+ * @param {String} type
+ * @param {String} value
+ * @inherits MongooseError
+ * @api private
+ */
+
+function StrictModeError(path, msg, immutable) {
+ msg = msg || 'Field `' + path + '` is not in schema and strict ' +
+ 'mode is set to throw.';
+ MongooseError.call(this, msg);
+ this.name = 'StrictModeError';
+ this.isImmutableError = !!immutable;
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+ this.path = path;
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+StrictModeError.prototype = Object.create(MongooseError.prototype);
+StrictModeError.prototype.constructor = MongooseError;
+
+module.exports = StrictModeError;
diff --git a/node_modules/mongoose/lib/error/validation.js b/node_modules/mongoose/lib/error/validation.js
new file mode 100644
index 0000000..6959ed5
--- /dev/null
+++ b/node_modules/mongoose/lib/error/validation.js
@@ -0,0 +1,114 @@
+/*!
+ * Module requirements
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+const util = require('util');
+
+/**
+ * Document Validation Error
+ *
+ * @api private
+ * @param {Document} instance
+ * @inherits MongooseError
+ */
+
+function ValidationError(instance) {
+ this.errors = {};
+ this._message = '';
+
+ if (instance && instance.constructor.name === 'model') {
+ this._message = instance.constructor.modelName + ' validation failed';
+ } else {
+ this._message = 'Validation failed';
+ }
+ MongooseError.call(this, this._message);
+ this.name = 'ValidationError';
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+
+ if (instance) {
+ instance.errors = this.errors;
+ }
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+ValidationError.prototype = Object.create(MongooseError.prototype);
+ValidationError.prototype.constructor = MongooseError;
+
+/**
+ * Console.log helper
+ */
+
+ValidationError.prototype.toString = function() {
+ return this.name + ': ' + _generateMessage(this);
+};
+
+/*!
+ * inspect helper
+ */
+
+ValidationError.prototype.inspect = function() {
+ return Object.assign(new Error(this.message), this);
+};
+
+if (util.inspect.custom) {
+ /*!
+ * Avoid Node deprecation warning DEP0079
+ */
+
+ ValidationError.prototype[util.inspect.custom] = ValidationError.prototype.inspect;
+}
+
+/*!
+ * Helper for JSON.stringify
+ */
+
+ValidationError.prototype.toJSON = function() {
+ return Object.assign({}, this, { message: this.message });
+};
+
+/*!
+ * add message
+ */
+
+ValidationError.prototype.addError = function(path, error) {
+ this.errors[path] = error;
+ this.message = this._message + ': ' + _generateMessage(this);
+};
+
+/*!
+ * ignore
+ */
+
+function _generateMessage(err) {
+ const keys = Object.keys(err.errors || {});
+ const len = keys.length;
+ const msgs = [];
+ let key;
+
+ for (let i = 0; i < len; ++i) {
+ key = keys[i];
+ if (err === err.errors[key]) {
+ continue;
+ }
+ msgs.push(key + ': ' + err.errors[key].message);
+ }
+
+ return msgs.join(', ');
+}
+
+/*!
+ * Module exports
+ */
+
+module.exports = exports = ValidationError;
diff --git a/node_modules/mongoose/lib/error/validator.js b/node_modules/mongoose/lib/error/validator.js
new file mode 100644
index 0000000..d07100c
--- /dev/null
+++ b/node_modules/mongoose/lib/error/validator.js
@@ -0,0 +1,89 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseError = require('./');
+
+/**
+ * Schema validator error
+ *
+ * @param {Object} properties
+ * @inherits MongooseError
+ * @api private
+ */
+
+function ValidatorError(properties) {
+ let msg = properties.message;
+ if (!msg) {
+ msg = MongooseError.messages.general.default;
+ }
+
+ const message = this.formatMessage(msg, properties);
+ MongooseError.call(this, message);
+
+ properties = Object.assign({}, properties, { message: message });
+ this.name = 'ValidatorError';
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this);
+ } else {
+ this.stack = new Error().stack;
+ }
+ this.properties = properties;
+ this.kind = properties.type;
+ this.path = properties.path;
+ this.value = properties.value;
+ this.reason = properties.reason;
+}
+
+/*!
+ * Inherits from MongooseError
+ */
+
+ValidatorError.prototype = Object.create(MongooseError.prototype);
+ValidatorError.prototype.constructor = MongooseError;
+
+/*!
+ * The object used to define this validator. Not enumerable to hide
+ * it from `require('util').inspect()` output re: gh-3925
+ */
+
+Object.defineProperty(ValidatorError.prototype, 'properties', {
+ enumerable: false,
+ writable: true,
+ value: null
+});
+
+/*!
+ * Formats error messages
+ */
+
+ValidatorError.prototype.formatMessage = function(msg, properties) {
+ if (typeof msg === 'function') {
+ return msg(properties);
+ }
+ const propertyNames = Object.keys(properties);
+ for (let i = 0; i < propertyNames.length; ++i) {
+ const propertyName = propertyNames[i];
+ if (propertyName === 'message') {
+ continue;
+ }
+ msg = msg.replace('{' + propertyName.toUpperCase() + '}', properties[propertyName]);
+ }
+ return msg;
+};
+
+/*!
+ * toString helper
+ */
+
+ValidatorError.prototype.toString = function() {
+ return this.message;
+};
+
+/*!
+ * exports
+ */
+
+module.exports = ValidatorError;
diff --git a/node_modules/mongoose/lib/error/version.js b/node_modules/mongoose/lib/error/version.js
new file mode 100644
index 0000000..9fe9201
--- /dev/null
+++ b/node_modules/mongoose/lib/error/version.js
@@ -0,0 +1,36 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./');
+
+/**
+ * Version Error constructor.
+ *
+ * @inherits MongooseError
+ * @api private
+ */
+
+function VersionError(doc, currentVersion, modifiedPaths) {
+ const modifiedPathsStr = modifiedPaths.join(', ');
+ MongooseError.call(this, 'No matching document found for id "' + doc._id +
+ '" version ' + currentVersion + ' modifiedPaths "' + modifiedPathsStr + '"');
+ this.name = 'VersionError';
+ this.version = currentVersion;
+ this.modifiedPaths = modifiedPaths;
+}
+
+/*!
+ * Inherits from MongooseError.
+ */
+
+VersionError.prototype = Object.create(MongooseError.prototype);
+VersionError.prototype.constructor = MongooseError;
+
+/*!
+ * exports
+ */
+
+module.exports = VersionError;
diff --git a/node_modules/mongoose/lib/helpers/arrayDepth.js b/node_modules/mongoose/lib/helpers/arrayDepth.js
new file mode 100644
index 0000000..0ac39ef
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/arrayDepth.js
@@ -0,0 +1,28 @@
+'use strict';
+
+module.exports = arrayDepth;
+
+function arrayDepth(arr) {
+ if (!Array.isArray(arr)) {
+ return { min: 0, max: 0 };
+ }
+ if (arr.length === 0) {
+ return { min: 1, max: 1 };
+ }
+
+ const res = arrayDepth(arr[0]);
+ for (let i = 1; i < arr.length; ++i) {
+ const _res = arrayDepth(arr[i]);
+ if (_res.min < res.min) {
+ res.min = _res.min;
+ }
+ if (_res.max > res.max) {
+ res.max = _res.max;
+ }
+ }
+
+ res.min = res.min + 1;
+ res.max = res.max + 1;
+
+ return res;
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/clone.js b/node_modules/mongoose/lib/helpers/clone.js
new file mode 100644
index 0000000..c0ed136
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/clone.js
@@ -0,0 +1,135 @@
+'use strict';
+
+
+const cloneRegExp = require('regexp-clone');
+const Decimal = require('../types/decimal128');
+const ObjectId = require('../types/objectid');
+const specialProperties = require('./specialProperties');
+const isMongooseObject = require('./isMongooseObject');
+const getFunctionName = require('./getFunctionName');
+const isBsonType = require('./isBsonType');
+const isObject = require('./isObject');
+const symbols = require('./symbols');
+
+
+/*!
+ * Object clone with Mongoose natives support.
+ *
+ * If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible.
+ *
+ * Functions are never cloned.
+ *
+ * @param {Object} obj the object to clone
+ * @param {Object} options
+ * @param {Boolean} isArrayChild true if cloning immediately underneath an array. Special case for minimize.
+ * @return {Object} the cloned object
+ * @api private
+ */
+
+function clone(obj, options, isArrayChild) {
+ if (obj == null) {
+ return obj;
+ }
+
+ if (Array.isArray(obj)) {
+ return cloneArray(obj, options);
+ }
+
+ if (isMongooseObject(obj)) {
+ // Single nested subdocs should apply getters later in `applyGetters()`
+ // when calling `toObject()`. See gh-7442, gh-8295
+ if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
+ options = Object.assign({}, options, { getters: false });
+ }
+ if (options && options.json && typeof obj.toJSON === 'function') {
+ return obj.toJSON(options);
+ }
+ return obj.toObject(options);
+ }
+
+ if (obj.constructor) {
+ switch (getFunctionName(obj.constructor)) {
+ case 'Object':
+ return cloneObject(obj, options, isArrayChild);
+ case 'Date':
+ return new obj.constructor(+obj);
+ case 'RegExp':
+ return cloneRegExp(obj);
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ if (obj instanceof ObjectId) {
+ return new ObjectId(obj.id);
+ }
+
+ if (isBsonType(obj, 'Decimal128')) {
+ if (options && options.flattenDecimals) {
+ return obj.toJSON();
+ }
+ return Decimal.fromString(obj.toString());
+ }
+
+ if (!obj.constructor && isObject(obj)) {
+ // object created with Object.create(null)
+ return cloneObject(obj, options, isArrayChild);
+ }
+
+ if (obj[symbols.schemaTypeSymbol]) {
+ return obj.clone();
+ }
+
+ // If we're cloning this object to go into a MongoDB command,
+ // and there's a `toBSON()` function, assume this object will be
+ // stored as a primitive in MongoDB and doesn't need to be cloned.
+ if (options && options.bson && typeof obj.toBSON === 'function') {
+ return obj;
+ }
+
+ if (obj.valueOf != null) {
+ return obj.valueOf();
+ }
+
+ return cloneObject(obj, options, isArrayChild);
+}
+module.exports = clone;
+
+/*!
+ * ignore
+ */
+
+function cloneObject(obj, options, isArrayChild) {
+ const minimize = options && options.minimize;
+ const ret = {};
+ let hasKeys;
+
+ for (const k in obj) {
+ if (specialProperties.has(k)) {
+ continue;
+ }
+
+ // Don't pass `isArrayChild` down
+ const val = clone(obj[k], options);
+
+ if (!minimize || (typeof val !== 'undefined')) {
+ if (minimize === false && typeof val === 'undefined') {
+ delete ret[k];
+ } else {
+ hasKeys || (hasKeys = true);
+ ret[k] = val;
+ }
+ }
+ }
+
+ return minimize && !isArrayChild ? hasKeys && ret : ret;
+}
+
+function cloneArray(arr, options) {
+ const ret = [];
+ for (let i = 0, l = arr.length; i < l; i++) {
+ ret.push(clone(arr[i], options, true));
+ }
+ return ret;
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/common.js b/node_modules/mongoose/lib/helpers/common.js
new file mode 100644
index 0000000..ed7dc42
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/common.js
@@ -0,0 +1,106 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const Binary = require('../driver').get().Binary;
+const Decimal128 = require('../types/decimal128');
+const ObjectId = require('../types/objectid');
+const isMongooseObject = require('./isMongooseObject');
+
+exports.flatten = flatten;
+exports.modifiedPaths = modifiedPaths;
+
+/*!
+ * ignore
+ */
+
+function flatten(update, path, options, schema) {
+ let keys;
+ if (update && isMongooseObject(update) && !Buffer.isBuffer(update)) {
+ keys = Object.keys(update.toObject({ transform: false, virtuals: false }));
+ } else {
+ keys = Object.keys(update || {});
+ }
+
+ const numKeys = keys.length;
+ const result = {};
+ path = path ? path + '.' : '';
+
+ for (let i = 0; i < numKeys; ++i) {
+ const key = keys[i];
+ const val = update[key];
+ result[path + key] = val;
+
+ // Avoid going into mixed paths if schema is specified
+ const keySchema = schema && schema.path && schema.path(path + key);
+ const isNested = schema && schema.nested && schema.nested[path + key];
+ if (keySchema && keySchema.instance === 'Mixed') continue;
+
+ if (shouldFlatten(val)) {
+ if (options && options.skipArrays && Array.isArray(val)) {
+ continue;
+ }
+ const flat = flatten(val, path + key, options, schema);
+ for (const k in flat) {
+ result[k] = flat[k];
+ }
+ if (Array.isArray(val)) {
+ result[path + key] = val;
+ }
+ }
+
+ if (isNested) {
+ const paths = Object.keys(schema.paths);
+ for (const p of paths) {
+ if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
+ result[p] = void 0;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * ignore
+ */
+
+function modifiedPaths(update, path, result) {
+ const keys = Object.keys(update || {});
+ const numKeys = keys.length;
+ result = result || {};
+ path = path ? path + '.' : '';
+
+ for (let i = 0; i < numKeys; ++i) {
+ const key = keys[i];
+ let val = update[key];
+
+ result[path + key] = true;
+ if (isMongooseObject(val) && !Buffer.isBuffer(val)) {
+ val = val.toObject({ transform: false, virtuals: false });
+ }
+ if (shouldFlatten(val)) {
+ modifiedPaths(val, path + key, result);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * ignore
+ */
+
+function shouldFlatten(val) {
+ return val &&
+ typeof val === 'object' &&
+ !(val instanceof Date) &&
+ !(val instanceof ObjectId) &&
+ (!Array.isArray(val) || val.length > 0) &&
+ !(val instanceof Buffer) &&
+ !(val instanceof Decimal128) &&
+ !(val instanceof Binary);
+}
diff --git a/node_modules/mongoose/lib/helpers/cursor/eachAsync.js b/node_modules/mongoose/lib/helpers/cursor/eachAsync.js
new file mode 100644
index 0000000..cd99280
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/cursor/eachAsync.js
@@ -0,0 +1,120 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const promiseOrCallback = require('../promiseOrCallback');
+
+/**
+ * Execute `fn` for every document in the cursor. If `fn` returns a promise,
+ * will wait for the promise to resolve before iterating on to the next one.
+ * Returns a promise that resolves when done.
+ *
+ * @param {Function} next the thunk to call to get the next document
+ * @param {Function} fn
+ * @param {Object} options
+ * @param {Function} [callback] executed when all docs have been processed
+ * @return {Promise}
+ * @api public
+ * @method eachAsync
+ */
+
+module.exports = function eachAsync(next, fn, options, callback) {
+ const parallel = options.parallel || 1;
+ const enqueue = asyncQueue();
+
+ const handleNextResult = function(doc, callback) {
+ const promise = fn(doc);
+ if (promise && typeof promise.then === 'function') {
+ promise.then(
+ function() { callback(null); },
+ function(error) { callback(error || new Error('`eachAsync()` promise rejected without error')); });
+ } else {
+ callback(null);
+ }
+ };
+
+ const iterate = function(finalCallback) {
+ let drained = false;
+ let handleResultsInProgress = 0;
+
+ let error = null;
+ for (let i = 0; i < parallel; ++i) {
+ enqueue(fetch);
+ }
+
+ function fetch(done) {
+ if (drained || error) {
+ return done();
+ }
+
+ next(function(err, doc) {
+ if (drained || error != null) {
+ return done();
+ }
+ if (err != null) {
+ error = err;
+ finalCallback(err);
+ return done();
+ }
+ if (doc == null) {
+ drained = true;
+ if (handleResultsInProgress <= 0) {
+ finalCallback(null);
+ }
+ return done();
+ }
+
+ ++handleResultsInProgress;
+
+ // Kick off the subsequent `next()` before handling the result, but
+ // make sure we know that we still have a result to handle re: #8422
+ process.nextTick(() => done());
+
+ handleNextResult(doc, function(err) {
+ --handleResultsInProgress;
+ if (err != null) {
+ error = err;
+ return finalCallback(err);
+ }
+ if (drained && handleResultsInProgress <= 0) {
+ return finalCallback(null);
+ }
+
+ setTimeout(() => enqueue(fetch), 0);
+ });
+ });
+ }
+ };
+
+ return promiseOrCallback(callback, cb => {
+ iterate(cb);
+ });
+};
+
+// `next()` can only execute one at a time, so make sure we always execute
+// `next()` in series, while still allowing multiple `fn()` instances to run
+// in parallel.
+function asyncQueue() {
+ const _queue = [];
+ let inProgress = null;
+ let id = 0;
+
+ return function enqueue(fn) {
+ if (_queue.length === 0 && inProgress == null) {
+ inProgress = id++;
+ return fn(_step);
+ }
+ _queue.push(fn);
+ };
+
+ function _step() {
+ inProgress = null;
+ if (_queue.length > 0) {
+ inProgress = id++;
+ const fn = _queue.shift();
+ fn(_step);
+ }
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js b/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js
new file mode 100644
index 0000000..755de88
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function checkEmbeddedDiscriminatorKeyProjection(userProjection, path, schema, selected, addedPaths) {
+ const userProjectedInPath = Object.keys(userProjection).
+ reduce((cur, key) => cur || key.startsWith(path + '.'), false);
+ const _discriminatorKey = path + '.' + schema.options.discriminatorKey;
+ if (!userProjectedInPath &&
+ addedPaths.length === 1 &&
+ addedPaths[0] === _discriminatorKey) {
+ selected.splice(selected.indexOf(_discriminatorKey), 1);
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js b/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js
new file mode 100644
index 0000000..04a3ded
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const getDiscriminatorByValue = require('./getDiscriminatorByValue');
+
+/*!
+ * Find the correct constructor, taking into account discriminators
+ */
+
+module.exports = function getConstructor(Constructor, value) {
+ const discriminatorKey = Constructor.schema.options.discriminatorKey;
+ if (value != null &&
+ Constructor.discriminators &&
+ value[discriminatorKey] != null) {
+ if (Constructor.discriminators[value[discriminatorKey]]) {
+ Constructor = Constructor.discriminators[value[discriminatorKey]];
+ } else {
+ const constructorByValue = getDiscriminatorByValue(Constructor, value[discriminatorKey]);
+ if (constructorByValue) {
+ Constructor = constructorByValue;
+ }
+ }
+ }
+
+ return Constructor;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js b/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js
new file mode 100644
index 0000000..87b3ad9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js
@@ -0,0 +1,27 @@
+'use strict';
+
+/*!
+* returns discriminator by discriminatorMapping.value
+*
+* @param {Model} model
+* @param {string} value
+*/
+
+module.exports = function getDiscriminatorByValue(model, value) {
+ let discriminator = null;
+ if (!model.discriminators) {
+ return discriminator;
+ }
+ for (const name in model.discriminators) {
+ const it = model.discriminators[name];
+ if (
+ it.schema &&
+ it.schema.discriminatorMapping &&
+ it.schema.discriminatorMapping.value == value
+ ) {
+ discriminator = it;
+ break;
+ }
+ }
+ return discriminator;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js b/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js
new file mode 100644
index 0000000..252d348
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js
@@ -0,0 +1,28 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function cleanModifiedSubpaths(doc, path, options) {
+ options = options || {};
+ const skipDocArrays = options.skipDocArrays;
+
+ let deleted = 0;
+ if (!doc) {
+ return deleted;
+ }
+ for (const modifiedPath of Object.keys(doc.$__.activePaths.states.modify)) {
+ if (skipDocArrays) {
+ const schemaType = doc.schema.path(modifiedPath);
+ if (schemaType && schemaType.$isMongooseDocumentArray) {
+ continue;
+ }
+ }
+ if (modifiedPath.startsWith(path + '.')) {
+ delete doc.$__.activePaths.states.modify[modifiedPath];
+ ++deleted;
+ }
+ }
+ return deleted;
+};
diff --git a/node_modules/mongoose/lib/helpers/document/compile.js b/node_modules/mongoose/lib/helpers/document/compile.js
new file mode 100644
index 0000000..ecc4f6f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/compile.js
@@ -0,0 +1,170 @@
+'use strict';
+
+const documentSchemaSymbol = require('../../helpers/symbols').documentSchemaSymbol;
+const get = require('../../helpers/get');
+const getSymbol = require('../../helpers/symbols').getSymbol;
+const utils = require('../../utils');
+
+let Document;
+
+/*!
+ * exports
+ */
+
+exports.compile = compile;
+exports.defineKey = defineKey;
+
+/*!
+ * Compiles schemas.
+ */
+
+function compile(tree, proto, prefix, options) {
+ Document = Document || require('../../document');
+ const keys = Object.keys(tree);
+ const len = keys.length;
+ let limb;
+ let key;
+
+ for (let i = 0; i < len; ++i) {
+ key = keys[i];
+ limb = tree[key];
+
+ const hasSubprops = utils.isPOJO(limb) && Object.keys(limb).length &&
+ (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type));
+ const subprops = hasSubprops ? limb : null;
+
+ defineKey(key, subprops, proto, prefix, keys, options);
+ }
+}
+
+/*!
+ * Defines the accessor named prop on the incoming prototype.
+ */
+
+function defineKey(prop, subprops, prototype, prefix, keys, options) {
+ Document = Document || require('../../document');
+ const path = (prefix ? prefix + '.' : '') + prop;
+ prefix = prefix || '';
+
+ if (subprops) {
+ Object.defineProperty(prototype, prop, {
+ enumerable: true,
+ configurable: true,
+ get: function() {
+ const _this = this;
+ if (!this.$__.getters) {
+ this.$__.getters = {};
+ }
+
+ if (!this.$__.getters[path]) {
+ const nested = Object.create(Document.prototype, getOwnPropertyDescriptors(this));
+
+ // save scope for nested getters/setters
+ if (!prefix) {
+ nested.$__.scope = this;
+ }
+ nested.$__.nestedPath = path;
+
+ Object.defineProperty(nested, 'schema', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: prototype.schema
+ });
+
+ Object.defineProperty(nested, documentSchemaSymbol, {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: prototype.schema
+ });
+
+ Object.defineProperty(nested, 'toObject', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return utils.clone(_this.get(path, null, {
+ virtuals: get(this, 'schema.options.toObject.virtuals', null)
+ }));
+ }
+ });
+
+ Object.defineProperty(nested, 'toJSON', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return _this.get(path, null, {
+ virtuals: get(_this, 'schema.options.toJSON.virtuals', null)
+ });
+ }
+ });
+
+ Object.defineProperty(nested, '$__isNested', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: true
+ });
+
+ const _isEmptyOptions = Object.freeze({
+ minimize: true,
+ virtuals: false,
+ getters: false,
+ transform: false
+ });
+ Object.defineProperty(nested, '$isEmpty', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return Object.keys(this.get(path, null, _isEmptyOptions) || {}).length === 0;
+ }
+ });
+
+ compile(subprops, nested, path, options);
+ this.$__.getters[path] = nested;
+ }
+
+ return this.$__.getters[path];
+ },
+ set: function(v) {
+ if (v instanceof Document) {
+ v = v.toObject({ transform: false });
+ }
+ const doc = this.$__.scope || this;
+ return doc.$set(path, v);
+ }
+ });
+ } else {
+ Object.defineProperty(prototype, prop, {
+ enumerable: true,
+ configurable: true,
+ get: function() {
+ return this[getSymbol].call(this.$__.scope || this, path);
+ },
+ set: function(v) {
+ return this.$set.call(this.$__.scope || this, path, v);
+ }
+ });
+ }
+}
+
+// gets descriptors for all properties of `object`
+// makes all properties non-enumerable to match previous behavior to #2211
+function getOwnPropertyDescriptors(object) {
+ const result = {};
+
+ Object.getOwnPropertyNames(object).forEach(function(key) {
+ result[key] = Object.getOwnPropertyDescriptor(object, key);
+ // Assume these are schema paths, ignore them re: #5470
+ if (result[key].get) {
+ delete result[key];
+ return;
+ }
+ result[key].enumerable = ['isNew', '$__', 'errors', '_doc', '$locals', '$op'].indexOf(key) === -1;
+ });
+
+ return result;
+}
diff --git a/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js b/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js
new file mode 100644
index 0000000..a2784e3
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const get = require('../get');
+
+/*!
+ * Like `schema.path()`, except with a document, because impossible to
+ * determine path type without knowing the embedded discriminator key.
+ */
+
+module.exports = function getEmbeddedDiscriminatorPath(doc, path, options) {
+ options = options || {};
+ const typeOnly = options.typeOnly;
+ const parts = path.split('.');
+ let schema = null;
+ let type = 'adhocOrUndefined';
+
+ for (let i = 0; i < parts.length; ++i) {
+ const subpath = parts.slice(0, i + 1).join('.');
+ schema = doc.schema.path(subpath);
+ if (schema == null) {
+ type = 'adhocOrUndefined';
+ continue;
+ }
+ if (schema.instance === 'Mixed') {
+ return typeOnly ? 'real' : schema;
+ }
+ type = doc.schema.pathType(subpath);
+ if ((schema.$isSingleNested || schema.$isMongooseDocumentArrayElement) &&
+ schema.schema.discriminators != null) {
+ const discriminators = schema.schema.discriminators;
+ const discriminatorKey = doc.get(subpath + '.' +
+ get(schema, 'schema.options.discriminatorKey'));
+ if (discriminatorKey == null || discriminators[discriminatorKey] == null) {
+ continue;
+ }
+ const rest = parts.slice(i + 1).join('.');
+ return getEmbeddedDiscriminatorPath(doc.get(subpath), rest, options);
+ }
+ }
+
+ // Are we getting the whole schema or just the type, 'real', 'nested', etc.
+ return typeOnly ? type : schema;
+};
diff --git a/node_modules/mongoose/lib/helpers/each.js b/node_modules/mongoose/lib/helpers/each.js
new file mode 100644
index 0000000..fe70069
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/each.js
@@ -0,0 +1,25 @@
+'use strict';
+
+module.exports = function each(arr, cb, done) {
+ if (arr.length === 0) {
+ return done();
+ }
+
+ let remaining = arr.length;
+ let err = null;
+ for (const v of arr) {
+ cb(v, function(_err) {
+ if (err != null) {
+ return;
+ }
+ if (_err != null) {
+ err = _err;
+ return done(err);
+ }
+
+ if (--remaining <= 0) {
+ return done();
+ }
+ });
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/get.js b/node_modules/mongoose/lib/helpers/get.js
new file mode 100644
index 0000000..dcb3881
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/get.js
@@ -0,0 +1,39 @@
+'use strict';
+
+/*!
+ * Simplified lodash.get to work around the annoying null quirk. See:
+ * https://github.com/lodash/lodash/issues/3659
+ */
+
+module.exports = function get(obj, path, def) {
+ const parts = path.split('.');
+ let rest = path;
+ let cur = obj;
+ for (const part of parts) {
+ if (cur == null) {
+ return def;
+ }
+
+ // `lib/cast.js` depends on being able to get dotted paths in updates,
+ // like `{ $set: { 'a.b': 42 } }`
+ if (cur[rest] != null) {
+ return cur[rest];
+ }
+
+ cur = getProperty(cur, part);
+
+ rest = rest.substr(part.length + 1);
+ }
+
+ return cur == null ? def : cur;
+};
+
+function getProperty(obj, prop) {
+ if (obj == null) {
+ return obj;
+ }
+ if (obj instanceof Map) {
+ return obj.get(prop);
+ }
+ return obj[prop];
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/getFunctionName.js b/node_modules/mongoose/lib/helpers/getFunctionName.js
new file mode 100644
index 0000000..87a2c69
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/getFunctionName.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function(fn) {
+ if (fn.name) {
+ return fn.name;
+ }
+ return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
+};
diff --git a/node_modules/mongoose/lib/helpers/immediate.js b/node_modules/mongoose/lib/helpers/immediate.js
new file mode 100644
index 0000000..ddb7060
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/immediate.js
@@ -0,0 +1,12 @@
+/*!
+ * Centralize this so we can more easily work around issues with people
+ * stubbing out `process.nextTick()` in tests using sinon:
+ * https://github.com/sinonjs/lolex#automatically-incrementing-mocked-time
+ * See gh-6074
+ */
+
+'use strict';
+
+module.exports = function immediate(cb) {
+ return process.nextTick(cb);
+};
diff --git a/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js b/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js
new file mode 100644
index 0000000..c975dcf
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const get = require('../get');
+
+module.exports = function isDefaultIdIndex(index) {
+ if (Array.isArray(index)) {
+ // Mongoose syntax
+ const keys = Object.keys(index[0]);
+ return keys.length === 1 && keys[0] === '_id' && index[0]._id !== 'hashed';
+ }
+
+ if (typeof index !== 'object') {
+ return false;
+ }
+
+ const key = get(index, 'key', {});
+ return Object.keys(key).length === 1 && key.hasOwnProperty('_id');
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/isBsonType.js b/node_modules/mongoose/lib/helpers/isBsonType.js
new file mode 100644
index 0000000..01435d3
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isBsonType.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const get = require('./get');
+
+/*!
+ * Get the bson type, if it exists
+ */
+
+function isBsonType(obj, typename) {
+ return get(obj, '_bsontype', void 0) === typename;
+}
+
+module.exports = isBsonType;
diff --git a/node_modules/mongoose/lib/helpers/isMongooseObject.js b/node_modules/mongoose/lib/helpers/isMongooseObject.js
new file mode 100644
index 0000000..016f9e6
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isMongooseObject.js
@@ -0,0 +1,21 @@
+'use strict';
+
+/*!
+ * Returns if `v` is a mongoose object that has a `toObject()` method we can use.
+ *
+ * This is for compatibility with libs like Date.js which do foolish things to Natives.
+ *
+ * @param {any} v
+ * @api private
+ */
+
+module.exports = function(v) {
+ if (v == null) {
+ return false;
+ }
+
+ return v.$__ != null || // Document
+ v.isMongooseArray || // Array or Document Array
+ v.isMongooseBuffer || // Buffer
+ v.$isMongooseMap; // Map
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/isObject.js b/node_modules/mongoose/lib/helpers/isObject.js
new file mode 100644
index 0000000..f8ac313
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isObject.js
@@ -0,0 +1,16 @@
+'use strict';
+
+/*!
+ * Determines if `arg` is an object.
+ *
+ * @param {Object|Array|String|Function|RegExp|any} arg
+ * @api private
+ * @return {Boolean}
+ */
+
+module.exports = function(arg) {
+ if (Buffer.isBuffer(arg)) {
+ return true;
+ }
+ return Object.prototype.toString.call(arg) === '[object Object]';
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyHooks.js b/node_modules/mongoose/lib/helpers/model/applyHooks.js
new file mode 100644
index 0000000..3dbca03
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyHooks.js
@@ -0,0 +1,135 @@
+'use strict';
+
+const symbols = require('../../schema/symbols');
+const promiseOrCallback = require('../promiseOrCallback');
+
+/*!
+ * ignore
+ */
+
+module.exports = applyHooks;
+
+/*!
+ * ignore
+ */
+
+applyHooks.middlewareFunctions = [
+ 'deleteOne',
+ 'save',
+ 'validate',
+ 'remove',
+ 'updateOne',
+ 'init'
+];
+
+/*!
+ * Register hooks for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+function applyHooks(model, schema, options) {
+ options = options || {};
+
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1,
+ nullResultByDefault: true,
+ contextParameter: true
+ };
+ const objToDecorate = options.decorateDoc ? model : model.prototype;
+
+ model.$appliedHooks = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ let childModel = null;
+ if (type.$isSingleNested) {
+ childModel = type.caster;
+ } else if (type.$isMongooseDocumentArray) {
+ childModel = type.Constructor;
+ } else {
+ continue;
+ }
+
+ if (childModel.$appliedHooks) {
+ continue;
+ }
+
+ applyHooks(childModel, type.schema, options);
+ if (childModel.discriminators != null) {
+ const keys = Object.keys(childModel.discriminators);
+ for (let j = 0; j < keys.length; ++j) {
+ applyHooks(childModel.discriminators[keys[j]],
+ childModel.discriminators[keys[j]].schema, options);
+ }
+ }
+ }
+
+ // Built-in hooks rely on hooking internal functions in order to support
+ // promises and make it so that `doc.save.toString()` provides meaningful
+ // information.
+
+ const middleware = schema.s.hooks.
+ filter(hook => {
+ if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
+ return !!hook['document'];
+ }
+ if (hook.name === 'remove') {
+ return hook['document'] == null || !!hook['document'];
+ }
+ return true;
+ }).
+ filter(hook => {
+ // If user has overwritten the method, don't apply built-in middleware
+ if (schema.methods[hook.name]) {
+ return !hook.fn[symbols.builtInMiddleware];
+ }
+
+ return true;
+ });
+
+ model._middleware = middleware;
+
+ objToDecorate.$__originalValidate = objToDecorate.$__originalValidate || objToDecorate.$__validate;
+
+ for (const method of ['save', 'validate', 'remove', 'deleteOne']) {
+ const toWrap = method === 'validate' ? '$__originalValidate' : `$__${method}`;
+ const wrapped = middleware.
+ createWrapper(method, objToDecorate[toWrap], null, kareemOptions);
+ objToDecorate[`$__${method}`] = wrapped;
+ }
+ objToDecorate.$__init = middleware.
+ createWrapperSync('init', objToDecorate.$__init, null, kareemOptions);
+
+ // Support hooks for custom methods
+ const customMethods = Object.keys(schema.methods);
+ const customMethodOptions = Object.assign({}, kareemOptions, {
+ // Only use `checkForPromise` for custom methods, because mongoose
+ // query thunks are not as consistent as I would like about returning
+ // a nullish value rather than the query. If a query thunk returns
+ // a query, `checkForPromise` causes infinite recursion
+ checkForPromise: true
+ });
+ for (const method of customMethods) {
+ if (!middleware.hasHooks(method)) {
+ // Don't wrap if there are no hooks for the custom method to avoid
+ // surprises. Also, `createWrapper()` enforces consistent async,
+ // so wrapping a sync method would break it.
+ continue;
+ }
+ const originalMethod = objToDecorate[method];
+ objToDecorate[method] = function() {
+ const args = Array.prototype.slice.call(arguments);
+ const cb = args.slice(-1).pop();
+ const argsWithoutCallback = typeof cb === 'function' ?
+ args.slice(0, args.length - 1) : args;
+ return promiseOrCallback(cb, callback => {
+ return this[`$__${method}`].apply(this,
+ argsWithoutCallback.concat([callback]));
+ }, model.events);
+ };
+ objToDecorate[`$__${method}`] = middleware.
+ createWrapper(method, originalMethod, null, customMethodOptions);
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyMethods.js b/node_modules/mongoose/lib/helpers/model/applyMethods.js
new file mode 100644
index 0000000..912f3aa
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyMethods.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const get = require('../get');
+
+/*!
+ * Register methods for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+module.exports = function applyMethods(model, schema) {
+ function apply(method, schema) {
+ Object.defineProperty(model.prototype, method, {
+ get: function() {
+ const h = {};
+ for (const k in schema.methods[method]) {
+ h[k] = schema.methods[method][k].bind(this);
+ }
+ return h;
+ },
+ configurable: true
+ });
+ }
+ for (const method of Object.keys(schema.methods)) {
+ const fn = schema.methods[method];
+ if (schema.tree.hasOwnProperty(method)) {
+ throw new Error('You have a method and a property in your schema both ' +
+ 'named "' + method + '"');
+ }
+ if (schema.reserved[method] &&
+ !get(schema, `methodOptions.${method}.suppressWarning`, false)) {
+ console.warn(`mongoose: the method name "${method}" is used by mongoose ` +
+ 'internally, overwriting it may cause bugs. If you\'re sure you know ' +
+ 'what you\'re doing, you can suppress this error by using ' +
+ `\`schema.method('${method}', fn, { suppressWarning: true })\`.`);
+ }
+ if (typeof fn === 'function') {
+ model.prototype[method] = fn;
+ } else {
+ apply(method, schema);
+ }
+ }
+
+ // Recursively call `applyMethods()` on child schemas
+ model.$appliedMethods = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ if (type.$isSingleNested && !type.caster.$appliedMethods) {
+ applyMethods(type.caster, type.schema);
+ }
+ if (type.$isMongooseDocumentArray && !type.Constructor.$appliedMethods) {
+ applyMethods(type.Constructor, type.schema);
+ }
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
new file mode 100644
index 0000000..219e289
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const middlewareFunctions = require('../query/applyQueryMiddleware').middlewareFunctions;
+const promiseOrCallback = require('../promiseOrCallback');
+
+module.exports = function applyStaticHooks(model, hooks, statics) {
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1
+ };
+
+ hooks = hooks.filter(hook => {
+ // If the custom static overwrites an existing query middleware, don't apply
+ // middleware to it by default. This avoids a potential backwards breaking
+ // change with plugins like `mongoose-delete` that use statics to overwrite
+ // built-in Mongoose functions.
+ if (middlewareFunctions.indexOf(hook.name) !== -1) {
+ return !!hook.model;
+ }
+ return hook.model !== false;
+ });
+
+ model.$__insertMany = hooks.createWrapper('insertMany',
+ model.$__insertMany, model, kareemOptions);
+
+ for (const key of Object.keys(statics)) {
+ if (hooks.hasHooks(key)) {
+ const original = model[key];
+
+ model[key] = function() {
+ const numArgs = arguments.length;
+ const lastArg = numArgs > 0 ? arguments[numArgs - 1] : null;
+ const cb = typeof lastArg === 'function' ? lastArg : null;
+ const args = Array.prototype.slice.
+ call(arguments, 0, cb == null ? numArgs : numArgs - 1);
+ // Special case: can't use `Kareem#wrap()` because it doesn't currently
+ // support wrapped functions that return a promise.
+ return promiseOrCallback(cb, callback => {
+ hooks.execPre(key, model, args, function(err) {
+ if (err != null) {
+ return callback(err);
+ }
+
+ let postCalled = 0;
+ const ret = original.apply(model, args.concat(post));
+ if (ret != null && typeof ret.then === 'function') {
+ ret.then(res => post(null, res), err => post(err));
+ }
+
+ function post(error, res) {
+ if (postCalled++ > 0) {
+ return;
+ }
+
+ if (error != null) {
+ return callback(error);
+ }
+
+ hooks.execPost(key, model, [res], function(error) {
+ if (error != null) {
+ return callback(error);
+ }
+ callback(null, res);
+ });
+ }
+ });
+ }, model.events);
+ };
+ }
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyStatics.js b/node_modules/mongoose/lib/helpers/model/applyStatics.js
new file mode 100644
index 0000000..3b9501e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStatics.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/*!
+ * Register statics for this model
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+module.exports = function applyStatics(model, schema) {
+ for (const i in schema.statics) {
+ model[i] = schema.statics[i];
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/castBulkWrite.js b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
new file mode 100644
index 0000000..1d8e51b
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
@@ -0,0 +1,160 @@
+'use strict';
+
+const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
+const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
+const cast = require('../../cast');
+const castUpdate = require('../query/castUpdate');
+const setDefaultsOnInsert = require('../setDefaultsOnInsert');
+
+/*!
+ * Given a model and a bulkWrite op, return a thunk that handles casting and
+ * validating the individual op.
+ */
+
+module.exports = function castBulkWrite(model, op, options) {
+ const now = model.base.now();
+ const schema = model.schema;
+
+ if (op['insertOne']) {
+ return (callback) => {
+ const doc = new model(op['insertOne']['document']);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['insertOne']['document'] = doc;
+ op['insertOne']['document'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ callback(null);
+ });
+ };
+ } else if (op['updateOne']) {
+ return (callback) => {
+ try {
+ if (!op['updateOne']['filter']) throw new Error('Must provide a filter object.');
+ if (!op['updateOne']['update']) throw new Error('Must provide an update object.');
+
+ _addDiscriminatorToObject(schema, op['updateOne']['filter']);
+ op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter']);
+ op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
+ strict: model.schema.options.strict,
+ overwrite: false
+ });
+ if (op['updateOne'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateOne'].upsert
+ });
+ }
+ if (model.schema.$timestamps != null) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
+ }
+ applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['updateMany']) {
+ return (callback) => {
+ try {
+ if (!op['updateMany']['filter']) throw new Error('Must provide a filter object.');
+ if (!op['updateMany']['update']) throw new Error('Must provide an update object.');
+
+ _addDiscriminatorToObject(schema, op['updateMany']['filter']);
+ op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter']);
+ op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
+ strict: model.schema.options.strict,
+ overwrite: false
+ });
+ if (op['updateMany'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateMany'].upsert
+ });
+ }
+ if (model.schema.$timestamps != null) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
+ }
+ applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['replaceOne']) {
+ return (callback) => {
+ _addDiscriminatorToObject(schema, op['replaceOne']['filter']);
+ try {
+ op['replaceOne']['filter'] = cast(model.schema,
+ op['replaceOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ // set `skipId`, otherwise we get "_id field cannot be changed"
+ const doc = new model(op['replaceOne']['replacement'], null, true);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['replaceOne']['replacement'] = doc;
+
+ op['replaceOne']['replacement'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ callback(null);
+ });
+ };
+ } else if (op['deleteOne']) {
+ return (callback) => {
+ _addDiscriminatorToObject(schema, op['deleteOne']['filter']);
+ try {
+ op['deleteOne']['filter'] = cast(model.schema,
+ op['deleteOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['deleteMany']) {
+ return (callback) => {
+ _addDiscriminatorToObject(schema, op['deleteMany']['filter']);
+ try {
+ op['deleteMany']['filter'] = cast(model.schema,
+ op['deleteMany']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else {
+ return (callback) => {
+ callback(new Error('Invalid op passed to `bulkWrite()`'), null);
+ };
+ }
+};
+
+function _addDiscriminatorToObject(schema, obj) {
+ if (schema == null) {
+ return;
+ }
+ if (schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
+ obj[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/discriminator.js b/node_modules/mongoose/lib/helpers/model/discriminator.js
new file mode 100644
index 0000000..51c7cc0
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/discriminator.js
@@ -0,0 +1,184 @@
+'use strict';
+
+const defineKey = require('../document/compile').defineKey;
+const get = require('../get');
+const utils = require('../../utils');
+
+const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
+ toJSON: true,
+ toObject: true,
+ _id: true,
+ id: true
+};
+
+/*!
+ * ignore
+ */
+
+module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
+ if (!(schema && schema.instanceOfSchema)) {
+ throw new Error('You must pass a valid discriminator Schema');
+ }
+
+ if (model.schema.discriminatorMapping &&
+ !model.schema.discriminatorMapping.isRoot) {
+ throw new Error('Discriminator "' + name +
+ '" can only be a discriminator of the root model');
+ }
+
+ if (applyPlugins) {
+ const applyPluginsToDiscriminators = get(model.base,
+ 'options.applyPluginsToDiscriminators', false);
+ // Even if `applyPluginsToDiscriminators` isn't set, we should still apply
+ // global plugins to schemas embedded in the discriminator schema (gh-7370)
+ model.base._applyPlugins(schema, {
+ skipTopLevel: !applyPluginsToDiscriminators
+ });
+ }
+
+ const key = model.schema.options.discriminatorKey;
+
+ const existingPath = model.schema.path(key);
+ if (existingPath != null) {
+ if (!utils.hasUserDefinedProperty(existingPath.options, 'select')) {
+ existingPath.options.select = true;
+ }
+ existingPath.options.$skipDiscriminatorCheck = true;
+ } else {
+ const baseSchemaAddition = {};
+ baseSchemaAddition[key] = {
+ default: void 0,
+ select: true,
+ $skipDiscriminatorCheck: true
+ };
+ baseSchemaAddition[key][model.schema.options.typeKey] = String;
+ model.schema.add(baseSchemaAddition);
+ defineKey(key, null, model.prototype, null, [key], model.schema.options);
+ }
+
+ if (schema.path(key) && schema.path(key).options.$skipDiscriminatorCheck !== true) {
+ throw new Error('Discriminator "' + name +
+ '" cannot have field with name "' + key + '"');
+ }
+
+ let value = name;
+ if (typeof tiedValue == 'string' && tiedValue.length) {
+ value = tiedValue;
+ }
+
+ function merge(schema, baseSchema) {
+ // Retain original schema before merging base schema
+ schema._baseSchema = baseSchema;
+ if (baseSchema.paths._id &&
+ baseSchema.paths._id.options &&
+ !baseSchema.paths._id.options.auto) {
+ schema.remove('_id');
+ }
+
+ // Find conflicting paths: if something is a path in the base schema
+ // and a nested path in the child schema, overwrite the base schema path.
+ // See gh-6076
+ const baseSchemaPaths = Object.keys(baseSchema.paths);
+ const conflictingPaths = [];
+ for (let i = 0; i < baseSchemaPaths.length; ++i) {
+ if (schema.nested[baseSchemaPaths[i]]) {
+ conflictingPaths.push(baseSchemaPaths[i]);
+ }
+ }
+
+ utils.merge(schema, baseSchema, {
+ omit: { discriminators: true, base: true },
+ omitNested: conflictingPaths.reduce((cur, path) => {
+ cur['tree.' + path] = true;
+ return cur;
+ }, {})
+ });
+
+ // Clean up conflicting paths _after_ merging re: gh-6076
+ for (let i = 0; i < conflictingPaths.length; ++i) {
+ delete schema.paths[conflictingPaths[i]];
+ }
+
+ // Rebuild schema models because schemas may have been merged re: #7884
+ schema.childSchemas.forEach(obj => {
+ obj.model.prototype.$__setSchema(obj.schema);
+ });
+
+ const obj = {};
+ obj[key] = {
+ default: value,
+ select: true,
+ set: function(newName) {
+ if (newName === value) {
+ return value;
+ }
+ throw new Error('Can\'t set discriminator key "' + key + '"');
+ },
+ $skipDiscriminatorCheck: true
+ };
+ obj[key][schema.options.typeKey] = existingPath ?
+ existingPath.instance :
+ String;
+ schema.add(obj);
+ schema.discriminatorMapping = { key: key, value: value, isRoot: false };
+
+ if (baseSchema.options.collection) {
+ schema.options.collection = baseSchema.options.collection;
+ }
+
+ const toJSON = schema.options.toJSON;
+ const toObject = schema.options.toObject;
+ const _id = schema.options._id;
+ const id = schema.options.id;
+
+ const keys = Object.keys(schema.options);
+ schema.options.discriminatorKey = baseSchema.options.discriminatorKey;
+
+ for (let i = 0; i < keys.length; ++i) {
+ const _key = keys[i];
+ if (!CUSTOMIZABLE_DISCRIMINATOR_OPTIONS[_key]) {
+ if (!utils.deepEqual(schema.options[_key], baseSchema.options[_key])) {
+ throw new Error('Can\'t customize discriminator option ' + _key +
+ ' (can only modify ' +
+ Object.keys(CUSTOMIZABLE_DISCRIMINATOR_OPTIONS).join(', ') +
+ ')');
+ }
+ }
+ }
+
+ schema.options = utils.clone(baseSchema.options);
+ if (toJSON) schema.options.toJSON = toJSON;
+ if (toObject) schema.options.toObject = toObject;
+ if (typeof _id !== 'undefined') {
+ schema.options._id = _id;
+ }
+ schema.options.id = id;
+ schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks);
+
+ schema.plugins = Array.prototype.slice.call(baseSchema.plugins);
+ schema.callQueue = baseSchema.callQueue.concat(schema.callQueue);
+ delete schema._requiredpaths; // reset just in case Schema#requiredPaths() was called on either schema
+ }
+
+ // merges base schema into new discriminator schema and sets new type field.
+ merge(schema, model.schema);
+
+ if (!model.discriminators) {
+ model.discriminators = {};
+ }
+
+ if (!model.schema.discriminatorMapping) {
+ model.schema.discriminatorMapping = { key: key, value: null, isRoot: true };
+ }
+ if (!model.schema.discriminators) {
+ model.schema.discriminators = {};
+ }
+
+ model.schema.discriminators[name] = schema;
+
+ if (model.discriminators[name]) {
+ throw new Error('Discriminator with name "' + name + '" already exists');
+ }
+
+ return schema;
+};
diff --git a/node_modules/mongoose/lib/helpers/once.js b/node_modules/mongoose/lib/helpers/once.js
new file mode 100644
index 0000000..0267579
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/once.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function once(fn) {
+ let called = false;
+ return function() {
+ if (called) {
+ return;
+ }
+ called = true;
+ return fn.apply(null, arguments);
+ };
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/parallelLimit.js b/node_modules/mongoose/lib/helpers/parallelLimit.js
new file mode 100644
index 0000000..9b07c02
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/parallelLimit.js
@@ -0,0 +1,55 @@
+'use strict';
+
+module.exports = parallelLimit;
+
+/*!
+ * ignore
+ */
+
+function parallelLimit(fns, limit, callback) {
+ let numInProgress = 0;
+ let numFinished = 0;
+ let error = null;
+
+ if (limit <= 0) {
+ throw new Error('Limit must be positive');
+ }
+
+ if (fns.length === 0) {
+ return callback(null, []);
+ }
+
+ for (let i = 0; i < fns.length && i < limit; ++i) {
+ _start();
+ }
+
+ function _start() {
+ fns[numFinished + numInProgress](_done(numFinished + numInProgress));
+ ++numInProgress;
+ }
+
+ const results = [];
+
+ function _done(index) {
+ return (err, res) => {
+ --numInProgress;
+ ++numFinished;
+
+ if (error != null) {
+ return;
+ }
+ if (err != null) {
+ error = err;
+ return callback(error);
+ }
+
+ results[index] = res;
+
+ if (numFinished === fns.length) {
+ return callback(null, results);
+ } else if (numFinished + numInProgress < fns.length) {
+ _start();
+ }
+ };
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js b/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js
new file mode 100644
index 0000000..5d46cfd
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = function SkipPopulateValue(val) {
+ if (!(this instanceof SkipPopulateValue)) {
+ return new SkipPopulateValue(val);
+ }
+
+ this.val = val;
+ return this;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js b/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js
new file mode 100644
index 0000000..b84f713
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js
@@ -0,0 +1,90 @@
+'use strict';
+
+const modelSymbol = require('../symbols').modelSymbol;
+
+module.exports = assignRawDocsToIdStructure;
+
+/*!
+ * Assign `vals` returned by mongo query to the `rawIds`
+ * structure returned from utils.getVals() honoring
+ * query sort order if specified by user.
+ *
+ * This can be optimized.
+ *
+ * Rules:
+ *
+ * if the value of the path is not an array, use findOne rules, else find.
+ * for findOne the results are assigned directly to doc path (including null results).
+ * for find, if user specified sort order, results are assigned directly
+ * else documents are put back in original order of array if found in results
+ *
+ * @param {Array} rawIds
+ * @param {Array} vals
+ * @param {Boolean} sort
+ * @api private
+ */
+
+function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, recursed) {
+ // honor user specified sort order
+ const newOrder = [];
+ const sorting = options.sort && rawIds.length > 1;
+ const nullIfNotFound = options.$nullIfNotFound;
+ let doc;
+ let sid;
+ let id;
+
+ for (let i = 0; i < rawIds.length; ++i) {
+ id = rawIds[i];
+
+ if (Array.isArray(id)) {
+ // handle [ [id0, id2], [id3] ]
+ assignRawDocsToIdStructure(id, resultDocs, resultOrder, options, true);
+ newOrder.push(id);
+ continue;
+ }
+
+ if (id === null && !sorting) {
+ // keep nulls for findOne unless sorting, which always
+ // removes them (backward compat)
+ newOrder.push(id);
+ continue;
+ }
+
+ sid = String(id);
+
+ doc = resultDocs[sid];
+ // If user wants separate copies of same doc, use this option
+ if (options.clone) {
+ doc = doc.constructor.hydrate(doc._doc);
+ }
+
+ if (recursed) {
+ if (doc) {
+ if (sorting) {
+ newOrder[resultOrder[sid]] = doc;
+ } else {
+ newOrder.push(doc);
+ }
+ } else if (id != null && id[modelSymbol] != null) {
+ newOrder.push(id);
+ } else {
+ newOrder.push(options.retainNullValues || nullIfNotFound ? null : id);
+ }
+ } else {
+ // apply findOne behavior - if document in results, assign, else assign null
+ newOrder[i] = doc || null;
+ }
+ }
+
+ rawIds.length = 0;
+ if (newOrder.length) {
+ // reassign the documents based on corrected order
+
+ // forEach skips over sparse entries in arrays so we
+ // can safely use this to our advantage dealing with sorted
+ // result sets too.
+ newOrder.forEach(function(doc, i) {
+ rawIds[i] = doc;
+ });
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/assignVals.js b/node_modules/mongoose/lib/helpers/populate/assignVals.js
new file mode 100644
index 0000000..bd93e81
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/assignVals.js
@@ -0,0 +1,239 @@
+'use strict';
+
+const SkipPopulateValue = require('./SkipPopulateValue');
+const assignRawDocsToIdStructure = require('./assignRawDocsToIdStructure');
+const get = require('../get');
+const getVirtual = require('./getVirtual');
+const leanPopulateMap = require('./leanPopulateMap');
+const mpath = require('mpath');
+const sift = require('sift').default;
+const utils = require('../../utils');
+
+module.exports = function assignVals(o) {
+ // Options that aren't explicitly listed in `populateOptions`
+ const userOptions = get(o, 'allOptions.options.options');
+ // `o.options` contains options explicitly listed in `populateOptions`, like
+ // `match` and `limit`.
+ const populateOptions = Object.assign({}, o.options, userOptions, {
+ justOne: o.justOne
+ });
+ populateOptions.$nullIfNotFound = o.isVirtual;
+
+ const originalIds = [].concat(o.rawIds);
+
+ // replace the original ids in our intermediate _ids structure
+ // with the documents found by query
+ assignRawDocsToIdStructure(o.rawIds, o.rawDocs, o.rawOrder, populateOptions);
+
+ // now update the original documents being populated using the
+ // result structure that contains real documents.
+ const docs = o.docs;
+ const rawIds = o.rawIds;
+ const options = o.options;
+ const count = o.count && o.isVirtual;
+
+ function setValue(val) {
+ if (count) {
+ return val;
+ }
+ if (val instanceof SkipPopulateValue) {
+ return val.val;
+ }
+ if (o.justOne === true && Array.isArray(val)) {
+ return valueFilter(val[0], options, populateOptions);
+ } else if (o.justOne === false && !Array.isArray(val)) {
+ return valueFilter([val], options, populateOptions);
+ }
+ return valueFilter(val, options, populateOptions);
+ }
+
+ for (let i = 0; i < docs.length; ++i) {
+ const existingVal = utils.getValue(o.path, docs[i]);
+ if (existingVal == null && !getVirtual(o.originalModel.schema, o.path)) {
+ continue;
+ }
+
+ let valueToSet;
+ if (count) {
+ valueToSet = numDocs(rawIds[i]);
+ } else if (Array.isArray(o.match)) {
+ valueToSet = Array.isArray(rawIds[i]) ?
+ sift(o.match[i], rawIds[i]) :
+ sift(o.match[i], [rawIds[i]])[0];
+ } else {
+ valueToSet = rawIds[i];
+ }
+
+ // If we're populating a map, the existing value will be an object, so
+ // we need to transform again
+ const originalSchema = o.originalModel.schema;
+ const isDoc = get(docs[i], '$__', null) != null;
+ let isMap = isDoc ?
+ existingVal instanceof Map :
+ utils.isPOJO(existingVal);
+ // If we pass the first check, also make sure the local field's schematype
+ // is map (re: gh-6460)
+ isMap = isMap && get(originalSchema._getSchema(o.path), '$isSchemaMap');
+ if (!o.isVirtual && isMap) {
+ const _keys = existingVal instanceof Map ?
+ Array.from(existingVal.keys()) :
+ Object.keys(existingVal);
+ valueToSet = valueToSet.reduce((cur, v, i) => {
+ cur.set(_keys[i], v);
+ return cur;
+ }, new Map());
+ }
+
+ if (o.isVirtual && isDoc) {
+ docs[i].populated(o.path, o.justOne ? originalIds[0] : originalIds, o.allOptions);
+ // If virtual populate and doc is already init-ed, need to walk through
+ // the actual doc to set rather than setting `_doc` directly
+ mpath.set(o.path, valueToSet, docs[i], setValue);
+ continue;
+ }
+
+ const parts = o.path.split('.');
+ let cur = docs[i];
+ const curPath = parts[0];
+ for (let j = 0; j < parts.length - 1; ++j) {
+ // If we get to an array with a dotted path, like `arr.foo`, don't set
+ // `foo` on the array.
+ if (Array.isArray(cur) && !utils.isArrayIndex(parts[j])) {
+ break;
+ }
+
+ if (cur[parts[j]] == null) {
+ // If nothing to set, avoid creating an unnecessary array. Otherwise
+ // we'll end up with a single doc in the array with only defaults.
+ // See gh-8342, gh-8455
+ const schematype = originalSchema._getSchema(curPath);
+ if (valueToSet == null && schematype != null && schematype.$isMongooseArray) {
+ return;
+ }
+ cur[parts[j]] = {};
+ }
+ cur = cur[parts[j]];
+ // If the property in MongoDB is a primitive, we won't be able to populate
+ // the nested path, so skip it. See gh-7545
+ if (typeof cur !== 'object') {
+ return;
+ }
+ }
+ if (docs[i].$__) {
+ docs[i].populated(o.path, o.allIds[i], o.allOptions);
+ }
+
+ // If lean, need to check that each individual virtual respects
+ // `justOne`, because you may have a populated virtual with `justOne`
+ // underneath an array. See gh-6867
+ utils.setValue(o.path, valueToSet, docs[i], setValue, false);
+ }
+};
+
+function numDocs(v) {
+ if (Array.isArray(v)) {
+ // If setting underneath an array of populated subdocs, we may have an
+ // array of arrays. See gh-7573
+ if (v.some(el => Array.isArray(el))) {
+ return v.map(el => numDocs(el));
+ }
+ return v.length;
+ }
+ return v == null ? 0 : 1;
+}
+
+/*!
+ * 1) Apply backwards compatible find/findOne behavior to sub documents
+ *
+ * find logic:
+ * a) filter out non-documents
+ * b) remove _id from sub docs when user specified
+ *
+ * findOne
+ * a) if no doc found, set to null
+ * b) remove _id from sub docs when user specified
+ *
+ * 2) Remove _ids when specified by users query.
+ *
+ * background:
+ * _ids are left in the query even when user excludes them so
+ * that population mapping can occur.
+ */
+
+function valueFilter(val, assignmentOpts, populateOptions) {
+ if (Array.isArray(val)) {
+ // find logic
+ const ret = [];
+ const numValues = val.length;
+ for (let i = 0; i < numValues; ++i) {
+ const subdoc = val[i];
+ if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null)) {
+ continue;
+ }
+ maybeRemoveId(subdoc, assignmentOpts);
+ ret.push(subdoc);
+ if (assignmentOpts.originalLimit &&
+ ret.length >= assignmentOpts.originalLimit) {
+ break;
+ }
+ }
+
+ // Since we don't want to have to create a new mongoosearray, make sure to
+ // modify the array in place
+ while (val.length > ret.length) {
+ Array.prototype.pop.apply(val, []);
+ }
+ for (let i = 0; i < ret.length; ++i) {
+ val[i] = ret[i];
+ }
+ return val;
+ }
+
+ // findOne
+ if (isPopulatedObject(val)) {
+ maybeRemoveId(val, assignmentOpts);
+ return val;
+ }
+
+ if (val instanceof Map) {
+ return val;
+ }
+
+ if (populateOptions.justOne === true) {
+ return (val == null ? val : null);
+ }
+ if (populateOptions.justOne === false) {
+ return [];
+ }
+ return val;
+}
+
+/*!
+ * Remove _id from `subdoc` if user specified "lean" query option
+ */
+
+function maybeRemoveId(subdoc, assignmentOpts) {
+ if (assignmentOpts.excludeId) {
+ if (typeof subdoc.$__setValue === 'function') {
+ delete subdoc._doc._id;
+ } else {
+ delete subdoc._id;
+ }
+ }
+}
+
+/*!
+ * Determine if `obj` is something we can set a populated path to. Can be a
+ * document, a lean document, or an array/map that contains docs.
+ */
+
+function isPopulatedObject(obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ return Array.isArray(obj) ||
+ obj.$isMongooseMap ||
+ obj.$__ != null ||
+ leanPopulateMap.has(obj);
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js b/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js
new file mode 100644
index 0000000..abc0e6e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js
@@ -0,0 +1,489 @@
+'use strict';
+
+const MongooseError = require('../../error/index');
+const SkipPopulateValue = require('./SkipPopulateValue');
+const get = require('../get');
+const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
+const isPathExcluded = require('../projection/isPathExcluded');
+const getSchemaTypes = require('./getSchemaTypes');
+const getVirtual = require('./getVirtual');
+const normalizeRefPath = require('./normalizeRefPath');
+const util = require('util');
+const utils = require('../../utils');
+
+const modelSymbol = require('../symbols').modelSymbol;
+const populateModelSymbol = require('../symbols').populateModelSymbol;
+const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
+
+module.exports = function getModelsMapForPopulate(model, docs, options) {
+ let i;
+ let doc;
+ const len = docs.length;
+ const available = {};
+ const map = [];
+ const modelNameFromQuery = options.model && options.model.modelName || options.model;
+ let schema;
+ let refPath;
+ let Model;
+ let currentOptions;
+ let modelNames;
+ let modelName;
+ let modelForFindSchema;
+
+ const originalModel = options.model;
+ let isVirtual = false;
+ const modelSchema = model.schema;
+
+ let allSchemaTypes = getSchemaTypes(modelSchema, null, options.path);
+ allSchemaTypes = Array.isArray(allSchemaTypes) ? allSchemaTypes : [allSchemaTypes].filter(v => v != null);
+ const _firstWithRefPath = allSchemaTypes.find(schematype => get(schematype, 'options.refPath', null) != null);
+
+ for (i = 0; i < len; i++) {
+ doc = docs[i];
+
+ schema = getSchemaTypes(modelSchema, doc, options.path);
+ const isUnderneathDocArray = schema && schema.$isUnderneathDocArray;
+ if (isUnderneathDocArray && get(options, 'options.sort') != null) {
+ return new MongooseError('Cannot populate with `sort` on path ' + options.path +
+ ' because it is a subproperty of a document array');
+ }
+
+ modelNames = null;
+ let isRefPath = !!_firstWithRefPath;
+ let normalizedRefPath = _firstWithRefPath ? get(_firstWithRefPath, 'options.refPath', null) : null;
+
+ if (Array.isArray(schema)) {
+ for (let j = 0; j < schema.length; ++j) {
+ let _modelNames;
+ let res;
+ try {
+ res = _getModelNames(doc, schema[j]);
+ _modelNames = res.modelNames;
+ isRefPath = isRefPath || res.isRefPath;
+ normalizedRefPath = normalizedRefPath || res.refPath;
+ } catch (error) {
+ return error;
+ }
+
+ if (isRefPath && !res.isRefPath) {
+ continue;
+ }
+ if (!_modelNames) {
+ continue;
+ }
+ modelNames = modelNames || [];
+ for (let x = 0; x < _modelNames.length; ++x) {
+ if (modelNames.indexOf(_modelNames[x]) === -1) {
+ modelNames.push(_modelNames[x]);
+ }
+ }
+ }
+ } else {
+ try {
+ const res = _getModelNames(doc, schema);
+ modelNames = res.modelNames;
+ isRefPath = res.isRefPath;
+ normalizedRefPath = res.refPath;
+ } catch (error) {
+ return error;
+ }
+
+ if (!modelNames) {
+ continue;
+ }
+ }
+
+ const _virtualRes = getVirtual(model.schema, options.path);
+ const virtual = _virtualRes == null ? null : _virtualRes.virtual;
+
+ let localField;
+ let count = false;
+ if (virtual && virtual.options) {
+ const virtualPrefix = _virtualRes.nestedSchemaPath ?
+ _virtualRes.nestedSchemaPath + '.' : '';
+ if (typeof virtual.options.localField === 'function') {
+ localField = virtualPrefix + virtual.options.localField.call(doc, doc);
+ } else {
+ localField = virtualPrefix + virtual.options.localField;
+ }
+ count = virtual.options.count;
+
+ if (virtual.options.skip != null && !options.hasOwnProperty('skip')) {
+ options.skip = virtual.options.skip;
+ }
+ if (virtual.options.limit != null && !options.hasOwnProperty('limit')) {
+ options.limit = virtual.options.limit;
+ }
+ if (virtual.options.perDocumentLimit != null && !options.hasOwnProperty('perDocumentLimit')) {
+ options.perDocumentLimit = virtual.options.perDocumentLimit;
+ }
+ } else {
+ localField = options.path;
+ }
+ let foreignField = virtual && virtual.options ?
+ virtual.options.foreignField :
+ '_id';
+
+ // `justOne = null` means we don't know from the schema whether the end
+ // result should be an array or a single doc. This can result from
+ // populating a POJO using `Model.populate()`
+ let justOne = null;
+ if ('justOne' in options && options.justOne !== void 0) {
+ justOne = options.justOne;
+ } else if (virtual && virtual.options && virtual.options.refPath) {
+ const normalizedRefPath =
+ normalizeRefPath(virtual.options.refPath, doc, options.path);
+ justOne = !!virtual.options.justOne;
+ isVirtual = true;
+ const refValue = utils.getValue(normalizedRefPath, doc);
+ modelNames = Array.isArray(refValue) ? refValue : [refValue];
+ } else if (virtual && virtual.options && virtual.options.ref) {
+ let normalizedRef;
+ if (typeof virtual.options.ref === 'function') {
+ normalizedRef = virtual.options.ref.call(doc, doc);
+ } else {
+ normalizedRef = virtual.options.ref;
+ }
+ justOne = !!virtual.options.justOne;
+ isVirtual = true;
+ if (!modelNames) {
+ modelNames = [].concat(normalizedRef);
+ }
+ } else if (schema && !schema[schemaMixedSymbol]) {
+ // Skip Mixed types because we explicitly don't do casting on those.
+ justOne = !schema.$isMongooseArray;
+ }
+
+ if (!modelNames) {
+ continue;
+ }
+
+ if (virtual && (!localField || !foreignField)) {
+ return new MongooseError('If you are populating a virtual, you must set the ' +
+ 'localField and foreignField options');
+ }
+
+ options.isVirtual = isVirtual;
+ options.virtual = virtual;
+ if (typeof localField === 'function') {
+ localField = localField.call(doc, doc);
+ }
+ if (typeof foreignField === 'function') {
+ foreignField = foreignField.call(doc);
+ }
+
+ const localFieldPathType = modelSchema._getPathType(localField);
+ const localFieldPath = localFieldPathType === 'real' ? modelSchema.path(localField) : localFieldPathType.schema;
+ const localFieldGetters = localFieldPath && localFieldPath.getters ? localFieldPath.getters : [];
+ let ret;
+
+ const _populateOptions = get(options, 'options', {});
+
+ const getters = 'getters' in _populateOptions ?
+ _populateOptions.getters :
+ options.isVirtual && get(virtual, 'options.getters', false);
+ if (localFieldGetters.length > 0 && getters) {
+ const hydratedDoc = (doc.$__ != null) ? doc : model.hydrate(doc);
+ const localFieldValue = utils.getValue(localField, doc);
+ if (Array.isArray(localFieldValue)) {
+ const localFieldHydratedValue = utils.getValue(localField.split('.').slice(0, -1), hydratedDoc);
+ ret = localFieldValue.map((localFieldArrVal, localFieldArrIndex) =>
+ localFieldPath.applyGetters(localFieldArrVal, localFieldHydratedValue[localFieldArrIndex]));
+ } else {
+ ret = localFieldPath.applyGetters(localFieldValue, hydratedDoc);
+ }
+ } else {
+ ret = convertTo_id(utils.getValue(localField, doc), schema);
+ }
+
+ const id = String(utils.getValue(foreignField, doc));
+ options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
+
+ let match = get(options, 'match', null) ||
+ get(currentOptions, 'match', null) ||
+ get(options, 'virtual.options.match', null) ||
+ get(options, 'virtual.options.options.match', null);
+
+ const hasMatchFunction = typeof match === 'function';
+ if (hasMatchFunction) {
+ match = match.call(doc, doc);
+ }
+
+ // Re: gh-8452. Embedded discriminators may not have `refPath`, so clear
+ // out embedded discriminator docs that don't have a `refPath` on the
+ // populated path.
+ if (isRefPath && normalizedRefPath != null) {
+ const pieces = normalizedRefPath.split('.');
+ let cur = '';
+ for (let i = 0; i < pieces.length; ++i) {
+ cur = cur + (cur.length === 0 ? '' : '.') + pieces[i];
+ const schematype = modelSchema.path(cur);
+ if (schematype != null &&
+ schematype.$isMongooseArray &&
+ schematype.caster.discriminators != null &&
+ Object.keys(schematype.caster.discriminators).length > 0) {
+ const subdocs = utils.getValue(cur, doc);
+ const remnant = options.path.substr(cur.length + 1);
+ const discriminatorKey = schematype.caster.schema.options.discriminatorKey;
+ modelNames = [];
+ for (const subdoc of subdocs) {
+ const discriminatorValue = utils.getValue(discriminatorKey, subdoc);
+ const discriminatorSchema = schematype.caster.discriminators[discriminatorValue].schema;
+ if (discriminatorSchema == null) {
+ continue;
+ }
+ const _path = discriminatorSchema.path(remnant);
+ if (_path == null || _path.options.refPath == null) {
+ const docValue = utils.getValue(localField.substr(cur.length + 1), subdoc);
+ ret = ret.map(v => v === docValue ? SkipPopulateValue(v) : v);
+ continue;
+ }
+ const modelName = utils.getValue(pieces.slice(i + 1).join('.'), subdoc);
+ modelNames.push(modelName);
+ }
+ }
+ }
+ }
+
+ let k = modelNames.length;
+ while (k--) {
+ modelName = modelNames[k];
+ if (modelName == null) {
+ continue;
+ }
+
+ // `PopulateOptions#connection`: if the model is passed as a string, the
+ // connection matters because different connections have different models.
+ const connection = options.connection != null ? options.connection : model.db;
+
+ try {
+ Model = originalModel && originalModel[modelSymbol] ?
+ originalModel :
+ modelName[modelSymbol] ? modelName : connection.model(modelName);
+ } catch (error) {
+ return error;
+ }
+
+ let ids = ret;
+ const flat = Array.isArray(ret) ? utils.array.flatten(ret) : [];
+
+ if (isRefPath && Array.isArray(ret) && flat.length === modelNames.length) {
+ ids = flat.filter((val, i) => modelNames[i] === modelName);
+ }
+
+ if (!available[modelName] || currentOptions.perDocumentLimit != null) {
+ currentOptions = {
+ model: Model
+ };
+
+ if (isVirtual && virtual.options && virtual.options.options) {
+ currentOptions.options = utils.clone(virtual.options.options);
+ }
+ utils.merge(currentOptions, options);
+
+ // Used internally for checking what model was used to populate this
+ // path.
+ options[populateModelSymbol] = Model;
+
+ available[modelName] = {
+ model: Model,
+ options: currentOptions,
+ match: hasMatchFunction ? [match] : match,
+ docs: [doc],
+ ids: [ids],
+ allIds: [ret],
+ localField: new Set([localField]),
+ foreignField: new Set([foreignField]),
+ justOne: justOne,
+ isVirtual: isVirtual,
+ virtual: virtual,
+ count: count,
+ [populateModelSymbol]: Model
+ };
+ map.push(available[modelName]);
+ } else {
+ available[modelName].localField.add(localField);
+ available[modelName].foreignField.add(foreignField);
+ available[modelName].docs.push(doc);
+ available[modelName].ids.push(ids);
+ available[modelName].allIds.push(ret);
+ if (hasMatchFunction) {
+ available[modelName].match.push(match);
+ }
+ }
+ }
+ }
+
+ function _getModelNames(doc, schema) {
+ let modelNames;
+ let discriminatorKey;
+ let isRefPath = false;
+
+ if (schema && schema.caster) {
+ schema = schema.caster;
+ }
+ if (schema && schema.$isSchemaMap) {
+ schema = schema.$__schemaType;
+ }
+
+ if (!schema && model.discriminators) {
+ discriminatorKey = model.schema.discriminatorMapping.key;
+ }
+
+ refPath = schema && schema.options && schema.options.refPath;
+
+ const normalizedRefPath = normalizeRefPath(refPath, doc, options.path);
+
+ if (modelNameFromQuery) {
+ modelNames = [modelNameFromQuery]; // query options
+ } else if (normalizedRefPath) {
+ if (options._queryProjection != null && isPathExcluded(options._queryProjection, normalizedRefPath)) {
+ throw new MongooseError('refPath `' + normalizedRefPath +
+ '` must not be excluded in projection, got ' +
+ util.inspect(options._queryProjection));
+ }
+
+ if (modelSchema.virtuals.hasOwnProperty(normalizedRefPath) && doc.$__ == null) {
+ modelNames = [modelSchema.virtuals[normalizedRefPath].applyGetters(void 0, doc)];
+ } else {
+ modelNames = utils.getValue(normalizedRefPath, doc);
+ }
+
+ if (Array.isArray(modelNames)) {
+ modelNames = utils.array.flatten(modelNames);
+ }
+
+ isRefPath = true;
+ } else {
+ let modelForCurrentDoc = model;
+ let schemaForCurrentDoc;
+
+ if (!schema && discriminatorKey) {
+ modelForFindSchema = utils.getValue(discriminatorKey, doc);
+ if (modelForFindSchema) {
+ // `modelForFindSchema` is the discriminator value, so we might need
+ // find the discriminated model name
+ const discriminatorModel = getDiscriminatorByValue(model, modelForFindSchema);
+ if (discriminatorModel != null) {
+ modelForCurrentDoc = discriminatorModel;
+ } else {
+ try {
+ modelForCurrentDoc = model.db.model(modelForFindSchema);
+ } catch (error) {
+ return error;
+ }
+ }
+
+ schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);
+
+ if (schemaForCurrentDoc && schemaForCurrentDoc.caster) {
+ schemaForCurrentDoc = schemaForCurrentDoc.caster;
+ }
+ }
+ } else {
+ schemaForCurrentDoc = schema;
+ }
+ const _virtualRes = getVirtual(modelForCurrentDoc.schema, options.path);
+ const virtual = _virtualRes == null ? null : _virtualRes.virtual;
+
+ let ref;
+ let refPath;
+
+ if ((ref = get(schemaForCurrentDoc, 'options.ref')) != null) {
+ ref = handleRefFunction(ref, doc);
+ modelNames = [ref];
+ } else if ((ref = get(virtual, 'options.ref')) != null) {
+ ref = handleRefFunction(ref, doc);
+
+ // When referencing nested arrays, the ref should be an Array
+ // of modelNames.
+ if (Array.isArray(ref)) {
+ modelNames = ref;
+ } else {
+ modelNames = [ref];
+ }
+
+ isVirtual = true;
+ } else if ((refPath = get(schemaForCurrentDoc, 'options.refPath')) != null) {
+ isRefPath = true;
+ refPath = normalizeRefPath(refPath, doc, options.path);
+ modelNames = utils.getValue(refPath, doc);
+ if (Array.isArray(modelNames)) {
+ modelNames = utils.array.flatten(modelNames);
+ }
+ } else {
+ // We may have a discriminator, in which case we don't want to
+ // populate using the base model by default
+ modelNames = discriminatorKey ? null : [model.modelName];
+ }
+ }
+
+ if (!modelNames) {
+ return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath };
+ }
+
+ if (!Array.isArray(modelNames)) {
+ modelNames = [modelNames];
+ }
+
+ return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath };
+ }
+
+ return map;
+};
+
+/*!
+ * ignore
+ */
+
+function handleRefFunction(ref, doc) {
+ if (typeof ref === 'function' && !ref[modelSymbol]) {
+ return ref.call(doc, doc);
+ }
+ return ref;
+}
+
+/*!
+ * Retrieve the _id of `val` if a Document or Array of Documents.
+ *
+ * @param {Array|Document|Any} val
+ * @return {Array|Document|Any}
+ */
+
+function convertTo_id(val, schema) {
+ if (val != null && val.$__ != null) return val._id;
+
+ if (Array.isArray(val)) {
+ for (let i = 0; i < val.length; ++i) {
+ if (val[i] != null && val[i].$__ != null) {
+ val[i] = val[i]._id;
+ }
+ }
+ if (val.isMongooseArray && val.$schema()) {
+ return val.$schema().cast(val, val.$parent());
+ }
+
+ return [].concat(val);
+ }
+
+ // `populate('map')` may be an object if populating on a doc that hasn't
+ // been hydrated yet
+ if (val != null &&
+ val.constructor.name === 'Object' &&
+ // The intent here is we should only flatten the object if we expect
+ // to get a Map in the end. Avoid doing this for mixed types.
+ (schema == null || schema[schemaMixedSymbol] == null)) {
+ const ret = [];
+ for (const key of Object.keys(val)) {
+ ret.push(val[key]);
+ }
+ return ret;
+ }
+ // If doc has already been hydrated, e.g. `doc.populate('map').execPopulate()`
+ // then `val` will already be a map
+ if (val instanceof Map) {
+ return Array.from(val.values());
+ }
+
+ return val;
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js b/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js
new file mode 100644
index 0000000..8db0079
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js
@@ -0,0 +1,198 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+const Mixed = require('../../schema/mixed');
+const get = require('../get');
+const leanPopulateMap = require('./leanPopulateMap');
+const mpath = require('mpath');
+
+const populateModelSymbol = require('../symbols').populateModelSymbol;
+
+/*!
+ * @param {Schema} schema
+ * @param {Object} doc POJO
+ * @param {string} path
+ */
+
+module.exports = function getSchemaTypes(schema, doc, path) {
+ const pathschema = schema.path(path);
+ const topLevelDoc = doc;
+
+ if (pathschema) {
+ return pathschema;
+ }
+
+ function search(parts, schema, subdoc, nestedPath) {
+ let p = parts.length + 1;
+ let foundschema;
+ let trypath;
+
+ while (p--) {
+ trypath = parts.slice(0, p).join('.');
+ foundschema = schema.path(trypath);
+
+ if (foundschema == null) {
+ continue;
+ }
+
+ if (foundschema.caster) {
+ // array of Mixed?
+ if (foundschema.caster instanceof Mixed) {
+ return foundschema.caster;
+ }
+
+ let schemas = null;
+ if (foundschema.schema != null && foundschema.schema.discriminators != null) {
+ const discriminators = foundschema.schema.discriminators;
+ const discriminatorKeyPath = trypath + '.' +
+ foundschema.schema.options.discriminatorKey;
+ const keys = subdoc ? mpath.get(discriminatorKeyPath, subdoc) || [] : [];
+ schemas = Object.keys(discriminators).
+ reduce(function(cur, discriminator) {
+ if (doc == null || keys.indexOf(discriminator) !== -1) {
+ cur.push(discriminators[discriminator]);
+ }
+ return cur;
+ }, []);
+ }
+
+ // Now that we found the array, we need to check if there
+ // are remaining document paths to look up for casting.
+ // Also we need to handle array.$.path since schema.path
+ // doesn't work for that.
+ // If there is no foundschema.schema we are dealing with
+ // a path like array.$
+ if (p !== parts.length && foundschema.schema) {
+ let ret;
+ if (parts[p] === '$') {
+ if (p + 1 === parts.length) {
+ // comments.$
+ return foundschema;
+ }
+ // comments.$.comments.$.title
+ ret = search(
+ parts.slice(p + 1),
+ schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+ return ret;
+ }
+
+ if (schemas != null && schemas.length > 0) {
+ ret = [];
+ for (let i = 0; i < schemas.length; ++i) {
+ const _ret = search(
+ parts.slice(p),
+ schemas[i],
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ if (_ret != null) {
+ _ret.$isUnderneathDocArray = _ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ if (_ret.$isUnderneathDocArray) {
+ ret.$isUnderneathDocArray = true;
+ }
+ ret.push(_ret);
+ }
+ }
+ return ret;
+ } else {
+ ret = search(
+ parts.slice(p),
+ foundschema.schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ } else if (p !== parts.length &&
+ foundschema.$isMongooseArray &&
+ foundschema.casterConstructor.$isMongooseArray) {
+ // Nested arrays. Drill down to the bottom of the nested array.
+ // Ignore discriminators.
+ let type = foundschema;
+ while (type.$isMongooseArray && !type.$isMongooseDocumentArray) {
+ type = type.casterConstructor;
+ }
+ return search(
+ parts.slice(p),
+ type.schema,
+ null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ }
+ }
+
+ const fullPath = nestedPath.concat([trypath]).join('.');
+ if (topLevelDoc != null && topLevelDoc.$__ && topLevelDoc.populated(fullPath) && p < parts.length) {
+ const model = doc.$__.populated[fullPath].options[populateModelSymbol];
+ if (model != null) {
+ const ret = search(
+ parts.slice(p),
+ model.schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !model.schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ }
+
+ const _val = get(topLevelDoc, trypath);
+ if (_val != null) {
+ const model = Array.isArray(_val) && _val.length > 0 ?
+ leanPopulateMap.get(_val[0]) :
+ leanPopulateMap.get(_val);
+ // Populated using lean, `leanPopulateMap` value is the foreign model
+ const schema = model != null ? model.schema : null;
+ if (schema != null) {
+ const ret = search(
+ parts.slice(p),
+ schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ }
+
+ return foundschema;
+ }
+ }
+
+ // look for arrays
+ const parts = path.split('.');
+ for (let i = 0; i < parts.length; ++i) {
+ if (parts[i] === '$') {
+ // Re: gh-5628, because `schema.path()` doesn't take $ into account.
+ parts[i] = '0';
+ }
+ }
+ return search(parts, schema, doc, []);
+};
diff --git a/node_modules/mongoose/lib/helpers/populate/getVirtual.js b/node_modules/mongoose/lib/helpers/populate/getVirtual.js
new file mode 100644
index 0000000..3f4a129
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getVirtual.js
@@ -0,0 +1,64 @@
+'use strict';
+
+module.exports = getVirtual;
+
+/*!
+ * ignore
+ */
+
+function getVirtual(schema, name) {
+ if (schema.virtuals[name]) {
+ return { virtual: schema.virtuals[name], path: void 0 };
+ }
+ const parts = name.split('.');
+ let cur = '';
+ let nestedSchemaPath = '';
+ for (let i = 0; i < parts.length; ++i) {
+ cur += (cur.length > 0 ? '.' : '') + parts[i];
+ if (schema.virtuals[cur]) {
+ if (i === parts.length - 1) {
+ return { virtual: schema.virtuals[cur], path: nestedSchemaPath };
+ }
+ continue;
+ }
+
+ if (schema.nested[cur]) {
+ continue;
+ }
+
+ if (schema.paths[cur] && schema.paths[cur].schema) {
+ schema = schema.paths[cur].schema;
+ const rest = parts.slice(i + 1).join('.');
+
+ if (schema.virtuals[rest]) {
+ if (i === parts.length - 2) {
+ return {
+ virtual: schema.virtuals[rest],
+ nestedSchemaPath: [nestedSchemaPath, cur].filter(v => !!v).join('.')
+ };
+ }
+ continue;
+ }
+
+ if (i + 1 < parts.length && schema.discriminators) {
+ for (const key of Object.keys(schema.discriminators)) {
+ const res = getVirtual(schema.discriminators[key], rest);
+ if (res != null) {
+ const _path = [nestedSchemaPath, cur, res.nestedSchemaPath].
+ filter(v => !!v).join('.');
+ return {
+ virtual: res.virtual,
+ nestedSchemaPath: _path
+ };
+ }
+ }
+ }
+
+ nestedSchemaPath += (nestedSchemaPath.length > 0 ? '.' : '') + cur;
+ cur = '';
+ continue;
+ }
+
+ return null;
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js b/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js
new file mode 100644
index 0000000..a333124
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js
@@ -0,0 +1,7 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = new WeakMap();
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js b/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js
new file mode 100644
index 0000000..233b741
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js
@@ -0,0 +1,45 @@
+'use strict';
+
+module.exports = function normalizeRefPath(refPath, doc, populatedPath) {
+ if (refPath == null) {
+ return refPath;
+ }
+
+ if (typeof refPath === 'function') {
+ refPath = refPath.call(doc, doc, populatedPath);
+ }
+
+ // If populated path has numerics, the end `refPath` should too. For example,
+ // if populating `a.0.b` instead of `a.b` and `b` has `refPath = a.c`, we
+ // should return `a.0.c` for the refPath.
+ const hasNumericProp = /(\.\d+$|\.\d+\.)/g;
+
+ if (hasNumericProp.test(populatedPath)) {
+ const chunks = populatedPath.split(hasNumericProp);
+
+ if (chunks[chunks.length - 1] === '') {
+ throw new Error('Can\'t populate individual element in an array');
+ }
+
+ let _refPath = '';
+ let _remaining = refPath;
+ // 2nd, 4th, etc. will be numeric props. For example: `[ 'a', '.0.', 'b' ]`
+ for (let i = 0; i < chunks.length; i += 2) {
+ const chunk = chunks[i];
+ if (_remaining.startsWith(chunk + '.')) {
+ _refPath += _remaining.substr(0, chunk.length) + chunks[i + 1];
+ _remaining = _remaining.substr(chunk.length + 1);
+ } else if (i === chunks.length - 1) {
+ _refPath += _remaining;
+ _remaining = '';
+ break;
+ } else {
+ throw new Error('Could not normalize ref path, chunk ' + chunk + ' not in populated path');
+ }
+ }
+
+ return _refPath;
+ }
+
+ return refPath;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/validateRef.js b/node_modules/mongoose/lib/helpers/populate/validateRef.js
new file mode 100644
index 0000000..9dc2b6f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/validateRef.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const MongooseError = require('../../error/mongooseError');
+const util = require('util');
+
+module.exports = validateRef;
+
+function validateRef(ref, path) {
+ if (typeof ref === 'string') {
+ return;
+ }
+
+ if (typeof ref === 'function') {
+ return;
+ }
+
+ throw new MongooseError('Invalid ref at path "' + path + '". Got ' +
+ util.inspect(ref, { depth: 0 }));
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/printJestWarning.js b/node_modules/mongoose/lib/helpers/printJestWarning.js
new file mode 100644
index 0000000..eb3a8eb
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/printJestWarning.js
@@ -0,0 +1,8 @@
+'use strict';
+
+if (typeof jest !== 'undefined' && typeof window !== 'undefined') {
+ console.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
+ 'with Jest\'s default jsdom test environment. Please make sure you read ' +
+ 'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
+ 'http://mongoosejs.com/docs/jest.html');
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js b/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js
new file mode 100644
index 0000000..67dfb39
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js
@@ -0,0 +1,18 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function isDefiningProjection(val) {
+ if (val == null) {
+ // `undefined` or `null` become exclusive projections
+ return true;
+ }
+ if (typeof val === 'object') {
+ // Only cases where a value does **not** define whether the whole projection
+ // is inclusive or exclusive are `$meta` and `$slice`.
+ return !('$meta' in val) && !('$slice' in val);
+ }
+ return true;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isExclusive.js b/node_modules/mongoose/lib/helpers/projection/isExclusive.js
new file mode 100644
index 0000000..8c64bc5
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isExclusive.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * ignore
+ */
+
+module.exports = function isExclusive(projection) {
+ const keys = Object.keys(projection);
+ let ki = keys.length;
+ let exclude = null;
+
+ if (ki === 1 && keys[0] === '_id') {
+ exclude = !!projection[keys[ki]];
+ } else {
+ while (ki--) {
+ // Does this projection explicitly define inclusion/exclusion?
+ // Explicitly avoid `$meta` and `$slice`
+ if (keys[ki] !== '_id' && isDefiningProjection(projection[keys[ki]])) {
+ exclude = !projection[keys[ki]];
+ break;
+ }
+ }
+ }
+
+ return exclude;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isInclusive.js b/node_modules/mongoose/lib/helpers/projection/isInclusive.js
new file mode 100644
index 0000000..098309f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isInclusive.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * ignore
+ */
+
+module.exports = function isInclusive(projection) {
+ if (projection == null) {
+ return false;
+ }
+
+ const props = Object.keys(projection);
+ const numProps = props.length;
+ if (numProps === 0) {
+ return false;
+ }
+
+ for (let i = 0; i < numProps; ++i) {
+ const prop = props[i];
+ // Plus paths can't define the projection (see gh-7050)
+ if (prop.startsWith('+')) {
+ continue;
+ }
+ // If field is truthy (1, true, etc.) and not an object, then this
+ // projection must be inclusive. If object, assume its $meta, $slice, etc.
+ if (isDefiningProjection(projection[prop]) && !!projection[prop]) {
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js b/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js
new file mode 100644
index 0000000..fc2592c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * Determines if `path` is excluded by `projection`
+ *
+ * @param {Object} projection
+ * @param {string} path
+ * @return {Boolean}
+ */
+
+module.exports = function isPathExcluded(projection, path) {
+ if (path === '_id') {
+ return projection._id === 0;
+ }
+
+ const paths = Object.keys(projection);
+ let type = null;
+
+ for (const _path of paths) {
+ if (isDefiningProjection(projection[_path])) {
+ type = projection[path] === 1 ? 'inclusive' : 'exclusive';
+ break;
+ }
+ }
+
+ if (type === 'inclusive') {
+ return projection[path] !== 1;
+ }
+ if (type === 'exclusive') {
+ return projection[path] === 0;
+ }
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js b/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js
new file mode 100644
index 0000000..8a05fc9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js
@@ -0,0 +1,28 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function isPathSelectedInclusive(fields, path) {
+ const chunks = path.split('.');
+ let cur = '';
+ let j;
+ let keys;
+ let numKeys;
+ for (let i = 0; i < chunks.length; ++i) {
+ cur += cur.length ? '.' : '' + chunks[i];
+ if (fields[cur]) {
+ keys = Object.keys(fields);
+ numKeys = keys.length;
+ for (j = 0; j < numKeys; ++j) {
+ if (keys[i].indexOf(cur + '.') === 0 && keys[i].indexOf(path) !== 0) {
+ continue;
+ }
+ }
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/parseProjection.js b/node_modules/mongoose/lib/helpers/projection/parseProjection.js
new file mode 100644
index 0000000..d2a44b1
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/parseProjection.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ * Convert a string or array into a projection object, retaining all
+ * `-` and `+` paths.
+ */
+
+module.exports = function parseProjection(v, retainMinusPaths) {
+ const type = typeof v;
+
+ if (type === 'string') {
+ v = v.split(/\s+/);
+ }
+ if (!Array.isArray(v) && Object.prototype.toString.call(v) !== '[object Arguments]') {
+ return v;
+ }
+
+ const len = v.length;
+ const ret = {};
+ for (let i = 0; i < len; ++i) {
+ let field = v[i];
+ if (!field) {
+ continue;
+ }
+ const include = '-' == field[0] ? 0 : 1;
+ if (!retainMinusPaths && include === 0) {
+ field = field.substring(1);
+ }
+ ret[field] = include;
+ }
+
+ return ret;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/promiseOrCallback.js b/node_modules/mongoose/lib/helpers/promiseOrCallback.js
new file mode 100644
index 0000000..a1aff55
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/promiseOrCallback.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const PromiseProvider = require('../promise_provider');
+
+const emittedSymbol = Symbol.for('mongoose:emitted');
+
+module.exports = function promiseOrCallback(callback, fn, ee) {
+ if (typeof callback === 'function') {
+ return fn(function(error) {
+ if (error != null) {
+ if (ee != null && ee.listeners('error').length > 0 && !error[emittedSymbol]) {
+ error[emittedSymbol] = true;
+ ee.emit('error', error);
+ }
+ try {
+ callback(error);
+ } catch (error) {
+ return process.nextTick(() => {
+ throw error;
+ });
+ }
+ return;
+ }
+ callback.apply(this, arguments);
+ });
+ }
+
+ const Promise = PromiseProvider.get();
+
+ return new Promise((resolve, reject) => {
+ fn(function(error, res) {
+ if (error != null) {
+ if (ee != null && ee.listeners('error').length > 0 && !error[emittedSymbol]) {
+ error[emittedSymbol] = true;
+ ee.emit('error', error);
+ }
+ return reject(error);
+ }
+ if (arguments.length > 2) {
+ return resolve(Array.prototype.slice.call(arguments, 1));
+ }
+ resolve(res);
+ });
+ });
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js b/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js
new file mode 100644
index 0000000..cb49260
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js
@@ -0,0 +1,15 @@
+'use strict';
+
+const utils = require('../../utils');
+
+module.exports = function applyGlobalMaxTimeMS(options, model) {
+ if (utils.hasUserDefinedProperty(options, 'maxTimeMS')) {
+ return;
+ }
+
+ if (utils.hasUserDefinedProperty(model.db.options, 'maxTimeMS')) {
+ options.maxTimeMS = model.db.options.maxTimeMS;
+ } else if (utils.hasUserDefinedProperty(model.base.options, 'maxTimeMS')) {
+ options.maxTimeMS = model.base.options.maxTimeMS;
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js b/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js
new file mode 100644
index 0000000..a08baf8
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js
@@ -0,0 +1,90 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = applyQueryMiddleware;
+
+/*!
+ * ignore
+ */
+
+applyQueryMiddleware.middlewareFunctions = [
+ 'count',
+ 'countDocuments',
+ 'deleteMany',
+ 'deleteOne',
+ 'distinct',
+ 'estimatedDocumentCount',
+ 'find',
+ 'findOne',
+ 'findOneAndDelete',
+ 'findOneAndRemove',
+ 'findOneAndReplace',
+ 'findOneAndUpdate',
+ 'remove',
+ 'replaceOne',
+ 'update',
+ 'updateMany',
+ 'updateOne',
+ 'validate'
+];
+
+/*!
+ * Apply query middleware
+ *
+ * @param {Query} query constructor
+ * @param {Model} model
+ */
+
+function applyQueryMiddleware(Query, model) {
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1,
+ nullResultByDefault: true
+ };
+
+ const middleware = model.hooks.filter(hook => {
+ const contexts = _getContexts(hook);
+ if (hook.name === 'updateOne') {
+ return contexts.query == null || !!contexts.query;
+ }
+ if (hook.name === 'deleteOne') {
+ return !!contexts.query || Object.keys(contexts).length === 0;
+ }
+ if (hook.name === 'validate' || hook.name === 'remove') {
+ return !!contexts.query;
+ }
+ return true;
+ });
+
+ // `update()` thunk has a different name because `_update` was already taken
+ Query.prototype._execUpdate = middleware.createWrapper('update',
+ Query.prototype._execUpdate, null, kareemOptions);
+ // `distinct()` thunk has a different name because `_distinct` was already taken
+ Query.prototype.__distinct = middleware.createWrapper('distinct',
+ Query.prototype.__distinct, null, kareemOptions);
+
+ // `validate()` doesn't have a thunk because it doesn't execute a query.
+ Query.prototype.validate = middleware.createWrapper('validate',
+ Query.prototype.validate, null, kareemOptions);
+
+ applyQueryMiddleware.middlewareFunctions.
+ filter(v => v !== 'update' && v !== 'distinct' && v !== 'validate').
+ forEach(fn => {
+ Query.prototype[`_${fn}`] = middleware.createWrapper(fn,
+ Query.prototype[`_${fn}`], null, kareemOptions);
+ });
+}
+
+function _getContexts(hook) {
+ const ret = {};
+ if (hook.hasOwnProperty('query')) {
+ ret.query = hook.query;
+ }
+ if (hook.hasOwnProperty('document')) {
+ ret.document = hook.document;
+ }
+ return ret;
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/castFilterPath.js b/node_modules/mongoose/lib/helpers/query/castFilterPath.js
new file mode 100644
index 0000000..74ff1c2
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/castFilterPath.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const isOperator = require('./isOperator');
+
+module.exports = function castFilterPath(query, schematype, val) {
+ const ctx = query;
+ const any$conditionals = Object.keys(val).some(isOperator);
+
+ if (!any$conditionals) {
+ return schematype.castForQueryWrapper({
+ val: val,
+ context: ctx
+ });
+ }
+
+ const ks = Object.keys(val);
+
+ let k = ks.length;
+
+ while (k--) {
+ const $cond = ks[k];
+ const nested = val[$cond];
+
+ if ($cond === '$not') {
+ if (nested && schematype && !schematype.caster) {
+ const _keys = Object.keys(nested);
+ if (_keys.length && isOperator(_keys[0])) {
+ for (const key in nested) {
+ nested[key] = schematype.castForQueryWrapper({
+ $conditional: key,
+ val: nested[key],
+ context: ctx
+ });
+ }
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: ctx
+ });
+ }
+ continue;
+ }
+ // cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: ctx
+ });
+ }
+ }
+
+ return val;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/castUpdate.js b/node_modules/mongoose/lib/helpers/query/castUpdate.js
new file mode 100644
index 0000000..bdad804
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/castUpdate.js
@@ -0,0 +1,524 @@
+'use strict';
+
+const CastError = require('../../error/cast');
+const MongooseError = require('../../error/mongooseError');
+const StrictModeError = require('../../error/strict');
+const ValidationError = require('../../error/validation');
+const castNumber = require('../../cast/number');
+const cast = require('../../cast');
+const getEmbeddedDiscriminatorPath = require('./getEmbeddedDiscriminatorPath');
+const handleImmutable = require('./handleImmutable');
+const moveImmutableProperties = require('../update/moveImmutableProperties');
+const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
+const utils = require('../../utils');
+
+/*!
+ * Casts an update op based on the given schema
+ *
+ * @param {Schema} schema
+ * @param {Object} obj
+ * @param {Object} options
+ * @param {Boolean} [options.overwrite] defaults to false
+ * @param {Boolean|String} [options.strict] defaults to true
+ * @param {Query} context passed to setters
+ * @return {Boolean} true iff the update is non-empty
+ */
+
+module.exports = function castUpdate(schema, obj, options, context, filter) {
+ if (obj == null) {
+ return undefined;
+ }
+ options = options || {};
+
+ // Update pipeline
+ if (Array.isArray(obj)) {
+ const len = obj.length;
+ for (let i = 0; i < len; ++i) {
+ const ops = Object.keys(obj[i]);
+ for (const op of ops) {
+ obj[i][op] = castPipelineOperator(op, obj[i][op]);
+ }
+ }
+ return obj;
+ }
+
+ const ops = Object.keys(obj);
+ let i = ops.length;
+ const ret = {};
+ let hasKeys;
+ let val;
+ let hasDollarKey = false;
+ const overwrite = options.overwrite;
+
+ filter = filter || {};
+
+ moveImmutableProperties(schema, obj, context);
+
+ while (i--) {
+ const op = ops[i];
+ // if overwrite is set, don't do any of the special $set stuff
+ if (op[0] !== '$' && !overwrite) {
+ // fix up $set sugar
+ if (!ret.$set) {
+ if (obj.$set) {
+ ret.$set = obj.$set;
+ } else {
+ ret.$set = {};
+ }
+ }
+ ret.$set[op] = obj[op];
+ ops.splice(i, 1);
+ if (!~ops.indexOf('$set')) ops.push('$set');
+ } else if (op === '$set') {
+ if (!ret.$set) {
+ ret[op] = obj[op];
+ }
+ } else {
+ ret[op] = obj[op];
+ }
+ }
+
+ // cast each value
+ i = ops.length;
+
+ // if we get passed {} for the update, we still need to respect that when it
+ // is an overwrite scenario
+ if (overwrite) {
+ hasKeys = true;
+ }
+
+ while (i--) {
+ const op = ops[i];
+ val = ret[op];
+ hasDollarKey = hasDollarKey || op.startsWith('$');
+
+ if (val &&
+ typeof val === 'object' &&
+ !Buffer.isBuffer(val) &&
+ (!overwrite || hasDollarKey)) {
+ hasKeys |= walkUpdatePath(schema, val, op, options, context, filter);
+ } else if (overwrite && ret && typeof ret === 'object') {
+ // if we are just using overwrite, cast the query and then we will
+ // *always* return the value, even if it is an empty object. We need to
+ // set hasKeys above because we need to account for the case where the
+ // user passes {} and wants to clobber the whole document
+ // Also, _walkUpdatePath expects an operation, so give it $set since that
+ // is basically what we're doing
+ walkUpdatePath(schema, ret, '$set', options, context, filter);
+ } else {
+ const msg = 'Invalid atomic update value for ' + op + '. '
+ + 'Expected an object, received ' + typeof val;
+ throw new Error(msg);
+ }
+
+ if (op.startsWith('$') && utils.isEmptyObject(val)) {
+ delete ret[op];
+ }
+ }
+
+ return hasKeys && ret;
+};
+
+/*!
+ * ignore
+ */
+
+function castPipelineOperator(op, val) {
+ if (op === '$unset') {
+ if (!Array.isArray(val) || val.find(v => typeof v !== 'string')) {
+ throw new MongooseError('Invalid $unset in pipeline, must be ' +
+ 'an array of strings');
+ }
+ return val;
+ }
+ if (op === '$project') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid $project in pipeline, must be an object');
+ }
+ return val;
+ }
+ if (op === '$addFields' || op === '$set') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid ' + op + ' in pipeline, must be an object');
+ }
+ return val;
+ } else if (op === '$replaceRoot' || op === '$replaceWith') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid ' + op + ' in pipeline, must be an object');
+ }
+ return val;
+ }
+
+ throw new MongooseError('Invalid update pipeline operator: "' + op + '"');
+}
+
+/*!
+ * Walk each path of obj and cast its values
+ * according to its schema.
+ *
+ * @param {Schema} schema
+ * @param {Object} obj - part of a query
+ * @param {String} op - the atomic operator ($pull, $set, etc)
+ * @param {Object} options
+ * @param {Boolean|String} [options.strict]
+ * @param {Boolean} [options.omitUndefined]
+ * @param {Query} context
+ * @param {String} pref - path prefix (internal only)
+ * @return {Bool} true if this path has keys to update
+ * @api private
+ */
+
+function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
+ const strict = options.strict;
+ const prefix = pref ? pref + '.' : '';
+ const keys = Object.keys(obj);
+ let i = keys.length;
+ let hasKeys = false;
+ let schematype;
+ let key;
+ let val;
+
+ let aggregatedError = null;
+
+ let useNestedStrict;
+ if (options.useNestedStrict === undefined) {
+ useNestedStrict = schema.options.useNestedStrict;
+ } else {
+ useNestedStrict = options.useNestedStrict;
+ }
+
+ while (i--) {
+ key = keys[i];
+ val = obj[key];
+
+ // `$pull` is special because we need to cast the RHS as a query, not as
+ // an update.
+ if (op === '$pull') {
+ schematype = schema._getSchema(prefix + key);
+ if (schematype != null && schematype.schema != null) {
+ obj[key] = cast(schematype.schema, obj[key], options, context);
+ hasKeys = true;
+ continue;
+ }
+ }
+
+ if (val && val.constructor.name === 'Object') {
+ // watch for embedded doc schemas
+ schematype = schema._getSchema(prefix + key);
+
+ if (handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
+ continue;
+ }
+
+ if (schematype && schematype.caster && op in castOps) {
+ // embedded doc schema
+ if ('$each' in val) {
+ hasKeys = true;
+ try {
+ obj[key] = {
+ $each: castUpdateVal(schematype, val.$each, op, key, context, prefix + key)
+ };
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (val.$slice != null) {
+ obj[key].$slice = val.$slice | 0;
+ }
+
+ if (val.$sort) {
+ obj[key].$sort = val.$sort;
+ }
+
+ if (val.$position != null) {
+ obj[key].$position = castNumber(val.$position);
+ }
+ } else {
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ }
+ } else if ((op === '$currentDate') || (op in castOps && schematype)) {
+ // $currentDate can take an object
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ } else {
+ const pathToCheck = (prefix + key);
+ const v = schema._getPathType(pathToCheck);
+ let _strict = strict;
+ if (useNestedStrict &&
+ v &&
+ v.schema &&
+ 'strict' in v.schema.options) {
+ _strict = v.schema.options.strict;
+ }
+
+ if (v.pathType === 'undefined') {
+ if (_strict === 'throw') {
+ throw new StrictModeError(pathToCheck);
+ } else if (_strict) {
+ delete obj[key];
+ continue;
+ }
+ }
+
+ // gh-2314
+ // we should be able to set a schema-less field
+ // to an empty object literal
+ hasKeys |= walkUpdatePath(schema, val, op, options, context, filter, prefix + key) ||
+ (utils.isObject(val) && Object.keys(val).length === 0);
+ }
+ } else {
+ const checkPath = (key === '$each' || key === '$or' || key === '$and' || key === '$in') ?
+ pref : prefix + key;
+ schematype = schema._getSchema(checkPath);
+
+ // You can use `$setOnInsert` with immutable keys
+ if (op !== '$setOnInsert' &&
+ handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
+ continue;
+ }
+
+ let pathDetails = schema._getPathType(checkPath);
+
+ // If no schema type, check for embedded discriminators because the
+ // filter or update may imply an embedded discriminator type. See #8378
+ if (schematype == null) {
+ const _res = getEmbeddedDiscriminatorPath(schema, obj, filter, checkPath);
+ if (_res.schematype != null) {
+ schematype = _res.schematype;
+ pathDetails = _res.type;
+ }
+ }
+
+ let isStrict = strict;
+ if (useNestedStrict &&
+ pathDetails &&
+ pathDetails.schema &&
+ 'strict' in pathDetails.schema.options) {
+ isStrict = pathDetails.schema.options.strict;
+ }
+
+ const skip = isStrict &&
+ !schematype &&
+ !/real|nested/.test(pathDetails.pathType);
+
+ if (skip) {
+ // Even if strict is `throw`, avoid throwing an error because of
+ // virtuals because of #6731
+ if (isStrict === 'throw' && schema.virtuals[checkPath] == null) {
+ throw new StrictModeError(prefix + key);
+ } else {
+ delete obj[key];
+ }
+ } else {
+ // gh-1845 temporary fix: ignore $rename. See gh-3027 for tracking
+ // improving this.
+ if (op === '$rename') {
+ hasKeys = true;
+ continue;
+ }
+
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (Array.isArray(obj[key]) && (op === '$addToSet' || op === '$push') && key !== '$each') {
+ if (schematype && schematype.caster && !schematype.caster.$isMongooseArray) {
+ obj[key] = { $each: obj[key] };
+ }
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ }
+ }
+ }
+
+ if (aggregatedError != null) {
+ throw aggregatedError;
+ }
+
+ return hasKeys;
+}
+
+/*!
+ * ignore
+ */
+
+function _handleCastError(error, query, key, aggregatedError) {
+ if (typeof query !== 'object' || !query.options.multipleCastError) {
+ throw error;
+ }
+ aggregatedError = aggregatedError || new ValidationError();
+ aggregatedError.addError(key, error);
+ return aggregatedError;
+}
+
+/*!
+ * These operators should be cast to numbers instead
+ * of their path schema type.
+ */
+
+const numberOps = {
+ $pop: 1,
+ $inc: 1
+};
+
+/*!
+ * These ops require no casting because the RHS doesn't do anything.
+ */
+
+const noCastOps = {
+ $unset: 1
+};
+
+/*!
+ * These operators require casting docs
+ * to real Documents for Update operations.
+ */
+
+const castOps = {
+ $push: 1,
+ $addToSet: 1,
+ $set: 1,
+ $setOnInsert: 1
+};
+
+/*!
+ * ignore
+ */
+
+const overwriteOps = {
+ $set: 1,
+ $setOnInsert: 1
+};
+
+/*!
+ * Casts `val` according to `schema` and atomic `op`.
+ *
+ * @param {SchemaType} schema
+ * @param {Object} val
+ * @param {String} op - the atomic operator ($pull, $set, etc)
+ * @param {String} $conditional
+ * @param {Query} context
+ * @api private
+ */
+
+function castUpdateVal(schema, val, op, $conditional, context, path) {
+ if (!schema) {
+ // non-existing schema path
+ if (op in numberOps) {
+ try {
+ return castNumber(val);
+ } catch (err) {
+ throw new CastError('number', val, path);
+ }
+ }
+ return val;
+ }
+
+ const cond = schema.caster && op in castOps &&
+ (utils.isObject(val) || Array.isArray(val));
+ if (cond && !overwriteOps[op]) {
+ // Cast values for ops that add data to MongoDB.
+ // Ensures embedded documents get ObjectIds etc.
+ let schemaArrayDepth = 0;
+ let cur = schema;
+ while (cur.$isMongooseArray) {
+ ++schemaArrayDepth;
+ cur = cur.caster;
+ }
+ let arrayDepth = 0;
+ let _val = val;
+ while (Array.isArray(_val)) {
+ ++arrayDepth;
+ _val = _val[0];
+ }
+
+ const additionalNesting = schemaArrayDepth - arrayDepth;
+ while (arrayDepth < schemaArrayDepth) {
+ val = [val];
+ ++arrayDepth;
+ }
+
+ let tmp = schema.applySetters(Array.isArray(val) ? val : [val], context);
+
+ for (let i = 0; i < additionalNesting; ++i) {
+ tmp = tmp[0];
+ }
+ return tmp;
+ }
+
+ if (op in noCastOps) {
+ return val;
+ }
+ if (op in numberOps) {
+ // Null and undefined not allowed for $pop, $inc
+ if (val == null) {
+ throw new CastError('number', val, schema.path);
+ }
+ if (op === '$inc') {
+ // Support `$inc` with long, int32, etc. (gh-4283)
+ return schema.castForQueryWrapper({
+ val: val,
+ context: context
+ });
+ }
+ try {
+ return castNumber(val);
+ } catch (error) {
+ throw new CastError('number', val, schema.path);
+ }
+ }
+ if (op === '$currentDate') {
+ if (typeof val === 'object') {
+ return { $type: val.$type };
+ }
+ return Boolean(val);
+ }
+
+ if (/^\$/.test($conditional)) {
+ return schema.castForQueryWrapper({
+ $conditional: $conditional,
+ val: val,
+ context: context
+ });
+ }
+
+ if (overwriteOps[op]) {
+ return schema.castForQueryWrapper({
+ val: val,
+ context: context,
+ $skipQueryCastForUpdate: val != null && schema.$isMongooseArray && schema.$fullPath != null && !schema.$fullPath.match(/\d+$/),
+ $applySetters: schema[schemaMixedSymbol] != null
+ });
+ }
+
+ return schema.castForQueryWrapper({ val: val, context: context });
+}
diff --git a/node_modules/mongoose/lib/helpers/query/completeMany.js b/node_modules/mongoose/lib/helpers/query/completeMany.js
new file mode 100644
index 0000000..aabe596
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/completeMany.js
@@ -0,0 +1,47 @@
+'use strict';
+
+const helpers = require('../../queryhelpers');
+
+module.exports = completeMany;
+
+/*!
+ * Given a model and an array of docs, hydrates all the docs to be instances
+ * of the model. Used to initialize docs returned from the db from `find()`
+ *
+ * @param {Model} model
+ * @param {Array} docs
+ * @param {Object} fields the projection used, including `select` from schemas
+ * @param {Object} userProvidedFields the user-specified projection
+ * @param {Object} opts
+ * @param {Array} [opts.populated]
+ * @param {ClientSession} [opts.session]
+ * @param {Function} callback
+ */
+
+function completeMany(model, docs, fields, userProvidedFields, opts, callback) {
+ const arr = [];
+ let count = docs.length;
+ const len = count;
+ let error = null;
+
+ function init(_error) {
+ if (_error != null) {
+ error = error || _error;
+ }
+ if (error != null) {
+ --count || process.nextTick(() => callback(error));
+ return;
+ }
+ --count || process.nextTick(() => callback(error, arr));
+ }
+
+ for (let i = 0; i < len; ++i) {
+ arr[i] = helpers.createModel(model, docs[i], fields, userProvidedFields);
+ try {
+ arr[i].init(docs[i], opts, init);
+ } catch (error) {
+ init(error);
+ }
+ arr[i].$session(opts.session);
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js b/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js
new file mode 100644
index 0000000..ff297ac
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js
@@ -0,0 +1,65 @@
+'use strict';
+
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const get = require('../get');
+
+/*!
+ * Like `schema.path()`, except with a document, because impossible to
+ * determine path type without knowing the embedded discriminator key.
+ */
+
+module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, path) {
+ const parts = path.split('.');
+ let schematype = null;
+ let type = 'adhocOrUndefined';
+
+ filter = filter || {};
+ update = update || {};
+
+ for (let i = 0; i < parts.length; ++i) {
+ const subpath = cleanPositionalOperators(parts.slice(0, i + 1).join('.'));
+ schematype = schema.path(subpath);
+ if (schematype == null) {
+ continue;
+ }
+
+ type = schema.pathType(subpath);
+ if ((schematype.$isSingleNested || schematype.$isMongooseDocumentArrayElement) &&
+ schematype.schema.discriminators != null) {
+ const discriminators = schematype.schema.discriminators;
+ const key = get(schematype, 'schema.options.discriminatorKey');
+ const discriminatorValuePath = subpath + '.' + key;
+ const discriminatorFilterPath =
+ discriminatorValuePath.replace(/\.\d+\./, '.');
+ let discriminatorKey = null;
+
+ if (discriminatorValuePath in filter) {
+ discriminatorKey = filter[discriminatorValuePath];
+ }
+ if (discriminatorFilterPath in filter) {
+ discriminatorKey = filter[discriminatorFilterPath];
+ }
+ const wrapperPath = subpath.replace(/\.\d+$/, '');
+ if (schematype.$isMongooseDocumentArrayElement &&
+ get(filter[wrapperPath], '$elemMatch.' + key) != null) {
+ discriminatorKey = filter[wrapperPath].$elemMatch[key];
+ }
+
+ if (discriminatorValuePath in update) {
+ discriminatorKey = update[discriminatorValuePath];
+ }
+
+ if (discriminatorKey == null || discriminators[discriminatorKey] == null) {
+ continue;
+ }
+ const rest = parts.slice(i + 1).join('.');
+ schematype = discriminators[discriminatorKey].path(rest);
+ if (schematype != null) {
+ type = discriminators[discriminatorKey]._getPathType(rest);
+ break;
+ }
+ }
+ }
+
+ return { type: type, schematype: schematype };
+};
diff --git a/node_modules/mongoose/lib/helpers/query/handleImmutable.js b/node_modules/mongoose/lib/helpers/query/handleImmutable.js
new file mode 100644
index 0000000..22adb3c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/handleImmutable.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const StrictModeError = require('../../error/strict');
+
+module.exports = function handleImmutable(schematype, strict, obj, key, fullPath, ctx) {
+ if (schematype == null || !schematype.options || !schematype.options.immutable) {
+ return false;
+ }
+ let immutable = schematype.options.immutable;
+
+ if (typeof immutable === 'function') {
+ immutable = immutable.call(ctx, ctx);
+ }
+ if (!immutable) {
+ return false;
+ }
+
+ if (strict === false) {
+ return false;
+ }
+ if (strict === 'throw') {
+ throw new StrictModeError(null,
+ `Field ${fullPath} is immutable and strict = 'throw'`);
+ }
+
+ delete obj[key];
+ return true;
+};
diff --git a/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js b/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js
new file mode 100644
index 0000000..958e1c9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js
@@ -0,0 +1,19 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function(obj) {
+ if (obj == null) {
+ return false;
+ }
+ const keys = Object.keys(obj);
+ const len = keys.length;
+ for (let i = 0; i < len; ++i) {
+ if (keys[i].startsWith('$')) {
+ return true;
+ }
+ }
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/query/isOperator.js b/node_modules/mongoose/lib/helpers/query/isOperator.js
new file mode 100644
index 0000000..3b98139
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/isOperator.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const specialKeys = new Set([
+ '$ref',
+ '$id',
+ '$db'
+]);
+
+module.exports = function isOperator(path) {
+ return path.startsWith('$') && !specialKeys.has(path);
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js b/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js
new file mode 100644
index 0000000..15f7e99
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js
@@ -0,0 +1,46 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function selectPopulatedFields(query) {
+ const opts = query._mongooseOptions;
+
+ if (opts.populate != null) {
+ const paths = Object.keys(opts.populate);
+ const userProvidedFields = query._userProvidedFields || {};
+ if (query.selectedInclusively()) {
+ for (let i = 0; i < paths.length; ++i) {
+ if (!isPathInFields(userProvidedFields, paths[i])) {
+ query.select(paths[i]);
+ } else if (userProvidedFields[paths[i]] === 0) {
+ delete query._fields[paths[i]];
+ }
+ }
+ } else if (query.selectedExclusively()) {
+ for (let i = 0; i < paths.length; ++i) {
+ if (userProvidedFields[paths[i]] == null) {
+ delete query._fields[paths[i]];
+ }
+ }
+ }
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function isPathInFields(userProvidedFields, path) {
+ const pieces = path.split('.');
+ const len = pieces.length;
+ let cur = pieces[0];
+ for (let i = 1; i < len; ++i) {
+ if (userProvidedFields[cur] != null) {
+ return true;
+ }
+ cur += '.' + pieces[i];
+ }
+ return userProvidedFields[cur] != null;
+}
diff --git a/node_modules/mongoose/lib/helpers/query/wrapThunk.js b/node_modules/mongoose/lib/helpers/query/wrapThunk.js
new file mode 100644
index 0000000..0005c33
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/wrapThunk.js
@@ -0,0 +1,18 @@
+'use strict';
+
+/*!
+ * A query thunk is the function responsible for sending the query to MongoDB,
+ * like `Query#_findOne()` or `Query#_execUpdate()`. The `Query#exec()` function
+ * calls a thunk. The term "thunk" here is the traditional Node.js definition:
+ * a function that takes exactly 1 parameter, a callback.
+ *
+ * This function defines common behavior for all query thunks.
+ */
+
+module.exports = function wrapThunk(fn) {
+ return function _wrappedThunk(cb) {
+ ++this._executionCount;
+
+ fn.call(this, cb);
+ };
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/addAutoId.js b/node_modules/mongoose/lib/helpers/schema/addAutoId.js
new file mode 100644
index 0000000..11a1f23
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/addAutoId.js
@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = function addAutoId(schema) {
+ const _obj = { _id: { auto: true } };
+ _obj._id[schema.options.typeKey] = 'ObjectId';
+ schema.add(_obj);
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/applyPlugins.js b/node_modules/mongoose/lib/helpers/schema/applyPlugins.js
new file mode 100644
index 0000000..1bc7727
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/applyPlugins.js
@@ -0,0 +1,45 @@
+'use strict';
+
+module.exports = function applyPlugins(schema, plugins, options, cacheKey) {
+ if (schema[cacheKey]) {
+ return;
+ }
+ schema[cacheKey] = true;
+
+ if (!options || !options.skipTopLevel) {
+ for (let i = 0; i < plugins.length; ++i) {
+ schema.plugin(plugins[i][0], plugins[i][1]);
+ }
+ }
+
+ options = Object.assign({}, options);
+ delete options.skipTopLevel;
+
+ if (options.applyPluginsToChildSchemas !== false) {
+ for (const path of Object.keys(schema.paths)) {
+ const type = schema.paths[path];
+ if (type.schema != null) {
+ applyPlugins(type.schema, plugins, options, cacheKey);
+
+ // Recompile schema because plugins may have changed it, see gh-7572
+ type.caster.prototype.$__setSchema(type.schema);
+ }
+ }
+ }
+
+ const discriminators = schema.discriminators;
+ if (discriminators == null) {
+ return;
+ }
+
+ const applyPluginsToDiscriminators = options.applyPluginsToDiscriminators;
+
+ const keys = Object.keys(discriminators);
+ for (let i = 0; i < keys.length; ++i) {
+ const discriminatorKey = keys[i];
+ const discriminatorSchema = discriminators[discriminatorKey];
+
+ applyPlugins(discriminatorSchema, plugins,
+ { skipTopLevel: !applyPluginsToDiscriminators }, cacheKey);
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js b/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js
new file mode 100644
index 0000000..168156d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const get = require('../get');
+
+module.exports = function applyWriteConcern(schema, options) {
+ const writeConcern = get(schema, 'options.writeConcern', {});
+ if (!('w' in options) && writeConcern.w != null) {
+ options.w = writeConcern.w;
+ }
+ if (!('j' in options) && writeConcern.j != null) {
+ options.j = writeConcern.j;
+ }
+ if (!('wtimeout' in options) && writeConcern.wtimeout != null) {
+ options.wtimeout = writeConcern.wtimeout;
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js b/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js
new file mode 100644
index 0000000..b467be4
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/**
+ * For consistency's sake, we replace positional operator `$` and array filters
+ * `$[]` and `$[foo]` with `0` when looking up schema paths.
+ */
+
+module.exports = function cleanPositionalOperators(path) {
+ return path.
+ replace(/\.\$(\[[^\]]*\])?\./g, '.0.').
+ replace(/\.(\[[^\]]*\])?\$$/g, '.0');
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/getIndexes.js b/node_modules/mongoose/lib/helpers/schema/getIndexes.js
new file mode 100644
index 0000000..bb33999
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/getIndexes.js
@@ -0,0 +1,142 @@
+'use strict';
+
+const get = require('../get');
+const helperIsObject = require('../isObject');
+
+/*!
+ * Gather all indexes defined in the schema, including single nested,
+ * document arrays, and embedded discriminators.
+ */
+
+module.exports = function getIndexes(schema) {
+ let indexes = [];
+ const schemaStack = new WeakMap();
+ const indexTypes = schema.constructor.indexTypes;
+ const indexByName = new Map();
+
+ const collectIndexes = function(schema, prefix, baseSchema) {
+ // Ignore infinitely nested schemas, if we've already seen this schema
+ // along this path there must be a cycle
+ if (schemaStack.has(schema)) {
+ return;
+ }
+ schemaStack.set(schema, true);
+
+ prefix = prefix || '';
+ const keys = Object.keys(schema.paths);
+ const length = keys.length;
+
+ for (let i = 0; i < length; ++i) {
+ const key = keys[i];
+ const path = schema.paths[key];
+ if (baseSchema != null && baseSchema.paths[key]) {
+ // If looking at an embedded discriminator schema, don't look at paths
+ // that the
+ continue;
+ }
+
+ if (path.$isMongooseDocumentArray || path.$isSingleNested) {
+ if (get(path, 'options.excludeIndexes') !== true &&
+ get(path, 'schemaOptions.excludeIndexes') !== true &&
+ get(path, 'schema.options.excludeIndexes') !== true) {
+ collectIndexes(path.schema, prefix + key + '.');
+ }
+
+ if (path.schema.discriminators != null) {
+ const discriminators = path.schema.discriminators;
+ const discriminatorKeys = Object.keys(discriminators);
+ for (const discriminatorKey of discriminatorKeys) {
+ collectIndexes(discriminators[discriminatorKey],
+ prefix + key + '.', path.schema);
+ }
+ }
+
+ // Retained to minimize risk of backwards breaking changes due to
+ // gh-6113
+ if (path.$isMongooseDocumentArray) {
+ continue;
+ }
+ }
+
+ const index = path._index || (path.caster && path.caster._index);
+
+ if (index !== false && index !== null && index !== undefined) {
+ const field = {};
+ const isObject = helperIsObject(index);
+ const options = isObject ? index : {};
+ const type = typeof index === 'string' ? index :
+ isObject ? index.type :
+ false;
+
+ if (type && indexTypes.indexOf(type) !== -1) {
+ field[prefix + key] = type;
+ } else if (options.text) {
+ field[prefix + key] = 'text';
+ delete options.text;
+ } else {
+ field[prefix + key] = 1;
+ }
+
+ delete options.type;
+ if (!('background' in options)) {
+ options.background = true;
+ }
+
+ const indexName = options && options.name;
+ if (typeof indexName === 'string') {
+ if (indexByName.has(indexName)) {
+ Object.assign(indexByName.get(indexName), field);
+ } else {
+ indexes.push([field, options]);
+ indexByName.set(indexName, field);
+ }
+ } else {
+ indexes.push([field, options]);
+ indexByName.set(indexName, field);
+ }
+ }
+ }
+
+ schemaStack.delete(schema);
+
+ if (prefix) {
+ fixSubIndexPaths(schema, prefix);
+ } else {
+ schema._indexes.forEach(function(index) {
+ if (!('background' in index[1])) {
+ index[1].background = true;
+ }
+ });
+ indexes = indexes.concat(schema._indexes);
+ }
+ };
+
+ collectIndexes(schema);
+ return indexes;
+
+ /*!
+ * Checks for indexes added to subdocs using Schema.index().
+ * These indexes need their paths prefixed properly.
+ *
+ * schema._indexes = [ [indexObj, options], [indexObj, options] ..]
+ */
+
+ function fixSubIndexPaths(schema, prefix) {
+ const subindexes = schema._indexes;
+ const len = subindexes.length;
+ for (let i = 0; i < len; ++i) {
+ const indexObj = subindexes[i][0];
+ const keys = Object.keys(indexObj);
+ const klen = keys.length;
+ const newindex = {};
+
+ // use forward iteration, order matters
+ for (let j = 0; j < klen; ++j) {
+ const key = keys[j];
+ newindex[prefix + key] = indexObj[key];
+ }
+
+ indexes.push([newindex, subindexes[i][1]]);
+ }
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/schema/getPath.js b/node_modules/mongoose/lib/helpers/schema/getPath.js
new file mode 100644
index 0000000..ccbc67c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/getPath.js
@@ -0,0 +1,35 @@
+'use strict';
+
+/*!
+ * Behaves like `Schema#path()`, except for it also digs into arrays without
+ * needing to put `.0.`, so `getPath(schema, 'docArr.elProp')` works.
+ */
+
+module.exports = function getPath(schema, path) {
+ let schematype = schema.path(path);
+ if (schematype != null) {
+ return schematype;
+ }
+
+ const pieces = path.split('.');
+ let cur = '';
+ let isArray = false;
+
+ for (const piece of pieces) {
+ if (/^\d+$/.test(piece) && isArray) {
+ continue;
+ }
+ cur = cur.length === 0 ? piece : cur + '.' + piece;
+
+ schematype = schema.path(cur);
+ if (schematype != null && schematype.schema) {
+ schema = schematype.schema;
+ cur = '';
+ if (schematype.$isMongooseDocumentArray) {
+ isArray = true;
+ }
+ }
+ }
+
+ return schematype;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/handleIdOption.js b/node_modules/mongoose/lib/helpers/schema/handleIdOption.js
new file mode 100644
index 0000000..569bf9f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/handleIdOption.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const addAutoId = require('./addAutoId');
+
+module.exports = function handleIdOption(schema, options) {
+ if (options == null || options._id == null) {
+ return schema;
+ }
+
+ schema = schema.clone();
+ if (!options._id) {
+ schema.remove('_id');
+ schema.options._id = false;
+ } else if (!schema.paths['_id']) {
+ addAutoId(schema);
+ schema.options._id = true;
+ }
+
+ return schema;
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js b/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js
new file mode 100644
index 0000000..1551b7c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js
@@ -0,0 +1,24 @@
+'use strict';
+
+module.exports = handleTimestampOption;
+
+/*!
+ * ignore
+ */
+
+function handleTimestampOption(arg, prop) {
+ if (arg == null) {
+ return null;
+ }
+
+ if (typeof arg === 'boolean') {
+ return prop;
+ }
+ if (typeof arg[prop] === 'boolean') {
+ return arg[prop] ? prop : null;
+ }
+ if (!(prop in arg)) {
+ return prop;
+ }
+ return arg[prop];
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/merge.js b/node_modules/mongoose/lib/helpers/schema/merge.js
new file mode 100644
index 0000000..d206500
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/merge.js
@@ -0,0 +1,19 @@
+'use strict';
+
+module.exports = function merge(s1, s2) {
+ s1.add(s2.tree || {});
+
+ s1.callQueue = s1.callQueue.concat(s2.callQueue);
+ s1.method(s2.methods);
+ s1.static(s2.statics);
+
+ for (const query in s2.query) {
+ s1.query[query] = s2.query[query];
+ }
+
+ for (const virtual in s2.virtuals) {
+ s1.virtuals[virtual] = s2.virtuals[virtual].clone();
+ }
+
+ s1.s.hooks.merge(s2.s.hooks, false);
+};
diff --git a/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js b/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js
new file mode 100644
index 0000000..14f647a
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const StrictModeError = require('../../error/strict');
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schematype) {
+ if (schematype.$immutable) {
+ schematype.$immutableSetter = createImmutableSetter(schematype.path,
+ schematype.options.immutable);
+ schematype.set(schematype.$immutableSetter);
+ } else if (schematype.$immutableSetter) {
+ schematype.setters = schematype.setters.
+ filter(fn => fn !== schematype.$immutableSetter);
+ delete schematype.$immutableSetter;
+ }
+};
+
+function createImmutableSetter(path, immutable) {
+ return function immutableSetter(v) {
+ if (this == null || this.$__ == null) {
+ return v;
+ }
+ if (this.isNew) {
+ return v;
+ }
+
+ const _immutable = typeof immutable === 'function' ?
+ immutable.call(this, this) :
+ immutable;
+ if (!_immutable) {
+ return v;
+ }
+ if (this.$__.strictMode === 'throw' && v !== this[path]) {
+ throw new StrictModeError(path, 'Path `' + path + '` is immutable ' +
+ 'and strict mode is set to throw.', true);
+ }
+
+ return this[path];
+ };
+}
diff --git a/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js b/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js
new file mode 100644
index 0000000..0545e80
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js
@@ -0,0 +1,120 @@
+'use strict';
+
+const modifiedPaths = require('./common').modifiedPaths;
+
+/**
+ * Applies defaults to update and findOneAndUpdate operations.
+ *
+ * @param {Object} filter
+ * @param {Schema} schema
+ * @param {Object} castedDoc
+ * @param {Object} options
+ * @method setDefaultsOnInsert
+ * @api private
+ */
+
+module.exports = function(filter, schema, castedDoc, options) {
+ const keys = Object.keys(castedDoc || {});
+ const updatedKeys = {};
+ const updatedValues = {};
+ const numKeys = keys.length;
+ const modified = {};
+
+ let hasDollarUpdate = false;
+
+ options = options || {};
+
+ if (!options.upsert || !options.setDefaultsOnInsert) {
+ return castedDoc;
+ }
+
+ for (let i = 0; i < numKeys; ++i) {
+ if (keys[i].startsWith('$')) {
+ modifiedPaths(castedDoc[keys[i]], '', modified);
+ hasDollarUpdate = true;
+ }
+ }
+
+ if (!hasDollarUpdate) {
+ modifiedPaths(castedDoc, '', modified);
+ }
+
+ const paths = Object.keys(filter);
+ const numPaths = paths.length;
+ for (let i = 0; i < numPaths; ++i) {
+ const path = paths[i];
+ const condition = filter[path];
+ if (condition && typeof condition === 'object') {
+ const conditionKeys = Object.keys(condition);
+ const numConditionKeys = conditionKeys.length;
+ let hasDollarKey = false;
+ for (let j = 0; j < numConditionKeys; ++j) {
+ if (conditionKeys[j].startsWith('$')) {
+ hasDollarKey = true;
+ break;
+ }
+ }
+ if (hasDollarKey) {
+ continue;
+ }
+ }
+ updatedKeys[path] = true;
+ modified[path] = true;
+ }
+
+ if (options && options.overwrite && !hasDollarUpdate) {
+ // Defaults will be set later, since we're overwriting we'll cast
+ // the whole update to a document
+ return castedDoc;
+ }
+
+ schema.eachPath(function(path, schemaType) {
+ // Skip single nested paths if underneath a map
+ const isUnderneathMap = schemaType.path.endsWith('.$*') ||
+ schemaType.path.indexOf('.$*.') !== -1;
+ if (schemaType.$isSingleNested && !isUnderneathMap) {
+ // Only handle nested schemas 1-level deep to avoid infinite
+ // recursion re: https://github.com/mongodb-js/mongoose-autopopulate/issues/11
+ schemaType.schema.eachPath(function(_path, _schemaType) {
+ if (_path === '_id' && _schemaType.auto) {
+ // Ignore _id if auto id so we don't create subdocs
+ return;
+ }
+
+ const def = _schemaType.getDefault(null, true);
+ if (!isModified(modified, path + '.' + _path) &&
+ typeof def !== 'undefined') {
+ castedDoc = castedDoc || {};
+ castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
+ castedDoc.$setOnInsert[path + '.' + _path] = def;
+ updatedValues[path + '.' + _path] = def;
+ }
+ });
+ } else {
+ const def = schemaType.getDefault(null, true);
+ if (!isModified(modified, path) && typeof def !== 'undefined') {
+ castedDoc = castedDoc || {};
+ castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
+ castedDoc.$setOnInsert[path] = def;
+ updatedValues[path] = def;
+ }
+ }
+ });
+
+ return castedDoc;
+};
+
+function isModified(modified, path) {
+ if (modified[path]) {
+ return true;
+ }
+ const sp = path.split('.');
+ let cur = sp[0];
+ for (let i = 1; i < sp.length; ++i) {
+ if (modified[cur]) {
+ return true;
+ }
+ cur += '.' + sp[i];
+ }
+ return false;
+}
diff --git a/node_modules/mongoose/lib/helpers/specialProperties.js b/node_modules/mongoose/lib/helpers/specialProperties.js
new file mode 100644
index 0000000..1e1aca5
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/specialProperties.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = new Set(['__proto__', 'constructor', 'prototype']);
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/symbols.js b/node_modules/mongoose/lib/helpers/symbols.js
new file mode 100644
index 0000000..3860f23
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/symbols.js
@@ -0,0 +1,14 @@
+'use strict';
+
+exports.arrayAtomicsSymbol = Symbol('mongoose#Array#_atomics');
+exports.arrayParentSymbol = Symbol('mongoose#Array#_parent');
+exports.arrayPathSymbol = Symbol('mongoose#Array#_path');
+exports.arraySchemaSymbol = Symbol('mongoose#Array#_schema');
+exports.documentArrayParent = Symbol('mongoose:documentArrayParent');
+exports.documentSchemaSymbol = Symbol('mongoose#Document#schema');
+exports.getSymbol = Symbol('mongoose#Document#get');
+exports.modelSymbol = Symbol('mongoose#Model');
+exports.objectIdSymbol = Symbol('mongoose#ObjectId');
+exports.populateModelSymbol = Symbol('mongoose.PopulateOptions#Model');
+exports.schemaTypeSymbol = Symbol('mongoose#schemaType');
+exports.validatorErrorSymbol = Symbol('mongoose:validatorError');
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js b/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js
new file mode 100644
index 0000000..4ab9719
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js
@@ -0,0 +1,180 @@
+'use strict';
+
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const handleTimestampOption = require('../schema/handleTimestampOption');
+
+module.exports = applyTimestampsToChildren;
+
+/*!
+ * ignore
+ */
+
+function applyTimestampsToChildren(now, update, schema) {
+ if (update == null) {
+ return;
+ }
+
+ const keys = Object.keys(update);
+ let key;
+ let createdAt;
+ let updatedAt;
+ let timestamps;
+ let path;
+
+ const hasDollarKey = keys.length && keys[0].startsWith('$');
+
+ if (hasDollarKey) {
+ if (update.$push) {
+ for (key in update.$push) {
+ const $path = schema.path(key);
+ if (update.$push[key] &&
+ $path &&
+ $path.$isMongooseDocumentArray &&
+ $path.schema.options.timestamps) {
+ timestamps = $path.schema.options.timestamps;
+ createdAt = handleTimestampOption(timestamps, 'createdAt');
+ updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ if (update.$push[key].$each) {
+ update.$push[key].$each.forEach(function(subdoc) {
+ if (updatedAt != null) {
+ subdoc[updatedAt] = now;
+ }
+ if (createdAt != null) {
+ subdoc[createdAt] = now;
+ }
+ });
+ } else {
+ if (updatedAt != null) {
+ update.$push[key][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ update.$push[key][createdAt] = now;
+ }
+ }
+ }
+ }
+ }
+ if (update.$set != null) {
+ const keys = Object.keys(update.$set);
+ for (key of keys) {
+ // Replace positional operator `$` and array filters `$[]` and `$[.*]`
+ const keyToSearch = cleanPositionalOperators(key);
+ path = schema.path(keyToSearch);
+ if (!path) {
+ continue;
+ }
+
+ let parentSchemaType = null;
+ const pieces = keyToSearch.split('.');
+ for (let i = pieces.length - 1; i > 0; --i) {
+ const s = schema.path(pieces.slice(0, i).join('.'));
+ if (s != null &&
+ (s.$isMongooseDocumentArray || s.$isSingleNested)) {
+ parentSchemaType = s;
+ break;
+ }
+ }
+
+ if (Array.isArray(update.$set[key]) && path.$isMongooseDocumentArray) {
+ applyTimestampsToDocumentArray(update.$set[key], path, now);
+ } else if (update.$set[key] && path.$isSingleNested) {
+ applyTimestampsToSingleNested(update.$set[key], path, now);
+ } else if (parentSchemaType != null) {
+ timestamps = parentSchemaType.schema.options.timestamps;
+ createdAt = handleTimestampOption(timestamps, 'createdAt');
+ updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+
+ if (!timestamps || updatedAt == null) {
+ continue;
+ }
+
+ if (parentSchemaType.$isSingleNested) {
+ // Single nested is easy
+ update.$set[parentSchemaType.path + '.' + updatedAt] = now;
+ continue;
+ }
+
+ let childPath = key.substr(parentSchemaType.path.length + 1);
+
+ if (/^\d+$/.test(childPath)) {
+ update.$set[parentSchemaType.path + '.' + childPath][updatedAt] = now;
+ continue;
+ }
+
+ const firstDot = childPath.indexOf('.');
+ childPath = firstDot !== -1 ? childPath.substr(0, firstDot) : childPath;
+
+ update.$set[parentSchemaType.path + '.' + childPath + '.' + updatedAt] = now;
+ } else if (path.schema != null && path.schema != schema && update.$set[key]) {
+ timestamps = path.schema.options.timestamps;
+ createdAt = handleTimestampOption(timestamps, 'createdAt');
+ updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+
+ if (!timestamps) {
+ continue;
+ }
+
+ if (updatedAt != null) {
+ update.$set[key][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ update.$set[key][createdAt] = now;
+ }
+ }
+ }
+ }
+ } else {
+ const keys = Object.keys(update).filter(key => !key.startsWith('$'));
+ for (key of keys) {
+ // Replace positional operator `$` and array filters `$[]` and `$[.*]`
+ const keyToSearch = cleanPositionalOperators(key);
+ path = schema.path(keyToSearch);
+ if (!path) {
+ continue;
+ }
+
+ if (Array.isArray(update[key]) && path.$isMongooseDocumentArray) {
+ applyTimestampsToDocumentArray(update[key], path, now);
+ } else if (update[key] != null && path.$isSingleNested) {
+ applyTimestampsToSingleNested(update[key], path, now);
+ }
+ }
+ }
+}
+
+function applyTimestampsToDocumentArray(arr, schematype, now) {
+ const timestamps = schematype.schema.options.timestamps;
+
+ if (!timestamps) {
+ return;
+ }
+
+ const len = arr.length;
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ for (let i = 0; i < len; ++i) {
+ if (updatedAt != null) {
+ arr[i][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ arr[i][createdAt] = now;
+ }
+ }
+}
+
+function applyTimestampsToSingleNested(subdoc, schematype, now) {
+ const timestamps = schematype.schema.options.timestamps;
+ if (!timestamps) {
+ return;
+ }
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ if (updatedAt != null) {
+ subdoc[updatedAt] = now;
+ }
+ if (createdAt != null) {
+ subdoc[createdAt] = now;
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js b/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js
new file mode 100644
index 0000000..7318232
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js
@@ -0,0 +1,78 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+const get = require('../get');
+
+module.exports = applyTimestampsToUpdate;
+
+/*!
+ * ignore
+ */
+
+function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options) {
+ const updates = currentUpdate;
+ let _updates = updates;
+ const overwrite = get(options, 'overwrite', false);
+ const timestamps = get(options, 'timestamps', true);
+
+ // Support skipping timestamps at the query level, see gh-6980
+ if (!timestamps || updates == null) {
+ return currentUpdate;
+ }
+
+ const skipCreatedAt = timestamps != null && timestamps.createdAt === false;
+ const skipUpdatedAt = timestamps != null && timestamps.updatedAt === false;
+
+ if (overwrite) {
+ if (currentUpdate && currentUpdate.$set) {
+ currentUpdate = currentUpdate.$set;
+ updates.$set = {};
+ _updates = updates.$set;
+ }
+ if (!skipUpdatedAt && updatedAt && !currentUpdate[updatedAt]) {
+ _updates[updatedAt] = now;
+ }
+ if (!skipCreatedAt && createdAt && !currentUpdate[createdAt]) {
+ _updates[createdAt] = now;
+ }
+ return updates;
+ }
+ currentUpdate = currentUpdate || {};
+
+ if (Array.isArray(updates)) {
+ // Update with aggregation pipeline
+ updates.push({ $set: { updatedAt: now } });
+
+ return updates;
+ }
+
+ updates.$set = updates.$set || {};
+ if (!skipUpdatedAt && updatedAt &&
+ (!currentUpdate.$currentDate || !currentUpdate.$currentDate[updatedAt])) {
+ updates.$set[updatedAt] = now;
+ if (updates.hasOwnProperty(updatedAt)) {
+ delete updates[updatedAt];
+ }
+ }
+
+ if (!skipCreatedAt && createdAt) {
+ if (currentUpdate[createdAt]) {
+ delete currentUpdate[createdAt];
+ }
+ if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
+ delete currentUpdate.$set[createdAt];
+ }
+
+ updates.$setOnInsert = updates.$setOnInsert || {};
+ updates.$setOnInsert[createdAt] = now;
+ }
+
+ if (Object.keys(updates.$set).length === 0) {
+ delete updates.$set;
+ }
+
+ return updates;
+}
diff --git a/node_modules/mongoose/lib/helpers/update/castArrayFilters.js b/node_modules/mongoose/lib/helpers/update/castArrayFilters.js
new file mode 100644
index 0000000..471fda3
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/castArrayFilters.js
@@ -0,0 +1,77 @@
+'use strict';
+
+const castFilterPath = require('../query/castFilterPath');
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const getPath = require('../schema/getPath');
+const modifiedPaths = require('./modifiedPaths');
+
+module.exports = function castArrayFilters(query) {
+ const arrayFilters = query.options.arrayFilters;
+ if (!Array.isArray(arrayFilters)) {
+ return;
+ }
+
+ const update = query.getUpdate();
+ const schema = query.schema;
+ const strictQuery = schema.options.strictQuery;
+
+ const updatedPaths = modifiedPaths(update);
+
+ const updatedPathsByFilter = Object.keys(updatedPaths).reduce((cur, path) => {
+ const matches = path.match(/\$\[[^\]]+\]/g);
+ if (matches == null) {
+ return cur;
+ }
+ for (const match of matches) {
+ const firstMatch = path.indexOf(match);
+ if (firstMatch !== path.lastIndexOf(match)) {
+ throw new Error(`Path '${path}' contains the same array filter multiple times`);
+ }
+ cur[match.substring(2, match.length - 1)] = path.
+ substr(0, firstMatch - 1).
+ replace(/\$\[[^\]]+\]/g, '0');
+ }
+ return cur;
+ }, {});
+
+ for (const filter of arrayFilters) {
+ if (filter == null) {
+ throw new Error(`Got null array filter in ${arrayFilters}`);
+ }
+ const firstKey = Object.keys(filter)[0];
+
+ if (filter[firstKey] == null) {
+ continue;
+ }
+
+ const dot = firstKey.indexOf('.');
+ let filterPath = dot === -1 ?
+ updatedPathsByFilter[firstKey] + '.0' :
+ updatedPathsByFilter[firstKey.substr(0, dot)] + '.0' + firstKey.substr(dot);
+
+ if (filterPath == null) {
+ throw new Error(`Filter path not found for ${firstKey}`);
+ }
+
+ // If there are multiple array filters in the path being updated, make sure
+ // to replace them so we can get the schema path.
+ filterPath = cleanPositionalOperators(filterPath);
+
+ const schematype = getPath(schema, filterPath);
+ if (schematype == null) {
+ if (!strictQuery) {
+ return;
+ }
+ // For now, treat `strictQuery = true` and `strictQuery = 'throw'` as
+ // equivalent for casting array filters. `strictQuery = true` doesn't
+ // quite work in this context because we never want to silently strip out
+ // array filters, even if the path isn't in the schema.
+ throw new Error(`Could not find path "${filterPath}" in schema`);
+ }
+ if (typeof filter[firstKey] === 'object') {
+ filter[firstKey] = castFilterPath(query, schematype, filter[firstKey]);
+ } else {
+ filter[firstKey] = schematype.castForQuery(filter[firstKey]);
+ }
+ }
+};
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/modifiedPaths.js b/node_modules/mongoose/lib/helpers/update/modifiedPaths.js
new file mode 100644
index 0000000..9cb567d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/modifiedPaths.js
@@ -0,0 +1,33 @@
+'use strict';
+
+const _modifiedPaths = require('../common').modifiedPaths;
+
+/**
+ * Given an update document with potential update operators (`$set`, etc.)
+ * returns an object whose keys are the directly modified paths.
+ *
+ * If there are any top-level keys that don't start with `$`, we assume those
+ * will get wrapped in a `$set`. The Mongoose Query is responsible for wrapping
+ * top-level keys in `$set`.
+ *
+ * @param {Object} update
+ * @return {Object} modified
+ */
+
+module.exports = function modifiedPaths(update) {
+ const keys = Object.keys(update);
+ const res = {};
+
+ const withoutDollarKeys = {};
+ for (const key of keys) {
+ if (key.startsWith('$')) {
+ _modifiedPaths(update[key], '', res);
+ continue;
+ }
+ withoutDollarKeys[key] = update[key];
+ }
+
+ _modifiedPaths(withoutDollarKeys, '', res);
+
+ return res;
+};
diff --git a/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js b/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js
new file mode 100644
index 0000000..d69e719
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const get = require('../get');
+
+/**
+ * Given an update, move all $set on immutable properties to $setOnInsert.
+ * No need to check for upserts, because there's no harm in setting
+ * $setOnInsert even if `upsert` is false.
+ */
+
+module.exports = function moveImmutableProperties(schema, update, ctx) {
+ if (update == null) {
+ return;
+ }
+
+ const keys = Object.keys(update);
+ for (const key of keys) {
+ const isDollarKey = key.startsWith('$');
+
+ if (key === '$set') {
+ const updatedPaths = Object.keys(update[key]);
+ for (const path of updatedPaths) {
+ _walkUpdatePath(schema, update[key], path, update, ctx);
+ }
+ } else if (!isDollarKey) {
+ _walkUpdatePath(schema, update, key, update, ctx);
+ }
+
+ }
+};
+
+function _walkUpdatePath(schema, op, path, update, ctx) {
+ const schematype = schema.path(path);
+ if (schematype == null) {
+ return;
+ }
+
+ let immutable = get(schematype, 'options.immutable', null);
+ if (immutable == null) {
+ return;
+ }
+ if (typeof immutable === 'function') {
+ immutable = immutable.call(ctx, ctx);
+ }
+
+ if (!immutable) {
+ return;
+ }
+
+ update.$setOnInsert = update.$setOnInsert || {};
+ update.$setOnInsert[path] = op[path];
+ delete op[path];
+}
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/updateValidators.js b/node_modules/mongoose/lib/helpers/updateValidators.js
new file mode 100644
index 0000000..bd2718d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/updateValidators.js
@@ -0,0 +1,254 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const ValidationError = require('../error/validation');
+const cleanPositionalOperators = require('./schema/cleanPositionalOperators');
+const flatten = require('./common').flatten;
+const modifiedPaths = require('./common').modifiedPaths;
+
+/**
+ * Applies validators and defaults to update and findOneAndUpdate operations,
+ * specifically passing a null doc as `this` to validators and defaults
+ *
+ * @param {Query} query
+ * @param {Schema} schema
+ * @param {Object} castedDoc
+ * @param {Object} options
+ * @method runValidatorsOnUpdate
+ * @api private
+ */
+
+module.exports = function(query, schema, castedDoc, options, callback) {
+ let _keys;
+ const keys = Object.keys(castedDoc || {});
+ let updatedKeys = {};
+ let updatedValues = {};
+ const isPull = {};
+ const arrayAtomicUpdates = {};
+ const numKeys = keys.length;
+ let hasDollarUpdate = false;
+ const modified = {};
+ let currentUpdate;
+ let key;
+ let i;
+
+ for (i = 0; i < numKeys; ++i) {
+ if (keys[i].startsWith('$')) {
+ hasDollarUpdate = true;
+ if (keys[i] === '$push' || keys[i] === '$addToSet') {
+ _keys = Object.keys(castedDoc[keys[i]]);
+ for (let ii = 0; ii < _keys.length; ++ii) {
+ currentUpdate = castedDoc[keys[i]][_keys[ii]];
+ if (currentUpdate && currentUpdate.$each) {
+ arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
+ concat(currentUpdate.$each);
+ } else {
+ arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
+ concat([currentUpdate]);
+ }
+ }
+ continue;
+ }
+ modifiedPaths(castedDoc[keys[i]], '', modified);
+ const flat = flatten(castedDoc[keys[i]], null, null, schema);
+ const paths = Object.keys(flat);
+ const numPaths = paths.length;
+ for (let j = 0; j < numPaths; ++j) {
+ const updatedPath = cleanPositionalOperators(paths[j]);
+ key = keys[i];
+ // With `$pull` we might flatten `$in`. Skip stuff nested under `$in`
+ // for the rest of the logic, it will get handled later.
+ if (updatedPath.includes('$')) {
+ continue;
+ }
+ if (key === '$set' || key === '$setOnInsert' ||
+ key === '$pull' || key === '$pullAll') {
+ updatedValues[updatedPath] = flat[paths[j]];
+ isPull[updatedPath] = key === '$pull' || key === '$pullAll';
+ } else if (key === '$unset') {
+ updatedValues[updatedPath] = undefined;
+ }
+ updatedKeys[updatedPath] = true;
+ }
+ }
+ }
+
+ if (!hasDollarUpdate) {
+ modifiedPaths(castedDoc, '', modified);
+ updatedValues = flatten(castedDoc, null, null, schema);
+ updatedKeys = Object.keys(updatedValues);
+ }
+
+ const updates = Object.keys(updatedValues);
+ const numUpdates = updates.length;
+ const validatorsToExecute = [];
+ const validationErrors = [];
+
+ const alreadyValidated = [];
+
+ const context = options && options.context === 'query' ? query : null;
+ function iter(i, v) {
+ const schemaPath = schema._getSchema(updates[i]);
+ if (schemaPath == null) {
+ return;
+ }
+ if (schemaPath.instance === 'Mixed' && schemaPath.path !== updates[i]) {
+ return;
+ }
+
+ if (v && Array.isArray(v.$in)) {
+ v.$in.forEach((v, i) => {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ v,
+ function(err) {
+ if (err) {
+ err.path = updates[i] + '.$in.' + i;
+ validationErrors.push(err);
+ }
+ callback(null);
+ },
+ context,
+ { updateValidator: true });
+ });
+ });
+ } else {
+ if (isPull[updates[i]] &&
+ schemaPath.$isMongooseArray) {
+ return;
+ }
+
+ if (schemaPath.$isMongooseDocumentArrayElement && v != null && v.$__ != null) {
+ alreadyValidated.push(updates[i]);
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(v, function(err) {
+ if (err) {
+ err.path = updates[i];
+ validationErrors.push(err);
+ return callback(null);
+ }
+
+ v.validate(function(err) {
+ if (err) {
+ if (err.errors) {
+ for (const key of Object.keys(err.errors)) {
+ const _err = err.errors[key];
+ _err.path = updates[i] + '.' + key;
+ validationErrors.push(_err);
+ }
+ } else {
+ err.path = updates[i];
+ validationErrors.push(err);
+ }
+ }
+ callback(null);
+ });
+ }, context, { updateValidator: true });
+ });
+ } else {
+ validatorsToExecute.push(function(callback) {
+ for (const path of alreadyValidated) {
+ if (updates[i].startsWith(path + '.')) {
+ return callback(null);
+ }
+ }
+ schemaPath.doValidate(v, function(err) {
+ if (err) {
+ err.path = updates[i];
+ validationErrors.push(err);
+ }
+ callback(null);
+ }, context, { updateValidator: true });
+ });
+ }
+ }
+ }
+ for (i = 0; i < numUpdates; ++i) {
+ iter(i, updatedValues[updates[i]]);
+ }
+
+ const arrayUpdates = Object.keys(arrayAtomicUpdates);
+ const numArrayUpdates = arrayUpdates.length;
+ for (i = 0; i < numArrayUpdates; ++i) {
+ (function(i) {
+ let schemaPath = schema._getSchema(arrayUpdates[i]);
+ if (schemaPath && schemaPath.$isMongooseDocumentArray) {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ arrayAtomicUpdates[arrayUpdates[i]],
+ function(err) {
+ if (err) {
+ err.path = arrayUpdates[i];
+ validationErrors.push(err);
+ }
+ callback(null);
+ },
+ options && options.context === 'query' ? query : null);
+ });
+ } else {
+ schemaPath = schema._getSchema(arrayUpdates[i] + '.0');
+ for (let j = 0; j < arrayAtomicUpdates[arrayUpdates[i]].length; ++j) {
+ (function(j) {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ arrayAtomicUpdates[arrayUpdates[i]][j],
+ function(err) {
+ if (err) {
+ err.path = arrayUpdates[i];
+ validationErrors.push(err);
+ }
+ callback(null);
+ },
+ options && options.context === 'query' ? query : null,
+ { updateValidator: true });
+ });
+ })(j);
+ }
+ }
+ })(i);
+ }
+
+ if (callback != null) {
+ let numValidators = validatorsToExecute.length;
+ if (numValidators === 0) {
+ return _done(callback);
+ }
+ for (const validator of validatorsToExecute) {
+ validator(function() {
+ if (--numValidators <= 0) {
+ _done(callback);
+ }
+ });
+ }
+
+ return;
+ }
+
+ return function(callback) {
+ let numValidators = validatorsToExecute.length;
+ if (numValidators === 0) {
+ return _done(callback);
+ }
+ for (const validator of validatorsToExecute) {
+ validator(function() {
+ if (--numValidators <= 0) {
+ _done(callback);
+ }
+ });
+ }
+ };
+
+ function _done(callback) {
+ if (validationErrors.length) {
+ const err = new ValidationError(null);
+ for (let i = 0; i < validationErrors.length; ++i) {
+ err.addError(validationErrors[i].path, validationErrors[i]);
+ }
+ return callback(err);
+ }
+ callback(null);
+ }
+};
diff --git a/node_modules/mongoose/lib/index.js b/node_modules/mongoose/lib/index.js
new file mode 100644
index 0000000..8db4da9
--- /dev/null
+++ b/node_modules/mongoose/lib/index.js
@@ -0,0 +1,1117 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+if (global.MONGOOSE_DRIVER_PATH) {
+ const deprecationWarning = 'The `MONGOOSE_DRIVER_PATH` global property is ' +
+ 'deprecated. Use `mongoose.driver.set()` instead.';
+ const setDriver = require('util').deprecate(function() {
+ require('./driver').set(require(global.MONGOOSE_DRIVER_PATH));
+ }, deprecationWarning);
+ setDriver();
+} else {
+ require('./driver').set(require('./drivers/node-mongodb-native'));
+}
+
+const Document = require('./document');
+const Schema = require('./schema');
+const SchemaType = require('./schematype');
+const SchemaTypes = require('./schema/index');
+const VirtualType = require('./virtualtype');
+const STATES = require('./connectionstate');
+const VALID_OPTIONS = require('./validoptions');
+const Types = require('./types');
+const Query = require('./query');
+const Model = require('./model');
+const applyPlugins = require('./helpers/schema/applyPlugins');
+const get = require('./helpers/get');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const legacyPluralize = require('mongoose-legacy-pluralize');
+const utils = require('./utils');
+const pkg = require('../package.json');
+const cast = require('./cast');
+const removeSubdocs = require('./plugins/removeSubdocs');
+const saveSubdocs = require('./plugins/saveSubdocs');
+const validateBeforeSave = require('./plugins/validateBeforeSave');
+
+const Aggregate = require('./aggregate');
+const PromiseProvider = require('./promise_provider');
+const shardingPlugin = require('./plugins/sharding');
+
+const defaultMongooseSymbol = Symbol.for('mongoose:default');
+
+require('./helpers/printJestWarning');
+
+/**
+ * Mongoose constructor.
+ *
+ * The exports object of the `mongoose` module is an instance of this class.
+ * Most apps will only use this one instance.
+ *
+ * ####Example:
+ * const mongoose = require('mongoose');
+ * mongoose instanceof mongoose.Mongoose; // true
+ *
+ * // Create a new Mongoose instance with its own `connect()`, `set()`, `model()`, etc.
+ * const m = new mongoose.Mongoose();
+ *
+ * @api public
+ * @param {Object} options see [`Mongoose#set()` docs](/docs/api/mongoose.html#mongoose_Mongoose-set)
+ */
+function Mongoose(options) {
+ this.connections = [];
+ this.models = {};
+ this.modelSchemas = {};
+ // default global options
+ this.options = Object.assign({
+ pluralization: true
+ }, options);
+ const conn = this.createConnection(); // default connection
+ conn.models = this.models;
+
+ if (this.options.pluralization) {
+ this._pluralize = legacyPluralize;
+ }
+
+ // If a user creates their own Mongoose instance, give them a separate copy
+ // of the `Schema` constructor so they get separate custom types. (gh-6933)
+ if (!options || !options[defaultMongooseSymbol]) {
+ const _this = this;
+ this.Schema = function() {
+ this.base = _this;
+ return Schema.apply(this, arguments);
+ };
+ this.Schema.prototype = Object.create(Schema.prototype);
+
+ Object.assign(this.Schema, Schema);
+ this.Schema.base = this;
+ this.Schema.Types = Object.assign({}, Schema.Types);
+ } else {
+ // Hack to work around babel's strange behavior with
+ // `import mongoose, { Schema } from 'mongoose'`. Because `Schema` is not
+ // an own property of a Mongoose global, Schema will be undefined. See gh-5648
+ for (const key of ['Schema', 'model']) {
+ this[key] = Mongoose.prototype[key];
+ }
+ }
+ this.Schema.prototype.base = this;
+
+ Object.defineProperty(this, 'plugins', {
+ configurable: false,
+ enumerable: true,
+ writable: false,
+ value: [
+ [saveSubdocs, { deduplicate: true }],
+ [validateBeforeSave, { deduplicate: true }],
+ [shardingPlugin, { deduplicate: true }],
+ [removeSubdocs, { deduplicate: true }]
+ ]
+ });
+}
+Mongoose.prototype.cast = cast;
+/**
+ * Expose connection states for user-land
+ *
+ * @memberOf Mongoose
+ * @property STATES
+ * @api public
+ */
+Mongoose.prototype.STATES = STATES;
+
+/**
+ * The underlying driver this Mongoose instance uses to communicate with
+ * the database. A driver is a Mongoose-specific interface that defines functions
+ * like `find()`.
+ *
+ * @memberOf Mongoose
+ * @property driver
+ * @api public
+ */
+
+Mongoose.prototype.driver = require('./driver');
+
+/**
+ * Sets mongoose options
+ *
+ * ####Example:
+ *
+ * mongoose.set('test', value) // sets the 'test' option to `value`
+ *
+ * mongoose.set('debug', true) // enable logging collection methods + arguments to the console
+ *
+ * mongoose.set('debug', function(collectionName, methodName, arg1, arg2...) {}); // use custom function to log collection methods + arguments
+ *
+ * Currently supported options are:
+ * - 'debug': prints the operations mongoose sends to MongoDB to the console
+ * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
+ * - 'useCreateIndex': false by default. Set to `true` to make Mongoose's default index build use `createIndex()` instead of `ensureIndex()` to avoid deprecation warnings from the MongoDB driver.
+ * - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
+ * - 'useNewUrlParser': false by default. Set to `true` to make all connections set the `useNewUrlParser` option by default
+ * - 'useUnifiedTopology': false by default. Set to `true` to make all connections set the `useUnifiedTopology` option by default
+ * - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
+ * - 'applyPluginsToDiscriminators': false by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
+ * - 'applyPluginsToChildSchemas': true by default. Set to false to skip applying global plugins to child schemas
+ * - 'objectIdGetter': true by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
+ * - 'runValidators': false by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
+ * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
+ * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
+ * - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
+ * - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
+ * - 'typePojoToMixed': true by default, may be `false` or `true`. Sets the default typePojoToMixed for schemas.
+ * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
+ * - 'autoIndex': true by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
+ *
+ * @param {String} key
+ * @param {String|Function|Boolean} value
+ * @api public
+ */
+
+Mongoose.prototype.set = function(key, value) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ if (VALID_OPTIONS.indexOf(key) === -1) throw new Error(`\`${key}\` is an invalid option.`);
+
+ if (arguments.length === 1) {
+ return _mongoose.options[key];
+ }
+
+ _mongoose.options[key] = value;
+
+ if (key === 'objectIdGetter') {
+ if (value) {
+ Object.defineProperty(mongoose.Types.ObjectId.prototype, '_id', {
+ enumerable: false,
+ configurable: true,
+ get: function() {
+ return this;
+ }
+ });
+ } else {
+ delete mongoose.Types.ObjectId.prototype._id;
+ }
+ }
+
+ return _mongoose;
+};
+
+/**
+ * Gets mongoose options
+ *
+ * ####Example:
+ *
+ * mongoose.get('test') // returns the 'test' value
+ *
+ * @param {String} key
+ * @method get
+ * @api public
+ */
+
+Mongoose.prototype.get = Mongoose.prototype.set;
+
+/**
+ * Creates a Connection instance.
+ *
+ * Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
+ *
+ *
+ * _Options passed take precedence over options included in connection strings._
+ *
+ * ####Example:
+ *
+ * // with mongodb:// URI
+ * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
+ *
+ * // and options
+ * var opts = { db: { native_parser: true }}
+ * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
+ *
+ * // replica sets
+ * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database');
+ *
+ * // and options
+ * var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
+ * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
+ *
+ * // and options
+ * var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
+ * db = mongoose.createConnection('localhost', 'database', port, opts)
+ *
+ * // initialize now, connect later
+ * db = mongoose.createConnection();
+ * db.openUri('localhost', 'database', port, [opts]);
+ *
+ * @param {String} [uri] a mongodb:// URI
+ * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html), except for 4 mongoose-specific options explained below.
+ * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
+ * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ * @param {Boolean} [options.useNewUrlParser=false] False by default. Set to `true` to make all connections set the `useNewUrlParser` option by default.
+ * @param {Boolean} [options.useUnifiedTopology=false] False by default. Set to `true` to make all connections set the `useUnifiedTopology` option by default.
+ * @param {Boolean} [options.useCreateIndex=true] Mongoose-specific option. If `true`, this connection will use [`createIndex()` instead of `ensureIndex()`](/docs/deprecations.html#ensureindex) for automatic index builds via [`Model.init()`](/docs/api.html#model_Model.init).
+ * @param {Boolean} [options.useFindAndModify=true] True by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
+ * @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
+ * @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
+ * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
+ * @param {Number} [options.poolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ * @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
+ * @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
+ * @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
+ * @return {Connection} the created Connection object. Connections are thenable, so you can do `await mongoose.createConnection()`
+ * @api public
+ */
+
+Mongoose.prototype.createConnection = function(uri, options, callback) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ const conn = new Connection(_mongoose);
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+ _mongoose.connections.push(conn);
+
+ if (arguments.length > 0) {
+ return conn.openUri(uri, options, callback);
+ }
+
+ return conn;
+};
+
+/**
+ * Opens the default mongoose connection.
+ *
+ * ####Example:
+ *
+ * mongoose.connect('mongodb://user:pass@localhost:port/database');
+ *
+ * // replica sets
+ * var uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase';
+ * mongoose.connect(uri);
+ *
+ * // with options
+ * mongoose.connect(uri, options);
+ *
+ * // optional callback that gets fired when initial connection completed
+ * var uri = 'mongodb://nonexistent.domain:27000';
+ * mongoose.connect(uri, function(error) {
+ * // if error is truthy, the initial connection failed.
+ * })
+ *
+ * @param {String} uri(s)
+ * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html), except for 4 mongoose-specific options explained below.
+ * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
+ * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
+ * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
+ * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
+ * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
+ * @param {Boolean} [options.useNewUrlParser=false] False by default. Set to `true` to opt in to the MongoDB driver's new URL parser logic.
+ * @param {Boolean} [options.useUnifiedTopology=false] False by default. Set to `true` to opt in to the MongoDB driver's replica set and sharded cluster monitoring engine.
+ * @param {Boolean} [options.useCreateIndex=true] Mongoose-specific option. If `true`, this connection will use [`createIndex()` instead of `ensureIndex()`](/docs/deprecations.html#ensureindex) for automatic index builds via [`Model.init()`](/docs/api.html#model_Model.init).
+ * @param {Boolean} [options.useFindAndModify=true] True by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
+ * @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
+ * @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
+ * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
+ * @param {Number} [options.poolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
+ * @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
+ * @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
+ * @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
+ * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
+ * @param {Function} [callback]
+ * @see Mongoose#createConnection #index_Mongoose-createConnection
+ * @api public
+ * @return {Promise} resolves to `this` if connection succeeded
+ */
+
+Mongoose.prototype.connect = function(uri, options, callback) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+ const conn = _mongoose.connection;
+ return conn.openUri(uri, options, callback).then(() => _mongoose);
+};
+
+/**
+ * Runs `.close()` on all connections in parallel.
+ *
+ * @param {Function} [callback] called after all connection close, or when first error occurred.
+ * @return {Promise} resolves when all connections are closed, or rejects with the first error that occurred.
+ * @api public
+ */
+
+Mongoose.prototype.disconnect = function(callback) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ return promiseOrCallback(callback, cb => {
+ let remaining = _mongoose.connections.length;
+ if (remaining <= 0) {
+ return cb(null);
+ }
+ _mongoose.connections.forEach(conn => {
+ conn.close(function(error) {
+ if (error) {
+ return cb(error);
+ }
+ if (!--remaining) {
+ cb(null);
+ }
+ });
+ });
+ });
+};
+
+/**
+ * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions)
+ * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/),
+ * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).
+ *
+ * Calling `mongoose.startSession()` is equivalent to calling `mongoose.connection.startSession()`.
+ * Sessions are scoped to a connection, so calling `mongoose.startSession()`
+ * starts a session on the [default mongoose connection](/docs/api.html#mongoose_Mongoose-connection).
+ *
+ * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#startSession)
+ * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
+ * @param {Function} [callback]
+ * @return {Promise} promise that resolves to a MongoDB driver `ClientSession`
+ * @api public
+ */
+
+Mongoose.prototype.startSession = function() {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ return _mongoose.connection.startSession.apply(_mongoose.connection, arguments);
+};
+
+/**
+ * Getter/setter around function for pluralizing collection names.
+ *
+ * @param {Function|null} [fn] overwrites the function used to pluralize collection names
+ * @return {Function|null} the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.
+ * @api public
+ */
+
+Mongoose.prototype.pluralize = function(fn) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ if (arguments.length > 0) {
+ _mongoose._pluralize = fn;
+ }
+ return _mongoose._pluralize;
+};
+
+/**
+ * Defines a model or retrieves it.
+ *
+ * Models defined on the `mongoose` instance are available to all connection
+ * created by the same `mongoose` instance.
+ *
+ * If you call `mongoose.model()` with twice the same name but a different schema,
+ * you will get an `OverwriteModelError`. If you call `mongoose.model()` with
+ * the same name and same schema, you'll get the same schema back.
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ *
+ * // define an Actor model with this mongoose instance
+ * const Schema = new Schema({ name: String });
+ * mongoose.model('Actor', schema);
+ *
+ * // create a new connection
+ * var conn = mongoose.createConnection(..);
+ *
+ * // create Actor model
+ * var Actor = conn.model('Actor', schema);
+ * conn.model('Actor') === Actor; // true
+ * conn.model('Actor', schema) === Actor; // true, same schema
+ * conn.model('Actor', schema, 'actors') === Actor; // true, same schema and collection name
+ *
+ * // This throws an `OverwriteModelError` because the schema is different.
+ * conn.model('Actor', new Schema({ name: String }));
+ *
+ * _When no `collection` argument is passed, Mongoose uses the model name. If you don't like this behavior, either pass a collection name, use `mongoose.pluralize()`, or set your schemas collection name option._
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ name: String }, { collection: 'actor' });
+ *
+ * // or
+ *
+ * schema.set('collection', 'actor');
+ *
+ * // or
+ *
+ * var collectionName = 'actor'
+ * var M = mongoose.model('Actor', schema, collectionName)
+ *
+ * @param {String|Function} name model name or class extending Model
+ * @param {Schema} [schema] the schema to use.
+ * @param {String} [collection] name (optional, inferred from model name)
+ * @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
+ * @return {Model} The model associated with `name`. Mongoose will create the model if it doesn't already exist.
+ * @api public
+ */
+
+Mongoose.prototype.model = function(name, schema, collection, skipInit) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ let model;
+ if (typeof name === 'function') {
+ model = name;
+ name = model.name;
+ if (!(model.prototype instanceof Model)) {
+ throw new _mongoose.Error('The provided class ' + name + ' must extend Model');
+ }
+ }
+
+ if (typeof schema === 'string') {
+ collection = schema;
+ schema = false;
+ }
+
+ if (utils.isObject(schema) && !(schema.instanceOfSchema)) {
+ schema = new Schema(schema);
+ }
+ if (schema && !schema.instanceOfSchema) {
+ throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
+ 'schema or a POJO');
+ }
+
+ if (typeof collection === 'boolean') {
+ skipInit = collection;
+ collection = null;
+ }
+
+ // handle internal options from connection.model()
+ let options;
+ if (skipInit && utils.isObject(skipInit)) {
+ options = skipInit;
+ skipInit = true;
+ } else {
+ options = {};
+ }
+
+ // look up schema for the collection.
+ if (!_mongoose.modelSchemas[name]) {
+ if (schema) {
+ // cache it so we only apply plugins once
+ _mongoose.modelSchemas[name] = schema;
+ } else {
+ throw new mongoose.Error.MissingSchemaError(name);
+ }
+ }
+
+ const originalSchema = schema;
+ if (schema) {
+ if (_mongoose.get('cloneSchemas')) {
+ schema = schema.clone();
+ }
+ _mongoose._applyPlugins(schema);
+ }
+
+ let sub;
+
+ // connection.model() may be passing a different schema for
+ // an existing model name. in this case don't read from cache.
+ if (_mongoose.models[name] && options.cache !== false) {
+ if (originalSchema &&
+ originalSchema.instanceOfSchema &&
+ originalSchema !== _mongoose.models[name].schema) {
+ throw new _mongoose.Error.OverwriteModelError(name);
+ }
+
+ if (collection && collection !== _mongoose.models[name].collection.name) {
+ // subclass current model with alternate collection
+ model = _mongoose.models[name];
+ schema = model.prototype.schema;
+ sub = model.__subclass(_mongoose.connection, schema, collection);
+ // do not cache the sub model
+ return sub;
+ }
+
+ return _mongoose.models[name];
+ }
+
+ // ensure a schema exists
+ if (!schema) {
+ schema = this.modelSchemas[name];
+ if (!schema) {
+ throw new mongoose.Error.MissingSchemaError(name);
+ }
+ }
+
+ // Apply relevant "global" options to the schema
+ if (!('pluralization' in schema.options)) {
+ schema.options.pluralization = _mongoose.options.pluralization;
+ }
+
+ if (!collection) {
+ collection = schema.get('collection') ||
+ utils.toCollectionName(name, _mongoose.pluralize());
+ }
+
+ const connection = options.connection || _mongoose.connection;
+ model = _mongoose.Model.compile(model || name, schema, collection, connection, _mongoose);
+
+ if (!skipInit) {
+ // Errors handled internally, so safe to ignore error
+ model.init(function $modelInitNoop() {});
+ }
+
+ if (options.cache === false) {
+ return model;
+ }
+
+ _mongoose.models[name] = model;
+ return _mongoose.models[name];
+};
+
+/**
+ * Removes the model named `name` from the default connection, if it exists.
+ * You can use this function to clean up any models you created in your tests to
+ * prevent OverwriteModelErrors.
+ *
+ * Equivalent to `mongoose.connection.deleteModel(name)`.
+ *
+ * ####Example:
+ *
+ * mongoose.model('User', new Schema({ name: String }));
+ * console.log(mongoose.model('User')); // Model object
+ * mongoose.deleteModel('User');
+ * console.log(mongoose.model('User')); // undefined
+ *
+ * // Usually useful in a Mocha `afterEach()` hook
+ * afterEach(function() {
+ * mongoose.deleteModel(/.+/); // Delete every model
+ * });
+ *
+ * @api public
+ * @param {String|RegExp} name if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.
+ * @return {Mongoose} this
+ */
+
+Mongoose.prototype.deleteModel = function(name) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ _mongoose.connection.deleteModel(name);
+ return _mongoose;
+};
+
+/**
+ * Returns an array of model names created on this instance of Mongoose.
+ *
+ * ####Note:
+ *
+ * _Does not include names of models created using `connection.model()`._
+ *
+ * @api public
+ * @return {Array}
+ */
+
+Mongoose.prototype.modelNames = function() {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ const names = Object.keys(_mongoose.models);
+ return names;
+};
+
+/**
+ * Applies global plugins to `schema`.
+ *
+ * @param {Schema} schema
+ * @api private
+ */
+
+Mongoose.prototype._applyPlugins = function(schema, options) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ options = options || {};
+ options.applyPluginsToDiscriminators = get(_mongoose,
+ 'options.applyPluginsToDiscriminators', false);
+ options.applyPluginsToChildSchemas = get(_mongoose,
+ 'options.applyPluginsToChildSchemas', true);
+ applyPlugins(schema, _mongoose.plugins, options, '$globalPluginsApplied');
+};
+
+/**
+ * Declares a global plugin executed on all Schemas.
+ *
+ * Equivalent to calling `.plugin(fn)` on each Schema you create.
+ *
+ * @param {Function} fn plugin callback
+ * @param {Object} [opts] optional options
+ * @return {Mongoose} this
+ * @see plugins ./plugins.html
+ * @api public
+ */
+
+Mongoose.prototype.plugin = function(fn, opts) {
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
+
+ _mongoose.plugins.push([fn, opts]);
+ return _mongoose;
+};
+
+/**
+ * The Mongoose module's default connection. Equivalent to `mongoose.connections[0]`, see [`connections`](#mongoose_Mongoose-connections).
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * mongoose.connect(...);
+ * mongoose.connection.on('error', cb);
+ *
+ * This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
+ *
+ * To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
+ *
+ * @memberOf Mongoose
+ * @instance
+ * @property {Connection} connection
+ * @api public
+ */
+
+Mongoose.prototype.__defineGetter__('connection', function() {
+ return this.connections[0];
+});
+
+Mongoose.prototype.__defineSetter__('connection', function(v) {
+ if (v instanceof Connection) {
+ this.connections[0] = v;
+ this.models = v.models;
+ }
+});
+
+/**
+ * An array containing all [connections](connections.html) associated with this
+ * Mongoose instance. By default, there is 1 connection. Calling
+ * [`createConnection()`](#mongoose_Mongoose-createConnection) adds a connection
+ * to this array.
+ *
+ * ####Example:
+ *
+ * const mongoose = require('mongoose');
+ * mongoose.connections.length; // 1, just the default connection
+ * mongoose.connections[0] === mongoose.connection; // true
+ *
+ * mongoose.createConnection('mongodb://localhost:27017/test');
+ * mongoose.connections.length; // 2
+ *
+ * @memberOf Mongoose
+ * @instance
+ * @property {Array} connections
+ * @api public
+ */
+
+Mongoose.prototype.connections;
+
+/*!
+ * Driver dependent APIs
+ */
+
+const driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
+
+/*!
+ * Connection
+ */
+
+const Connection = require(driver + '/connection');
+
+/*!
+ * Collection
+ */
+
+const Collection = require(driver + '/collection');
+
+/**
+ * The Mongoose Aggregate constructor
+ *
+ * @method Aggregate
+ * @api public
+ */
+
+Mongoose.prototype.Aggregate = Aggregate;
+
+/**
+ * The Mongoose Collection constructor
+ *
+ * @method Collection
+ * @api public
+ */
+
+Mongoose.prototype.Collection = Collection;
+
+/**
+ * The Mongoose [Connection](#connection_Connection) constructor
+ *
+ * @memberOf Mongoose
+ * @instance
+ * @method Connection
+ * @api public
+ */
+
+Mongoose.prototype.Connection = Connection;
+
+/**
+ * The Mongoose version
+ *
+ * #### Example
+ *
+ * console.log(mongoose.version); // '5.x.x'
+ *
+ * @property version
+ * @api public
+ */
+
+Mongoose.prototype.version = pkg.version;
+
+/**
+ * The Mongoose constructor
+ *
+ * The exports of the mongoose module is an instance of this class.
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var mongoose2 = new mongoose.Mongoose();
+ *
+ * @method Mongoose
+ * @api public
+ */
+
+Mongoose.prototype.Mongoose = Mongoose;
+
+/**
+ * The Mongoose [Schema](#schema_Schema) constructor
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var Schema = mongoose.Schema;
+ * var CatSchema = new Schema(..);
+ *
+ * @method Schema
+ * @api public
+ */
+
+Mongoose.prototype.Schema = Schema;
+
+/**
+ * The Mongoose [SchemaType](#schematype_SchemaType) constructor
+ *
+ * @method SchemaType
+ * @api public
+ */
+
+Mongoose.prototype.SchemaType = SchemaType;
+
+/**
+ * The various Mongoose SchemaTypes.
+ *
+ * ####Note:
+ *
+ * _Alias of mongoose.Schema.Types for backwards compatibility._
+ *
+ * @property SchemaTypes
+ * @see Schema.SchemaTypes #schema_Schema.Types
+ * @api public
+ */
+
+Mongoose.prototype.SchemaTypes = Schema.Types;
+
+/**
+ * The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
+ *
+ * @method VirtualType
+ * @api public
+ */
+
+Mongoose.prototype.VirtualType = VirtualType;
+
+/**
+ * The various Mongoose Types.
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var array = mongoose.Types.Array;
+ *
+ * ####Types:
+ *
+ * - [ObjectId](#types-objectid-js)
+ * - [Buffer](#types-buffer-js)
+ * - [SubDocument](#types-embedded-js)
+ * - [Array](#types-array-js)
+ * - [DocumentArray](#types-documentarray-js)
+ *
+ * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
+ *
+ * var ObjectId = mongoose.Types.ObjectId;
+ * var id1 = new ObjectId;
+ *
+ * @property Types
+ * @api public
+ */
+
+Mongoose.prototype.Types = Types;
+
+/**
+ * The Mongoose [Query](#query_Query) constructor.
+ *
+ * @method Query
+ * @api public
+ */
+
+Mongoose.prototype.Query = Query;
+
+/**
+ * The Mongoose [Promise](#promise_Promise) constructor.
+ *
+ * @memberOf Mongoose
+ * @instance
+ * @property Promise
+ * @api public
+ */
+
+Object.defineProperty(Mongoose.prototype, 'Promise', {
+ get: function() {
+ return PromiseProvider.get();
+ },
+ set: function(lib) {
+ PromiseProvider.set(lib);
+ }
+});
+
+/**
+ * Storage layer for mongoose promises
+ *
+ * @method PromiseProvider
+ * @api public
+ */
+
+Mongoose.prototype.PromiseProvider = PromiseProvider;
+
+/**
+ * The Mongoose [Model](#model_Model) constructor.
+ *
+ * @method Model
+ * @api public
+ */
+
+Mongoose.prototype.Model = Model;
+
+/**
+ * The Mongoose [Document](#document-js) constructor.
+ *
+ * @method Document
+ * @api public
+ */
+
+Mongoose.prototype.Document = Document;
+
+/**
+ * The Mongoose DocumentProvider constructor. Mongoose users should not have to
+ * use this directly
+ *
+ * @method DocumentProvider
+ * @api public
+ */
+
+Mongoose.prototype.DocumentProvider = require('./document_provider');
+
+/**
+ * The Mongoose ObjectId [SchemaType](/docs/schematypes.html). Used for
+ * declaring paths in your schema that should be
+ * [MongoDB ObjectIds](https://docs.mongodb.com/manual/reference/method/ObjectId/).
+ * Do not use this to create a new ObjectId instance, use `mongoose.Types.ObjectId`
+ * instead.
+ *
+ * ####Example:
+ *
+ * const childSchema = new Schema({ parentId: mongoose.ObjectId });
+ *
+ * @property ObjectId
+ * @api public
+ */
+
+Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
+
+/**
+ * Returns true if Mongoose can cast the given value to an ObjectId, or
+ * false otherwise.
+ *
+ * ####Example:
+ *
+ * mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
+ * mongoose.isValidObjectId('0123456789ab'); // true
+ * mongoose.isValidObjectId(6); // false
+ *
+ * @method isValidObjectId
+ * @api public
+ */
+
+Mongoose.prototype.isValidObjectId = function(v) {
+ if (v == null) {
+ return true;
+ }
+ const base = this || mongoose;
+ const ObjectId = base.driver.get().ObjectId;
+ if (v instanceof ObjectId) {
+ return true;
+ }
+
+ if (v._id != null) {
+ if (v._id instanceof ObjectId) {
+ return true;
+ }
+ if (v._id.toString instanceof Function) {
+ v = v._id.toString();
+ return typeof v === 'string' && (v.length === 12 || v.length === 24);
+ }
+ }
+
+ if (v.toString instanceof Function) {
+ v = v.toString();
+ }
+
+ if (typeof v === 'string' && (v.length === 12 || v.length === 24)) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * The Mongoose Decimal128 [SchemaType](/docs/schematypes.html). Used for
+ * declaring paths in your schema that should be
+ * [128-bit decimal floating points](http://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-decimal.html).
+ * Do not use this to create a new Decimal128 instance, use `mongoose.Types.Decimal128`
+ * instead.
+ *
+ * ####Example:
+ *
+ * const vehicleSchema = new Schema({ fuelLevel: mongoose.Decimal128 });
+ *
+ * @property Decimal128
+ * @api public
+ */
+
+Mongoose.prototype.Decimal128 = SchemaTypes.Decimal128;
+
+/**
+ * The Mongoose Mixed [SchemaType](/docs/schematypes.html). Used for
+ * declaring paths in your schema that Mongoose's change tracking, casting,
+ * and validation should ignore.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ arbitrary: mongoose.Mixed });
+ *
+ * @property Mixed
+ * @api public
+ */
+
+Mongoose.prototype.Mixed = SchemaTypes.Mixed;
+
+/**
+ * The Mongoose Date [SchemaType](/docs/schematypes.html).
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ test: Date });
+ * schema.path('test') instanceof mongoose.Date; // true
+ *
+ * @property Date
+ * @api public
+ */
+
+Mongoose.prototype.Date = SchemaTypes.Date;
+
+/**
+ * The Mongoose Number [SchemaType](/docs/schematypes.html). Used for
+ * declaring paths in your schema that Mongoose should cast to numbers.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ num: mongoose.Number });
+ * // Equivalent to:
+ * const schema = new Schema({ num: 'number' });
+ *
+ * @property Number
+ * @api public
+ */
+
+Mongoose.prototype.Number = SchemaTypes.Number;
+
+/**
+ * The [MongooseError](#error_MongooseError) constructor.
+ *
+ * @method Error
+ * @api public
+ */
+
+Mongoose.prototype.Error = require('./error/index');
+
+/**
+ * Mongoose uses this function to get the current time when setting
+ * [timestamps](/docs/guide.html#timestamps). You may stub out this function
+ * using a tool like [Sinon](https://www.npmjs.com/package/sinon) for testing.
+ *
+ * @method now
+ * @returns Date the current time
+ * @api public
+ */
+
+Mongoose.prototype.now = function now() { return new Date(); };
+
+/**
+ * The Mongoose CastError constructor
+ *
+ * @method CastError
+ * @param {String} type The name of the type
+ * @param {Any} value The value that failed to cast
+ * @param {String} path The path `a.b.c` in the doc where this cast error occurred
+ * @param {Error} [reason] The original error that was thrown
+ * @api public
+ */
+
+Mongoose.prototype.CastError = require('./error/cast');
+
+/**
+ * The constructor used for schematype options
+ *
+ * @method SchemaTypeOptions
+ * @api public
+ */
+
+Mongoose.prototype.SchemaTypeOptions = require('./options/SchemaTypeOptions');
+
+/**
+ * The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.
+ *
+ * @property mongo
+ * @api public
+ */
+
+Mongoose.prototype.mongo = require('mongodb');
+
+/**
+ * The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.
+ *
+ * @property mquery
+ * @api public
+ */
+
+Mongoose.prototype.mquery = require('mquery');
+
+/*!
+ * The exports object is an instance of Mongoose.
+ *
+ * @api public
+ */
+
+const mongoose = module.exports = exports = new Mongoose({
+ [defaultMongooseSymbol]: true
+});
diff --git a/node_modules/mongoose/lib/internal.js b/node_modules/mongoose/lib/internal.js
new file mode 100644
index 0000000..7642477
--- /dev/null
+++ b/node_modules/mongoose/lib/internal.js
@@ -0,0 +1,38 @@
+/*!
+ * Dependencies
+ */
+
+'use strict';
+
+const StateMachine = require('./statemachine');
+const ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default', 'ignore');
+
+module.exports = exports = InternalCache;
+
+function InternalCache() {
+ this.strictMode = undefined;
+ this.selected = undefined;
+ this.shardval = undefined;
+ this.saveError = undefined;
+ this.validationError = undefined;
+ this.adhocPaths = undefined;
+ this.removing = undefined;
+ this.inserting = undefined;
+ this.saving = undefined;
+ this.version = undefined;
+ this.getters = {};
+ this._id = undefined;
+ this.populate = undefined; // what we want to populate in this doc
+ this.populated = undefined;// the _ids that have been populated
+ this.wasPopulated = false; // if this doc was the result of a population
+ this.scope = undefined;
+ this.activePaths = new ActiveRoster;
+ this.pathsToScopes = {};
+ this.cachedRequired = {};
+ this.session = null;
+ this.$setCalled = new Set();
+
+ // embedded docs
+ this.ownerDocument = undefined;
+ this.fullPath = undefined;
+}
diff --git a/node_modules/mongoose/lib/model.js b/node_modules/mongoose/lib/model.js
new file mode 100644
index 0000000..13ad9e5
--- /dev/null
+++ b/node_modules/mongoose/lib/model.js
@@ -0,0 +1,4893 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const Aggregate = require('./aggregate');
+const ChangeStream = require('./cursor/ChangeStream');
+const Document = require('./document');
+const DocumentNotFoundError = require('./error/notFound');
+const DivergentArrayError = require('./error/divergentArray');
+const EventEmitter = require('events').EventEmitter;
+const MongooseBuffer = require('./types/buffer');
+const MongooseError = require('./error/index');
+const OverwriteModelError = require('./error/overwriteModel');
+const PromiseProvider = require('./promise_provider');
+const Query = require('./query');
+const RemoveOptions = require('./options/removeOptions');
+const SaveOptions = require('./options/saveOptions');
+const Schema = require('./schema');
+const ServerSelectionError = require('./error/serverSelection');
+const SkipPopulateValue = require('./helpers/populate/SkipPopulateValue');
+const ValidationError = require('./error/validation');
+const VersionError = require('./error/version');
+const ParallelSaveError = require('./error/parallelSave');
+const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
+const applyHooks = require('./helpers/model/applyHooks');
+const applyMethods = require('./helpers/model/applyMethods');
+const applyStaticHooks = require('./helpers/model/applyStaticHooks');
+const applyStatics = require('./helpers/model/applyStatics');
+const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
+const assignVals = require('./helpers/populate/assignVals');
+const castBulkWrite = require('./helpers/model/castBulkWrite');
+const discriminator = require('./helpers/model/discriminator');
+const each = require('./helpers/each');
+const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
+const getModelsMapForPopulate = require('./helpers/populate/getModelsMapForPopulate');
+const immediate = require('./helpers/immediate');
+const internalToObjectOptions = require('./options').internalToObjectOptions;
+const isDefaultIdIndex = require('./helpers/indexes/isDefaultIdIndex');
+const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
+const get = require('./helpers/get');
+const leanPopulateMap = require('./helpers/populate/leanPopulateMap');
+const modifiedPaths = require('./helpers/update/modifiedPaths');
+const mpath = require('mpath');
+const parallelLimit = require('./helpers/parallelLimit');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const parseProjection = require('./helpers/projection/parseProjection');
+const util = require('util');
+const utils = require('./utils');
+
+const VERSION_WHERE = 1;
+const VERSION_INC = 2;
+const VERSION_ALL = VERSION_WHERE | VERSION_INC;
+
+const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
+const modelCollectionSymbol = Symbol('mongoose#Model#collection');
+const modelDbSymbol = Symbol('mongoose#Model#db');
+const modelSymbol = require('./helpers/symbols').modelSymbol;
+const subclassedSymbol = Symbol('mongoose#Model#subclassed');
+
+const saveToObjectOptions = Object.assign({}, internalToObjectOptions, {
+ bson: true
+});
+
+/**
+ * A Model is a class that's your primary tool for interacting with MongoDB.
+ * An instance of a Model is called a [Document](./api.html#Document).
+ *
+ * In Mongoose, the term "Model" refers to subclasses of the `mongoose.Model`
+ * class. You should not use the `mongoose.Model` class directly. The
+ * [`mongoose.model()`](./api.html#mongoose_Mongoose-model) and
+ * [`connection.model()`](./api.html#connection_Connection-model) functions
+ * create subclasses of `mongoose.Model` as shown below.
+ *
+ * ####Example:
+ *
+ * // `UserModel` is a "Model", a subclass of `mongoose.Model`.
+ * const UserModel = mongoose.model('User', new Schema({ name: String }));
+ *
+ * // You can use a Model to create new documents using `new`:
+ * const userDoc = new UserModel({ name: 'Foo' });
+ * await userDoc.save();
+ *
+ * // You also use a model to create queries:
+ * const userFromDb = await UserModel.findOne({ name: 'Foo' });
+ *
+ * @param {Object} doc values for initial set
+ * @param [fields] optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](./api.html#query_Query-select).
+ * @inherits Document http://mongoosejs.com/docs/api.html#document-js
+ * @event `error`: If listening to this event, 'error' is emitted when a document was saved without passing a callback and an `error` occurred. If not listening, the event bubbles to the connection used to create this Model.
+ * @event `index`: Emitted after `Model#ensureIndexes` completes. If an error occurred it is passed with the event.
+ * @event `index-single-start`: Emitted when an individual index starts within `Model#ensureIndexes`. The fields and options being used to build the index are also passed with the event.
+ * @event `index-single-done`: Emitted when an individual index finishes within `Model#ensureIndexes`. If an error occurred it is passed with the event. The fields, options, and index name are also passed.
+ * @api public
+ */
+
+function Model(doc, fields, skipId) {
+ if (fields instanceof Schema) {
+ throw new TypeError('2nd argument to `Model` must be a POJO or string, ' +
+ '**not** a schema. Make sure you\'re calling `mongoose.model()`, not ' +
+ '`mongoose.Model()`.');
+ }
+ Document.call(this, doc, fields, skipId);
+}
+
+/*!
+ * Inherits from Document.
+ *
+ * All Model.prototype features are available on
+ * top level (non-sub) documents.
+ */
+
+Model.prototype.__proto__ = Document.prototype;
+Model.prototype.$isMongooseModelPrototype = true;
+
+/**
+ * Connection the model uses.
+ *
+ * @api public
+ * @property db
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.db;
+
+/**
+ * Collection the model uses.
+ *
+ * This property is read-only. Modifying this property is a no-op.
+ *
+ * @api public
+ * @property collection
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.collection;
+
+/**
+ * The name of the model
+ *
+ * @api public
+ * @property modelName
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.modelName;
+
+/**
+ * Additional properties to attach to the query when calling `save()` and
+ * `isNew` is false.
+ *
+ * @api public
+ * @property $where
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.$where;
+
+/**
+ * If this is a discriminator model, `baseModelName` is the name of
+ * the base model.
+ *
+ * @api public
+ * @property baseModelName
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.baseModelName;
+
+/**
+ * Event emitter that reports any errors that occurred. Useful for global error
+ * handling.
+ *
+ * ####Example:
+ *
+ * MyModel.events.on('error', err => console.log(err.message));
+ *
+ * // Prints a 'CastError' because of the above handler
+ * await MyModel.findOne({ _id: 'notanid' }).catch(noop);
+ *
+ * @api public
+ * @fires error whenever any query or model function errors
+ * @memberOf Model
+ * @static events
+ */
+
+Model.events;
+
+/*!
+ * Compiled middleware for this model. Set in `applyHooks()`.
+ *
+ * @api private
+ * @property _middleware
+ * @memberOf Model
+ * @static
+ */
+
+Model._middleware;
+
+/*!
+ * ignore
+ */
+
+function _applyCustomWhere(doc, where) {
+ if (doc.$where == null) {
+ return;
+ }
+
+ const keys = Object.keys(doc.$where);
+ const len = keys.length;
+ for (let i = 0; i < len; ++i) {
+ where[keys[i]] = doc.$where[keys[i]];
+ }
+}
+
+/*!
+ * ignore
+ */
+
+Model.prototype.$__handleSave = function(options, callback) {
+ const _this = this;
+ let saveOptions = {};
+
+ if ('safe' in options) {
+ _handleSafe(options);
+ }
+ applyWriteConcern(this.schema, options);
+ if ('w' in options) {
+ saveOptions.w = options.w;
+ }
+ if ('j' in options) {
+ saveOptions.j = options.j;
+ }
+ if ('wtimeout' in options) {
+ saveOptions.wtimeout = options.wtimeout;
+ }
+ if ('checkKeys' in options) {
+ saveOptions.checkKeys = options.checkKeys;
+ }
+
+ const session = this.$session();
+ if (!saveOptions.hasOwnProperty('session')) {
+ saveOptions.session = session;
+ }
+
+ if (Object.keys(saveOptions).length === 0) {
+ saveOptions = null;
+ }
+
+ if (this.isNew) {
+ // send entire doc
+ const obj = this.toObject(saveToObjectOptions);
+
+ if ((obj || {})._id === void 0) {
+ // documents must have an _id else mongoose won't know
+ // what to update later if more changes are made. the user
+ // wouldn't know what _id was generated by mongodb either
+ // nor would the ObjectId generated by mongodb necessarily
+ // match the schema definition.
+ setTimeout(function() {
+ callback(new MongooseError('document must have an _id before saving'));
+ }, 0);
+ return;
+ }
+
+ this.$__version(true, obj);
+ this[modelCollectionSymbol].insertOne(obj, saveOptions, function(err, ret) {
+ if (err) {
+ _setIsNew(_this, true);
+
+ callback(err, null);
+ return;
+ }
+
+ callback(null, ret);
+ });
+ this.$__reset();
+ _setIsNew(this, false);
+ // Make it possible to retry the insert
+ this.$__.inserting = true;
+ } else {
+ // Make sure we don't treat it as a new object on error,
+ // since it already exists
+ this.$__.inserting = false;
+
+ const delta = this.$__delta();
+
+ if (delta) {
+ if (delta instanceof MongooseError) {
+ callback(delta);
+ return;
+ }
+
+ const where = this.$__where(delta[0]);
+ if (where instanceof MongooseError) {
+ callback(where);
+ return;
+ }
+
+ _applyCustomWhere(this, where);
+
+ this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions, function(err, ret) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ ret.$where = where;
+ callback(null, ret);
+ });
+ } else {
+ this.constructor.exists(this.$__where(), saveOptions)
+ .then((documentExists)=>{
+ if (!documentExists) throw new DocumentNotFoundError(this.$__where(), this.constructor.modelName);
+
+ this.$__reset();
+ callback();
+ })
+ .catch(callback);
+ return;
+ }
+
+ _setIsNew(this, false);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+Model.prototype.$__save = function(options, callback) {
+ this.$__handleSave(options, (error, result) => {
+ const hooks = this.schema.s.hooks;
+ if (error) {
+ return hooks.execPost('save:error', this, [this], { error: error }, (error) => {
+ callback(error, this);
+ });
+ }
+
+ // store the modified paths before the document is reset
+ const modifiedPaths = this.modifiedPaths();
+
+ this.$__reset();
+
+ let numAffected = 0;
+ if (get(options, 'safe.w') !== 0 && get(options, 'w') !== 0) {
+ // Skip checking if write succeeded if writeConcern is set to
+ // unacknowledged writes, because otherwise `numAffected` will always be 0
+ if (result) {
+ if (Array.isArray(result)) {
+ numAffected = result.length;
+ } else if (result.result && result.result.n !== undefined) {
+ numAffected = result.result.n;
+ } else if (result.result && result.result.nModified !== undefined) {
+ numAffected = result.result.nModified;
+ } else {
+ numAffected = result;
+ }
+ }
+
+ // was this an update that required a version bump?
+ if (this.$__.version && !this.$__.inserting) {
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
+ this.$__.version = undefined;
+
+ const key = this.schema.options.versionKey;
+ const version = this.$__getValue(key) || 0;
+
+ if (numAffected <= 0) {
+ // the update failed. pass an error back
+ const err = this.$__.$versionError ||
+ new VersionError(this, version, modifiedPaths);
+ return callback(err);
+ }
+
+ // increment version if was successful
+ if (doIncrement) {
+ this.$__setValue(key, version + 1);
+ }
+ }
+
+ if (result != null && numAffected <= 0) {
+ error = new DocumentNotFoundError(result.$where,
+ this.constructor.modelName, numAffected, result);
+ return hooks.execPost('save:error', this, [this], { error: error }, (error) => {
+ callback(error, this);
+ });
+ }
+ }
+ this.$__.saving = undefined;
+ this.emit('save', this, numAffected);
+ this.constructor.emit('save', this, numAffected);
+ callback(null, this);
+ });
+};
+
+/*!
+ * ignore
+ */
+
+function generateVersionError(doc, modifiedPaths) {
+ const key = doc.schema.options.versionKey;
+ if (!key) {
+ return null;
+ }
+ const version = doc.$__getValue(key) || 0;
+ return new VersionError(doc, version, modifiedPaths);
+}
+
+/**
+ * Saves this document.
+ *
+ * ####Example:
+ *
+ * product.sold = Date.now();
+ * product = await product.save();
+ *
+ * If save is successful, the returned promise will fulfill with the document
+ * saved.
+ *
+ * ####Example:
+ *
+ * const newProduct = await product.save();
+ * newProduct === product; // true
+ *
+ * @param {Object} [options] options optional options
+ * @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
+ * @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](http://mongoosejs.com//docs/guide.html#safe). Use the `w` option instead.
+ * @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
+ * @param {Number|String} [options.w] set the [write concern](https://docs.mongodb.com/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
+ * @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
+ * @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names)
+ * @param {Boolean} [options.timestamps=true] if `false` and [timestamps](./guide.html#timestamps) are enabled, skip timestamps for this `save()`.
+ * @param {Function} [fn] optional callback
+ * @throws {DocumentNotFoundError} if this [save updates an existing document](api.html#document_Document-isNew) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
+ * @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
+ * @api public
+ * @see middleware http://mongoosejs.com/docs/middleware.html
+ */
+
+Model.prototype.save = function(options, fn) {
+ let parallelSave;
+ this.$op = 'save';
+
+ if (this.$__.saving) {
+ parallelSave = new ParallelSaveError(this);
+ } else {
+ this.$__.saving = new ParallelSaveError(this);
+ }
+
+ if (typeof options === 'function') {
+ fn = options;
+ options = undefined;
+ }
+
+ options = new SaveOptions(options);
+ if (options.hasOwnProperty('session')) {
+ this.$session(options.session);
+ }
+
+ this.$__.$versionError = generateVersionError(this, this.modifiedPaths());
+
+ fn = this.constructor.$handleCallbackError(fn);
+
+ return promiseOrCallback(fn, cb => {
+ cb = this.constructor.$wrapCallback(cb);
+
+ if (parallelSave) {
+ this.$__handleReject(parallelSave);
+ return cb(parallelSave);
+ }
+
+ this.$__.saveOptions = options;
+
+ this.$__save(options, error => {
+ this.$__.saving = undefined;
+ delete this.$__.saveOptions;
+ delete this.$__.$versionError;
+ this.$op = null;
+
+ if (error) {
+ this.$__handleReject(error);
+ return cb(error);
+ }
+ cb(null, this);
+ });
+ }, this.constructor.events);
+};
+
+/*!
+ * Determines whether versioning should be skipped for the given path
+ *
+ * @param {Document} self
+ * @param {String} path
+ * @return {Boolean} true if versioning should be skipped for the given path
+ */
+function shouldSkipVersioning(self, path) {
+ const skipVersioning = self.schema.options.skipVersioning;
+ if (!skipVersioning) return false;
+
+ // Remove any array indexes from the path
+ path = path.replace(/\.\d+\./, '.');
+
+ return skipVersioning[path];
+}
+
+/*!
+ * Apply the operation to the delta (update) clause as
+ * well as track versioning for our where clause.
+ *
+ * @param {Document} self
+ * @param {Object} where
+ * @param {Object} delta
+ * @param {Object} data
+ * @param {Mixed} val
+ * @param {String} [operation]
+ */
+
+function operand(self, where, delta, data, val, op) {
+ // delta
+ op || (op = '$set');
+ if (!delta[op]) delta[op] = {};
+ delta[op][data.path] = val;
+
+ // disabled versioning?
+ if (self.schema.options.versionKey === false) return;
+
+ // path excluded from versioning?
+ if (shouldSkipVersioning(self, data.path)) return;
+
+ // already marked for versioning?
+ if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return;
+
+ switch (op) {
+ case '$set':
+ case '$unset':
+ case '$pop':
+ case '$pull':
+ case '$pullAll':
+ case '$push':
+ case '$addToSet':
+ break;
+ default:
+ // nothing to do
+ return;
+ }
+
+ // ensure updates sent with positional notation are
+ // editing the correct array element.
+ // only increment the version if an array position changes.
+ // modifying elements of an array is ok if position does not change.
+ if (op === '$push' || op === '$addToSet' || op === '$pullAll' || op === '$pull') {
+ self.$__.version = VERSION_INC;
+ } else if (/^\$p/.test(op)) {
+ // potentially changing array positions
+ self.increment();
+ } else if (Array.isArray(val)) {
+ // $set an array
+ self.increment();
+ } else if (/\.\d+\.|\.\d+$/.test(data.path)) {
+ // now handling $set, $unset
+ // subpath of array
+ self.$__.version = VERSION_WHERE;
+ }
+}
+
+/*!
+ * Compiles an update and where clause for a `val` with _atomics.
+ *
+ * @param {Document} self
+ * @param {Object} where
+ * @param {Object} delta
+ * @param {Object} data
+ * @param {Array} value
+ */
+
+function handleAtomics(self, where, delta, data, value) {
+ if (delta.$set && delta.$set[data.path]) {
+ // $set has precedence over other atomics
+ return;
+ }
+
+ if (typeof value.$__getAtomics === 'function') {
+ value.$__getAtomics().forEach(function(atomic) {
+ const op = atomic[0];
+ const val = atomic[1];
+ operand(self, where, delta, data, val, op);
+ });
+ return;
+ }
+
+ // legacy support for plugins
+
+ const atomics = value[arrayAtomicsSymbol];
+ const ops = Object.keys(atomics);
+ let i = ops.length;
+ let val;
+ let op;
+
+ if (i === 0) {
+ // $set
+
+ if (utils.isMongooseObject(value)) {
+ value = value.toObject({ depopulate: 1, _isNested: true });
+ } else if (value.valueOf) {
+ value = value.valueOf();
+ }
+
+ return operand(self, where, delta, data, value);
+ }
+
+ function iter(mem) {
+ return utils.isMongooseObject(mem)
+ ? mem.toObject({ depopulate: 1, _isNested: true })
+ : mem;
+ }
+
+ while (i--) {
+ op = ops[i];
+ val = atomics[op];
+
+ if (utils.isMongooseObject(val)) {
+ val = val.toObject({ depopulate: true, transform: false, _isNested: true });
+ } else if (Array.isArray(val)) {
+ val = val.map(iter);
+ } else if (val.valueOf) {
+ val = val.valueOf();
+ }
+
+ if (op === '$addToSet') {
+ val = { $each: val };
+ }
+
+ operand(self, where, delta, data, val, op);
+ }
+}
+
+/**
+ * Produces a special query document of the modified properties used in updates.
+ *
+ * @api private
+ * @method $__delta
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.$__delta = function() {
+ const dirty = this.$__dirty();
+ if (!dirty.length && VERSION_ALL !== this.$__.version) {
+ return;
+ }
+
+ const where = {};
+ const delta = {};
+ const len = dirty.length;
+ const divergent = [];
+ let d = 0;
+
+ where._id = this._doc._id;
+ // If `_id` is an object, need to depopulate, but also need to be careful
+ // because `_id` can technically be null (see gh-6406)
+ if (get(where, '_id.$__', null) != null) {
+ where._id = where._id.toObject({ transform: false, depopulate: true });
+ }
+
+ for (; d < len; ++d) {
+ const data = dirty[d];
+ let value = data.value;
+
+ const match = checkDivergentArray(this, data.path, value);
+ if (match) {
+ divergent.push(match);
+ continue;
+ }
+
+ const pop = this.populated(data.path, true);
+ if (!pop && this.$__.selected) {
+ // If any array was selected using an $elemMatch projection, we alter the path and where clause
+ // NOTE: MongoDB only supports projected $elemMatch on top level array.
+ const pathSplit = data.path.split('.');
+ const top = pathSplit[0];
+ if (this.$__.selected[top] && this.$__.selected[top].$elemMatch) {
+ // If the selected array entry was modified
+ if (pathSplit.length > 1 && pathSplit[1] == 0 && typeof where[top] === 'undefined') {
+ where[top] = this.$__.selected[top];
+ pathSplit[1] = '$';
+ data.path = pathSplit.join('.');
+ }
+ // if the selected array was modified in any other way throw an error
+ else {
+ divergent.push(data.path);
+ continue;
+ }
+ }
+ }
+
+ if (divergent.length) continue;
+
+ if (value === undefined) {
+ operand(this, where, delta, data, 1, '$unset');
+ } else if (value === null) {
+ operand(this, where, delta, data, null);
+ } else if (value.isMongooseArray && value.$path() && value[arrayAtomicsSymbol]) {
+ // arrays and other custom types (support plugins etc)
+ handleAtomics(this, where, delta, data, value);
+ } else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
+ // MongooseBuffer
+ value = value.toObject();
+ operand(this, where, delta, data, value);
+ } else {
+ value = utils.clone(value, {
+ depopulate: true,
+ transform: false,
+ virtuals: false,
+ getters: false,
+ _isNested: true
+ });
+ operand(this, where, delta, data, value);
+ }
+ }
+
+ if (divergent.length) {
+ return new DivergentArrayError(divergent);
+ }
+
+ if (this.$__.version) {
+ this.$__version(where, delta);
+ }
+
+ return [where, delta];
+};
+
+/*!
+ * Determine if array was populated with some form of filter and is now
+ * being updated in a manner which could overwrite data unintentionally.
+ *
+ * @see https://github.com/Automattic/mongoose/issues/1334
+ * @param {Document} doc
+ * @param {String} path
+ * @return {String|undefined}
+ */
+
+function checkDivergentArray(doc, path, array) {
+ // see if we populated this path
+ const pop = doc.populated(path, true);
+
+ if (!pop && doc.$__.selected) {
+ // If any array was selected using an $elemMatch projection, we deny the update.
+ // NOTE: MongoDB only supports projected $elemMatch on top level array.
+ const top = path.split('.')[0];
+ if (doc.$__.selected[top + '.$']) {
+ return top;
+ }
+ }
+
+ if (!(pop && array && array.isMongooseArray)) return;
+
+ // If the array was populated using options that prevented all
+ // documents from being returned (match, skip, limit) or they
+ // deselected the _id field, $pop and $set of the array are
+ // not safe operations. If _id was deselected, we do not know
+ // how to remove elements. $pop will pop off the _id from the end
+ // of the array in the db which is not guaranteed to be the
+ // same as the last element we have here. $set of the entire array
+ // would be similarily destructive as we never received all
+ // elements of the array and potentially would overwrite data.
+ const check = pop.options.match ||
+ pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted
+ pop.options.options && pop.options.options.skip || // 0 is permitted
+ pop.options.select && // deselected _id?
+ (pop.options.select._id === 0 ||
+ /\s?-_id\s?/.test(pop.options.select));
+
+ if (check) {
+ const atomics = array[arrayAtomicsSymbol];
+ if (Object.keys(atomics).length === 0 || atomics.$set || atomics.$pop) {
+ return path;
+ }
+ }
+}
+
+/**
+ * Appends versioning to the where and update clauses.
+ *
+ * @api private
+ * @method $__version
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.$__version = function(where, delta) {
+ const key = this.schema.options.versionKey;
+
+ if (where === true) {
+ // this is an insert
+ if (key) this.$__setValue(key, delta[key] = 0);
+ return;
+ }
+
+ // updates
+
+ // only apply versioning if our versionKey was selected. else
+ // there is no way to select the correct version. we could fail
+ // fast here and force them to include the versionKey but
+ // thats a bit intrusive. can we do this automatically?
+ if (!this.isSelected(key)) {
+ return;
+ }
+
+ // $push $addToSet don't need the where clause set
+ if (VERSION_WHERE === (VERSION_WHERE & this.$__.version)) {
+ const value = this.$__getValue(key);
+ if (value != null) where[key] = value;
+ }
+
+ if (VERSION_INC === (VERSION_INC & this.$__.version)) {
+ if (get(delta.$set, key, null) != null) {
+ // Version key is getting set, means we'll increment the doc's version
+ // after a successful save, so we should set the incremented version so
+ // future saves don't fail (gh-5779)
+ ++delta.$set[key];
+ } else {
+ delta.$inc = delta.$inc || {};
+ delta.$inc[key] = 1;
+ }
+ }
+};
+
+/**
+ * Signal that we desire an increment of this documents version.
+ *
+ * ####Example:
+ *
+ * Model.findById(id, function (err, doc) {
+ * doc.increment();
+ * doc.save(function (err) { .. })
+ * })
+ *
+ * @see versionKeys http://mongoosejs.com/docs/guide.html#versionKey
+ * @api public
+ */
+
+Model.prototype.increment = function increment() {
+ this.$__.version = VERSION_ALL;
+ return this;
+};
+
+/**
+ * Returns a query object
+ *
+ * @api private
+ * @method $__where
+ * @memberOf Model
+ * @instance
+ */
+
+Model.prototype.$__where = function _where(where) {
+ where || (where = {});
+
+ if (!where._id) {
+ where._id = this._doc._id;
+ }
+
+ if (this._doc._id === void 0) {
+ return new MongooseError('No _id found on document!');
+ }
+
+ return where;
+};
+
+/**
+ * Removes this document from the db.
+ *
+ * ####Example:
+ * product.remove(function (err, product) {
+ * if (err) return handleError(err);
+ * Product.findById(product._id, function (err, product) {
+ * console.log(product) // null
+ * })
+ * })
+ *
+ *
+ * As an extra measure of flow control, remove will return a Promise (bound to `fn` if passed) so it could be chained, or hooked to recieve errors
+ *
+ * ####Example:
+ * product.remove().then(function (product) {
+ * ...
+ * }).catch(function (err) {
+ * assert.ok(err)
+ * })
+ *
+ * @param {Object} [options]
+ * @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
+ * @param {function(err,product)} [fn] optional callback
+ * @return {Promise} Promise
+ * @api public
+ */
+
+Model.prototype.remove = function remove(options, fn) {
+ if (typeof options === 'function') {
+ fn = options;
+ options = undefined;
+ }
+
+ options = new RemoveOptions(options);
+ if (options.hasOwnProperty('session')) {
+ this.$session(options.session);
+ }
+ this.$op = 'remove';
+
+ fn = this.constructor.$handleCallbackError(fn);
+
+ return promiseOrCallback(fn, cb => {
+ cb = this.constructor.$wrapCallback(cb);
+ this.$__remove(options, (err, res) => {
+ this.$op = null;
+ cb(err, res);
+ });
+ }, this.constructor.events);
+};
+
+/**
+ * Alias for remove
+ */
+
+Model.prototype.delete = Model.prototype.remove;
+
+/**
+ * Removes this document from the db. Equivalent to `.remove()`.
+ *
+ * ####Example:
+ * product = await product.deleteOne();
+ * await Product.findById(product._id); // null
+ *
+ * @param {function(err,product)} [fn] optional callback
+ * @return {Promise} Promise
+ * @api public
+ */
+
+Model.prototype.deleteOne = function deleteOne(options, fn) {
+ if (typeof options === 'function') {
+ fn = options;
+ options = undefined;
+ }
+
+ if (!options) {
+ options = {};
+ }
+
+ fn = this.constructor.$handleCallbackError(fn);
+
+ return promiseOrCallback(fn, cb => {
+ cb = this.constructor.$wrapCallback(cb);
+ this.$__deleteOne(options, cb);
+ }, this.constructor.events);
+};
+
+/*!
+ * ignore
+ */
+
+Model.prototype.$__remove = function $__remove(options, cb) {
+ if (this.$__.isDeleted) {
+ return immediate(() => cb(null, this));
+ }
+
+ const where = this.$__where();
+ if (where instanceof MongooseError) {
+ return cb(where);
+ }
+
+ _applyCustomWhere(this, where);
+
+ const session = this.$session();
+ if (!options.hasOwnProperty('session')) {
+ options.session = session;
+ }
+
+ this[modelCollectionSymbol].deleteOne(where, options, err => {
+ if (!err) {
+ this.$__.isDeleted = true;
+ this.emit('remove', this);
+ this.constructor.emit('remove', this);
+ return cb(null, this);
+ }
+ this.$__.isDeleted = false;
+ cb(err);
+ });
+};
+
+/*!
+ * ignore
+ */
+
+Model.prototype.$__deleteOne = Model.prototype.$__remove;
+
+/**
+ * Returns another Model instance.
+ *
+ * ####Example:
+ *
+ * var doc = new Tank;
+ * doc.model('User').findById(id, callback);
+ *
+ * @param {String} name model name
+ * @api public
+ */
+
+Model.prototype.model = function model(name) {
+ return this[modelDbSymbol].model(name);
+};
+
+/**
+ * Returns true if at least one document exists in the database that matches
+ * the given `filter`, and false otherwise.
+ *
+ * Under the hood, `MyModel.exists({ answer: 42 })` is equivalent to
+ * `MyModel.findOne({ answer: 42 }).select({ _id: 1 }).lean().then(doc => !!doc)`
+ *
+ * ####Example:
+ * await Character.deleteMany({});
+ * await Character.create({ name: 'Jean-Luc Picard' });
+ *
+ * await Character.exists({ name: /picard/i }); // true
+ * await Character.exists({ name: /riker/i }); // false
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOne()`
+ *
+ * @param {Object} filter
+ * @param {Function} [callback] callback
+ * @return {Promise}
+ */
+
+Model.exists = function exists(filter, options, callback) {
+ _checkContext(this, 'exists');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const query = this.findOne(filter).
+ select({ _id: 1 }).
+ lean().
+ setOptions(options);
+
+ if (typeof callback === 'function') {
+ query.exec(function(err, doc) {
+ if (err != null) {
+ return callback(err);
+ }
+ callback(null, !!doc);
+ });
+ return;
+ }
+
+ return query.then(doc => !!doc);
+};
+
+/**
+ * Adds a discriminator type.
+ *
+ * ####Example:
+ *
+ * function BaseSchema() {
+ * Schema.apply(this, arguments);
+ *
+ * this.add({
+ * name: String,
+ * createdAt: Date
+ * });
+ * }
+ * util.inherits(BaseSchema, Schema);
+ *
+ * var PersonSchema = new BaseSchema();
+ * var BossSchema = new BaseSchema({ department: String });
+ *
+ * var Person = mongoose.model('Person', PersonSchema);
+ * var Boss = Person.discriminator('Boss', BossSchema);
+ * new Boss().__t; // "Boss". `__t` is the default `discriminatorKey`
+ *
+ * var employeeSchema = new Schema({ boss: ObjectId });
+ * var Employee = Person.discriminator('Employee', employeeSchema, 'staff');
+ * new Employee().__t; // "staff" because of 3rd argument above
+ *
+ * @param {String} name discriminator model name
+ * @param {Schema} schema discriminator model schema
+ * @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ * @return {Model} The newly created discriminator model
+ * @api public
+ */
+
+Model.discriminator = function(name, schema, value) {
+ let model;
+ if (typeof name === 'function') {
+ model = name;
+ name = utils.getFunctionName(model);
+ if (!(model.prototype instanceof Model)) {
+ throw new MongooseError('The provided class ' + name + ' must extend Model');
+ }
+ }
+
+ _checkContext(this, 'discriminator');
+
+ schema = discriminator(this, name, schema, value, true);
+ if (this.db.models[name]) {
+ throw new OverwriteModelError(name);
+ }
+
+ schema.$isRootDiscriminator = true;
+ schema.$globalPluginsApplied = true;
+
+ model = this.db.model(model || name, schema, this.collection.name);
+ this.discriminators[name] = model;
+ const d = this.discriminators[name];
+ d.prototype.__proto__ = this.prototype;
+ Object.defineProperty(d, 'baseModelName', {
+ value: this.modelName,
+ configurable: true,
+ writable: false
+ });
+
+ // apply methods and statics
+ applyMethods(d, schema);
+ applyStatics(d, schema);
+
+ if (this[subclassedSymbol] != null) {
+ for (const submodel of this[subclassedSymbol]) {
+ submodel.discriminators = submodel.discriminators || {};
+ submodel.discriminators[name] =
+ model.__subclass(model.db, schema, submodel.collection.name);
+ }
+ }
+
+ return d;
+};
+
+/*!
+ * Make sure `this` is a model
+ */
+
+function _checkContext(ctx, fnName) {
+ // Check context, because it is easy to mistakenly type
+ // `new Model.discriminator()` and get an incomprehensible error
+ if (ctx == null || ctx === global) {
+ throw new MongooseError('`Model.' + fnName + '()` cannot run without a ' +
+ 'model as `this`. Make sure you are calling `MyModel.' + fnName + '()` ' +
+ 'where `MyModel` is a Mongoose model.');
+ } else if (ctx[modelSymbol] == null) {
+ throw new MongooseError('`Model.' + fnName + '()` cannot run without a ' +
+ 'model as `this`. Make sure you are not calling ' +
+ '`new Model.' + fnName + '()`');
+ }
+}
+
+// Model (class) features
+
+/*!
+ * Give the constructor the ability to emit events.
+ */
+
+for (const i in EventEmitter.prototype) {
+ Model[i] = EventEmitter.prototype[i];
+}
+
+/**
+ * This function is responsible for building [indexes](https://docs.mongodb.com/manual/indexes/),
+ * unless [`autoIndex`](http://mongoosejs.com/docs/guide.html#autoIndex) is turned off.
+ *
+ * Mongoose calls this function automatically when a model is created using
+ * [`mongoose.model()`](/docs/api.html#mongoose_Mongoose-model) or
+ * [`connection.model()`](/docs/api.html#connection_Connection-model), so you
+ * don't need to call it. This function is also idempotent, so you may call it
+ * to get back a promise that will resolve when your indexes are finished
+ * building as an alternative to [`MyModel.on('index')`](/docs/guide.html#indexes)
+ *
+ * ####Example:
+ *
+ * var eventSchema = new Schema({ thing: { type: 'string', unique: true }})
+ * // This calls `Event.init()` implicitly, so you don't need to call
+ * // `Event.init()` on your own.
+ * var Event = mongoose.model('Event', eventSchema);
+ *
+ * Event.init().then(function(Event) {
+ * // You can also use `Event.on('index')` if you prefer event emitters
+ * // over promises.
+ * console.log('Indexes are done building!');
+ * });
+ *
+ * @api public
+ * @param {Function} [callback]
+ * @returns {Promise}
+ */
+
+Model.init = function init(callback) {
+ _checkContext(this, 'init');
+
+ this.schema.emit('init', this);
+
+ if (this.$init != null) {
+ if (callback) {
+ this.$init.then(() => callback(), err => callback(err));
+ return null;
+ }
+ return this.$init;
+ }
+
+ const Promise = PromiseProvider.get();
+ const autoIndex = utils.getOption('autoIndex',
+ this.schema.options, this.db.config, this.db.base.options);
+ const autoCreate = this.schema.options.autoCreate == null ?
+ this.db.config.autoCreate :
+ this.schema.options.autoCreate;
+
+ const _ensureIndexes = autoIndex ?
+ cb => this.ensureIndexes({ _automatic: true }, cb) :
+ cb => cb();
+ const _createCollection = autoCreate ?
+ cb => this.createCollection({}, cb) :
+ cb => cb();
+
+ this.$init = new Promise((resolve, reject) => {
+ _createCollection(error => {
+ if (error) {
+ return reject(error);
+ }
+ _ensureIndexes(error => {
+ if (error) {
+ return reject(error);
+ }
+ resolve(this);
+ });
+ });
+ });
+
+ if (callback) {
+ this.$init.then(() => callback(), err => callback(err));
+ this.$caught = true;
+ return null;
+ } else {
+ const _catch = this.$init.catch;
+ const _this = this;
+ this.$init.catch = function() {
+ this.$caught = true;
+ return _catch.apply(_this.$init, arguments);
+ };
+ }
+
+ return this.$init;
+};
+
+
+/**
+ * Create the collection for this model. By default, if no indexes are specified,
+ * mongoose will not create the collection for the model until any documents are
+ * created. Use this method to create the collection explicitly.
+ *
+ * Note 1: You may need to call this before starting a transaction
+ * See https://docs.mongodb.com/manual/core/transactions/#transactions-and-operations
+ *
+ * Note 2: You don't have to call this if your schema contains index or unique field.
+ * In that case, just use `Model.init()`
+ *
+ * ####Example:
+ *
+ * var userSchema = new Schema({ name: String })
+ * var User = mongoose.model('User', userSchema);
+ *
+ * User.createCollection().then(function(collection) {
+ * console.log('Collection is created!');
+ * });
+ *
+ * @api public
+ * @param {Object} [options] see [MongoDB driver docs](http://mongodb.github.io/node-mongodb-native/3.1/api/Db.html#createCollection)
+ * @param {Function} [callback]
+ * @returns {Promise}
+ */
+
+Model.createCollection = function createCollection(options, callback) {
+ _checkContext(this, 'createCollection');
+
+ if (typeof options === 'string') {
+ throw new MongooseError('You can\'t specify a new collection name in Model.createCollection.' +
+ 'This is not like Connection.createCollection. Only options are accepted here.');
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const schemaCollation = get(this, 'schema.options.collation', null);
+ if (schemaCollation != null) {
+ options = Object.assign({ collation: schemaCollation }, options);
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+
+ this.db.createCollection(this.collection.collectionName, options, utils.tick((error) => {
+ if (error) {
+ return cb(error);
+ }
+ this.collection = this.db.collection(this.collection.collectionName, options);
+ cb(null, this.collection);
+ }));
+ }, this.events);
+};
+
+/**
+ * Makes the indexes in MongoDB match the indexes defined in this model's
+ * schema. This function will drop any indexes that are not defined in
+ * the model's schema except the `_id` index, and build any indexes that
+ * are in your schema but not in MongoDB.
+ *
+ * See the [introductory blog post](http://thecodebarbarian.com/whats-new-in-mongoose-5-2-syncindexes)
+ * for more information.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: { type: String, unique: true } });
+ * const Customer = mongoose.model('Customer', schema);
+ * await Customer.createIndex({ age: 1 }); // Index is not in schema
+ * // Will drop the 'age' index and create an index on `name`
+ * await Customer.syncIndexes();
+ *
+ * @param {Object} [options] options to pass to `ensureIndexes()`
+ * @param {Boolean} [options.background=null] if specified, overrides each index's `background` property
+ * @param {Function} [callback] optional callback
+ * @return {Promise|undefined} Returns `undefined` if callback is specified, returns a promise if no callback.
+ * @api public
+ */
+
+Model.syncIndexes = function syncIndexes(options, callback) {
+ _checkContext(this, 'syncIndexes');
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+
+ this.createCollection(err => {
+ if (err) {
+ return cb(err);
+ }
+ this.cleanIndexes((err, dropped) => {
+ if (err != null) {
+ return cb(err);
+ }
+ this.createIndexes(options, err => {
+ if (err != null) {
+ return cb(err);
+ }
+ cb(null, dropped);
+ });
+ });
+ });
+ }, this.events);
+};
+
+/**
+ * Deletes all indexes that aren't defined in this model's schema. Used by
+ * `syncIndexes()`.
+ *
+ * The returned promise resolves to a list of the dropped indexes' names as an array
+ *
+ * @param {Function} [callback] optional callback
+ * @return {Promise|undefined} Returns `undefined` if callback is specified, returns a promise if no callback.
+ * @api public
+ */
+
+Model.cleanIndexes = function cleanIndexes(callback) {
+ _checkContext(this, 'cleanIndexes');
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ const collection = this.collection;
+
+ this.listIndexes((err, indexes) => {
+ if (err != null) {
+ return cb(err);
+ }
+
+ const schemaIndexes = this.schema.indexes();
+ const toDrop = [];
+
+ for (const index of indexes) {
+ let found = false;
+ // Never try to drop `_id` index, MongoDB server doesn't allow it
+ if (isDefaultIdIndex(index)) {
+ continue;
+ }
+
+ for (const schemaIndex of schemaIndexes) {
+ if (isIndexEqual(this, schemaIndex, index)) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ toDrop.push(index.name);
+ }
+ }
+
+ if (toDrop.length === 0) {
+ return cb(null, []);
+ }
+
+ dropIndexes(toDrop, cb);
+ });
+
+ function dropIndexes(toDrop, cb) {
+ let remaining = toDrop.length;
+ let error = false;
+ toDrop.forEach(indexName => {
+ collection.dropIndex(indexName, err => {
+ if (err != null) {
+ error = true;
+ return cb(err);
+ }
+ if (!error) {
+ --remaining || cb(null, toDrop);
+ }
+ });
+ });
+ }
+ });
+};
+
+/*!
+ * ignore
+ */
+
+function isIndexEqual(model, schemaIndex, dbIndex) {
+ const key = schemaIndex[0];
+ const options = _decorateDiscriminatorIndexOptions(model,
+ utils.clone(schemaIndex[1]));
+
+ // If these options are different, need to rebuild the index
+ const optionKeys = [
+ 'unique',
+ 'partialFilterExpression',
+ 'sparse',
+ 'expireAfterSeconds',
+ 'collation'
+ ];
+ for (const key of optionKeys) {
+ if (!(key in options) && !(key in dbIndex)) {
+ continue;
+ }
+ if (!utils.deepEqual(options[key], dbIndex[key])) {
+ return false;
+ }
+ }
+
+ const schemaIndexKeys = Object.keys(key);
+ const dbIndexKeys = Object.keys(dbIndex.key);
+ if (schemaIndexKeys.length !== dbIndexKeys.length) {
+ return false;
+ }
+ for (let i = 0; i < schemaIndexKeys.length; ++i) {
+ if (schemaIndexKeys[i] !== dbIndexKeys[i]) {
+ return false;
+ }
+ if (!utils.deepEqual(key[schemaIndexKeys[i]], dbIndex.key[dbIndexKeys[i]])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Lists the indexes currently defined in MongoDB. This may or may not be
+ * the same as the indexes defined in your schema depending on whether you
+ * use the [`autoIndex` option](/docs/guide.html#autoIndex) and if you
+ * build indexes manually.
+ *
+ * @param {Function} [cb] optional callback
+ * @return {Promise|undefined} Returns `undefined` if callback is specified, returns a promise if no callback.
+ * @api public
+ */
+
+Model.listIndexes = function init(callback) {
+ _checkContext(this, 'listIndexes');
+
+ const _listIndexes = cb => {
+ this.collection.listIndexes().toArray(cb);
+ };
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+
+ // Buffering
+ if (this.collection.buffer) {
+ this.collection.addQueue(_listIndexes, [cb]);
+ } else {
+ _listIndexes(cb);
+ }
+ }, this.events);
+};
+
+/**
+ * Sends `createIndex` commands to mongo for each index declared in the schema.
+ * The `createIndex` commands are sent in series.
+ *
+ * ####Example:
+ *
+ * Event.ensureIndexes(function (err) {
+ * if (err) return handleError(err);
+ * });
+ *
+ * After completion, an `index` event is emitted on this `Model` passing an error if one occurred.
+ *
+ * ####Example:
+ *
+ * var eventSchema = new Schema({ thing: { type: 'string', unique: true }})
+ * var Event = mongoose.model('Event', eventSchema);
+ *
+ * Event.on('index', function (err) {
+ * if (err) console.error(err); // error occurred during index creation
+ * })
+ *
+ * _NOTE: It is not recommended that you run this in production. Index creation may impact database performance depending on your load. Use with caution._
+ *
+ * @param {Object} [options] internal options
+ * @param {Function} [cb] optional callback
+ * @return {Promise}
+ * @api public
+ */
+
+Model.ensureIndexes = function ensureIndexes(options, callback) {
+ _checkContext(this, 'ensureIndexes');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+
+ _ensureIndexes(this, options || {}, error => {
+ if (error) {
+ return cb(error);
+ }
+ cb(null);
+ });
+ }, this.events);
+};
+
+/**
+ * Similar to `ensureIndexes()`, except for it uses the [`createIndex`](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#createIndex)
+ * function.
+ *
+ * @param {Object} [options] internal options
+ * @param {Function} [cb] optional callback
+ * @return {Promise}
+ * @api public
+ */
+
+Model.createIndexes = function createIndexes(options, callback) {
+ _checkContext(this, 'createIndexes');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ options = options || {};
+ options.createIndex = true;
+ return this.ensureIndexes(options, callback);
+};
+
+/*!
+ * ignore
+ */
+
+function _ensureIndexes(model, options, callback) {
+ const indexes = model.schema.indexes();
+ let indexError;
+
+ options = options || {};
+
+ const done = function(err) {
+ if (err && !model.$caught) {
+ model.emit('error', err);
+ }
+ model.emit('index', err || indexError);
+ callback && callback(err);
+ };
+
+ for (const index of indexes) {
+ if (isDefaultIdIndex(index)) {
+ console.warn('mongoose: Cannot specify a custom index on `_id` for ' +
+ 'model name "' + model.modelName + '", ' +
+ 'MongoDB does not allow overwriting the default `_id` index. See ' +
+ 'http://bit.ly/mongodb-id-index');
+ }
+ }
+
+ if (!indexes.length) {
+ immediate(function() {
+ done();
+ });
+ return;
+ }
+ // Indexes are created one-by-one to support how MongoDB < 2.4 deals
+ // with background indexes.
+
+ const indexSingleDone = function(err, fields, options, name) {
+ model.emit('index-single-done', err, fields, options, name);
+ };
+ const indexSingleStart = function(fields, options) {
+ model.emit('index-single-start', fields, options);
+ };
+
+ const baseSchema = model.schema._baseSchema;
+ const baseSchemaIndexes = baseSchema ? baseSchema.indexes() : [];
+
+ const create = function() {
+ if (options._automatic) {
+ if (model.schema.options.autoIndex === false ||
+ (model.schema.options.autoIndex == null && model.db.config.autoIndex === false)) {
+ return done();
+ }
+ }
+
+ const index = indexes.shift();
+ if (!index) {
+ return done();
+ }
+
+ if (baseSchemaIndexes.find(i => utils.deepEqual(i, index))) {
+ return create();
+ }
+
+ const indexFields = utils.clone(index[0]);
+ const indexOptions = utils.clone(index[1]);
+
+ _decorateDiscriminatorIndexOptions(model, indexOptions);
+ if ('safe' in options) {
+ _handleSafe(options);
+ }
+ applyWriteConcern(model.schema, indexOptions);
+
+ indexSingleStart(indexFields, options);
+ let useCreateIndex = !!model.base.options.useCreateIndex;
+ if ('useCreateIndex' in model.db.config) {
+ useCreateIndex = !!model.db.config.useCreateIndex;
+ }
+ if ('createIndex' in options) {
+ useCreateIndex = !!options.createIndex;
+ }
+ if ('background' in options) {
+ indexOptions.background = options.background;
+ }
+
+ const methodName = useCreateIndex ? 'createIndex' : 'ensureIndex';
+ model.collection[methodName](indexFields, indexOptions, utils.tick(function(err, name) {
+ indexSingleDone(err, indexFields, indexOptions, name);
+ if (err) {
+ if (!indexError) {
+ indexError = err;
+ }
+ if (!model.$caught) {
+ model.emit('error', err);
+ }
+ }
+ create();
+ }));
+ };
+
+ immediate(function() {
+ // If buffering is off, do this manually.
+ if (options._automatic && !model.collection.collection) {
+ model.collection.addQueue(create, []);
+ } else {
+ create();
+ }
+ });
+}
+
+function _decorateDiscriminatorIndexOptions(model, indexOptions) {
+ // If the model is a discriminator and it has a unique index, add a
+ // partialFilterExpression by default so the unique index will only apply
+ // to that discriminator.
+ if (model.baseModelName != null && indexOptions.unique &&
+ !('partialFilterExpression' in indexOptions) &&
+ !('sparse' in indexOptions)) {
+
+ const value = (
+ model.schema.discriminatorMapping &&
+ model.schema.discriminatorMapping.value
+ ) || model.modelName;
+
+ indexOptions.partialFilterExpression = {
+ [model.schema.options.discriminatorKey]: value
+ };
+ }
+ return indexOptions;
+}
+
+const safeDeprecationWarning = 'Mongoose: the `safe` option for `save()` is ' +
+ 'deprecated. Use the `w` option instead: http://bit.ly/mongoose-save';
+
+const _handleSafe = util.deprecate(function _handleSafe(options) {
+ if (options.safe) {
+ if (typeof options.safe === 'boolean') {
+ options.w = options.safe;
+ delete options.safe;
+ }
+ if (typeof options.safe === 'object') {
+ options.w = options.safe.w;
+ options.j = options.safe.j;
+ options.wtimeout = options.safe.wtimeout;
+ delete options.safe;
+ }
+ }
+}, safeDeprecationWarning);
+
+/**
+ * Schema the model uses.
+ *
+ * @property schema
+ * @receiver Model
+ * @api public
+ * @memberOf Model
+ */
+
+Model.schema;
+
+/*!
+ * Connection instance the model uses.
+ *
+ * @property db
+ * @api public
+ * @memberOf Model
+ */
+
+Model.db;
+
+/*!
+ * Collection the model uses.
+ *
+ * @property collection
+ * @api public
+ * @memberOf Model
+ */
+
+Model.collection;
+
+/**
+ * Base Mongoose instance the model uses.
+ *
+ * @property base
+ * @api public
+ * @memberOf Model
+ */
+
+Model.base;
+
+/**
+ * Registered discriminators for this model.
+ *
+ * @property discriminators
+ * @api public
+ * @memberOf Model
+ */
+
+Model.discriminators;
+
+/**
+ * Translate any aliases fields/conditions so the final query or document object is pure
+ *
+ * ####Example:
+ *
+ * Character
+ * .find(Character.translateAliases({
+ * '名': 'Eddard Stark' // Alias for 'name'
+ * })
+ * .exec(function(err, characters) {})
+ *
+ * ####Note:
+ * Only translate arguments of object type anything else is returned raw
+ *
+ * @param {Object} raw fields/conditions that may contain aliased keys
+ * @return {Object} the translated 'pure' fields/conditions
+ */
+Model.translateAliases = function translateAliases(fields) {
+ _checkContext(this, 'translateAliases');
+
+ const translate = (key, value) => {
+ let alias;
+ const translated = [];
+ const fieldKeys = key.split('.');
+ let currentSchema = this.schema;
+ for (const i in fieldKeys) {
+ const name = fieldKeys[i];
+ if (currentSchema && currentSchema.aliases[name]) {
+ alias = currentSchema.aliases[name];
+ // Alias found,
+ translated.push(alias);
+ } else {
+ // Alias not found, so treat as un-aliased key
+ translated.push(name);
+ }
+
+ // Check if aliased path is a schema
+ if (currentSchema && currentSchema.paths[alias]) {
+ currentSchema = currentSchema.paths[alias].schema;
+ }
+ else
+ currentSchema = null;
+ }
+
+ const translatedKey = translated.join('.');
+ if (fields instanceof Map)
+ fields.set(translatedKey, value);
+ else
+ fields[translatedKey] = value;
+
+ if (translatedKey !== key) {
+ // We'll be using the translated key instead
+ if (fields instanceof Map) {
+ // Delete from map
+ fields.delete(key);
+ } else {
+ // Delete from object
+ delete fields[key]; // We'll be using the translated key instead
+ }
+ }
+ return fields;
+ };
+
+ if (typeof fields === 'object') {
+ // Fields is an object (query conditions or document fields)
+ if (fields instanceof Map) {
+ // A Map was supplied
+ for (const field of new Map(fields)) {
+ fields = translate(field[0], field[1]);
+ }
+ } else {
+ // Infer a regular object was supplied
+ for (const key of Object.keys(fields)) {
+ fields = translate(key, fields[key]);
+ if (key[0] === '$') {
+ if (Array.isArray(fields[key])) {
+ for (const i in fields[key]) {
+ // Recursively translate nested queries
+ fields[key][i] = this.translateAliases(fields[key][i]);
+ }
+ }
+ }
+ }
+ }
+
+ return fields;
+ } else {
+ // Don't know typeof fields
+ return fields;
+ }
+};
+
+/**
+ * Removes all documents that match `conditions` from the collection.
+ * To remove just the first document that matches `conditions`, set the `single`
+ * option to true.
+ *
+ * ####Example:
+ *
+ * const res = await Character.remove({ name: 'Eddard Stark' });
+ * res.deletedCount; // Number of documents removed
+ *
+ * ####Note:
+ *
+ * This method sends a remove command directly to MongoDB, no Mongoose documents
+ * are involved. Because no Mongoose documents are involved, Mongoose does
+ * not execute [document middleware](/docs/middleware.html#types-of-middleware).
+ *
+ * @param {Object} conditions
+ * @param {Object} [options]
+ * @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this operation.
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.remove = function remove(conditions, options, callback) {
+ _checkContext(this, 'remove');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ // get the mongodb collection object
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.setOptions(options);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.remove(conditions, callback);
+};
+
+/**
+ * Deletes the first document that matches `conditions` from the collection.
+ * Behaves like `remove()`, but deletes at most one document regardless of the
+ * `single` option.
+ *
+ * ####Example:
+ *
+ * Character.deleteOne({ name: 'Eddard Stark' }, function (err) {});
+ *
+ * ####Note:
+ *
+ * Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
+ *
+ * @param {Object} conditions
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.deleteOne = function deleteOne(conditions, options, callback) {
+ _checkContext(this, 'deleteOne');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ options = null;
+ }
+ else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.setOptions(options);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.deleteOne(conditions, callback);
+};
+
+/**
+ * Deletes all of the documents that match `conditions` from the collection.
+ * Behaves like `remove()`, but deletes all documents that match `conditions`
+ * regardless of the `single` option.
+ *
+ * ####Example:
+ *
+ * Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, function (err) {});
+ *
+ * ####Note:
+ *
+ * Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
+ *
+ * @param {Object} conditions
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.deleteMany = function deleteMany(conditions, options, callback) {
+ _checkContext(this, 'deleteMany');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.setOptions(options);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.deleteMany(conditions, callback);
+};
+
+/**
+ * Finds documents.
+ *
+ * The `filter` are cast to their respective SchemaTypes before the command is sent.
+ * See our [query casting tutorial](/docs/tutorials/query_casting.html) for
+ * more information on how Mongoose casts `filter`.
+ *
+ * ####Examples:
+ *
+ * // named john and at least 18
+ * MyModel.find({ name: 'john', age: { $gte: 18 }});
+ *
+ * // executes, passing results to callback
+ * MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
+ *
+ * // executes, name LIKE john and only selecting the "name" and "friends" fields
+ * MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
+ *
+ * // passing options
+ * MyModel.find({ name: /john/i }, null, { skip: 10 })
+ *
+ * // passing options and executes
+ * MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {});
+ *
+ * // executing a query explicitly
+ * var query = MyModel.find({ name: /john/i }, null, { skip: 10 })
+ * query.exec(function (err, docs) {});
+ *
+ * // using the promise returned from executing a query
+ * var query = MyModel.find({ name: /john/i }, null, { skip: 10 });
+ * var promise = query.exec();
+ * promise.addBack(function (err, docs) {});
+ *
+ * @param {Object|ObjectId} filter
+ * @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](http://mongoosejs.com/docs/api.html#query_Query-select)
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see field selection #query_Query-select
+ * @see query casting /docs/tutorials/query_casting.html
+ * @api public
+ */
+
+Model.find = function find(conditions, projection, options, callback) {
+ _checkContext(this, 'find');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ projection = null;
+ options = null;
+ } else if (typeof projection === 'function') {
+ callback = projection;
+ projection = null;
+ options = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(projection);
+
+ mq.setOptions(options);
+ if (this.schema.discriminatorMapping &&
+ this.schema.discriminatorMapping.isRoot &&
+ mq.selectedInclusively()) {
+ // Need to select discriminator key because original schema doesn't have it
+ mq.select(this.schema.options.discriminatorKey);
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.find(conditions, callback);
+};
+
+/**
+ * Finds a single document by its _id field. `findById(id)` is almost*
+ * equivalent to `findOne({ _id: id })`. If you want to query by a document's
+ * `_id`, use `findById()` instead of `findOne()`.
+ *
+ * The `id` is cast based on the Schema before sending the command.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOne()`
+ *
+ * \* Except for how it treats `undefined`. If you use `findOne()`, you'll see
+ * that `findOne(undefined)` and `findOne({ _id: undefined })` are equivalent
+ * to `findOne({})` and return arbitrary documents. However, mongoose
+ * translates `findById(undefined)` into `findOne({ _id: null })`.
+ *
+ * ####Example:
+ *
+ * // find adventure by id and execute
+ * Adventure.findById(id, function (err, adventure) {});
+ *
+ * // same as above
+ * Adventure.findById(id).exec(callback);
+ *
+ * // select only the adventures name and length
+ * Adventure.findById(id, 'name length', function (err, adventure) {});
+ *
+ * // same as above
+ * Adventure.findById(id, 'name length').exec(callback);
+ *
+ * // include all properties except for `length`
+ * Adventure.findById(id, '-length').exec(function (err, adventure) {});
+ *
+ * // passing options (in this case return the raw js objects, not mongoose documents by passing `lean`
+ * Adventure.findById(id, 'name', { lean: true }, function (err, doc) {});
+ *
+ * // same as above
+ * Adventure.findById(id, 'name').lean().exec(function (err, doc) {});
+ *
+ * @param {Any} id value of `_id` to query by
+ * @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see field selection #query_Query-select
+ * @see lean queries /docs/tutorials/lean.html
+ * @see findById in Mongoose https://masteringjs.io/tutorials/mongoose/find-by-id
+ * @api public
+ */
+
+Model.findById = function findById(id, projection, options, callback) {
+ _checkContext(this, 'findById');
+
+ if (typeof id === 'undefined') {
+ id = null;
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return this.findOne({ _id: id }, projection, options, callback);
+};
+
+/**
+ * Finds one document.
+ *
+ * The `conditions` are cast to their respective SchemaTypes before the command is sent.
+ *
+ * *Note:* `conditions` is optional, and if `conditions` is null or undefined,
+ * mongoose will send an empty `findOne` command to MongoDB, which will return
+ * an arbitrary document. If you're querying by `_id`, use `findById()` instead.
+ *
+ * ####Example:
+ *
+ * // find one iphone adventures - iphone adventures??
+ * Adventure.findOne({ type: 'iphone' }, function (err, adventure) {});
+ *
+ * // same as above
+ * Adventure.findOne({ type: 'iphone' }).exec(function (err, adventure) {});
+ *
+ * // select only the adventures name
+ * Adventure.findOne({ type: 'iphone' }, 'name', function (err, adventure) {});
+ *
+ * // same as above
+ * Adventure.findOne({ type: 'iphone' }, 'name').exec(function (err, adventure) {});
+ *
+ * // specify options, in this case lean
+ * Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }, callback);
+ *
+ * // same as above
+ * Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }).exec(callback);
+ *
+ * // chaining findOne queries (same as above)
+ * Adventure.findOne({ type: 'iphone' }).select('name').lean().exec(callback);
+ *
+ * @param {Object} [conditions]
+ * @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see field selection #query_Query-select
+ * @see lean queries /docs/tutorials/lean.html
+ * @api public
+ */
+
+Model.findOne = function findOne(conditions, projection, options, callback) {
+ _checkContext(this, 'findOne');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ } else if (typeof projection === 'function') {
+ callback = projection;
+ projection = null;
+ options = null;
+ } else if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ projection = null;
+ options = null;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(projection);
+
+ mq.setOptions(options);
+ if (this.schema.discriminatorMapping &&
+ this.schema.discriminatorMapping.isRoot &&
+ mq.selectedInclusively()) {
+ mq.select(this.schema.options.discriminatorKey);
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.findOne(conditions, callback);
+};
+
+/**
+ * Estimates the number of documents in the MongoDB collection. Faster than
+ * using `countDocuments()` for large collections because
+ * `estimatedDocumentCount()` uses collection metadata rather than scanning
+ * the entire collection.
+ *
+ * ####Example:
+ *
+ * const numAdventures = Adventure.estimatedDocumentCount();
+ *
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.estimatedDocumentCount = function estimatedDocumentCount(options, callback) {
+ _checkContext(this, 'estimatedDocumentCount');
+
+ const mq = new this.Query({}, {}, this, this.collection);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.estimatedDocumentCount(options, callback);
+};
+
+/**
+ * Counts number of documents matching `filter` in a database collection.
+ *
+ * ####Example:
+ *
+ * Adventure.countDocuments({ type: 'jungle' }, function (err, count) {
+ * console.log('there are %d jungle adventures', count);
+ * });
+ *
+ * If you want to count all documents in a large collection,
+ * use the [`estimatedDocumentCount()` function](/docs/api.html#model_Model.estimatedDocumentCount)
+ * instead. If you call `countDocuments({})`, MongoDB will always execute
+ * a full collection scan and **not** use any indexes.
+ *
+ * The `countDocuments()` function is similar to `count()`, but there are a
+ * [few operators that `countDocuments()` does not support](https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments).
+ * Below are the operators that `count()` supports but `countDocuments()` does not,
+ * and the suggested replacement:
+ *
+ * - `$where`: [`$expr`](https://docs.mongodb.com/manual/reference/operator/query/expr/)
+ * - `$near`: [`$geoWithin`](https://docs.mongodb.com/manual/reference/operator/query/geoWithin/) with [`$center`](https://docs.mongodb.com/manual/reference/operator/query/center/#op._S_center)
+ * - `$nearSphere`: [`$geoWithin`](https://docs.mongodb.com/manual/reference/operator/query/geoWithin/) with [`$centerSphere`](https://docs.mongodb.com/manual/reference/operator/query/centerSphere/#op._S_centerSphere)
+ *
+ * @param {Object} filter
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.countDocuments = function countDocuments(conditions, callback) {
+ _checkContext(this, 'countDocuments');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.countDocuments(conditions, callback);
+};
+
+/**
+ * Counts number of documents that match `filter` in a database collection.
+ *
+ * This method is deprecated. If you want to count the number of documents in
+ * a collection, e.g. `count({})`, use the [`estimatedDocumentCount()` function](/docs/api.html#model_Model.estimatedDocumentCount)
+ * instead. Otherwise, use the [`countDocuments()`](/docs/api.html#model_Model.countDocuments) function instead.
+ *
+ * ####Example:
+ *
+ * Adventure.count({ type: 'jungle' }, function (err, count) {
+ * if (err) ..
+ * console.log('there are %d jungle adventures', count);
+ * });
+ *
+ * @deprecated
+ * @param {Object} filter
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.count = function count(conditions, callback) {
+ _checkContext(this, 'count');
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+
+ callback = this.$handleCallbackError(callback);
+
+ return mq.count(conditions, callback);
+};
+
+/**
+ * Creates a Query for a `distinct` operation.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * ####Example
+ *
+ * Link.distinct('url', { clicks: {$gt: 100}}, function (err, result) {
+ * if (err) return handleError(err);
+ *
+ * assert(Array.isArray(result));
+ * console.log('unique urls with more than 100 clicks', result);
+ * })
+ *
+ * var query = Link.distinct('url');
+ * query.exec(callback);
+ *
+ * @param {String} field
+ * @param {Object} [conditions] optional
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.distinct = function distinct(field, conditions, callback) {
+ _checkContext(this, 'distinct');
+
+ const mq = new this.Query({}, {}, this, this.collection);
+
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ }
+ callback = this.$handleCallbackError(callback);
+
+ return mq.distinct(field, conditions, callback);
+};
+
+/**
+ * Creates a Query, applies the passed conditions, and returns the Query.
+ *
+ * For example, instead of writing:
+ *
+ * User.find({age: {$gte: 21, $lte: 65}}, callback);
+ *
+ * we can instead write:
+ *
+ * User.where('age').gte(21).lte(65).exec(callback);
+ *
+ * Since the Query class also supports `where` you can continue chaining
+ *
+ * User
+ * .where('age').gte(21).lte(65)
+ * .where('name', /^b/i)
+ * ... etc
+ *
+ * @param {String} path
+ * @param {Object} [val] optional value
+ * @return {Query}
+ * @api public
+ */
+
+Model.where = function where(path, val) {
+ _checkContext(this, 'where');
+
+ void val; // eslint
+ const mq = new this.Query({}, {}, this, this.collection).find({});
+ return mq.where.apply(mq, arguments);
+};
+
+/**
+ * Creates a `Query` and specifies a `$where` condition.
+ *
+ * Sometimes you need to query for things in mongodb using a JavaScript expression. You can do so via `find({ $where: javascript })`, or you can use the mongoose shortcut method $where via a Query chain or from your mongoose Model.
+ *
+ * Blog.$where('this.username.indexOf("val") !== -1').exec(function (err, docs) {});
+ *
+ * @param {String|Function} argument is a javascript string or anonymous function
+ * @method $where
+ * @memberOf Model
+ * @return {Query}
+ * @see Query.$where #query_Query-%24where
+ * @api public
+ */
+
+Model.$where = function $where() {
+ _checkContext(this, '$where');
+
+ const mq = new this.Query({}, {}, this, this.collection).find({});
+ return mq.$where.apply(mq, arguments);
+};
+
+/**
+ * Issues a mongodb findAndModify update command.
+ *
+ * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.
+ *
+ * ####Options:
+ *
+ * - `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
+ * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
+ * - `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findOneAndUpdate(conditions, update, options, callback) // executes
+ * A.findOneAndUpdate(conditions, update, options) // returns Query
+ * A.findOneAndUpdate(conditions, update, callback) // executes
+ * A.findOneAndUpdate(conditions, update) // returns Query
+ * A.findOneAndUpdate() // returns Query
+ *
+ * ####Note:
+ *
+ * All top level update keys which are not `atomic` operation names are treated as set operations:
+ *
+ * ####Example:
+ *
+ * var query = { name: 'borne' };
+ * Model.findOneAndUpdate(query, { name: 'jason bourne' }, options, callback)
+ *
+ * // is sent as
+ * Model.findOneAndUpdate(query, { $set: { name: 'jason bourne' }}, options, callback)
+ *
+ * This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
+ *
+ * ####Note:
+ *
+ * Values are cast to their appropriate types when using the findAndModify helpers.
+ * However, the below are not executed by default.
+ *
+ * - defaults. Use the `setDefaultsOnInsert` option to override.
+ *
+ * `findAndModify` helpers support limited validation. You can
+ * enable these by setting the `runValidators` options,
+ * respectively.
+ *
+ * If you need full-fledged validation, use the traditional approach of first
+ * retrieving the document.
+ *
+ * Model.findById(id, function (err, doc) {
+ * if (err) ..
+ * doc.name = 'jason bourne';
+ * doc.save(callback);
+ * });
+ *
+ * @param {Object} [conditions]
+ * @param {Object} [update]
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see Tutorial /docs/tutorials/findoneandupdate.html
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Model.findOneAndUpdate = function(conditions, update, options, callback) {
+ _checkContext(this, 'findOneAndUpdate');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ } else if (arguments.length === 1) {
+ if (typeof conditions === 'function') {
+ const msg = 'Model.findOneAndUpdate(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options, callback)\n'
+ + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options)\n'
+ + ' ' + this.modelName + '.findOneAndUpdate(conditions, update)\n'
+ + ' ' + this.modelName + '.findOneAndUpdate(update)\n'
+ + ' ' + this.modelName + '.findOneAndUpdate()\n';
+ throw new TypeError(msg);
+ }
+ update = conditions;
+ conditions = undefined;
+ }
+ callback = this.$handleCallbackError(callback);
+
+ let fields;
+ if (options) {
+ fields = options.fields || options.projection;
+ }
+
+ update = utils.clone(update, {
+ depopulate: true,
+ _isNested: true
+ });
+
+ _decorateUpdateWithVersionKey(update, options, this.schema.options.versionKey);
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(fields);
+
+ return mq.findOneAndUpdate(conditions, update, options, callback);
+};
+
+/*!
+ * Decorate the update with a version key, if necessary
+ */
+
+function _decorateUpdateWithVersionKey(update, options, versionKey) {
+ if (!versionKey || !get(options, 'upsert', false)) {
+ return;
+ }
+
+ const updatedPaths = modifiedPaths(update);
+ if (!updatedPaths[versionKey]) {
+ if (options.overwrite) {
+ update[versionKey] = 0;
+ } else {
+ if (!update.$setOnInsert) {
+ update.$setOnInsert = {};
+ }
+ update.$setOnInsert[versionKey] = 0;
+ }
+ }
+}
+
+/**
+ * Issues a mongodb findAndModify update command by a document's _id field.
+ * `findByIdAndUpdate(id, ...)` is equivalent to `findOneAndUpdate({ _id: id }, ...)`.
+ *
+ * Finds a matching document, updates it according to the `update` arg,
+ * passing any `options`, and returns the found document (if any) to the
+ * callback. The query executes if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndUpdate()`
+ *
+ * ####Options:
+ *
+ * - `new`: bool - true to return the modified document rather than the original. defaults to false
+ * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
+ * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `select`: sets the document fields to return
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findByIdAndUpdate(id, update, options, callback) // executes
+ * A.findByIdAndUpdate(id, update, options) // returns Query
+ * A.findByIdAndUpdate(id, update, callback) // executes
+ * A.findByIdAndUpdate(id, update) // returns Query
+ * A.findByIdAndUpdate() // returns Query
+ *
+ * ####Note:
+ *
+ * All top level update keys which are not `atomic` operation names are treated as set operations:
+ *
+ * ####Example:
+ *
+ * Model.findByIdAndUpdate(id, { name: 'jason bourne' }, options, callback)
+ *
+ * // is sent as
+ * Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options, callback)
+ *
+ * This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
+ *
+ * ####Note:
+ *
+ * Values are cast to their appropriate types when using the findAndModify helpers.
+ * However, the below are not executed by default.
+ *
+ * - defaults. Use the `setDefaultsOnInsert` option to override.
+ *
+ * `findAndModify` helpers support limited validation. You can
+ * enable these by setting the `runValidators` options,
+ * respectively.
+ *
+ * If you need full-fledged validation, use the traditional approach of first
+ * retrieving the document.
+ *
+ * Model.findById(id, function (err, doc) {
+ * if (err) ..
+ * doc.name = 'jason bourne';
+ * doc.save(callback);
+ * });
+ *
+ * @param {Object|Number|String} id value of `_id` to query by
+ * @param {Object} [update]
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and the [Mongoose lean tutorial](/docs/tutorials/lean.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see Model.findOneAndUpdate #model_Model.findOneAndUpdate
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Model.findByIdAndUpdate = function(id, update, options, callback) {
+ _checkContext(this, 'findByIdAndUpdate');
+
+ callback = this.$handleCallbackError(callback);
+ if (arguments.length === 1) {
+ if (typeof id === 'function') {
+ const msg = 'Model.findByIdAndUpdate(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findByIdAndUpdate(id, callback)\n'
+ + ' ' + this.modelName + '.findByIdAndUpdate(id)\n'
+ + ' ' + this.modelName + '.findByIdAndUpdate()\n';
+ throw new TypeError(msg);
+ }
+ return this.findOneAndUpdate({ _id: id }, undefined);
+ }
+
+ // if a model is passed in instead of an id
+ if (id instanceof Document) {
+ id = id._id;
+ }
+
+ return this.findOneAndUpdate.call(this, { _id: id }, update, options, callback);
+};
+
+/**
+ * Issue a MongoDB `findOneAndDelete()` command.
+ *
+ * Finds a matching document, removes it, and passes the found document
+ * (if any) to the callback.
+ *
+ * Executes the query if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndDelete()`
+ *
+ * This function differs slightly from `Model.findOneAndRemove()` in that
+ * `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/),
+ * as opposed to a `findOneAndDelete()` command. For most mongoose use cases,
+ * this distinction is purely pedantic. You should use `findOneAndDelete()`
+ * unless you have a good reason not to.
+ *
+ * ####Options:
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `select`: sets the document fields to return
+ * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findOneAndDelete(conditions, options, callback) // executes
+ * A.findOneAndDelete(conditions, options) // return Query
+ * A.findOneAndDelete(conditions, callback) // executes
+ * A.findOneAndDelete(conditions) // returns Query
+ * A.findOneAndDelete() // returns Query
+ *
+ * Values are cast to their appropriate types when using the findAndModify helpers.
+ * However, the below are not executed by default.
+ *
+ * - defaults. Use the `setDefaultsOnInsert` option to override.
+ *
+ * `findAndModify` helpers support limited validation. You can
+ * enable these by setting the `runValidators` options,
+ * respectively.
+ *
+ * If you need full-fledged validation, use the traditional approach of first
+ * retrieving the document.
+ *
+ * Model.findById(id, function (err, doc) {
+ * if (err) ..
+ * doc.name = 'jason bourne';
+ * doc.save(callback);
+ * });
+ *
+ * @param {Object} conditions
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.findOneAndDelete = function(conditions, options, callback) {
+ _checkContext(this, 'findOneAndDelete');
+
+ if (arguments.length === 1 && typeof conditions === 'function') {
+ const msg = 'Model.findOneAndDelete(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findOneAndDelete(conditions, callback)\n'
+ + ' ' + this.modelName + '.findOneAndDelete(conditions)\n'
+ + ' ' + this.modelName + '.findOneAndDelete()\n';
+ throw new TypeError(msg);
+ }
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = undefined;
+ }
+ callback = this.$handleCallbackError(callback);
+
+ let fields;
+ if (options) {
+ fields = options.select;
+ options.select = undefined;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(fields);
+
+ return mq.findOneAndDelete(conditions, options, callback);
+};
+
+/**
+ * Issue a MongoDB `findOneAndDelete()` command by a document's _id field.
+ * In other words, `findByIdAndDelete(id)` is a shorthand for
+ * `findOneAndDelete({ _id: id })`.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndDelete()`
+ *
+ * @param {Object|Number|String} id value of `_id` to query by
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see Model.findOneAndRemove #model_Model.findOneAndRemove
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ */
+
+Model.findByIdAndDelete = function(id, options, callback) {
+ _checkContext(this, 'findByIdAndDelete');
+
+ if (arguments.length === 1 && typeof id === 'function') {
+ const msg = 'Model.findByIdAndDelete(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findByIdAndDelete(id, callback)\n'
+ + ' ' + this.modelName + '.findByIdAndDelete(id)\n'
+ + ' ' + this.modelName + '.findByIdAndDelete()\n';
+ throw new TypeError(msg);
+ }
+ callback = this.$handleCallbackError(callback);
+
+ return this.findOneAndDelete({ _id: id }, options, callback);
+};
+
+/**
+ * Issue a MongoDB `findOneAndReplace()` command.
+ *
+ * Finds a matching document, replaces it with the provided doc, and passes the
+ * returned doc to the callback.
+ *
+ * Executes the query if `callback` is passed.
+ *
+ * This function triggers the following query middleware.
+ *
+ * - `findOneAndReplace()`
+ *
+ * ####Options:
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `select`: sets the document fields to return
+ * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findOneAndReplace(conditions, options, callback) // executes
+ * A.findOneAndReplace(conditions, options) // return Query
+ * A.findOneAndReplace(conditions, callback) // executes
+ * A.findOneAndReplace(conditions) // returns Query
+ * A.findOneAndReplace() // returns Query
+ *
+ * Values are cast to their appropriate types when using the findAndModify helpers.
+ * However, the below are not executed by default.
+ *
+ * - defaults. Use the `setDefaultsOnInsert` option to override.
+ *
+ * @param {Object} filter Replace the first document that matches this filter
+ * @param {Object} [replacement] Replace with this document
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](http://mongoosejs.com/docs/api.html#query_Query-lean).
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Function} [callback]
+ * @return {Query}
+ * @api public
+ */
+
+Model.findOneAndReplace = function(filter, replacement, options, callback) {
+ _checkContext(this, 'findOneAndReplace');
+
+ if (arguments.length === 1 && typeof filter === 'function') {
+ const msg = 'Model.findOneAndReplace(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findOneAndReplace(conditions, callback)\n'
+ + ' ' + this.modelName + '.findOneAndReplace(conditions)\n'
+ + ' ' + this.modelName + '.findOneAndReplace()\n';
+ throw new TypeError(msg);
+ }
+
+ if (arguments.length === 3 && typeof options === 'function') {
+ callback = options;
+ options = replacement;
+ replacement = void 0;
+ }
+ if (arguments.length === 2 && typeof replacement === 'function') {
+ callback = replacement;
+ replacement = void 0;
+ options = void 0;
+ }
+ callback = this.$handleCallbackError(callback);
+
+ let fields;
+ if (options) {
+ fields = options.select;
+ options.select = undefined;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(fields);
+
+ return mq.findOneAndReplace(filter, replacement, options, callback);
+};
+
+/**
+ * Issue a mongodb findAndModify remove command.
+ *
+ * Finds a matching document, removes it, passing the found document (if any) to the callback.
+ *
+ * Executes the query if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndRemove()`
+ *
+ * ####Options:
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `select`: sets the document fields to return
+ * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findOneAndRemove(conditions, options, callback) // executes
+ * A.findOneAndRemove(conditions, options) // return Query
+ * A.findOneAndRemove(conditions, callback) // executes
+ * A.findOneAndRemove(conditions) // returns Query
+ * A.findOneAndRemove() // returns Query
+ *
+ * Values are cast to their appropriate types when using the findAndModify helpers.
+ * However, the below are not executed by default.
+ *
+ * - defaults. Use the `setDefaultsOnInsert` option to override.
+ *
+ * `findAndModify` helpers support limited validation. You can
+ * enable these by setting the `runValidators` options,
+ * respectively.
+ *
+ * If you need full-fledged validation, use the traditional approach of first
+ * retrieving the document.
+ *
+ * Model.findById(id, function (err, doc) {
+ * if (err) ..
+ * doc.name = 'jason bourne';
+ * doc.save(callback);
+ * });
+ *
+ * @param {Object} conditions
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Model.findOneAndRemove = function(conditions, options, callback) {
+ _checkContext(this, 'findOneAndRemove');
+
+ if (arguments.length === 1 && typeof conditions === 'function') {
+ const msg = 'Model.findOneAndRemove(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findOneAndRemove(conditions, callback)\n'
+ + ' ' + this.modelName + '.findOneAndRemove(conditions)\n'
+ + ' ' + this.modelName + '.findOneAndRemove()\n';
+ throw new TypeError(msg);
+ }
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = undefined;
+ }
+ callback = this.$handleCallbackError(callback);
+
+ let fields;
+ if (options) {
+ fields = options.select;
+ options.select = undefined;
+ }
+
+ const mq = new this.Query({}, {}, this, this.collection);
+ mq.select(fields);
+
+ return mq.findOneAndRemove(conditions, options, callback);
+};
+
+/**
+ * Issue a mongodb findAndModify remove command by a document's _id field. `findByIdAndRemove(id, ...)` is equivalent to `findOneAndRemove({ _id: id }, ...)`.
+ *
+ * Finds a matching document, removes it, passing the found document (if any) to the callback.
+ *
+ * Executes the query if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndRemove()`
+ *
+ * ####Options:
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `select`: sets the document fields to return
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
+ *
+ * ####Examples:
+ *
+ * A.findByIdAndRemove(id, options, callback) // executes
+ * A.findByIdAndRemove(id, options) // return Query
+ * A.findByIdAndRemove(id, callback) // executes
+ * A.findByIdAndRemove(id) // returns Query
+ * A.findByIdAndRemove() // returns Query
+ *
+ * @param {Object|Number|String} id value of `_id` to query by
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see Model.findOneAndRemove #model_Model.findOneAndRemove
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ */
+
+Model.findByIdAndRemove = function(id, options, callback) {
+ _checkContext(this, 'findByIdAndRemove');
+
+ if (arguments.length === 1 && typeof id === 'function') {
+ const msg = 'Model.findByIdAndRemove(): First argument must not be a function.\n\n'
+ + ' ' + this.modelName + '.findByIdAndRemove(id, callback)\n'
+ + ' ' + this.modelName + '.findByIdAndRemove(id)\n'
+ + ' ' + this.modelName + '.findByIdAndRemove()\n';
+ throw new TypeError(msg);
+ }
+ callback = this.$handleCallbackError(callback);
+
+ return this.findOneAndRemove({ _id: id }, options, callback);
+};
+
+/**
+ * Shortcut for saving one or more documents to the database.
+ * `MyModel.create(docs)` does `new MyModel(doc).save()` for every doc in
+ * docs.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `save()`
+ *
+ * ####Example:
+ *
+ * // pass a spread of docs and a callback
+ * Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) {
+ * if (err) // ...
+ * });
+ *
+ * // pass an array of docs
+ * var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
+ * Candy.create(array, function (err, candies) {
+ * if (err) // ...
+ *
+ * var jellybean = candies[0];
+ * var snickers = candies[1];
+ * // ...
+ * });
+ *
+ * // callback is optional; use the returned promise if you like:
+ * var promise = Candy.create({ type: 'jawbreaker' });
+ * promise.then(function (jawbreaker) {
+ * // ...
+ * })
+ *
+ * @param {Array|Object} docs Documents to insert, as a spread or array
+ * @param {Object} [options] Options passed down to `save()`. To specify `options`, `docs` **must** be an array, not a spread.
+ * @param {Function} [callback] callback
+ * @return {Promise}
+ * @api public
+ */
+
+Model.create = function create(doc, options, callback) {
+ _checkContext(this, 'create');
+
+ let args;
+ let cb;
+ const discriminatorKey = this.schema.options.discriminatorKey;
+
+ if (Array.isArray(doc)) {
+ args = doc;
+ cb = typeof options === 'function' ? options : callback;
+ options = options != null && typeof options === 'object' ? options : {};
+ } else {
+ const last = arguments[arguments.length - 1];
+ options = {};
+ // Handle falsy callbacks re: #5061
+ if (typeof last === 'function' || !last) {
+ cb = last;
+ args = utils.args(arguments, 0, arguments.length - 1);
+ } else {
+ args = utils.args(arguments);
+ }
+
+ if (args.length === 2 &&
+ args[0] != null &&
+ args[1] != null &&
+ args[0].session == null &&
+ last.session != null &&
+ last.session.constructor.name === 'ClientSession' &&
+ !this.schema.path('session')) {
+ // Probably means the user is running into the common mistake of trying
+ // to use a spread to specify options, see gh-7535
+ console.warn('WARNING: to pass a `session` to `Model.create()` in ' +
+ 'Mongoose, you **must** pass an array as the first argument. See: ' +
+ 'https://mongoosejs.com/docs/api.html#model_Model.create');
+ }
+ }
+
+ return promiseOrCallback(cb, cb => {
+ cb = this.$wrapCallback(cb);
+ if (args.length === 0) {
+ return cb(null);
+ }
+
+ const toExecute = [];
+ let firstError;
+ args.forEach(doc => {
+ toExecute.push(callback => {
+ const Model = this.discriminators && doc[discriminatorKey] != null ?
+ this.discriminators[doc[discriminatorKey]] || getDiscriminatorByValue(this, doc[discriminatorKey]) :
+ this;
+ if (Model == null) {
+ throw new MongooseError(`Discriminator "${doc[discriminatorKey]}" not ` +
+ `found for model "${this.modelName}"`);
+ }
+ let toSave = doc;
+ const callbackWrapper = (error, doc) => {
+ if (error) {
+ if (!firstError) {
+ firstError = error;
+ }
+ return callback(null, { error: error });
+ }
+ callback(null, { doc: doc });
+ };
+
+ if (!(toSave instanceof Model)) {
+ try {
+ toSave = new Model(toSave);
+ } catch (error) {
+ return callbackWrapper(error);
+ }
+ }
+
+ toSave.save(options, callbackWrapper);
+ });
+ });
+
+ let numFns = toExecute.length;
+ if (numFns === 0) {
+ return cb(null, []);
+ }
+ const _done = (error, res) => {
+ const savedDocs = [];
+ const len = res.length;
+ for (let i = 0; i < len; ++i) {
+ if (res[i].doc) {
+ savedDocs.push(res[i].doc);
+ }
+ }
+
+ if (firstError) {
+ return cb(firstError, savedDocs);
+ }
+
+ if (doc instanceof Array) {
+ cb(null, savedDocs);
+ } else {
+ cb.apply(this, [null].concat(savedDocs));
+ }
+ };
+
+ const _res = [];
+ toExecute.forEach((fn, i) => {
+ fn((err, res) => {
+ _res[i] = res;
+ if (--numFns <= 0) {
+ return _done(null, _res);
+ }
+ });
+ });
+ }, this.events);
+};
+
+/**
+ * _Requires a replica set running MongoDB >= 3.6.0._ Watches the
+ * underlying collection for changes using
+ * [MongoDB change streams](https://docs.mongodb.com/manual/changeStreams/).
+ *
+ * This function does **not** trigger any middleware. In particular, it
+ * does **not** trigger aggregate middleware.
+ *
+ * The ChangeStream object is an event emitter that emits the following events:
+ *
+ * - 'change': A change occurred, see below example
+ * - 'error': An unrecoverable error occurred. In particular, change streams currently error out if they lose connection to the replica set primary. Follow [this GitHub issue](https://github.com/Automattic/mongoose/issues/6799) for updates.
+ * - 'end': Emitted if the underlying stream is closed
+ * - 'close': Emitted if the underlying stream is closed
+ *
+ * ####Example:
+ *
+ * const doc = await Person.create({ name: 'Ned Stark' });
+ * const changeStream = Person.watch().on('change', change => console.log(change));
+ * // Will print from the above `console.log()`:
+ * // { _id: { _data: ... },
+ * // operationType: 'delete',
+ * // ns: { db: 'mydb', coll: 'Person' },
+ * // documentKey: { _id: 5a51b125c5500f5aa094c7bd } }
+ * await doc.remove();
+ *
+ * @param {Array} [pipeline]
+ * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#watch)
+ * @return {ChangeStream} mongoose-specific change stream wrapper, inherits from EventEmitter
+ * @api public
+ */
+
+Model.watch = function(pipeline, options) {
+ _checkContext(this, 'watch');
+
+ const changeStreamThunk = cb => {
+ if (this.collection.buffer) {
+ this.collection.addQueue(() => {
+ if (this.closed) {
+ return;
+ }
+ const driverChangeStream = this.collection.watch(pipeline, options);
+ cb(null, driverChangeStream);
+ });
+ } else {
+ const driverChangeStream = this.collection.watch(pipeline, options);
+ cb(null, driverChangeStream);
+ }
+ };
+
+ return new ChangeStream(changeStreamThunk, pipeline, options);
+};
+
+/**
+ * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions)
+ * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/),
+ * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).
+ *
+ * Calling `MyModel.startSession()` is equivalent to calling `MyModel.db.startSession()`.
+ *
+ * This function does not trigger any middleware.
+ *
+ * ####Example:
+ *
+ * const session = await Person.startSession();
+ * let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
+ * await doc.remove();
+ * // `doc` will always be null, even if reading from a replica set
+ * // secondary. Without causal consistency, it is possible to
+ * // get a doc back from the below query if the query reads from a
+ * // secondary that is experiencing replication lag.
+ * doc = await Person.findOne({ name: 'Ned Stark' }, null, { session, readPreference: 'secondary' });
+ *
+ * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#startSession)
+ * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
+ * @param {Function} [callback]
+ * @return {Promise} promise that resolves to a MongoDB driver `ClientSession`
+ * @api public
+ */
+
+Model.startSession = function() {
+ _checkContext(this, 'startSession');
+
+ return this.db.startSession.apply(this.db, arguments);
+};
+
+/**
+ * Shortcut for validating an array of documents and inserting them into
+ * MongoDB if they're all valid. This function is faster than `.create()`
+ * because it only sends one operation to the server, rather than one for each
+ * document.
+ *
+ * Mongoose always validates each document **before** sending `insertMany`
+ * to MongoDB. So if one document has a validation error, no documents will
+ * be saved, unless you set
+ * [the `ordered` option to false](https://docs.mongodb.com/manual/reference/method/db.collection.insertMany/#error-handling).
+ *
+ * This function does **not** trigger save middleware.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `insertMany()`
+ *
+ * ####Example:
+ *
+ * var arr = [{ name: 'Star Wars' }, { name: 'The Empire Strikes Back' }];
+ * Movies.insertMany(arr, function(error, docs) {});
+ *
+ * @param {Array|Object|*} doc(s)
+ * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#insertMany)
+ * @param {Boolean} [options.ordered = true] if true, will fail fast on the first error encountered. If false, will insert all the documents it can and report errors later. An `insertMany()` with `ordered = false` is called an "unordered" `insertMany()`.
+ * @param {Boolean} [options.rawResult = false] if false, the returned promise resolves to the documents that passed mongoose document validation. If `true`, will return the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~insertWriteOpCallback) with a `mongoose` property that contains `validationErrors` if this is an unordered `insertMany`.
+ * @param {Boolean} [options.lean = false] if `true`, skips hydrating and validating the documents. This option is useful if you need the extra performance, but Mongoose won't validate the documents before inserting.
+ * @param {Function} [callback] callback
+ * @return {Promise}
+ * @api public
+ */
+
+Model.insertMany = function(arr, options, callback) {
+ _checkContext(this, 'insertMany');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+ return promiseOrCallback(callback, cb => {
+ this.$__insertMany(arr, options, cb);
+ }, this.events);
+};
+
+/*!
+ * ignore
+ */
+
+Model.$__insertMany = function(arr, options, callback) {
+ const _this = this;
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+ if (callback) {
+ callback = this.$handleCallbackError(callback);
+ callback = this.$wrapCallback(callback);
+ }
+ callback = callback || utils.noop;
+ options = options || {};
+ const limit = get(options, 'limit', 1000);
+ const rawResult = get(options, 'rawResult', false);
+ const ordered = get(options, 'ordered', true);
+ const lean = get(options, 'lean', false);
+
+ if (!Array.isArray(arr)) {
+ arr = [arr];
+ }
+
+ const validationErrors = [];
+ const toExecute = arr.map(doc =>
+ callback => {
+ if (!(doc instanceof _this)) {
+ try {
+ doc = new _this(doc);
+ } catch (err) {
+ return callback(err);
+ }
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ // If option `lean` is set to true bypass validation
+ if (lean) {
+ // we have to execute callback at the nextTick to be compatible
+ // with parallelLimit, as `results` variable has TDZ issue if we
+ // execute the callback synchronously
+ return process.nextTick(() => callback(null, doc));
+ }
+ doc.validate({ __noPromise: true }, function(error) {
+ if (error) {
+ // Option `ordered` signals that insert should be continued after reaching
+ // a failing insert. Therefore we delegate "null", meaning the validation
+ // failed. It's up to the next function to filter out all failed models
+ if (ordered === false) {
+ validationErrors.push(error);
+ return callback(null, null);
+ }
+ return callback(error);
+ }
+ callback(null, doc);
+ });
+ });
+
+ parallelLimit(toExecute, limit, function(error, docs) {
+ if (error) {
+ callback(error, null);
+ return;
+ }
+ // We filter all failed pre-validations by removing nulls
+ const docAttributes = docs.filter(function(doc) {
+ return doc != null;
+ });
+ // Quickly escape while there aren't any valid docAttributes
+ if (docAttributes.length < 1) {
+ callback(null, []);
+ return;
+ }
+ const docObjects = docAttributes.map(function(doc) {
+ if (doc.schema.options.versionKey) {
+ doc[doc.schema.options.versionKey] = 0;
+ }
+ if (doc.initializeTimestamps) {
+ return doc.initializeTimestamps().toObject(internalToObjectOptions);
+ }
+ return doc.toObject(internalToObjectOptions);
+ });
+
+ _this.collection.insertMany(docObjects, options, function(error, res) {
+ if (error) {
+ callback(error, null);
+ return;
+ }
+ for (let i = 0; i < docAttributes.length; ++i) {
+ docAttributes[i].$__reset();
+ _setIsNew(docAttributes[i], false);
+ }
+ if (rawResult) {
+ if (ordered === false) {
+ // Decorate with mongoose validation errors in case of unordered,
+ // because then still do `insertMany()`
+ res.mongoose = {
+ validationErrors: validationErrors
+ };
+ }
+ return callback(null, res);
+ }
+ callback(null, docAttributes);
+ });
+ });
+};
+
+/*!
+ * ignore
+ */
+
+function _setIsNew(doc, val) {
+ doc.isNew = val;
+ doc.emit('isNew', val);
+ doc.constructor.emit('isNew', val);
+
+ const subdocs = doc.$__getAllSubdocs();
+ for (const subdoc of subdocs) {
+ subdoc.isNew = val;
+ }
+}
+
+/**
+ * Sends multiple `insertOne`, `updateOne`, `updateMany`, `replaceOne`,
+ * `deleteOne`, and/or `deleteMany` operations to the MongoDB server in one
+ * command. This is faster than sending multiple independent operations (like)
+ * if you use `create()`) because with `bulkWrite()` there is only one round
+ * trip to MongoDB.
+ *
+ * Mongoose will perform casting on all operations you provide.
+ *
+ * This function does **not** trigger any middleware, not `save()` nor `update()`.
+ * If you need to trigger
+ * `save()` middleware for every document use [`create()`](http://mongoosejs.com/docs/api.html#model_Model.create) instead.
+ *
+ * ####Example:
+ *
+ * Character.bulkWrite([
+ * {
+ * insertOne: {
+ * document: {
+ * name: 'Eddard Stark',
+ * title: 'Warden of the North'
+ * }
+ * }
+ * },
+ * {
+ * updateOne: {
+ * filter: { name: 'Eddard Stark' },
+ * // If you were using the MongoDB driver directly, you'd need to do
+ * // `update: { $set: { title: ... } }` but mongoose adds $set for
+ * // you.
+ * update: { title: 'Hand of the King' }
+ * }
+ * },
+ * {
+ * deleteOne: {
+ * {
+ * filter: { name: 'Eddard Stark' }
+ * }
+ * }
+ * }
+ * ]).then(res => {
+ * // Prints "1 1 1"
+ * console.log(res.insertedCount, res.modifiedCount, res.deletedCount);
+ * });
+ *
+ * The [supported operations](https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/#db.collection.bulkWrite) are:
+ *
+ * - `insertOne`
+ * - `updateOne`
+ * - `updateMany`
+ * - `deleteOne`
+ * - `deleteMany`
+ * - `replaceOne`
+ *
+ * @param {Array} ops
+ * @param {Object} [ops.insertOne.document] The document to insert
+ * @param {Object} [opts.updateOne.filter] Update the first document that matches this filter
+ * @param {Object} [opts.updateOne.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
+ * @param {Boolean} [opts.updateOne.upsert=false] If true, insert a doc if none match
+ * @param {Object} [opts.updateOne.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
+ * @param {Array} [opts.updateOne.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
+ * @param {Object} [opts.updateMany.filter] Update all the documents that match this filter
+ * @param {Object} [opts.updateMany.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
+ * @param {Boolean} [opts.updateMany.upsert=false] If true, insert a doc if no documents match `filter`
+ * @param {Object} [opts.updateMany.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
+ * @param {Array} [opts.updateMany.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
+ * @param {Object} [opts.deleteOne.filter] Delete the first document that matches this filter
+ * @param {Object} [opts.deleteMany.filter] Delete all documents that match this filter
+ * @param {Object} [opts.replaceOne.filter] Replace the first document that matches this filter
+ * @param {Object} [opts.replaceOne.replacement] The replacement document
+ * @param {Boolean} [opts.replaceOne.upsert=false] If true, insert a doc if no documents match `filter`
+ * @param {Object} [options]
+ * @param {Boolean} [options.ordered=true] If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
+ * @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](/docs/transactions.html).
+ * @param {String|number} [options.w=1] The [write concern](https://docs.mongodb.com/manual/reference/write-concern/). See [`Query#w()`](/docs/api.html#query_Query-w) for more information.
+ * @param {number} [options.wtimeout=null] The [write concern timeout](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout).
+ * @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://docs.mongodb.com/manual/reference/write-concern/#j-option)
+ * @param {Boolean} [options.bypassDocumentValidation=false] If true, disable [MongoDB server-side schema validation](https://docs.mongodb.com/manual/core/schema-validation/) for all writes in this bulk.
+ * @param {Function} [callback] callback `function(error, bulkWriteOpResult) {}`
+ * @return {Promise} resolves to a [`BulkWriteOpResult`](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult) if the operation succeeds
+ * @api public
+ */
+
+Model.bulkWrite = function(ops, options, callback) {
+ _checkContext(this, 'bulkWrite');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+ options = options || {};
+
+ const validations = ops.map(op => castBulkWrite(this, op, options));
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+ each(validations, (fn, cb) => fn(cb), error => {
+ if (error) {
+ return cb(error);
+ }
+
+ this.collection.bulkWrite(ops, options, (error, res) => {
+ if (error) {
+ return cb(error);
+ }
+
+ cb(null, res);
+ });
+ });
+ }, this.events);
+};
+
+/**
+ * Shortcut for creating a new Document from existing raw data, pre-saved in the DB.
+ * The document returned has no paths marked as modified initially.
+ *
+ * ####Example:
+ *
+ * // hydrate previous data into a Mongoose document
+ * var mongooseCandy = Candy.hydrate({ _id: '54108337212ffb6d459f854c', type: 'jelly bean' });
+ *
+ * @param {Object} obj
+ * @return {Document} document instance
+ * @api public
+ */
+
+Model.hydrate = function(obj) {
+ _checkContext(this, 'hydrate');
+
+ const model = require('./queryhelpers').createModel(this, obj);
+ model.init(obj);
+ return model;
+};
+
+/**
+ * Updates one document in the database without returning it.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `update()`
+ *
+ * ####Examples:
+ *
+ * MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
+ *
+ * const res = await MyModel.update({ name: 'Tobi' }, { ferret: true });
+ * res.n; // Number of documents that matched `{ name: 'Tobi' }`
+ * // Number of documents that were changed. If every doc matched already
+ * // had `ferret` set to `true`, `nModified` will be 0.
+ * res.nModified;
+ *
+ * ####Valid options:
+ *
+ * - `strict` (boolean): overrides the [schema-level `strict` option](/docs/guide.html#strict) for this update
+ * - `upsert` (boolean): whether to create the doc if it doesn't match (false)
+ * - `writeConcern` (object): sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * - `omitUndefined` (boolean): If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * - `multi` (boolean): whether multiple documents should be updated (false)
+ * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * - `setDefaultsOnInsert` (boolean): if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * - `timestamps` (boolean): If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * - `overwrite` (boolean): disables update-only mode, allowing you to overwrite the doc (false)
+ *
+ * All `update` values are cast to their appropriate SchemaTypes before being sent.
+ *
+ * The `callback` function receives `(err, rawResponse)`.
+ *
+ * - `err` is the error if any occurred
+ * - `rawResponse` is the full response from Mongo
+ *
+ * ####Note:
+ *
+ * All top level keys which are not `atomic` operation names are treated as set operations:
+ *
+ * ####Example:
+ *
+ * var query = { name: 'borne' };
+ * Model.update(query, { name: 'jason bourne' }, options, callback);
+ *
+ * // is sent as
+ * Model.update(query, { $set: { name: 'jason bourne' }}, options, function(err, res));
+ * // if overwrite option is false. If overwrite is true, sent without the $set wrapper.
+ *
+ * This helps prevent accidentally overwriting all documents in your collection with `{ name: 'jason bourne' }`.
+ *
+ * ####Note:
+ *
+ * Be careful to not use an existing model instance for the update clause (this won't work and can cause weird behavior like infinite loops). Also, ensure that the update clause does not have an _id property, which causes Mongo to return a "Mod on _id not allowed" error.
+ *
+ * ####Note:
+ *
+ * Mongoose casts values and runs setters when using update. The following
+ * features are **not** applied by default.
+ *
+ * - [defaults](/docs/defaults.html#the-setdefaultsoninsert-option)
+ * - [validators](/docs/validation.html#update-validators)
+ * - middleware
+ *
+ * If you need document middleware and fully-featured validation, load the
+ * document first and then use [`save()`](/docs/api.html#model_Model-save).
+ *
+ * Model.findOne({ name: 'borne' }, function (err, doc) {
+ * if (err) ..
+ * doc.name = 'jason bourne';
+ * doc.save(callback);
+ * })
+ *
+ * @see strict http://mongoosejs.com/docs/guide.html#strict
+ * @see response http://docs.mongodb.org/v2.6/reference/command/update/#output
+ * @param {Object} filter
+ * @param {Object} doc
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.multi=false] whether multiple documents should be updated or just the first one that matches `filter`.
+ * @param {Boolean} [options.runValidators=false] if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * @param {Boolean} [options.setDefaultsOnInsert=false] if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://docs.mongodb.com/manual/reference/operator/update/) in `doc`, Mongoose will wrap `doc` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @param {Function} [callback]
+ * @return {Query}
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @api public
+ */
+
+Model.update = function update(conditions, doc, options, callback) {
+ _checkContext(this, 'update');
+
+ return _update(this, 'update', conditions, doc, options, callback);
+};
+
+/**
+ * Same as `update()`, except MongoDB will update _all_ documents that match
+ * `filter` (as opposed to just the first one) regardless of the value of
+ * the `multi` option.
+ *
+ * **Note** updateMany will _not_ fire update middleware. Use `pre('updateMany')`
+ * and `post('updateMany')` instead.
+ *
+ * ####Example:
+ * const res = await Person.updateMany({ name: /Stark$/ }, { isDeleted: true });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `updateMany()`
+ *
+ * @param {Object} filter
+ * @param {Object} doc
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
+ * @return {Query}
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @api public
+ */
+
+Model.updateMany = function updateMany(conditions, doc, options, callback) {
+ _checkContext(this, 'updateMany');
+
+ return _update(this, 'updateMany', conditions, doc, options, callback);
+};
+
+/**
+ * Same as `update()`, except it does not support the `multi` or `overwrite`
+ * options.
+ *
+ * - MongoDB will update _only_ the first document that matches `filter` regardless of the value of the `multi` option.
+ * - Use `replaceOne()` if you want to overwrite an entire document rather than using atomic operators like `$set`.
+ *
+ * ####Example:
+ * const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `updateOne()`
+ *
+ * @param {Object} filter
+ * @param {Object} doc
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @return {Query}
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @api public
+ */
+
+Model.updateOne = function updateOne(conditions, doc, options, callback) {
+ _checkContext(this, 'updateOne');
+
+ return _update(this, 'updateOne', conditions, doc, options, callback);
+};
+
+/**
+ * Same as `update()`, except MongoDB replace the existing document with the
+ * given document (no atomic operators like `$set`).
+ *
+ * ####Example:
+ * const res = await Person.replaceOne({ _id: 24601 }, { name: 'Jean Valjean' });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `replaceOne()`
+ *
+ * @param {Object} filter
+ * @param {Object} doc
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
+ * @return {Query}
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @return {Query}
+ * @api public
+ */
+
+Model.replaceOne = function replaceOne(conditions, doc, options, callback) {
+ _checkContext(this, 'replaceOne');
+
+ const versionKey = get(this, 'schema.options.versionKey', null);
+ if (versionKey && !doc[versionKey]) {
+ doc[versionKey] = 0;
+ }
+
+ return _update(this, 'replaceOne', conditions, doc, options, callback);
+};
+
+/*!
+ * Common code for `updateOne()`, `updateMany()`, `replaceOne()`, and `update()`
+ * because they need to do the same thing
+ */
+
+function _update(model, op, conditions, doc, options, callback) {
+ const mq = new model.Query({}, {}, model, model.collection);
+
+ callback = model.$handleCallbackError(callback);
+ // gh-2406
+ // make local deep copy of conditions
+ if (conditions instanceof Document) {
+ conditions = conditions.toObject();
+ } else {
+ conditions = utils.clone(conditions);
+ }
+ options = typeof options === 'function' ? options : utils.clone(options);
+
+ const versionKey = get(model, 'schema.options.versionKey', null);
+ _decorateUpdateWithVersionKey(doc, options, versionKey);
+
+ return mq[op](conditions, doc, options, callback);
+}
+
+/**
+ * Executes a mapReduce command.
+ *
+ * `o` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver implementation. See [node-mongodb-native mapReduce() documentation](http://mongodb.github.io/node-mongodb-native/api-generated/collection.html#mapreduce) for more detail about options.
+ *
+ * This function does not trigger any middleware.
+ *
+ * ####Example:
+ *
+ * var o = {};
+ * // `map()` and `reduce()` are run on the MongoDB server, not Node.js,
+ * // these functions are converted to strings
+ * o.map = function () { emit(this.name, 1) };
+ * o.reduce = function (k, vals) { return vals.length };
+ * User.mapReduce(o, function (err, results) {
+ * console.log(results)
+ * })
+ *
+ * ####Other options:
+ *
+ * - `query` {Object} query filter object.
+ * - `sort` {Object} sort input objects using this key
+ * - `limit` {Number} max number of documents
+ * - `keeptemp` {Boolean, default:false} keep temporary data
+ * - `finalize` {Function} finalize function
+ * - `scope` {Object} scope variables exposed to map/reduce/finalize during execution
+ * - `jsMode` {Boolean, default:false} it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X
+ * - `verbose` {Boolean, default:false} provide statistics on job execution time.
+ * - `readPreference` {String}
+ * - `out*` {Object, default: {inline:1}} sets the output target for the map reduce job.
+ *
+ * ####* out options:
+ *
+ * - `{inline:1}` the results are returned in an array
+ * - `{replace: 'collectionName'}` add the results to collectionName: the results replace the collection
+ * - `{reduce: 'collectionName'}` add the results to collectionName: if dups are detected, uses the reducer / finalize functions
+ * - `{merge: 'collectionName'}` add the results to collectionName: if dups exist the new docs overwrite the old
+ *
+ * If `options.out` is set to `replace`, `merge`, or `reduce`, a Model instance is returned that can be used for further querying. Queries run against this model are all executed with the [`lean` option](/docs/tutorials/lean.html); meaning only the js object is returned and no Mongoose magic is applied (getters, setters, etc).
+ *
+ * ####Example:
+ *
+ * var o = {};
+ * // You can also define `map()` and `reduce()` as strings if your
+ * // linter complains about `emit()` not being defined
+ * o.map = 'function () { emit(this.name, 1) }';
+ * o.reduce = 'function (k, vals) { return vals.length }';
+ * o.out = { replace: 'createdCollectionNameForResults' }
+ * o.verbose = true;
+ *
+ * User.mapReduce(o, function (err, model, stats) {
+ * console.log('map reduce took %d ms', stats.processtime)
+ * model.find().where('value').gt(10).exec(function (err, docs) {
+ * console.log(docs);
+ * });
+ * })
+ *
+ * // `mapReduce()` returns a promise. However, ES6 promises can only
+ * // resolve to exactly one value,
+ * o.resolveToObject = true;
+ * var promise = User.mapReduce(o);
+ * promise.then(function (res) {
+ * var model = res.model;
+ * var stats = res.stats;
+ * console.log('map reduce took %d ms', stats.processtime)
+ * return model.find().where('value').gt(10).exec();
+ * }).then(function (docs) {
+ * console.log(docs);
+ * }).then(null, handleError).end()
+ *
+ * @param {Object} o an object specifying map-reduce options
+ * @param {Function} [callback] optional callback
+ * @see http://www.mongodb.org/display/DOCS/MapReduce
+ * @return {Promise}
+ * @api public
+ */
+
+Model.mapReduce = function mapReduce(o, callback) {
+ _checkContext(this, 'mapReduce');
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+
+ if (!Model.mapReduce.schema) {
+ const opts = { noId: true, noVirtualId: true, strict: false };
+ Model.mapReduce.schema = new Schema({}, opts);
+ }
+
+ if (!o.out) o.out = { inline: 1 };
+ if (o.verbose !== false) o.verbose = true;
+
+ o.map = String(o.map);
+ o.reduce = String(o.reduce);
+
+ if (o.query) {
+ let q = new this.Query(o.query);
+ q.cast(this);
+ o.query = q._conditions;
+ q = undefined;
+ }
+
+ this.collection.mapReduce(null, null, o, (err, res) => {
+ if (err) {
+ return cb(err);
+ }
+ if (res.collection) {
+ // returned a collection, convert to Model
+ const model = Model.compile('_mapreduce_' + res.collection.collectionName,
+ Model.mapReduce.schema, res.collection.collectionName, this.db,
+ this.base);
+
+ model._mapreduce = true;
+ res.model = model;
+
+ return cb(null, res);
+ }
+
+ cb(null, res);
+ });
+ }, this.events);
+};
+
+/**
+ * Performs [aggregations](http://docs.mongodb.org/manual/applications/aggregation/) on the models collection.
+ *
+ * If a `callback` is passed, the `aggregate` is executed and a `Promise` is returned. If a callback is not passed, the `aggregate` itself is returned.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `aggregate()`
+ *
+ * ####Example:
+ *
+ * // Find the max balance of all accounts
+ * Users.aggregate([
+ * { $group: { _id: null, maxBalance: { $max: '$balance' }}},
+ * { $project: { _id: 0, maxBalance: 1 }}
+ * ]).
+ * then(function (res) {
+ * console.log(res); // [ { maxBalance: 98000 } ]
+ * });
+ *
+ * // Or use the aggregation pipeline builder.
+ * Users.aggregate().
+ * group({ _id: null, maxBalance: { $max: '$balance' } }).
+ * project('-id maxBalance').
+ * exec(function (err, res) {
+ * if (err) return handleError(err);
+ * console.log(res); // [ { maxBalance: 98 } ]
+ * });
+ *
+ * ####NOTE:
+ *
+ * - Mongoose does **not** cast aggregation pipelines to the model's schema because `$project` and `$group` operators allow redefining the "shape" of the documents at any stage of the pipeline, which may leave documents in an incompatible format. You can use the [mongoose-cast-aggregation plugin](https://github.com/AbdelrahmanHafez/mongoose-cast-aggregation) to enable minimal casting for aggregation pipelines.
+ * - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
+ *
+ * @see Aggregate #aggregate_Aggregate
+ * @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/
+ * @param {Array} [pipeline] aggregation pipeline as an array of objects
+ * @param {Function} [callback]
+ * @return {Aggregate}
+ * @api public
+ */
+
+Model.aggregate = function aggregate(pipeline, callback) {
+ _checkContext(this, 'aggregate');
+
+ if (arguments.length > 2 || get(pipeline, 'constructor.name') === 'Object') {
+ throw new MongooseError('Mongoose 5.x disallows passing a spread of operators ' +
+ 'to `Model.aggregate()`. Instead of ' +
+ '`Model.aggregate({ $match }, { $skip })`, do ' +
+ '`Model.aggregate([{ $match }, { $skip }])`');
+ }
+
+ if (typeof pipeline === 'function') {
+ callback = pipeline;
+ pipeline = [];
+ }
+
+ const aggregate = new Aggregate(pipeline || []);
+ aggregate.model(this);
+
+ if (typeof callback === 'undefined') {
+ return aggregate;
+ }
+
+ callback = this.$handleCallbackError(callback);
+ callback = this.$wrapCallback(callback);
+
+ aggregate.exec(callback);
+ return aggregate;
+};
+
+/**
+ * Casts and validates the given object against this model's schema, passing the
+ * given `context` to custom validators.
+ *
+ * ####Example:
+ *
+ * const Model = mongoose.model('Test', Schema({
+ * name: { type: String, required: true },
+ * age: { type: Number, required: true }
+ * });
+ *
+ * try {
+ * await Model.validate({ name: null }, ['name'])
+ * } catch (err) {
+ * err instanceof mongoose.Error.ValidationError; // true
+ * Object.keys(err.errors); // ['name']
+ * }
+ *
+ * @param {Object} obj
+ * @param {Array} pathsToValidate
+ * @param {Object} [context]
+ * @param {Function} [callback]
+ * @return {Promise|undefined}
+ * @api public
+ */
+
+Model.validate = function validate(obj, pathsToValidate, context, callback) {
+ return promiseOrCallback(callback, cb => {
+ const schema = this.schema;
+ let paths = Object.keys(schema.paths);
+
+ if (pathsToValidate != null) {
+ const _pathsToValidate = new Set(pathsToValidate);
+ paths = paths.filter(p => {
+ const pieces = p.split('.');
+ let cur = pieces[0];
+ for (let i = 0; i < pieces.length; ++i) {
+ if (_pathsToValidate.has(cur)) {
+ return true;
+ }
+ cur += '.' + pieces[i];
+ }
+ return _pathsToValidate.has(p);
+ });
+ }
+
+ let remaining = paths.length;
+ let error = null;
+ for (const path of paths) {
+ const schematype = schema.path(path);
+ if (schematype == null) {
+ _checkDone();
+ continue;
+ }
+
+ const pieces = path.split('.');
+ let cur = obj;
+ for (let i = 0; i < pieces.length - 1; ++i) {
+ cur = cur[pieces[i]];
+ }
+
+ let val = get(obj, path, void 0);
+
+ if (val != null) {
+ try {
+ val = schematype.cast(val);
+ cur[pieces[pieces.length - 1]] = val;
+ } catch (err) {
+ error = error || new ValidationError();
+ error.addError(path, err);
+
+ _checkDone();
+ continue;
+ }
+ }
+
+ schematype.doValidate(val, err => {
+ if (err) {
+ error = error || new ValidationError();
+ if (err instanceof ValidationError) {
+ for (const _err of Object.keys(err.errors)) {
+ error.addError(`${path}.${err.errors[_err].path}`, _err);
+ }
+ } else {
+ error.addError(err.path, err);
+ }
+ }
+ _checkDone();
+ }, context);
+ }
+
+ function _checkDone() {
+ if (--remaining <= 0) {
+ return cb(error);
+ }
+ }
+ });
+};
+
+/**
+ * Implements `$geoSearch` functionality for Mongoose
+ *
+ * This function does not trigger any middleware
+ *
+ * ####Example:
+ *
+ * var options = { near: [10, 10], maxDistance: 5 };
+ * Locations.geoSearch({ type : "house" }, options, function(err, res) {
+ * console.log(res);
+ * });
+ *
+ * ####Options:
+ * - `near` {Array} x,y point to search for
+ * - `maxDistance` {Number} the maximum distance from the point near that a result can be
+ * - `limit` {Number} The maximum number of results to return
+ * - `lean` {Object|Boolean} return the raw object instead of the Mongoose Model
+ *
+ * @param {Object} conditions an object that specifies the match condition (required)
+ * @param {Object} options for the geoSearch, some (near, maxDistance) are required
+ * @param {Object|Boolean} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and the [Mongoose lean tutorial](/docs/tutorials/lean.html).
+ * @param {Function} [callback] optional callback
+ * @return {Promise}
+ * @see http://docs.mongodb.org/manual/reference/command/geoSearch/
+ * @see http://docs.mongodb.org/manual/core/geohaystack/
+ * @api public
+ */
+
+Model.geoSearch = function(conditions, options, callback) {
+ _checkContext(this, 'geoSearch');
+
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+ let error;
+ if (conditions === undefined || !utils.isObject(conditions)) {
+ error = new MongooseError('Must pass conditions to geoSearch');
+ } else if (!options.near) {
+ error = new MongooseError('Must specify the near option in geoSearch');
+ } else if (!Array.isArray(options.near)) {
+ error = new MongooseError('near option must be an array [x, y]');
+ }
+
+ if (error) {
+ return cb(error);
+ }
+
+ // send the conditions in the options object
+ options.search = conditions;
+
+ this.collection.geoHaystackSearch(options.near[0], options.near[1], options, (err, res) => {
+ if (err) {
+ return cb(err);
+ }
+
+ let count = res.results.length;
+ if (options.lean || count === 0) {
+ return cb(null, res.results);
+ }
+
+ const errSeen = false;
+
+ function init(err) {
+ if (err && !errSeen) {
+ return cb(err);
+ }
+
+ if (!--count && !errSeen) {
+ cb(null, res.results);
+ }
+ }
+
+ for (let i = 0; i < res.results.length; ++i) {
+ const temp = res.results[i];
+ res.results[i] = new this();
+ res.results[i].init(temp, {}, init);
+ }
+ });
+ }, this.events);
+};
+
+/**
+ * Populates document references.
+ *
+ * ####Available top-level options:
+ *
+ * - path: space delimited path(s) to populate
+ * - select: optional fields to select
+ * - match: optional query conditions to match
+ * - model: optional name of the model to use for population
+ * - options: optional query options like sort, limit, etc
+ * - justOne: optional boolean, if true Mongoose will always set `path` to an array. Inferred from schema by default.
+ *
+ * ####Examples:
+ *
+ * // populates a single object
+ * User.findById(id, function (err, user) {
+ * var opts = [
+ * { path: 'company', match: { x: 1 }, select: 'name' },
+ * { path: 'notes', options: { limit: 10 }, model: 'override' }
+ * ];
+ *
+ * User.populate(user, opts, function (err, user) {
+ * console.log(user);
+ * });
+ * });
+ *
+ * // populates an array of objects
+ * User.find(match, function (err, users) {
+ * var opts = [{ path: 'company', match: { x: 1 }, select: 'name' }];
+ *
+ * var promise = User.populate(users, opts);
+ * promise.then(console.log).end();
+ * })
+ *
+ * // imagine a Weapon model exists with two saved documents:
+ * // { _id: 389, name: 'whip' }
+ * // { _id: 8921, name: 'boomerang' }
+ * // and this schema:
+ * // new Schema({
+ * // name: String,
+ * // weapon: { type: ObjectId, ref: 'Weapon' }
+ * // });
+ *
+ * var user = { name: 'Indiana Jones', weapon: 389 };
+ * Weapon.populate(user, { path: 'weapon', model: 'Weapon' }, function (err, user) {
+ * console.log(user.weapon.name); // whip
+ * })
+ *
+ * // populate many plain objects
+ * var users = [{ name: 'Indiana Jones', weapon: 389 }]
+ * users.push({ name: 'Batman', weapon: 8921 })
+ * Weapon.populate(users, { path: 'weapon' }, function (err, users) {
+ * users.forEach(function (user) {
+ * console.log('%s uses a %s', users.name, user.weapon.name)
+ * // Indiana Jones uses a whip
+ * // Batman uses a boomerang
+ * });
+ * });
+ * // Note that we didn't need to specify the Weapon model because
+ * // it is in the schema's ref
+ *
+ * @param {Document|Array} docs Either a single document or array of documents to populate.
+ * @param {Object} options A hash of key/val (path, options) used for population.
+ * @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
+ * @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](/docs/schematypes.html#schematype-options).
+ * @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
+ * @param {Object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://docs.mongodb.com/manual/tutorial/query-documents/), or a function that returns a filter object.
+ * @param {Boolean} [options.skipInvalidIds=false] By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type.
+ * @param {Number} [options.perDocumentLimit=null] For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
+ * @param {Object} [options.options=null] Additional options like `limit` and `lean`.
+ * @param {Function} [callback(err,doc)] Optional callback, executed upon completion. Receives `err` and the `doc(s)`.
+ * @return {Promise}
+ * @api public
+ */
+
+Model.populate = function(docs, paths, callback) {
+ _checkContext(this, 'populate');
+
+ const _this = this;
+
+ // normalized paths
+ paths = utils.populate(paths);
+
+ // data that should persist across subPopulate calls
+ const cache = {};
+
+ callback = this.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, cb => {
+ cb = this.$wrapCallback(cb);
+ _populate(_this, docs, paths, cache, cb);
+ }, this.events);
+};
+
+/*!
+ * Populate helper
+ *
+ * @param {Model} model the model to use
+ * @param {Document|Array} docs Either a single document or array of documents to populate.
+ * @param {Object} paths
+ * @param {Function} [cb(err,doc)] Optional callback, executed upon completion. Receives `err` and the `doc(s)`.
+ * @return {Function}
+ * @api private
+ */
+
+function _populate(model, docs, paths, cache, callback) {
+ const length = paths.length;
+ let pending = paths.length;
+
+ if (length === 0) {
+ return callback(null, docs);
+ }
+
+ // each path has its own query options and must be executed separately
+ for (let i = 0; i < length; ++i) {
+ populate(model, docs, paths[i], next);
+ }
+
+ function next(err) {
+ if (err) {
+ return callback(err, null);
+ }
+ if (--pending) {
+ return;
+ }
+ callback(null, docs);
+ }
+}
+
+/*!
+ * Populates `docs`
+ */
+const excludeIdReg = /\s?-_id\s?/;
+const excludeIdRegGlobal = /\s?-_id\s?/g;
+
+function populate(model, docs, options, callback) {
+ // normalize single / multiple docs passed
+ if (!Array.isArray(docs)) {
+ docs = [docs];
+ }
+
+ if (docs.length === 0 || docs.every(utils.isNullOrUndefined)) {
+ return callback();
+ }
+
+ const modelsMap = getModelsMapForPopulate(model, docs, options);
+
+ if (modelsMap instanceof MongooseError) {
+ return immediate(function() {
+ callback(modelsMap);
+ });
+ }
+
+ const len = modelsMap.length;
+ let vals = [];
+
+ function flatten(item) {
+ // no need to include undefined values in our query
+ return undefined !== item;
+ }
+
+ let _remaining = len;
+ let hasOne = false;
+ const params = [];
+ for (let i = 0; i < len; ++i) {
+ const mod = modelsMap[i];
+ let select = mod.options.select;
+ const match = _formatMatch(mod.match);
+
+ let ids = utils.array.flatten(mod.ids, flatten);
+ ids = utils.array.unique(ids);
+
+ const assignmentOpts = {};
+ assignmentOpts.sort = get(mod, 'options.options.sort', void 0);
+ assignmentOpts.excludeId = excludeIdReg.test(select) || (select && select._id === 0);
+
+ if (ids.length === 0 || ids.every(utils.isNullOrUndefined)) {
+ // Ensure that we set populate virtuals to 0 or empty array even
+ // if we don't actually execute a query because they don't have
+ // a value by default. See gh-7731, gh-8230
+ --_remaining;
+ if (mod.count || mod.isVirtual) {
+ _assign(model, [], mod, assignmentOpts);
+ }
+ continue;
+ }
+
+ hasOne = true;
+ if (mod.foreignField.size === 1) {
+ const foreignField = Array.from(mod.foreignField)[0];
+ const foreignSchemaType = mod.model.schema.path(foreignField);
+ if (foreignField !== '_id' || !match['_id']) {
+ ids = _filterInvalidIds(ids, foreignSchemaType, mod.options.skipInvalidIds);
+ match[foreignField] = { $in: ids };
+ }
+ } else {
+ const $or = [];
+ if (Array.isArray(match.$or)) {
+ match.$and = [{ $or: match.$or }, { $or: $or }];
+ delete match.$or;
+ } else {
+ match.$or = $or;
+ }
+ for (const foreignField of mod.foreignField) {
+ if (foreignField !== '_id' || !match['_id']) {
+ const foreignSchemaType = mod.model.schema.path(foreignField);
+ ids = _filterInvalidIds(ids, foreignSchemaType, mod.options.skipInvalidIds);
+ $or.push({ [foreignField]: { $in: ids } });
+ }
+ }
+ }
+
+ if (assignmentOpts.excludeId) {
+ // override the exclusion from the query so we can use the _id
+ // for document matching during assignment. we'll delete the
+ // _id back off before returning the result.
+ if (typeof select === 'string') {
+ select = select.replace(excludeIdRegGlobal, ' ');
+ } else {
+ // preserve original select conditions by copying
+ select = utils.object.shallowCopy(select);
+ delete select._id;
+ }
+ }
+
+ if (mod.options.options && mod.options.options.limit != null) {
+ assignmentOpts.originalLimit = mod.options.options.limit;
+ } else if (mod.options.limit != null) {
+ assignmentOpts.originalLimit = mod.options.limit;
+ }
+
+ params.push([mod, match, select, assignmentOpts, _next]);
+ }
+
+ if (!hasOne) {
+ return callback();
+ }
+
+ for (const arr of params) {
+ _execPopulateQuery.apply(null, arr);
+ }
+
+ function _next(err, valsFromDb) {
+ if (err != null) {
+ return callback(err, null);
+ }
+ vals = vals.concat(valsFromDb);
+ if (--_remaining === 0) {
+ _done();
+ }
+ }
+
+ function _done() {
+ for (const arr of params) {
+ const mod = arr[0];
+ const assignmentOpts = arr[3];
+ _assign(model, vals, mod, assignmentOpts);
+ }
+ callback();
+ }
+}
+
+/*!
+ * ignore
+ */
+
+function _execPopulateQuery(mod, match, select, assignmentOpts, callback) {
+ const subPopulate = utils.clone(mod.options.populate);
+
+ const queryOptions = Object.assign({
+ skip: mod.options.skip,
+ limit: mod.options.limit,
+ perDocumentLimit: mod.options.perDocumentLimit
+ }, mod.options.options);
+
+ if (mod.count) {
+ delete queryOptions.skip;
+ }
+
+ if (queryOptions.perDocumentLimit != null) {
+ queryOptions.limit = queryOptions.perDocumentLimit;
+ delete queryOptions.perDocumentLimit;
+ } else if (queryOptions.limit != null) {
+ queryOptions.limit = queryOptions.limit * mod.ids.length;
+ }
+
+ const query = mod.model.find(match, select, queryOptions);
+ // If we're doing virtual populate and projection is inclusive and foreign
+ // field is not selected, automatically select it because mongoose needs it.
+ // If projection is exclusive and client explicitly unselected the foreign
+ // field, that's the client's fault.
+ for (const foreignField of mod.foreignField) {
+ if (foreignField !== '_id' && query.selectedInclusively() &&
+ !isPathSelectedInclusive(query._fields, foreignField)) {
+ query.select(foreignField);
+ }
+ }
+
+ // If using count, still need the `foreignField` so we can match counts
+ // to documents, otherwise we would need a separate `count()` for every doc.
+ if (mod.count) {
+ for (const foreignField of mod.foreignField) {
+ query.select(foreignField);
+ }
+ }
+
+ // If we need to sub-populate, call populate recursively
+ if (subPopulate) {
+ query.populate(subPopulate);
+ }
+
+ query.exec(callback);
+}
+
+/*!
+ * ignore
+ */
+
+function _assign(model, vals, mod, assignmentOpts) {
+ const options = mod.options;
+ const isVirtual = mod.isVirtual;
+ const justOne = mod.justOne;
+ let _val;
+ const lean = get(options, 'options.lean', false);
+ const projection = parseProjection(get(options, 'select', null), true) ||
+ parseProjection(get(options, 'options.select', null), true);
+ const len = vals.length;
+ const rawOrder = {};
+ const rawDocs = {};
+ let key;
+ let val;
+
+ // Clone because `assignRawDocsToIdStructure` will mutate the array
+ const allIds = utils.clone(mod.allIds);
+
+ // optimization:
+ // record the document positions as returned by
+ // the query result.
+ for (let i = 0; i < len; i++) {
+ val = vals[i];
+ if (val == null) {
+ continue;
+ }
+ for (const foreignField of mod.foreignField) {
+ _val = utils.getValue(foreignField, val);
+ if (Array.isArray(_val)) {
+ _val = utils.array.flatten(_val);
+ const _valLength = _val.length;
+ for (let j = 0; j < _valLength; ++j) {
+ let __val = _val[j];
+ if (__val instanceof Document) {
+ __val = __val._id;
+ }
+ key = String(__val);
+ if (rawDocs[key]) {
+ if (Array.isArray(rawDocs[key])) {
+ rawDocs[key].push(val);
+ rawOrder[key].push(i);
+ } else {
+ rawDocs[key] = [rawDocs[key], val];
+ rawOrder[key] = [rawOrder[key], i];
+ }
+ } else {
+ if (isVirtual && !justOne) {
+ rawDocs[key] = [val];
+ rawOrder[key] = [i];
+ } else {
+ rawDocs[key] = val;
+ rawOrder[key] = i;
+ }
+ }
+ }
+ } else {
+ if (_val instanceof Document) {
+ _val = _val._id;
+ }
+ key = String(_val);
+ if (rawDocs[key]) {
+ if (Array.isArray(rawDocs[key])) {
+ rawDocs[key].push(val);
+ rawOrder[key].push(i);
+ } else {
+ rawDocs[key] = [rawDocs[key], val];
+ rawOrder[key] = [rawOrder[key], i];
+ }
+ } else {
+ rawDocs[key] = val;
+ rawOrder[key] = i;
+ }
+ }
+ // flag each as result of population
+ if (lean) {
+ leanPopulateMap.set(val, mod.model);
+ } else {
+ val.$__.wasPopulated = true;
+ }
+
+ // gh-8460: if user used `-foreignField`, assume this means they
+ // want the foreign field unset even if it isn't excluded in the query.
+ if (projection != null && projection.hasOwnProperty('-' + foreignField)) {
+ if (val.$__ != null) {
+ val.set(foreignField, void 0);
+ } else {
+ mpath.unset(foreignField, val);
+ }
+ }
+ }
+ }
+
+ assignVals({
+ originalModel: model,
+ // If virtual, make sure to not mutate original field
+ rawIds: mod.isVirtual ? allIds : mod.allIds,
+ allIds: allIds,
+ foreignField: mod.foreignField,
+ rawDocs: rawDocs,
+ rawOrder: rawOrder,
+ docs: mod.docs,
+ path: options.path,
+ options: assignmentOpts,
+ justOne: mod.justOne,
+ isVirtual: mod.isVirtual,
+ allOptions: mod,
+ lean: lean,
+ virtual: mod.virtual,
+ count: mod.count,
+ match: mod.match
+ });
+}
+
+/*!
+ * Optionally filter out invalid ids that don't conform to foreign field's schema
+ * to avoid cast errors (gh-7706)
+ */
+
+function _filterInvalidIds(ids, foreignSchemaType, skipInvalidIds) {
+ ids = ids.filter(v => !(v instanceof SkipPopulateValue));
+ if (!skipInvalidIds) {
+ return ids;
+ }
+ return ids.filter(id => {
+ try {
+ foreignSchemaType.cast(id);
+ return true;
+ } catch (err) {
+ return false;
+ }
+ });
+}
+
+/*!
+ * Format `mod.match` given that it may be an array that we need to $or if
+ * the client has multiple docs with match functions
+ */
+
+function _formatMatch(match) {
+ if (Array.isArray(match)) {
+ if (match.length > 1) {
+ return { $or: [].concat(match.map(m => Object.assign({}, m))) };
+ }
+ return Object.assign({}, match[0]);
+ }
+ return Object.assign({}, match);
+}
+
+/*!
+ * Compiler utility.
+ *
+ * @param {String|Function} name model name or class extending Model
+ * @param {Schema} schema
+ * @param {String} collectionName
+ * @param {Connection} connection
+ * @param {Mongoose} base mongoose instance
+ */
+
+Model.compile = function compile(name, schema, collectionName, connection, base) {
+ const versioningEnabled = schema.options.versionKey !== false;
+
+ if (versioningEnabled && !schema.paths[schema.options.versionKey]) {
+ // add versioning to top level documents only
+ const o = {};
+ o[schema.options.versionKey] = Number;
+ schema.add(o);
+ }
+
+ let model;
+ if (typeof name === 'function' && name.prototype instanceof Model) {
+ model = name;
+ name = model.name;
+ schema.loadClass(model, false);
+ model.prototype.$isMongooseModelPrototype = true;
+ } else {
+ // generate new class
+ model = function model(doc, fields, skipId) {
+ model.hooks.execPreSync('createModel', doc);
+ if (!(this instanceof model)) {
+ return new model(doc, fields, skipId);
+ }
+ const discriminatorKey = model.schema.options.discriminatorKey;
+
+ if (model.discriminators == null || doc == null || doc[discriminatorKey] == null) {
+ Model.call(this, doc, fields, skipId);
+ return;
+ }
+
+ // If discriminator key is set, use the discriminator instead (gh-7586)
+ const Discriminator = model.discriminators[doc[discriminatorKey]] ||
+ getDiscriminatorByValue(model, doc[discriminatorKey]);
+ if (Discriminator != null) {
+ return new Discriminator(doc, fields, skipId);
+ }
+
+ // Otherwise, just use the top-level model
+ Model.call(this, doc, fields, skipId);
+ };
+ }
+
+ model.hooks = schema.s.hooks.clone();
+ model.base = base;
+ model.modelName = name;
+
+ if (!(model.prototype instanceof Model)) {
+ model.__proto__ = Model;
+ model.prototype.__proto__ = Model.prototype;
+ }
+ model.model = function model(name) {
+ return this.db.model(name);
+ };
+ model.db = connection;
+ model.prototype.db = connection;
+ model.prototype[modelDbSymbol] = connection;
+ model.discriminators = model.prototype.discriminators = undefined;
+ model[modelSymbol] = true;
+ model.events = new EventEmitter();
+
+ model.prototype.$__setSchema(schema);
+
+ const _userProvidedOptions = schema._userProvidedOptions || {};
+
+ // `bufferCommands` is true by default...
+ let bufferCommands = true;
+ // First, take the global option
+ if (connection.base.get('bufferCommands') != null) {
+ bufferCommands = connection.base.get('bufferCommands');
+ }
+ // Connection-specific overrides the global option
+ if (connection.config.bufferCommands != null) {
+ bufferCommands = connection.config.bufferCommands;
+ }
+ // And schema options override global and connection
+ if (_userProvidedOptions.bufferCommands != null) {
+ bufferCommands = _userProvidedOptions.bufferCommands;
+ }
+
+ const collectionOptions = {
+ bufferCommands: bufferCommands,
+ capped: schema.options.capped,
+ autoCreate: schema.options.autoCreate,
+ Promise: model.base.Promise
+ };
+
+ model.prototype.collection = connection.collection(
+ collectionName,
+ collectionOptions
+ );
+ model.prototype[modelCollectionSymbol] = model.prototype.collection;
+
+ // apply methods and statics
+ applyMethods(model, schema);
+ applyStatics(model, schema);
+ applyHooks(model, schema);
+ applyStaticHooks(model, schema.s.hooks, schema.statics);
+
+ model.schema = model.prototype.schema;
+ model.collection = model.prototype.collection;
+
+ // Create custom query constructor
+ model.Query = function() {
+ Query.apply(this, arguments);
+ };
+ model.Query.prototype = Object.create(Query.prototype);
+ model.Query.base = Query.base;
+ applyQueryMiddleware(model.Query, model);
+ applyQueryMethods(model, schema.query);
+
+ return model;
+};
+
+/*!
+ * Register custom query methods for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+function applyQueryMethods(model, methods) {
+ for (const i in methods) {
+ model.Query.prototype[i] = methods[i];
+ }
+}
+
+/*!
+ * Subclass this model with `conn`, `schema`, and `collection` settings.
+ *
+ * @param {Connection} conn
+ * @param {Schema} [schema]
+ * @param {String} [collection]
+ * @return {Model}
+ */
+
+Model.__subclass = function subclass(conn, schema, collection) {
+ // subclass model using this connection and collection name
+ const _this = this;
+
+ const Model = function Model(doc, fields, skipId) {
+ if (!(this instanceof Model)) {
+ return new Model(doc, fields, skipId);
+ }
+ _this.call(this, doc, fields, skipId);
+ };
+
+ Model.__proto__ = _this;
+ Model.prototype.__proto__ = _this.prototype;
+ Model.db = conn;
+ Model.prototype.db = conn;
+ Model.prototype[modelDbSymbol] = conn;
+
+ _this[subclassedSymbol] = _this[subclassedSymbol] || [];
+ _this[subclassedSymbol].push(Model);
+ if (_this.discriminators != null) {
+ Model.discriminators = {};
+ for (const key of Object.keys(_this.discriminators)) {
+ Model.discriminators[key] = _this.discriminators[key].
+ __subclass(_this.db, _this.discriminators[key].schema, collection);
+ }
+ }
+
+ const s = schema && typeof schema !== 'string'
+ ? schema
+ : _this.prototype.schema;
+
+ const options = s.options || {};
+ const _userProvidedOptions = s._userProvidedOptions || {};
+
+ if (!collection) {
+ collection = _this.prototype.schema.get('collection') ||
+ utils.toCollectionName(_this.modelName, this.base.pluralize());
+ }
+
+ let bufferCommands = true;
+ if (s) {
+ if (conn.config.bufferCommands != null) {
+ bufferCommands = conn.config.bufferCommands;
+ }
+ if (_userProvidedOptions.bufferCommands != null) {
+ bufferCommands = _userProvidedOptions.bufferCommands;
+ }
+ }
+ const collectionOptions = {
+ bufferCommands: bufferCommands,
+ capped: s && options.capped
+ };
+
+ Model.prototype.collection = conn.collection(collection, collectionOptions);
+ Model.prototype[modelCollectionSymbol] = Model.prototype.collection;
+ Model.collection = Model.prototype.collection;
+ // Errors handled internally, so ignore
+ Model.init(() => {});
+ return Model;
+};
+
+Model.$handleCallbackError = function(callback) {
+ if (callback == null) {
+ return callback;
+ }
+ if (typeof callback !== 'function') {
+ throw new MongooseError('Callback must be a function, got ' + callback);
+ }
+
+ const _this = this;
+ return function() {
+ try {
+ callback.apply(null, arguments);
+ } catch (error) {
+ _this.emit('error', error);
+ }
+ };
+};
+
+/*!
+ * ignore
+ */
+
+Model.$wrapCallback = function(callback) {
+ const serverSelectionError = new ServerSelectionError();
+ const _this = this;
+
+ return function(err) {
+ if (err != null && err.name === 'MongoServerSelectionError') {
+ arguments[0] = serverSelectionError.assimilateError(err);
+ }
+ if (err != null && err.name === 'MongoNetworkError' && err.message.endsWith('timed out')) {
+ _this.db.emit('timeout');
+ }
+
+ return callback.apply(null, arguments);
+ };
+};
+
+/**
+ * Helper for console.log. Given a model named 'MyModel', returns the string
+ * `'Model { MyModel }'`.
+ *
+ * ####Example:
+ *
+ * const MyModel = mongoose.model('Test', Schema({ name: String }));
+ * MyModel.inspect(); // 'Model { Test }'
+ * console.log(MyModel); // Prints 'Model { Test }'
+ *
+ * @api public
+ */
+
+Model.inspect = function() {
+ return `Model { ${this.modelName} }`;
+};
+
+if (util.inspect.custom) {
+ /*!
+ * Avoid Node deprecation warning DEP0079
+ */
+
+ Model[util.inspect.custom] = Model.inspect;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = Model;
diff --git a/node_modules/mongoose/lib/options.js b/node_modules/mongoose/lib/options.js
new file mode 100644
index 0000000..8e9fc29
--- /dev/null
+++ b/node_modules/mongoose/lib/options.js
@@ -0,0 +1,14 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+exports.internalToObjectOptions = {
+ transform: false,
+ virtuals: false,
+ getters: false,
+ _skipDepopulateTopLevel: true,
+ depopulate: true,
+ flattenDecimals: false
+};
diff --git a/node_modules/mongoose/lib/options/PopulateOptions.js b/node_modules/mongoose/lib/options/PopulateOptions.js
new file mode 100644
index 0000000..a438dd1
--- /dev/null
+++ b/node_modules/mongoose/lib/options/PopulateOptions.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const clone = require('../helpers/clone');
+
+class PopulateOptions {
+ constructor(obj) {
+ this._docs = {};
+
+ if (obj == null) {
+ return;
+ }
+ obj = clone(obj);
+ Object.assign(this, obj);
+ if (typeof obj.subPopulate === 'object') {
+ this.populate = obj.subPopulate;
+ }
+
+
+ if (obj.perDocumentLimit != null && obj.limit != null) {
+ throw new Error('Can not use `limit` and `perDocumentLimit` at the same time. Path: `' + obj.path + '`.' );
+ }
+ }
+}
+
+/**
+ * The connection used to look up models by name. If not specified, Mongoose
+ * will default to using the connection associated with the model in
+ * `PopulateOptions#model`.
+ *
+ * @memberOf PopulateOptions
+ * @property {Connection} connection
+ * @api public
+ */
+
+module.exports = PopulateOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaArrayOptions.js b/node_modules/mongoose/lib/options/SchemaArrayOptions.js
new file mode 100644
index 0000000..ddd0b37
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaArrayOptions.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on an Array schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ tags: [String] });
+ * schema.path('tags').options; // SchemaArrayOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaArrayOptions
+ */
+
+class SchemaArrayOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If this is an array of strings, an array of allowed values for this path.
+ * Throws an error if this array isn't an array of strings.
+ *
+ * @api public
+ * @property enum
+ * @memberOf SchemaArrayOptions
+ * @type Array
+ * @instance
+ */
+
+Object.defineProperty(SchemaArrayOptions.prototype, 'enum', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaArrayOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaBufferOptions.js b/node_modules/mongoose/lib/options/SchemaBufferOptions.js
new file mode 100644
index 0000000..258130d
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaBufferOptions.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a Buffer schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ bitmap: Buffer });
+ * schema.path('bitmap').options; // SchemaBufferOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaBufferOptions
+ */
+
+class SchemaBufferOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * Set the default subtype for this buffer.
+ *
+ * @api public
+ * @property subtype
+ * @memberOf SchemaBufferOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaBufferOptions.prototype, 'subtype', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaBufferOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaDateOptions.js b/node_modules/mongoose/lib/options/SchemaDateOptions.js
new file mode 100644
index 0000000..09bf27f
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaDateOptions.js
@@ -0,0 +1,64 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a Date schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ startedAt: Date });
+ * schema.path('startedAt').options; // SchemaDateOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaDateOptions
+ */
+
+class SchemaDateOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If set, Mongoose adds a validator that checks that this path is after the
+ * given `min`.
+ *
+ * @api public
+ * @property min
+ * @memberOf SchemaDateOptions
+ * @type Date
+ * @instance
+ */
+
+Object.defineProperty(SchemaDateOptions.prototype, 'min', opts);
+
+/**
+ * If set, Mongoose adds a validator that checks that this path is before the
+ * given `max`.
+ *
+ * @api public
+ * @property max
+ * @memberOf SchemaDateOptions
+ * @type Date
+ * @instance
+ */
+
+Object.defineProperty(SchemaDateOptions.prototype, 'max', opts);
+
+/**
+ * If set, Mongoose creates a TTL index on this path.
+ *
+ * @api public
+ * @property expires
+ * @memberOf SchemaDateOptions
+ * @type Date
+ * @instance
+ */
+
+Object.defineProperty(SchemaDateOptions.prototype, 'expires', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaDateOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaDocumentArrayOptions.js b/node_modules/mongoose/lib/options/SchemaDocumentArrayOptions.js
new file mode 100644
index 0000000..f3fb7a9
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaDocumentArrayOptions.js
@@ -0,0 +1,68 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on an Document Array schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ users: [{ name: string }] });
+ * schema.path('users').options; // SchemaDocumentArrayOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaDocumentOptions
+ */
+
+class SchemaDocumentArrayOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If `true`, Mongoose will skip building any indexes defined in this array's schema.
+ * If not set, Mongoose will build all indexes defined in this array's schema.
+ *
+ * ####Example:
+ *
+ * const childSchema = Schema({ name: { type: String, index: true } });
+ * // If `excludeIndexes` is `true`, Mongoose will skip building an index
+ * // on `arr.name`. Otherwise, Mongoose will build an index on `arr.name`.
+ * const parentSchema = Schema({
+ * arr: { type: [childSchema], excludeIndexes: true }
+ * });
+ *
+ * @api public
+ * @property excludeIndexes
+ * @memberOf SchemaDocumentArrayOptions
+ * @type Array
+ * @instance
+ */
+
+Object.defineProperty(SchemaDocumentArrayOptions.prototype, 'excludeIndexes', opts);
+
+/**
+ * If set, overwrites the child schema's `_id` option.
+ *
+ * ####Example:
+ *
+ * const childSchema = Schema({ name: String });
+ * const parentSchema = Schema({
+ * child: { type: childSchema, _id: false }
+ * });
+ * parentSchema.path('child').schema.options._id; // false
+ *
+ * @api public
+ * @property _id
+ * @memberOf SchemaDocumentArrayOptions
+ * @type Array
+ * @instance
+ */
+
+Object.defineProperty(SchemaDocumentArrayOptions.prototype, '_id', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaDocumentArrayOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaMapOptions.js b/node_modules/mongoose/lib/options/SchemaMapOptions.js
new file mode 100644
index 0000000..335d84a
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaMapOptions.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a Map schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ socialMediaHandles: { type: Map, of: String } });
+ * schema.path('socialMediaHandles').options; // SchemaMapOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaMapOptions
+ */
+
+class SchemaMapOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If set, specifies the type of this map's values. Mongoose will cast
+ * this map's values to the given type.
+ *
+ * If not set, Mongoose will not cast the map's values.
+ *
+ * ####Example:
+ *
+ * // Mongoose will cast `socialMediaHandles` values to strings
+ * const schema = new Schema({ socialMediaHandles: { type: Map, of: String } });
+ * schema.path('socialMediaHandles').options.of; // String
+ *
+ * @api public
+ * @property of
+ * @memberOf SchemaMapOptions
+ * @type Function|string
+ * @instance
+ */
+
+Object.defineProperty(SchemaMapOptions.prototype, 'of', opts);
+
+module.exports = SchemaMapOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaNumberOptions.js b/node_modules/mongoose/lib/options/SchemaNumberOptions.js
new file mode 100644
index 0000000..42b0a01
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaNumberOptions.js
@@ -0,0 +1,74 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a Number schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ count: Number });
+ * schema.path('count').options; // SchemaNumberOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaNumberOptions
+ */
+
+class SchemaNumberOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If set, Mongoose adds a validator that checks that this path is at least the
+ * given `min`.
+ *
+ * @api public
+ * @property min
+ * @memberOf SchemaNumberOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaNumberOptions.prototype, 'min', opts);
+
+/**
+ * If set, Mongoose adds a validator that checks that this path is less than the
+ * given `max`.
+ *
+ * @api public
+ * @property max
+ * @memberOf SchemaNumberOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaNumberOptions.prototype, 'max', opts);
+
+/**
+ * If set, Mongoose adds a validator that checks that this path is strictly
+ * equal to one of the given values.
+ *
+ * ####Example:
+ * const schema = new Schema({
+ * favoritePrime: {
+ * type: Number,
+ * enum: [3, 5, 7]
+ * }
+ * });
+ * schema.path('favoritePrime').options.enum; // [3, 5, 7]
+ *
+ * @api public
+ * @property enum
+ * @memberOf SchemaNumberOptions
+ * @type Array
+ * @instance
+ */
+
+Object.defineProperty(SchemaNumberOptions.prototype, 'enum', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaNumberOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaObjectIdOptions.js b/node_modules/mongoose/lib/options/SchemaObjectIdOptions.js
new file mode 100644
index 0000000..cf887d0
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaObjectIdOptions.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on an ObjectId schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ testId: mongoose.ObjectId });
+ * schema.path('testId').options; // SchemaObjectIdOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaObjectIdOptions
+ */
+
+class SchemaObjectIdOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If truthy, uses Mongoose's default built-in ObjectId path.
+ *
+ * @api public
+ * @property auto
+ * @memberOf SchemaObjectIdOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaObjectIdOptions.prototype, 'auto', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaObjectIdOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaSingleNestedOptions.js b/node_modules/mongoose/lib/options/SchemaSingleNestedOptions.js
new file mode 100644
index 0000000..c916d0f
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaSingleNestedOptions.js
@@ -0,0 +1,42 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a single nested schematype.
+ *
+ * ####Example:
+ *
+ * const schema = Schema({ child: Schema({ name: String }) });
+ * schema.path('child').options; // SchemaSingleNestedOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaSingleNestedOptions
+ */
+
+class SchemaSingleNestedOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * If set, overwrites the child schema's `_id` option.
+ *
+ * ####Example:
+ *
+ * const childSchema = Schema({ name: String });
+ * const parentSchema = Schema({
+ * child: { type: childSchema, _id: false }
+ * });
+ * parentSchema.path('child').schema.options._id; // false
+ *
+ * @api public
+ * @property of
+ * @memberOf SchemaSingleNestedOptions
+ * @type Function|string
+ * @instance
+ */
+
+Object.defineProperty(SchemaSingleNestedOptions.prototype, '_id', opts);
+
+module.exports = SchemaSingleNestedOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaStringOptions.js b/node_modules/mongoose/lib/options/SchemaStringOptions.js
new file mode 100644
index 0000000..7654993
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaStringOptions.js
@@ -0,0 +1,116 @@
+'use strict';
+
+const SchemaTypeOptions = require('./SchemaTypeOptions');
+
+/**
+ * The options defined on a string schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: String });
+ * schema.path('name').options; // SchemaStringOptions instance
+ *
+ * @api public
+ * @inherits SchemaTypeOptions
+ * @constructor SchemaStringOptions
+ */
+
+class SchemaStringOptions extends SchemaTypeOptions {}
+
+const opts = require('./propertyOptions');
+
+/**
+ * Array of allowed values for this path
+ *
+ * @api public
+ * @property enum
+ * @memberOf SchemaStringOptions
+ * @type Array
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'enum', opts);
+
+/**
+ * Attach a validator that succeeds if the data string matches the given regular
+ * expression, and fails otherwise.
+ *
+ * @api public
+ * @property match
+ * @memberOf SchemaStringOptions
+ * @type RegExp
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'match', opts);
+
+/**
+ * If truthy, Mongoose will add a custom setter that lowercases this string
+ * using JavaScript's built-in `String#toLowerCase()`.
+ *
+ * @api public
+ * @property lowercase
+ * @memberOf SchemaStringOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'lowercase', opts);
+
+/**
+ * If truthy, Mongoose will add a custom setter that removes leading and trailing
+ * whitespace using JavaScript's built-in `String#trim()`.
+ *
+ * @api public
+ * @property trim
+ * @memberOf SchemaStringOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'trim', opts);
+
+/**
+ * If truthy, Mongoose will add a custom setter that uppercases this string
+ * using JavaScript's built-in `String#toUpperCase()`.
+ *
+ * @api public
+ * @property uppercase
+ * @memberOf SchemaStringOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'uppercase', opts);
+
+/**
+ * If set, Mongoose will add a custom validator that ensures the given
+ * string's `length` is at least the given number.
+ *
+ * @api public
+ * @property minlength
+ * @memberOf SchemaStringOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'minlength', opts);
+
+/**
+ * If set, Mongoose will add a custom validator that ensures the given
+ * string's `length` is at most the given number.
+ *
+ * @api public
+ * @property maxlength
+ * @memberOf SchemaStringOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaStringOptions.prototype, 'maxlength', opts);
+
+/*!
+ * ignore
+ */
+
+module.exports = SchemaStringOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/SchemaTypeOptions.js b/node_modules/mongoose/lib/options/SchemaTypeOptions.js
new file mode 100644
index 0000000..5dc5995
--- /dev/null
+++ b/node_modules/mongoose/lib/options/SchemaTypeOptions.js
@@ -0,0 +1,232 @@
+'use strict';
+
+const clone = require('../helpers/clone');
+
+/**
+ * The options defined on a schematype.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: String });
+ * schema.path('name').options instanceof mongoose.SchemaTypeOptions; // true
+ *
+ * @api public
+ * @constructor SchemaTypeOptions
+ */
+
+class SchemaTypeOptions {
+ constructor(obj) {
+ if (obj == null) {
+ return this;
+ }
+ Object.assign(this, clone(obj));
+ }
+}
+
+const opts = require('./propertyOptions');
+
+/**
+ * The type to cast this path to.
+ *
+ * @api public
+ * @property type
+ * @memberOf SchemaTypeOptions
+ * @type Function|String|Object
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'type', opts);
+
+/**
+ * Function or object describing how to validate this schematype.
+ *
+ * @api public
+ * @property validate
+ * @memberOf SchemaTypeOptions
+ * @type Function|Object
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'validate', opts);
+
+/**
+ * Allows overriding casting logic for this individual path. If a string, the
+ * given string overwrites Mongoose's default cast error message.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({
+ * num: {
+ * type: Number,
+ * cast: '{VALUE} is not a valid number'
+ * }
+ * });
+ *
+ * // Throws 'CastError: "bad" is not a valid number'
+ * schema.path('num').cast('bad');
+ *
+ * const Model = mongoose.model('Test', schema);
+ * const doc = new Model({ num: 'fail' });
+ * const err = doc.validateSync();
+ *
+ * err.errors['num']; // 'CastError: "fail" is not a valid number'
+ *
+ * @api public
+ * @property cast
+ * @memberOf SchemaTypeOptions
+ * @type String
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'cast', opts);
+
+/**
+ * If true, attach a required validator to this path, which ensures this path
+ * path cannot be set to a nullish value. If a function, Mongoose calls the
+ * function and only checks for nullish values if the function returns a truthy value.
+ *
+ * @api public
+ * @property required
+ * @memberOf SchemaTypeOptions
+ * @type Function|Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'required', opts);
+
+/**
+ * The default value for this path. If a function, Mongoose executes the function
+ * and uses the return value as the default.
+ *
+ * @api public
+ * @property default
+ * @memberOf SchemaTypeOptions
+ * @type Function|Any
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'default', opts);
+
+/**
+ * The model that `populate()` should use if populating this path.
+ *
+ * @api public
+ * @property ref
+ * @memberOf SchemaTypeOptions
+ * @type Function|String
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'ref', opts);
+
+/**
+ * Whether to include or exclude this path by default when loading documents
+ * using `find()`, `findOne()`, etc.
+ *
+ * @api public
+ * @property select
+ * @memberOf SchemaTypeOptions
+ * @type Boolean|Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'select', opts);
+
+/**
+ * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
+ * build an index on this path when the model is
+ * compiled.
+ *
+ * @api public
+ * @property index
+ * @memberOf SchemaTypeOptions
+ * @type Boolean|Number|Object
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'index', opts);
+
+/**
+ * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose
+ * will build a unique index on this path when the
+ * model is compiled. [The `unique` option is **not** a validator](/docs/validation.html#the-unique-option-is-not-a-validator).
+ *
+ * @api public
+ * @property unique
+ * @memberOf SchemaTypeOptions
+ * @type Boolean|Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'unique', opts);
+
+/**
+ * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
+ * disallow changes to this path once the document
+ * is saved to the database for the first time. Read more about [immutability in Mongoose here](http://thecodebarbarian.com/whats-new-in-mongoose-5-6-immutable-properties.html).
+ *
+ * @api public
+ * @property immutable
+ * @memberOf SchemaTypeOptions
+ * @type Function|Boolean
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'immutable', opts);
+
+/**
+ * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
+ * build a sparse index on this path.
+ *
+ * @api public
+ * @property sparse
+ * @memberOf SchemaTypeOptions
+ * @type Boolean|Number
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'sparse', opts);
+
+/**
+ * If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose
+ * will build a text index on this path.
+ *
+ * @api public
+ * @property text
+ * @memberOf SchemaTypeOptions
+ * @type Boolean|Number|Object
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'text', opts);
+
+/**
+ * Define a transform function for this individual schema type.
+ * Only called when calling `toJSON()` or `toObject()`.
+ *
+ * ####Example:
+ *
+ * const schema = Schema({
+ * myDate: {
+ * type: Date,
+ * transform: v => v.getFullYear()
+ * }
+ * });
+ * const Model = mongoose.model('Test', schema);
+ *
+ * const doc = new Model({ myDate: new Date('2019/06/01') });
+ * doc.myDate instanceof Date; // true
+ *
+ * const res = doc.toObject({ transform: true });
+ * res.myDate; // 2019
+ *
+ * @api public
+ * @property transform
+ * @memberOf SchemaTypeOptions
+ * @type Function
+ * @instance
+ */
+
+Object.defineProperty(SchemaTypeOptions.prototype, 'transform', opts);
+
+module.exports = SchemaTypeOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/VirtualOptions.js b/node_modules/mongoose/lib/options/VirtualOptions.js
new file mode 100644
index 0000000..a266414
--- /dev/null
+++ b/node_modules/mongoose/lib/options/VirtualOptions.js
@@ -0,0 +1,164 @@
+'use strict';
+
+const opts = require('./propertyOptions');
+
+class VirtualOptions {
+ constructor(obj) {
+ Object.assign(this, obj);
+
+ if (obj != null && obj.options != null) {
+ this.options = Object.assign({}, obj.options);
+ }
+ }
+}
+
+/**
+ * Marks this virtual as a populate virtual, and specifies the model to
+ * use for populate.
+ *
+ * @api public
+ * @property ref
+ * @memberOf VirtualOptions
+ * @type String|Model|Function
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'ref', opts);
+
+/**
+ * Marks this virtual as a populate virtual, and specifies the path that
+ * contains the name of the model to populate
+ *
+ * @api public
+ * @property refPath
+ * @memberOf VirtualOptions
+ * @type String|Function
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'refPath', opts);
+
+/**
+ * The name of the property in the local model to match to `foreignField`
+ * in the foreign model.
+ *
+ * @api public
+ * @property localField
+ * @memberOf VirtualOptions
+ * @type String|Function
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'localField', opts);
+
+/**
+ * The name of the property in the foreign model to match to `localField`
+ * in the local model.
+ *
+ * @api public
+ * @property foreignField
+ * @memberOf VirtualOptions
+ * @type String|Function
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'foreignField', opts);
+
+/**
+ * Whether to populate this virtual as a single document (true) or an
+ * array of documents (false).
+ *
+ * @api public
+ * @property justOne
+ * @memberOf VirtualOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'justOne', opts);
+
+/**
+ * If true, populate just the number of documents where `localField`
+ * matches `foreignField`, as opposed to the documents themselves.
+ *
+ * If `count` is set, it overrides `justOne`.
+ *
+ * @api public
+ * @property count
+ * @memberOf VirtualOptions
+ * @type Boolean
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'count', opts);
+
+/**
+ * Add an additional filter to populate, in addition to `localField`
+ * matches `foreignField`.
+ *
+ * @api public
+ * @property match
+ * @memberOf VirtualOptions
+ * @type Object|Function
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'match', opts);
+
+/**
+ * Additional options to pass to the query used to `populate()`:
+ *
+ * - `sort`
+ * - `skip`
+ * - `limit`
+ *
+ * @api public
+ * @property options
+ * @memberOf VirtualOptions
+ * @type Object
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'options', opts);
+
+/**
+ * If true, add a `skip` to the query used to `populate()`.
+ *
+ * @api public
+ * @property skip
+ * @memberOf VirtualOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'skip', opts);
+
+/**
+ * If true, add a `limit` to the query used to `populate()`.
+ *
+ * @api public
+ * @property limit
+ * @memberOf VirtualOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'limit', opts);
+
+/**
+ * The `limit` option for `populate()` has [some unfortunate edge cases](/docs/populate.html#query-conditions)
+ * when working with multiple documents, like `.find().populate()`. The
+ * `perDocumentLimit` option makes `populate()` execute a separate query
+ * for each document returned from `find()` to ensure each document
+ * gets up to `perDocumentLimit` populated docs if possible.
+ *
+ * @api public
+ * @property perDocumentLimit
+ * @memberOf VirtualOptions
+ * @type Number
+ * @instance
+ */
+
+Object.defineProperty(VirtualOptions.prototype, 'perDocumentLimit', opts);
+
+module.exports = VirtualOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/propertyOptions.js b/node_modules/mongoose/lib/options/propertyOptions.js
new file mode 100644
index 0000000..b7488a3
--- /dev/null
+++ b/node_modules/mongoose/lib/options/propertyOptions.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = Object.freeze({
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+});
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/removeOptions.js b/node_modules/mongoose/lib/options/removeOptions.js
new file mode 100644
index 0000000..0d91586
--- /dev/null
+++ b/node_modules/mongoose/lib/options/removeOptions.js
@@ -0,0 +1,14 @@
+'use strict';
+
+const clone = require('../helpers/clone');
+
+class RemoveOptions {
+ constructor(obj) {
+ if (obj == null) {
+ return;
+ }
+ Object.assign(this, clone(obj));
+ }
+}
+
+module.exports = RemoveOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/options/saveOptions.js b/node_modules/mongoose/lib/options/saveOptions.js
new file mode 100644
index 0000000..22ef437
--- /dev/null
+++ b/node_modules/mongoose/lib/options/saveOptions.js
@@ -0,0 +1,14 @@
+'use strict';
+
+const clone = require('../helpers/clone');
+
+class SaveOptions {
+ constructor(obj) {
+ if (obj == null) {
+ return;
+ }
+ Object.assign(this, clone(obj));
+ }
+}
+
+module.exports = SaveOptions;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/plugins/idGetter.js b/node_modules/mongoose/lib/plugins/idGetter.js
new file mode 100644
index 0000000..f4e6356
--- /dev/null
+++ b/node_modules/mongoose/lib/plugins/idGetter.js
@@ -0,0 +1,28 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schema) {
+ // ensure the documents receive an id getter unless disabled
+ const autoIdGetter = !schema.paths['id'] &&
+ (!schema.options.noVirtualId && schema.options.id);
+ if (!autoIdGetter) {
+ return;
+ }
+
+ schema.virtual('id').get(idGetter);
+};
+
+/*!
+ * Returns this documents _id cast to a string.
+ */
+
+function idGetter() {
+ if (this._id != null) {
+ return String(this._id);
+ }
+
+ return null;
+}
diff --git a/node_modules/mongoose/lib/plugins/removeSubdocs.js b/node_modules/mongoose/lib/plugins/removeSubdocs.js
new file mode 100644
index 0000000..44b2ea6
--- /dev/null
+++ b/node_modules/mongoose/lib/plugins/removeSubdocs.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const each = require('../helpers/each');
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schema) {
+ const unshift = true;
+ schema.s.hooks.pre('remove', false, function(next) {
+ if (this.ownerDocument) {
+ next();
+ return;
+ }
+
+ const _this = this;
+ const subdocs = this.$__getAllSubdocs();
+
+ each(subdocs, function(subdoc, cb) {
+ subdoc.$__remove(cb);
+ }, function(error) {
+ if (error) {
+ return _this.schema.s.hooks.execPost('remove:error', _this, [_this], { error: error }, function(error) {
+ next(error);
+ });
+ }
+ next();
+ });
+ }, null, unshift);
+};
diff --git a/node_modules/mongoose/lib/plugins/saveSubdocs.js b/node_modules/mongoose/lib/plugins/saveSubdocs.js
new file mode 100644
index 0000000..c0a3144
--- /dev/null
+++ b/node_modules/mongoose/lib/plugins/saveSubdocs.js
@@ -0,0 +1,66 @@
+'use strict';
+
+const each = require('../helpers/each');
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schema) {
+ const unshift = true;
+ schema.s.hooks.pre('save', false, function(next) {
+ if (this.ownerDocument) {
+ next();
+ return;
+ }
+
+ const _this = this;
+ const subdocs = this.$__getAllSubdocs();
+
+ if (!subdocs.length) {
+ next();
+ return;
+ }
+
+ each(subdocs, function(subdoc, cb) {
+ subdoc.schema.s.hooks.execPre('save', subdoc, function(err) {
+ cb(err);
+ });
+ }, function(error) {
+ if (error) {
+ return _this.schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
+ next(error);
+ });
+ }
+ next();
+ });
+ }, null, unshift);
+
+ schema.s.hooks.post('save', function(doc, next) {
+ if (this.ownerDocument) {
+ next();
+ return;
+ }
+
+ const _this = this;
+ const subdocs = this.$__getAllSubdocs();
+
+ if (!subdocs.length) {
+ next();
+ return;
+ }
+
+ each(subdocs, function(subdoc, cb) {
+ subdoc.schema.s.hooks.execPost('save', subdoc, [subdoc], function(err) {
+ cb(err);
+ });
+ }, function(error) {
+ if (error) {
+ return _this.schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
+ next(error);
+ });
+ }
+ next();
+ });
+ }, null, unshift);
+};
diff --git a/node_modules/mongoose/lib/plugins/sharding.js b/node_modules/mongoose/lib/plugins/sharding.js
new file mode 100644
index 0000000..560053e
--- /dev/null
+++ b/node_modules/mongoose/lib/plugins/sharding.js
@@ -0,0 +1,83 @@
+'use strict';
+
+const objectIdSymbol = require('../helpers/symbols').objectIdSymbol;
+const utils = require('../utils');
+
+/*!
+ * ignore
+ */
+
+module.exports = function shardingPlugin(schema) {
+ schema.post('init', function() {
+ storeShard.call(this);
+ return this;
+ });
+ schema.pre('save', function(next) {
+ applyWhere.call(this);
+ next();
+ });
+ schema.pre('remove', function(next) {
+ applyWhere.call(this);
+ next();
+ });
+ schema.post('save', function() {
+ storeShard.call(this);
+ });
+};
+
+/*!
+ * ignore
+ */
+
+function applyWhere() {
+ let paths;
+ let len;
+
+ if (this.$__.shardval) {
+ paths = Object.keys(this.$__.shardval);
+ len = paths.length;
+
+ this.$where = this.$where || {};
+ for (let i = 0; i < len; ++i) {
+ this.$where[paths[i]] = this.$__.shardval[paths[i]];
+ }
+ }
+}
+
+/*!
+ * ignore
+ */
+
+module.exports.storeShard = storeShard;
+
+/*!
+ * ignore
+ */
+
+function storeShard() {
+ // backwards compat
+ const key = this.schema.options.shardKey || this.schema.options.shardkey;
+ if (!utils.isPOJO(key)) {
+ return;
+ }
+
+ const orig = this.$__.shardval = {};
+ const paths = Object.keys(key);
+ const len = paths.length;
+ let val;
+
+ for (let i = 0; i < len; ++i) {
+ val = this.$__getValue(paths[i]);
+ if (val == null) {
+ orig[paths[i]] = val;
+ } else if (utils.isMongooseObject(val)) {
+ orig[paths[i]] = val.toObject({ depopulate: true, _isNested: true });
+ } else if (val instanceof Date || val[objectIdSymbol]) {
+ orig[paths[i]] = val;
+ } else if (typeof val.valueOf === 'function') {
+ orig[paths[i]] = val.valueOf();
+ } else {
+ orig[paths[i]] = val;
+ }
+ }
+}
diff --git a/node_modules/mongoose/lib/plugins/validateBeforeSave.js b/node_modules/mongoose/lib/plugins/validateBeforeSave.js
new file mode 100644
index 0000000..4635de1
--- /dev/null
+++ b/node_modules/mongoose/lib/plugins/validateBeforeSave.js
@@ -0,0 +1,45 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schema) {
+ const unshift = true;
+ schema.pre('save', false, function validateBeforeSave(next, options) {
+ const _this = this;
+ // Nested docs have their own presave
+ if (this.ownerDocument) {
+ return next();
+ }
+
+ const hasValidateBeforeSaveOption = options &&
+ (typeof options === 'object') &&
+ ('validateBeforeSave' in options);
+
+ let shouldValidate;
+ if (hasValidateBeforeSaveOption) {
+ shouldValidate = !!options.validateBeforeSave;
+ } else {
+ shouldValidate = this.schema.options.validateBeforeSave;
+ }
+
+ // Validate
+ if (shouldValidate) {
+ const hasValidateModifiedOnlyOption = options &&
+ (typeof options === 'object') &&
+ ('validateModifiedOnly' in options);
+ const validateOptions = hasValidateModifiedOnlyOption ?
+ { validateModifiedOnly: options.validateModifiedOnly } :
+ null;
+ this.validate(validateOptions, function(error) {
+ return _this.schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
+ _this.$op = 'save';
+ next(error);
+ });
+ });
+ } else {
+ next();
+ }
+ }, null, unshift);
+};
diff --git a/node_modules/mongoose/lib/promise_provider.js b/node_modules/mongoose/lib/promise_provider.js
new file mode 100644
index 0000000..3febf36
--- /dev/null
+++ b/node_modules/mongoose/lib/promise_provider.js
@@ -0,0 +1,49 @@
+/*!
+ * ignore
+ */
+
+'use strict';
+
+const assert = require('assert');
+const mquery = require('mquery');
+
+/**
+ * Helper for multiplexing promise implementations
+ *
+ * @api private
+ */
+
+const store = {
+ _promise: null
+};
+
+/**
+ * Get the current promise constructor
+ *
+ * @api private
+ */
+
+store.get = function() {
+ return store._promise;
+};
+
+/**
+ * Set the current promise constructor
+ *
+ * @api private
+ */
+
+store.set = function(lib) {
+ assert.ok(typeof lib === 'function',
+ `mongoose.Promise must be a function, got ${lib}`);
+ store._promise = lib;
+ mquery.Promise = lib;
+};
+
+/*!
+ * Use native promises by default
+ */
+
+store.set(global.Promise);
+
+module.exports = store;
diff --git a/node_modules/mongoose/lib/query.js b/node_modules/mongoose/lib/query.js
new file mode 100644
index 0000000..681093e
--- /dev/null
+++ b/node_modules/mongoose/lib/query.js
@@ -0,0 +1,5324 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const CastError = require('./error/cast');
+const DocumentNotFoundError = require('./error/notFound');
+const Kareem = require('kareem');
+const MongooseError = require('./error/mongooseError');
+const ObjectParameterError = require('./error/objectParameter');
+const QueryCursor = require('./cursor/QueryCursor');
+const ReadPreference = require('./driver').get().ReadPreference;
+const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
+const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
+const cast = require('./cast');
+const castArrayFilters = require('./helpers/update/castArrayFilters');
+const castUpdate = require('./helpers/query/castUpdate');
+const completeMany = require('./helpers/query/completeMany');
+const get = require('./helpers/get');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
+const hasDollarKeys = require('./helpers/query/hasDollarKeys');
+const helpers = require('./queryhelpers');
+const isInclusive = require('./helpers/projection/isInclusive');
+const mquery = require('mquery');
+const parseProjection = require('./helpers/projection/parseProjection');
+const selectPopulatedFields = require('./helpers/query/selectPopulatedFields');
+const setDefaultsOnInsert = require('./helpers/setDefaultsOnInsert');
+const slice = require('sliced');
+const updateValidators = require('./helpers/updateValidators');
+const util = require('util');
+const utils = require('./utils');
+const wrapThunk = require('./helpers/query/wrapThunk');
+
+/**
+ * Query constructor used for building queries. You do not need
+ * to instantiate a `Query` directly. Instead use Model functions like
+ * [`Model.find()`](/docs/api.html#find_find).
+ *
+ * ####Example:
+ *
+ * const query = MyModel.find(); // `query` is an instance of `Query`
+ * query.setOptions({ lean : true });
+ * query.collection(MyModel.collection);
+ * query.where('age').gte(21).exec(callback);
+ *
+ * // You can instantiate a query directly. There is no need to do
+ * // this unless you're an advanced user with a very good reason to.
+ * const query = new mongoose.Query();
+ *
+ * @param {Object} [options]
+ * @param {Object} [model]
+ * @param {Object} [conditions]
+ * @param {Object} [collection] Mongoose collection
+ * @api public
+ */
+
+function Query(conditions, options, model, collection) {
+ // this stuff is for dealing with custom queries created by #toConstructor
+ if (!this._mongooseOptions) {
+ this._mongooseOptions = {};
+ }
+ options = options || {};
+
+ this._transforms = [];
+ this._hooks = new Kareem();
+ this._executionCount = 0;
+
+ // this is the case where we have a CustomQuery, we need to check if we got
+ // options passed in, and if we did, merge them in
+ const keys = Object.keys(options);
+ for (let i = 0; i < keys.length; ++i) {
+ const k = keys[i];
+ this._mongooseOptions[k] = options[k];
+ }
+
+ if (collection) {
+ this.mongooseCollection = collection;
+ }
+
+ if (model) {
+ this.model = model;
+ this.schema = model.schema;
+ }
+
+ // this is needed because map reduce returns a model that can be queried, but
+ // all of the queries on said model should be lean
+ if (this.model && this.model._mapreduce) {
+ this.lean();
+ }
+
+ // inherit mquery
+ mquery.call(this, this.mongooseCollection, options);
+
+ if (conditions) {
+ this.find(conditions);
+ }
+
+ this.options = this.options || {};
+
+ // For gh-6880. mquery still needs to support `fields` by default for old
+ // versions of MongoDB
+ this.$useProjection = true;
+
+ const collation = get(this, 'schema.options.collation', null);
+ if (collation != null) {
+ this.options.collation = collation;
+ }
+}
+
+/*!
+ * inherit mquery
+ */
+
+Query.prototype = new mquery;
+Query.prototype.constructor = Query;
+Query.base = mquery.prototype;
+
+/**
+ * Flag to opt out of using `$geoWithin`.
+ *
+ * mongoose.Query.use$geoWithin = false;
+ *
+ * MongoDB 2.4 deprecated the use of `$within`, replacing it with `$geoWithin`. Mongoose uses `$geoWithin` by default (which is 100% backward compatible with `$within`). If you are running an older version of MongoDB, set this flag to `false` so your `within()` queries continue to work.
+ *
+ * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/
+ * @default true
+ * @property use$geoWithin
+ * @memberOf Query
+ * @receiver Query
+ * @api public
+ */
+
+Query.use$geoWithin = mquery.use$geoWithin;
+
+/**
+ * Converts this query to a customized, reusable query constructor with all arguments and options retained.
+ *
+ * ####Example
+ *
+ * // Create a query for adventure movies and read from the primary
+ * // node in the replica-set unless it is down, in which case we'll
+ * // read from a secondary node.
+ * var query = Movie.find({ tags: 'adventure' }).read('primaryPreferred');
+ *
+ * // create a custom Query constructor based off these settings
+ * var Adventure = query.toConstructor();
+ *
+ * // Adventure is now a subclass of mongoose.Query and works the same way but with the
+ * // default query parameters and options set.
+ * Adventure().exec(callback)
+ *
+ * // further narrow down our query results while still using the previous settings
+ * Adventure().where({ name: /^Life/ }).exec(callback);
+ *
+ * // since Adventure is a stand-alone constructor we can also add our own
+ * // helper methods and getters without impacting global queries
+ * Adventure.prototype.startsWith = function (prefix) {
+ * this.where({ name: new RegExp('^' + prefix) })
+ * return this;
+ * }
+ * Object.defineProperty(Adventure.prototype, 'highlyRated', {
+ * get: function () {
+ * this.where({ rating: { $gt: 4.5 }});
+ * return this;
+ * }
+ * })
+ * Adventure().highlyRated.startsWith('Life').exec(callback)
+ *
+ * @return {Query} subclass-of-Query
+ * @api public
+ */
+
+Query.prototype.toConstructor = function toConstructor() {
+ const model = this.model;
+ const coll = this.mongooseCollection;
+
+ const CustomQuery = function(criteria, options) {
+ if (!(this instanceof CustomQuery)) {
+ return new CustomQuery(criteria, options);
+ }
+ this._mongooseOptions = utils.clone(p._mongooseOptions);
+ Query.call(this, criteria, options || null, model, coll);
+ };
+
+ util.inherits(CustomQuery, model.Query);
+
+ // set inherited defaults
+ const p = CustomQuery.prototype;
+
+ p.options = {};
+
+ // Need to handle `sort()` separately because entries-style `sort()` syntax
+ // `sort([['prop1', 1]])` confuses mquery into losing the outer nested array.
+ // See gh-8159
+ const options = Object.assign({}, this.options);
+ if (options.sort != null) {
+ p.sort(options.sort);
+ delete options.sort;
+ }
+ p.setOptions(options);
+
+ p.op = this.op;
+ p._conditions = utils.clone(this._conditions);
+ p._fields = utils.clone(this._fields);
+ p._update = utils.clone(this._update, {
+ flattenDecimals: false
+ });
+ p._path = this._path;
+ p._distinct = this._distinct;
+ p._collection = this._collection;
+ p._mongooseOptions = this._mongooseOptions;
+
+ return CustomQuery;
+};
+
+/**
+ * Specifies a javascript function or expression to pass to MongoDBs query system.
+ *
+ * ####Example
+ *
+ * query.$where('this.comments.length === 10 || this.name.length === 5')
+ *
+ * // or
+ *
+ * query.$where(function () {
+ * return this.comments.length === 10 || this.name.length === 5;
+ * })
+ *
+ * ####NOTE:
+ *
+ * Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`.
+ * **Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.**
+ *
+ * @see $where http://docs.mongodb.org/manual/reference/operator/where/
+ * @method $where
+ * @param {String|Function} js javascript string or function
+ * @return {Query} this
+ * @memberOf Query
+ * @instance
+ * @method $where
+ * @api public
+ */
+
+/**
+ * Specifies a `path` for use with chaining.
+ *
+ * ####Example
+ *
+ * // instead of writing:
+ * User.find({age: {$gte: 21, $lte: 65}}, callback);
+ *
+ * // we can instead write:
+ * User.where('age').gte(21).lte(65);
+ *
+ * // passing query conditions is permitted
+ * User.find().where({ name: 'vonderful' })
+ *
+ * // chaining
+ * User
+ * .where('age').gte(21).lte(65)
+ * .where('name', /^vonderful/i)
+ * .where('friends').slice(10)
+ * .exec(callback)
+ *
+ * @method where
+ * @memberOf Query
+ * @instance
+ * @param {String|Object} [path]
+ * @param {any} [val]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.slice = function() {
+ if (arguments.length === 0) {
+ return this;
+ }
+
+ this._validate('slice');
+
+ let path;
+ let val;
+
+ if (arguments.length === 1) {
+ const arg = arguments[0];
+ if (typeof arg === 'object' && !Array.isArray(arg)) {
+ const keys = Object.keys(arg);
+ const numKeys = keys.length;
+ for (let i = 0; i < numKeys; ++i) {
+ this.slice(keys[i], arg[keys[i]]);
+ }
+ return this;
+ }
+ this._ensurePath('slice');
+ path = this._path;
+ val = arguments[0];
+ } else if (arguments.length === 2) {
+ if ('number' === typeof arguments[0]) {
+ this._ensurePath('slice');
+ path = this._path;
+ val = slice(arguments);
+ } else {
+ path = arguments[0];
+ val = arguments[1];
+ }
+ } else if (arguments.length === 3) {
+ path = arguments[0];
+ val = slice(arguments, 1);
+ }
+
+ const p = {};
+ p[path] = { $slice: val };
+ this.select(p);
+
+ return this;
+};
+
+
+/**
+ * Specifies the complementary comparison value for paths specified with `where()`
+ *
+ * ####Example
+ *
+ * User.where('age').equals(49);
+ *
+ * // is the same as
+ *
+ * User.where('age', 49);
+ *
+ * @method equals
+ * @memberOf Query
+ * @instance
+ * @param {Object} val
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Specifies arguments for an `$or` condition.
+ *
+ * ####Example
+ *
+ * query.or([{ color: 'red' }, { status: 'emergency' }])
+ *
+ * @see $or http://docs.mongodb.org/manual/reference/operator/or/
+ * @method or
+ * @memberOf Query
+ * @instance
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Specifies arguments for a `$nor` condition.
+ *
+ * ####Example
+ *
+ * query.nor([{ color: 'green' }, { status: 'ok' }])
+ *
+ * @see $nor http://docs.mongodb.org/manual/reference/operator/nor/
+ * @method nor
+ * @memberOf Query
+ * @instance
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Specifies arguments for a `$and` condition.
+ *
+ * ####Example
+ *
+ * query.and([{ color: 'green' }, { status: 'ok' }])
+ *
+ * @method and
+ * @memberOf Query
+ * @instance
+ * @see $and http://docs.mongodb.org/manual/reference/operator/and/
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Specifies a `$gt` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * ####Example
+ *
+ * Thing.find().where('age').gt(21)
+ *
+ * // or
+ * Thing.find().gt('age', 21)
+ *
+ * @method gt
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @see $gt http://docs.mongodb.org/manual/reference/operator/gt/
+ * @api public
+ */
+
+/**
+ * Specifies a `$gte` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method gte
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @see $gte http://docs.mongodb.org/manual/reference/operator/gte/
+ * @api public
+ */
+
+/**
+ * Specifies a `$lt` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method lt
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @see $lt http://docs.mongodb.org/manual/reference/operator/lt/
+ * @api public
+ */
+
+/**
+ * Specifies a `$lte` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method lte
+ * @see $lte http://docs.mongodb.org/manual/reference/operator/lte/
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a `$ne` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @see $ne http://docs.mongodb.org/manual/reference/operator/ne/
+ * @method ne
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an `$in` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @see $in http://docs.mongodb.org/manual/reference/operator/in/
+ * @method in
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an `$nin` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @see $nin http://docs.mongodb.org/manual/reference/operator/nin/
+ * @method nin
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an `$all` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * ####Example:
+ *
+ * MyModel.find().where('pets').all(['dog', 'cat', 'ferret']);
+ * // Equivalent:
+ * MyModel.find().all('pets', ['dog', 'cat', 'ferret']);
+ *
+ * @see $all http://docs.mongodb.org/manual/reference/operator/all/
+ * @method all
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Array} val
+ * @api public
+ */
+
+/**
+ * Specifies a `$size` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * ####Example
+ *
+ * MyModel.where('tags').size(0).exec(function (err, docs) {
+ * if (err) return handleError(err);
+ *
+ * assert(Array.isArray(docs));
+ * console.log('documents with 0 tags', docs);
+ * })
+ *
+ * @see $size http://docs.mongodb.org/manual/reference/operator/size/
+ * @method size
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a `$regex` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @see $regex http://docs.mongodb.org/manual/reference/operator/regex/
+ * @method regex
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {String|RegExp} val
+ * @api public
+ */
+
+/**
+ * Specifies a `maxDistance` query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/
+ * @method maxDistance
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a `$mod` condition, filters documents for documents whose
+ * `path` property is a number that is equal to `remainder` modulo `divisor`.
+ *
+ * ####Example
+ *
+ * // All find products whose inventory is odd
+ * Product.find().mod('inventory', [2, 1]);
+ * Product.find().where('inventory').mod([2, 1]);
+ * // This syntax is a little strange, but supported.
+ * Product.find().where('inventory').mod(2, 1);
+ *
+ * @method mod
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Array} val must be of length 2, first element is `divisor`, 2nd element is `remainder`.
+ * @return {Query} this
+ * @see $mod http://docs.mongodb.org/manual/reference/operator/mod/
+ * @api public
+ */
+
+Query.prototype.mod = function() {
+ let val;
+ let path;
+
+ if (arguments.length === 1) {
+ this._ensurePath('mod');
+ val = arguments[0];
+ path = this._path;
+ } else if (arguments.length === 2 && !Array.isArray(arguments[1])) {
+ this._ensurePath('mod');
+ val = slice(arguments);
+ path = this._path;
+ } else if (arguments.length === 3) {
+ val = slice(arguments, 1);
+ path = arguments[0];
+ } else {
+ val = arguments[1];
+ path = arguments[0];
+ }
+
+ const conds = this._conditions[path] || (this._conditions[path] = {});
+ conds.$mod = val;
+ return this;
+};
+
+/**
+ * Specifies an `$exists` condition
+ *
+ * ####Example
+ *
+ * // { name: { $exists: true }}
+ * Thing.where('name').exists()
+ * Thing.where('name').exists(true)
+ * Thing.find().exists('name')
+ *
+ * // { name: { $exists: false }}
+ * Thing.where('name').exists(false);
+ * Thing.find().exists('name', false);
+ *
+ * @method exists
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val
+ * @return {Query} this
+ * @see $exists http://docs.mongodb.org/manual/reference/operator/exists/
+ * @api public
+ */
+
+/**
+ * Specifies an `$elemMatch` condition
+ *
+ * ####Example
+ *
+ * query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}})
+ *
+ * query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})
+ *
+ * query.elemMatch('comment', function (elem) {
+ * elem.where('author').equals('autobot');
+ * elem.where('votes').gte(5);
+ * })
+ *
+ * query.where('comment').elemMatch(function (elem) {
+ * elem.where({ author: 'autobot' });
+ * elem.where('votes').gte(5);
+ * })
+ *
+ * @method elemMatch
+ * @memberOf Query
+ * @instance
+ * @param {String|Object|Function} path
+ * @param {Object|Function} filter
+ * @return {Query} this
+ * @see $elemMatch http://docs.mongodb.org/manual/reference/operator/elemMatch/
+ * @api public
+ */
+
+/**
+ * Defines a `$within` or `$geoWithin` argument for geo-spatial queries.
+ *
+ * ####Example
+ *
+ * query.where(path).within().box()
+ * query.where(path).within().circle()
+ * query.where(path).within().geometry()
+ *
+ * query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
+ * query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
+ * query.where('loc').within({ polygon: [[],[],[],[]] });
+ *
+ * query.where('loc').within([], [], []) // polygon
+ * query.where('loc').within([], []) // box
+ * query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
+ *
+ * **MUST** be used after `where()`.
+ *
+ * ####NOTE:
+ *
+ * As of Mongoose 3.7, `$geoWithin` is always used for queries. To change this behavior, see [Query.use$geoWithin](#query_Query-use%2524geoWithin).
+ *
+ * ####NOTE:
+ *
+ * In Mongoose 3.7, `within` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within).
+ *
+ * @method within
+ * @see $polygon http://docs.mongodb.org/manual/reference/operator/polygon/
+ * @see $box http://docs.mongodb.org/manual/reference/operator/box/
+ * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/
+ * @see $center http://docs.mongodb.org/manual/reference/operator/center/
+ * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/
+ * @memberOf Query
+ * @instance
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Specifies a `$slice` projection for an array.
+ *
+ * ####Example
+ *
+ * query.slice('comments', 5)
+ * query.slice('comments', -5)
+ * query.slice('comments', [10, 5])
+ * query.where('comments').slice(5)
+ * query.where('comments').slice([-10, 5])
+ *
+ * @method slice
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Number} val number/range of elements to slice
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements
+ * @see $slice http://docs.mongodb.org/manual/reference/projection/slice/#prj._S_slice
+ * @api public
+ */
+
+/**
+ * Specifies the maximum number of documents the query will return.
+ *
+ * ####Example
+ *
+ * query.limit(20)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method limit
+ * @memberOf Query
+ * @instance
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies the number of documents to skip.
+ *
+ * ####Example
+ *
+ * query.skip(100).limit(20)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method skip
+ * @memberOf Query
+ * @instance
+ * @param {Number} val
+ * @see cursor.skip http://docs.mongodb.org/manual/reference/method/cursor.skip/
+ * @api public
+ */
+
+/**
+ * Specifies the maxScan option.
+ *
+ * ####Example
+ *
+ * query.maxScan(100)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method maxScan
+ * @memberOf Query
+ * @instance
+ * @param {Number} val
+ * @see maxScan http://docs.mongodb.org/manual/reference/operator/maxScan/
+ * @api public
+ */
+
+/**
+ * Specifies the batchSize option.
+ *
+ * ####Example
+ *
+ * query.batchSize(100)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method batchSize
+ * @memberOf Query
+ * @instance
+ * @param {Number} val
+ * @see batchSize http://docs.mongodb.org/manual/reference/method/cursor.batchSize/
+ * @api public
+ */
+
+/**
+ * Specifies the `comment` option.
+ *
+ * ####Example
+ *
+ * query.comment('login query')
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method comment
+ * @memberOf Query
+ * @instance
+ * @param {String} val
+ * @see comment http://docs.mongodb.org/manual/reference/operator/comment/
+ * @api public
+ */
+
+/**
+ * Specifies this query as a `snapshot` query.
+ *
+ * ####Example
+ *
+ * query.snapshot() // true
+ * query.snapshot(true)
+ * query.snapshot(false)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method snapshot
+ * @memberOf Query
+ * @instance
+ * @see snapshot http://docs.mongodb.org/manual/reference/operator/snapshot/
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Sets query hints.
+ *
+ * ####Example
+ *
+ * query.hint({ indexA: 1, indexB: -1})
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method hint
+ * @memberOf Query
+ * @instance
+ * @param {Object} val a hint object
+ * @return {Query} this
+ * @see $hint http://docs.mongodb.org/manual/reference/operator/hint/
+ * @api public
+ */
+
+/**
+ * Get/set the current projection (AKA fields). Pass `null` to remove the
+ * current projection.
+ *
+ * Unlike `projection()`, the `select()` function modifies the current
+ * projection in place. This function overwrites the existing projection.
+ *
+ * ####Example:
+ *
+ * const q = Model.find();
+ * q.projection(); // null
+ *
+ * q.select('a b');
+ * q.projection(); // { a: 1, b: 1 }
+ *
+ * q.projection({ c: 1 });
+ * q.projection(); // { c: 1 }
+ *
+ * q.projection(null);
+ * q.projection(); // null
+ *
+ *
+ * @method projection
+ * @memberOf Query
+ * @instance
+ * @param {Object|null} arg
+ * @return {Object} the current projection
+ * @api public
+ */
+
+Query.prototype.projection = function(arg) {
+ if (arguments.length === 0) {
+ return this._fields;
+ }
+
+ this._fields = {};
+ this._userProvidedFields = {};
+ this.select(arg);
+ return this._fields;
+};
+
+/**
+ * Specifies which document fields to include or exclude (also known as the query "projection")
+ *
+ * When using string syntax, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included. Lastly, if a path is prefixed with `+`, it forces inclusion of the path, which is useful for paths excluded at the [schema level](/docs/api.html#schematype_SchemaType-select).
+ *
+ * A projection _must_ be either inclusive or exclusive. In other words, you must
+ * either list the fields to include (which excludes all others), or list the fields
+ * to exclude (which implies all other fields are included). The [`_id` field is the only exception because MongoDB includes it by default](https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/#suppress-id-field).
+ *
+ * ####Example
+ *
+ * // include a and b, exclude other fields
+ * query.select('a b');
+ *
+ * // exclude c and d, include other fields
+ * query.select('-c -d');
+ *
+ * // Use `+` to override schema-level `select: false` without making the
+ * // projection inclusive.
+ * const schema = new Schema({
+ * foo: { type: String, select: false },
+ * bar: String
+ * });
+ * // ...
+ * query.select('+foo'); // Override foo's `select: false` without excluding `bar`
+ *
+ * // or you may use object notation, useful when
+ * // you have keys already prefixed with a "-"
+ * query.select({ a: 1, b: 1 });
+ * query.select({ c: 0, d: 0 });
+ *
+ *
+ * @method select
+ * @memberOf Query
+ * @instance
+ * @param {Object|String} arg
+ * @return {Query} this
+ * @see SchemaType
+ * @api public
+ */
+
+Query.prototype.select = function select() {
+ let arg = arguments[0];
+ if (!arg) return this;
+ let i;
+
+ if (arguments.length !== 1) {
+ throw new Error('Invalid select: select only takes 1 argument');
+ }
+
+ this._validate('select');
+
+ const fields = this._fields || (this._fields = {});
+ const userProvidedFields = this._userProvidedFields || (this._userProvidedFields = {});
+
+ arg = parseProjection(arg);
+
+ if (utils.isObject(arg)) {
+ const keys = Object.keys(arg);
+ for (i = 0; i < keys.length; ++i) {
+ fields[keys[i]] = arg[keys[i]];
+ userProvidedFields[keys[i]] = arg[keys[i]];
+ }
+ return this;
+ }
+
+ throw new TypeError('Invalid select() argument. Must be string or object.');
+};
+
+/**
+ * _DEPRECATED_ Sets the slaveOk option.
+ *
+ * **Deprecated** in MongoDB 2.2 in favor of [read preferences](#query_Query-read).
+ *
+ * ####Example:
+ *
+ * query.slaveOk() // true
+ * query.slaveOk(true)
+ * query.slaveOk(false)
+ *
+ * @method slaveOk
+ * @memberOf Query
+ * @instance
+ * @deprecated use read() preferences instead if on mongodb >= 2.2
+ * @param {Boolean} v defaults to true
+ * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
+ * @see slaveOk http://docs.mongodb.org/manual/reference/method/rs.slaveOk/
+ * @see read() #query_Query-read
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Determines the MongoDB nodes from which to read.
+ *
+ * ####Preferences:
+ *
+ * primary - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
+ * secondary Read from secondary if available, otherwise error.
+ * primaryPreferred Read from primary if available, otherwise a secondary.
+ * secondaryPreferred Read from a secondary if available, otherwise read from the primary.
+ * nearest All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.
+ *
+ * Aliases
+ *
+ * p primary
+ * pp primaryPreferred
+ * s secondary
+ * sp secondaryPreferred
+ * n nearest
+ *
+ * ####Example:
+ *
+ * new Query().read('primary')
+ * new Query().read('p') // same as primary
+ *
+ * new Query().read('primaryPreferred')
+ * new Query().read('pp') // same as primaryPreferred
+ *
+ * new Query().read('secondary')
+ * new Query().read('s') // same as secondary
+ *
+ * new Query().read('secondaryPreferred')
+ * new Query().read('sp') // same as secondaryPreferred
+ *
+ * new Query().read('nearest')
+ * new Query().read('n') // same as nearest
+ *
+ * // read from secondaries with matching tags
+ * new Query().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }])
+ *
+ * Read more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).
+ *
+ * @method read
+ * @memberOf Query
+ * @instance
+ * @param {String} pref one of the listed preference options or aliases
+ * @param {Array} [tags] optional tags for this query
+ * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
+ * @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.read = function read(pref, tags) {
+ // first cast into a ReadPreference object to support tags
+ const read = new ReadPreference(pref, tags);
+ this.options.readPreference = read;
+ return this;
+};
+
+/**
+ * Sets the [MongoDB session](https://docs.mongodb.com/manual/reference/server-sessions/)
+ * associated with this query. Sessions are how you mark a query as part of a
+ * [transaction](/docs/transactions.html).
+ *
+ * Calling `session(null)` removes the session from this query.
+ *
+ * ####Example:
+ *
+ * const s = await mongoose.startSession();
+ * await mongoose.model('Person').findOne({ name: 'Axl Rose' }).session(s);
+ *
+ * @method session
+ * @memberOf Query
+ * @instance
+ * @param {ClientSession} [session] from `await conn.startSession()`
+ * @see Connection.prototype.startSession() /docs/api.html#connection_Connection-startSession
+ * @see mongoose.startSession() /docs/api.html#mongoose_Mongoose-startSession
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.session = function session(v) {
+ if (v == null) {
+ delete this.options.session;
+ }
+ this.options.session = v;
+ return this;
+};
+
+/**
+ * Sets the specified number of `mongod` servers, or tag set of `mongod` servers,
+ * that must acknowledge this write before this write is considered successful.
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndReplace()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to the schema's [`writeConcern.w` option](/docs/guide.html#writeConcern)
+ *
+ * ####Example:
+ *
+ * // The 'majority' option means the `deleteOne()` promise won't resolve
+ * // until the `deleteOne()` has propagated to the majority of the replica set
+ * await mongoose.model('Person').
+ * deleteOne({ name: 'Ned Stark' }).
+ * w('majority');
+ *
+ * @method w
+ * @memberOf Query
+ * @instance
+ * @param {String|number} val 0 for fire-and-forget, 1 for acknowledged by one server, 'majority' for majority of the replica set, or [any of the more advanced options](https://docs.mongodb.com/manual/reference/write-concern/#w-option).
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#w-option
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.w = function w(val) {
+ if (val == null) {
+ delete this.options.w;
+ }
+ this.options.w = val;
+ return this;
+};
+
+/**
+ * Requests acknowledgement that this operation has been persisted to MongoDB's
+ * on-disk journal.
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndReplace()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to the schema's [`writeConcern.j` option](/docs/guide.html#writeConcern)
+ *
+ * ####Example:
+ *
+ * await mongoose.model('Person').deleteOne({ name: 'Ned Stark' }).j(true);
+ *
+ * @method j
+ * @memberOf Query
+ * @instance
+ * @param {boolean} val
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#j-option
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.j = function j(val) {
+ if (val == null) {
+ delete this.options.j;
+ }
+ this.options.j = val;
+ return this;
+};
+
+/**
+ * If [`w > 1`](/docs/api.html#query_Query-w), the maximum amount of time to
+ * wait for this write to propagate through the replica set before this
+ * operation fails. The default is `0`, which means no timeout.
+ *
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndReplace()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to the schema's [`writeConcern.wtimeout` option](/docs/guide.html#writeConcern)
+ *
+ * ####Example:
+ *
+ * // The `deleteOne()` promise won't resolve until this `deleteOne()` has
+ * // propagated to at least `w = 2` members of the replica set. If it takes
+ * // longer than 1 second, this `deleteOne()` will fail.
+ * await mongoose.model('Person').
+ * deleteOne({ name: 'Ned Stark' }).
+ * w(2).
+ * wtimeout(1000);
+ *
+ * @method wtimeout
+ * @memberOf Query
+ * @instance
+ * @param {number} ms number of milliseconds to wait
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#wtimeout
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.wtimeout = function wtimeout(ms) {
+ if (ms == null) {
+ delete this.options.wtimeout;
+ }
+ this.options.wtimeout = ms;
+ return this;
+};
+
+/**
+ * Sets the readConcern option for the query.
+ *
+ * ####Example:
+ *
+ * new Query().readConcern('local')
+ * new Query().readConcern('l') // same as local
+ *
+ * new Query().readConcern('available')
+ * new Query().readConcern('a') // same as available
+ *
+ * new Query().readConcern('majority')
+ * new Query().readConcern('m') // same as majority
+ *
+ * new Query().readConcern('linearizable')
+ * new Query().readConcern('lz') // same as linearizable
+ *
+ * new Query().readConcern('snapshot')
+ * new Query().readConcern('s') // same as snapshot
+ *
+ *
+ * ####Read Concern Level:
+ *
+ * local MongoDB 3.2+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
+ * available MongoDB 3.6+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
+ * majority MongoDB 3.2+ The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure.
+ * linearizable MongoDB 3.4+ The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results.
+ * snapshot MongoDB 4.0+ Only available for operations within multi-document transactions. Upon transaction commit with write concern "majority", the transaction operations are guaranteed to have read from a snapshot of majority-committed data.
+ *
+ * Aliases
+ *
+ * l local
+ * a available
+ * m majority
+ * lz linearizable
+ * s snapshot
+ *
+ * Read more about how to use read concern [here](https://docs.mongodb.com/manual/reference/read-concern/).
+ *
+ * @memberOf Query
+ * @method readConcern
+ * @param {String} level one of the listed read concern level or their aliases
+ * @see mongodb https://docs.mongodb.com/manual/reference/read-concern/
+ * @return {Query} this
+ * @api public
+ */
+
+/**
+ * Gets query options.
+ *
+ * ####Example:
+ *
+ * var query = new Query();
+ * query.limit(10);
+ * query.setOptions({ maxTimeMS: 1000 })
+ * query.getOptions(); // { limit: 10, maxTimeMS: 1000 }
+ *
+ * @return {Object} the options
+ * @api public
+ */
+
+Query.prototype.getOptions = function() {
+ return this.options;
+};
+
+/**
+ * Sets query options. Some options only make sense for certain operations.
+ *
+ * ####Options:
+ *
+ * The following options are only for `find()`:
+ *
+ * - [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors)
+ * - [sort](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsort(\)%7D%7D)
+ * - [limit](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D)
+ * - [skip](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D)
+ * - [maxscan](https://docs.mongodb.org/v3.2/reference/operator/meta/maxScan/#metaOp._S_maxScan)
+ * - [batchSize](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D)
+ * - [comment](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment)
+ * - [snapshot](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D)
+ * - [readPreference](http://docs.mongodb.org/manual/applications/replication/#read-preference)
+ * - [hint](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint)
+ *
+ * The following options are only for write operations: `update()`, `updateOne()`, `updateMany()`, `replaceOne()`, `findOneAndUpdate()`, and `findByIdAndUpdate()`:
+ *
+ * - [upsert](https://docs.mongodb.com/manual/reference/method/db.collection.update/)
+ * - [writeConcern](https://docs.mongodb.com/manual/reference/method/db.collection.update/)
+ * - [timestamps](https://mongoosejs.com/docs/guide.html#timestamps): If `timestamps` is set in the schema, set this option to `false` to skip timestamps for that particular update. Has no effect if `timestamps` is not enabled in the schema options.
+ * - omitUndefined: delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ *
+ * The following options are only for `find()`, `findOne()`, `findById()`, `findOneAndUpdate()`, and `findByIdAndUpdate()`:
+ *
+ * - [lean](./api.html#query_Query-lean)
+ * - [populate](/docs/populate.html)
+ * - [projection](/docs/api/query.html#query_Query-projection)
+ *
+ * The following options are only for all operations **except** `update()`, `updateOne()`, `updateMany()`, `remove()`, `deleteOne()`, and `deleteMany()`:
+ *
+ * - [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/)
+ *
+ * The following options are for `findOneAndUpdate()` and `findOneAndRemove()`
+ *
+ * - [useFindAndModify](/docs/deprecations.html#findandmodify)
+ * - rawResult
+ *
+ * The following options are for all operations:
+ *
+ * - [collation](https://docs.mongodb.com/manual/reference/collation/)
+ * - [session](https://docs.mongodb.com/manual/reference/server-sessions/)
+ * - [explain](https://docs.mongodb.com/manual/reference/method/cursor.explain/)
+ *
+ * @param {Object} options
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.setOptions = function(options, overwrite) {
+ // overwrite is only for internal use
+ if (overwrite) {
+ // ensure that _mongooseOptions & options are two different objects
+ this._mongooseOptions = (options && utils.clone(options)) || {};
+ this.options = options || {};
+
+ if ('populate' in options) {
+ this.populate(this._mongooseOptions);
+ }
+ return this;
+ }
+
+ if (options == null) {
+ return this;
+ }
+ if (typeof options !== 'object') {
+ throw new Error('Options must be an object, got "' + options + '"');
+ }
+
+ if (Array.isArray(options.populate)) {
+ const populate = options.populate;
+ delete options.populate;
+ const _numPopulate = populate.length;
+ for (let i = 0; i < _numPopulate; ++i) {
+ this.populate(populate[i]);
+ }
+ }
+
+ if ('useFindAndModify' in options) {
+ this._mongooseOptions.useFindAndModify = options.useFindAndModify;
+ delete options.useFindAndModify;
+ }
+ if ('omitUndefined' in options) {
+ this._mongooseOptions.omitUndefined = options.omitUndefined;
+ delete options.omitUndefined;
+ }
+
+ return Query.base.setOptions.call(this, options);
+};
+
+/**
+ * Sets the [`explain` option](https://docs.mongodb.com/manual/reference/method/cursor.explain/),
+ * which makes this query return detailed execution stats instead of the actual
+ * query result. This method is useful for determining what index your queries
+ * use.
+ *
+ * Calling `query.explain(v)` is equivalent to `query.setOption({ explain: v })`
+ *
+ * ####Example:
+ *
+ * const query = new Query();
+ * const res = await query.find({ a: 1 }).explain('queryPlanner');
+ * console.log(res);
+ *
+ * @param {String} [verbose] The verbosity mode. Either 'queryPlanner', 'executionStats', or 'allPlansExecution'. The default is 'queryPlanner'
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.explain = function(verbose) {
+ if (arguments.length === 0) {
+ this.options.explain = true;
+ return this;
+ }
+ this.options.explain = verbose;
+ return this;
+};
+
+/**
+ * Sets the [maxTimeMS](https://docs.mongodb.com/manual/reference/method/cursor.maxTimeMS/)
+ * option. This will tell the MongoDB server to abort if the query or write op
+ * has been running for more than `ms` milliseconds.
+ *
+ * Calling `query.maxTimeMS(v)` is equivalent to `query.setOption({ maxTimeMS: v })`
+ *
+ * ####Example:
+ *
+ * const query = new Query();
+ * // Throws an error 'operation exceeded time limit' as long as there's
+ * // >= 1 doc in the queried collection
+ * const res = await query.find({ $where: 'sleep(1000) || true' }).maxTimeMS(100);
+ *
+ * @param {Number} [ms] The number of milliseconds
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.maxTimeMS = function(ms) {
+ this.options.maxTimeMS = ms;
+ return this;
+};
+
+/**
+ * Returns the current query filter (also known as conditions) as a POJO.
+ *
+ * ####Example:
+ *
+ * const query = new Query();
+ * query.find({ a: 1 }).where('b').gt(2);
+ * query.getFilter(); // { a: 1, b: { $gt: 2 } }
+ *
+ * @return {Object} current query filter
+ * @api public
+ */
+
+Query.prototype.getFilter = function() {
+ return this._conditions;
+};
+
+/**
+ * Returns the current query filter. Equivalent to `getFilter()`.
+ *
+ * You should use `getFilter()` instead of `getQuery()` where possible. `getQuery()`
+ * will likely be deprecated in a future release.
+ *
+ * ####Example:
+ *
+ * var query = new Query();
+ * query.find({ a: 1 }).where('b').gt(2);
+ * query.getQuery(); // { a: 1, b: { $gt: 2 } }
+ *
+ * @return {Object} current query filter
+ * @api public
+ */
+
+Query.prototype.getQuery = function() {
+ return this._conditions;
+};
+
+/**
+ * Sets the query conditions to the provided JSON object.
+ *
+ * ####Example:
+ *
+ * var query = new Query();
+ * query.find({ a: 1 })
+ * query.setQuery({ a: 2 });
+ * query.getQuery(); // { a: 2 }
+ *
+ * @param {Object} new query conditions
+ * @return {undefined}
+ * @api public
+ */
+
+Query.prototype.setQuery = function(val) {
+ this._conditions = val;
+};
+
+/**
+ * Returns the current update operations as a JSON object.
+ *
+ * ####Example:
+ *
+ * var query = new Query();
+ * query.update({}, { $set: { a: 5 } });
+ * query.getUpdate(); // { $set: { a: 5 } }
+ *
+ * @return {Object} current update operations
+ * @api public
+ */
+
+Query.prototype.getUpdate = function() {
+ return this._update;
+};
+
+/**
+ * Sets the current update operation to new value.
+ *
+ * ####Example:
+ *
+ * var query = new Query();
+ * query.update({}, { $set: { a: 5 } });
+ * query.setUpdate({ $set: { b: 6 } });
+ * query.getUpdate(); // { $set: { b: 6 } }
+ *
+ * @param {Object} new update operation
+ * @return {undefined}
+ * @api public
+ */
+
+Query.prototype.setUpdate = function(val) {
+ this._update = val;
+};
+
+/**
+ * Returns fields selection for this query.
+ *
+ * @method _fieldsForExec
+ * @return {Object}
+ * @api private
+ * @receiver Query
+ */
+
+Query.prototype._fieldsForExec = function() {
+ return utils.clone(this._fields);
+};
+
+
+/**
+ * Return an update document with corrected `$set` operations.
+ *
+ * @method _updateForExec
+ * @api private
+ * @receiver Query
+ */
+
+Query.prototype._updateForExec = function() {
+ const update = utils.clone(this._update, {
+ transform: false,
+ depopulate: true
+ });
+ const ops = Object.keys(update);
+ let i = ops.length;
+ const ret = {};
+
+ while (i--) {
+ const op = ops[i];
+
+ if (this.options.overwrite) {
+ ret[op] = update[op];
+ continue;
+ }
+
+ if ('$' !== op[0]) {
+ // fix up $set sugar
+ if (!ret.$set) {
+ if (update.$set) {
+ ret.$set = update.$set;
+ } else {
+ ret.$set = {};
+ }
+ }
+ ret.$set[op] = update[op];
+ ops.splice(i, 1);
+ if (!~ops.indexOf('$set')) ops.push('$set');
+ } else if ('$set' === op) {
+ if (!ret.$set) {
+ ret[op] = update[op];
+ }
+ } else {
+ ret[op] = update[op];
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * Makes sure _path is set.
+ *
+ * @method _ensurePath
+ * @param {String} method
+ * @api private
+ * @receiver Query
+ */
+
+/**
+ * Determines if `conds` can be merged using `mquery().merge()`
+ *
+ * @method canMerge
+ * @memberOf Query
+ * @instance
+ * @param {Object} conds
+ * @return {Boolean}
+ * @api private
+ */
+
+/**
+ * Returns default options for this query.
+ *
+ * @param {Model} model
+ * @api private
+ */
+
+Query.prototype._optionsForExec = function(model) {
+ const options = utils.clone(this.options);
+
+ delete options.populate;
+ model = model || this.model;
+
+ if (!model) {
+ return options;
+ }
+
+ const safe = get(model, 'schema.options.safe', null);
+ if (!('safe' in options) && safe != null) {
+ setSafe(options, safe);
+ }
+
+ // Apply schema-level `writeConcern` option
+ applyWriteConcern(model.schema, options);
+
+ const readPreference = get(model, 'schema.options.read');
+ if (!('readPreference' in options) && readPreference) {
+ options.readPreference = readPreference;
+ }
+
+ if (options.upsert !== void 0) {
+ options.upsert = !!options.upsert;
+ }
+
+ return options;
+};
+
+/*!
+ * ignore
+ */
+
+const safeDeprecationWarning = 'Mongoose: the `safe` option is deprecated. ' +
+ 'Use write concerns instead: http://bit.ly/mongoose-w';
+
+const setSafe = util.deprecate(function setSafe(options, safe) {
+ options.safe = safe;
+}, safeDeprecationWarning);
+
+/**
+ * Sets the lean option.
+ *
+ * Documents returned from queries with the `lean` option enabled are plain
+ * javascript objects, not [Mongoose Documents](#document-js). They have no
+ * `save` method, getters/setters, virtuals, or other Mongoose features.
+ *
+ * ####Example:
+ *
+ * new Query().lean() // true
+ * new Query().lean(true)
+ * new Query().lean(false)
+ *
+ * const docs = await Model.find().lean();
+ * docs[0] instanceof mongoose.Document; // false
+ *
+ * [Lean is great for high-performance, read-only cases](/docs/tutorials/lean.html),
+ * especially when combined
+ * with [cursors](/docs/queries.html#streaming).
+ *
+ * If you need virtuals, getters/setters, or defaults with `lean()`, you need
+ * to use a plugin. See:
+ *
+ * - [mongoose-lean-virtuals](https://plugins.mongoosejs.io/plugins/lean-virtuals)
+ * - [mongoose-lean-getters](https://plugins.mongoosejs.io/plugins/lean-getters)
+ * - [mongoose-lean-defaults](https://www.npmjs.com/package/mongoose-lean-defaults)
+ *
+ * @param {Boolean|Object} bool defaults to true
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.lean = function(v) {
+ this._mongooseOptions.lean = arguments.length ? v : true;
+ return this;
+};
+
+/**
+ * Returns an object containing the Mongoose-specific options for this query,
+ * including `lean` and `populate`.
+ *
+ * Mongoose-specific options are different from normal options (`sort`, `limit`, etc.)
+ * because they are **not** sent to the MongoDB server.
+ *
+ * ####Example:
+ *
+ * const q = new Query();
+ * q.mongooseOptions().lean; // undefined
+ *
+ * q.lean();
+ * q.mongooseOptions().lean; // true
+ *
+ * This function is useful for writing [query middleware](/docs/middleware.html).
+ * Below is a full list of properties the return value from this function may have:
+ *
+ * - `populate`
+ * - `lean`
+ * - `omitUndefined`
+ * - `strict`
+ * - `nearSphere`
+ * - `useFindAndModify`
+ *
+ * @return {Object} Mongoose-specific options
+ * @param public
+ */
+
+Query.prototype.mongooseOptions = function() {
+ return this._mongooseOptions;
+};
+
+/**
+ * Adds a `$set` to this query's update without changing the operation.
+ * This is useful for query middleware so you can add an update regardless
+ * of whether you use `updateOne()`, `updateMany()`, `findOneAndUpdate()`, etc.
+ *
+ * ####Example:
+ *
+ * // Updates `{ $set: { updatedAt: new Date() } }`
+ * new Query().updateOne({}, {}).set('updatedAt', new Date());
+ * new Query().updateMany({}, {}).set({ updatedAt: new Date() });
+ *
+ * @param {String|Object} path path or object of key/value pairs to set
+ * @param {Any} [val] the value to set
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.set = function(path, val) {
+ if (typeof path === 'object') {
+ const keys = Object.keys(path);
+ for (const key of keys) {
+ this.set(key, path[key]);
+ }
+ return this;
+ }
+
+ this._update = this._update || {};
+ this._update.$set = this._update.$set || {};
+ this._update.$set[path] = val;
+ return this;
+};
+
+/**
+ * For update operations, returns the value of a path in the update's `$set`.
+ * Useful for writing getters/setters that can work with both update operations
+ * and `save()`.
+ *
+ * ####Example:
+ *
+ * const query = Model.updateOne({}, { $set: { name: 'Jean-Luc Picard' } });
+ * query.get('name'); // 'Jean-Luc Picard'
+ *
+ * @param {String|Object} path path or object of key/value pairs to set
+ * @param {Any} [val] the value to set
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.get = function get(path) {
+ const update = this._update;
+ if (update == null) {
+ return void 0;
+ }
+ const $set = update.$set;
+ if ($set == null) {
+ return update[path];
+ }
+
+ if (utils.hasUserDefinedProperty(update, path)) {
+ return update[path];
+ }
+ if (utils.hasUserDefinedProperty($set, path)) {
+ return $set[path];
+ }
+
+ return void 0;
+};
+
+/**
+ * Gets/sets the error flag on this query. If this flag is not null or
+ * undefined, the `exec()` promise will reject without executing.
+ *
+ * ####Example:
+ *
+ * Query().error(); // Get current error value
+ * Query().error(null); // Unset the current error
+ * Query().error(new Error('test')); // `exec()` will resolve with test
+ * Schema.pre('find', function() {
+ * if (!this.getQuery().userId) {
+ * this.error(new Error('Not allowed to query without setting userId'));
+ * }
+ * });
+ *
+ * Note that query casting runs **after** hooks, so cast errors will override
+ * custom errors.
+ *
+ * ####Example:
+ * var TestSchema = new Schema({ num: Number });
+ * var TestModel = db.model('Test', TestSchema);
+ * TestModel.find({ num: 'not a number' }).error(new Error('woops')).exec(function(error) {
+ * // `error` will be a cast error because `num` failed to cast
+ * });
+ *
+ * @param {Error|null} err if set, `exec()` will fail fast before sending the query to MongoDB
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.error = function error(err) {
+ if (arguments.length === 0) {
+ return this._error;
+ }
+
+ this._error = err;
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+Query.prototype._unsetCastError = function _unsetCastError() {
+ if (this._error != null && !(this._error instanceof CastError)) {
+ return;
+ }
+ return this.error(null);
+};
+
+/**
+ * Getter/setter around the current mongoose-specific options for this query
+ * Below are the current Mongoose-specific options.
+ *
+ * - `populate`: an array representing what paths will be populated. Should have one entry for each call to [`Query.prototype.populate()`](/docs/api.html#query_Query-populate)
+ * - `lean`: if truthy, Mongoose will not [hydrate](/docs/api.html#model_Model.hydrate) any documents that are returned from this query. See [`Query.prototype.lean()`](/docs/api.html#query_Query-lean) for more information.
+ * - `strict`: controls how Mongoose handles keys that aren't in the schema for updates. This option is `true` by default, which means Mongoose will silently strip any paths in the update that aren't in the schema. See the [`strict` mode docs](/docs/guide.html#strict) for more information.
+ * - `strictQuery`: controls how Mongoose handles keys that aren't in the schema for the query `filter`. This option is `false` by default for backwards compatibility, which means Mongoose will allow `Model.find({ foo: 'bar' })` even if `foo` is not in the schema. See the [`strictQuery` docs](/docs/guide.html#strictQuery) for more information.
+ * - `useFindAndModify`: used to work around the [`findAndModify()` deprecation warning](/docs/deprecations.html#findandmodify)
+ * - `omitUndefined`: delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * - `nearSphere`: use `$nearSphere` instead of `near()`. See the [`Query.prototype.nearSphere()` docs](/docs/api.html#query_Query-nearSphere)
+ *
+ * Mongoose maintains a separate object for internal options because
+ * Mongoose sends `Query.prototype.options` to the MongoDB server, and the
+ * above options are not relevant for the MongoDB server.
+ *
+ * @param {Object} options if specified, overwrites the current options
+ * @return {Object} the options
+ * @api public
+ */
+
+Query.prototype.mongooseOptions = function(v) {
+ if (arguments.length > 0) {
+ this._mongooseOptions = v;
+ }
+ return this._mongooseOptions;
+};
+
+/*!
+ * ignore
+ */
+
+Query.prototype._castConditions = function() {
+ try {
+ this.cast(this.model);
+ this._unsetCastError();
+ } catch (err) {
+ this.error(err);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function _castArrayFilters(query) {
+ try {
+ castArrayFilters(query);
+ } catch (err) {
+ query.error(err);
+ }
+}
+
+/**
+ * Thunk around find()
+ *
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api private
+ */
+Query.prototype._find = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return null;
+ }
+
+ callback = _wrapThunkCallback(this, callback);
+
+ this._applyPaths();
+ this._fields = this._castFields(this._fields);
+
+ const fields = this._fieldsForExec();
+ const mongooseOptions = this._mongooseOptions;
+ const _this = this;
+ const userProvidedFields = _this._userProvidedFields || {};
+
+ applyGlobalMaxTimeMS(this.options, this.model);
+
+ // Separate options to pass down to `completeMany()` in case we need to
+ // set a session on the document
+ const completeManyOptions = Object.assign({}, {
+ session: get(this, 'options.session', null)
+ });
+
+ const cb = (err, docs) => {
+ if (err) {
+ return callback(err);
+ }
+
+ if (docs.length === 0) {
+ return callback(null, docs);
+ }
+ if (this.options.explain) {
+ return callback(null, docs);
+ }
+
+ if (!mongooseOptions.populate) {
+ return mongooseOptions.lean ?
+ callback(null, docs) :
+ completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions, callback);
+ }
+
+ const pop = helpers.preparePopulationOptionsMQ(_this, mongooseOptions);
+ completeManyOptions.populated = pop;
+ _this.model.populate(docs, pop, function(err, docs) {
+ if (err) return callback(err);
+ return mongooseOptions.lean ?
+ callback(null, docs) :
+ completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions, callback);
+ });
+ };
+
+ const options = this._optionsForExec();
+ options.projection = this._fieldsForExec();
+ const filter = this._conditions;
+
+ this._collection.find(filter, options, cb);
+ return null;
+});
+
+/**
+ * Find all documents that match `selector`. The result will be an array of documents.
+ *
+ * If there are too many documents in the result to fit in memory, use
+ * [`Query.prototype.cursor()`](api.html#query_Query-cursor)
+ *
+ * ####Example
+ *
+ * // Using async/await
+ * const arr = await Movie.find({ year: { $gte: 1980, $lte: 1989 } });
+ *
+ * // Using callbacks
+ * Movie.find({ year: { $gte: 1980, $lte: 1989 } }, function(err, arr) {});
+ *
+ * @param {Object|ObjectId} [filter] mongodb selector. If not specified, returns all documents.
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.find = function(conditions, callback) {
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = {};
+ }
+
+ conditions = utils.toObject(conditions);
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (conditions != null) {
+ this.error(new ObjectParameterError(conditions, 'filter', 'find'));
+ }
+
+ // if we don't have a callback, then just return the query object
+ if (!callback) {
+ return Query.base.find.call(this);
+ }
+
+ this._find(callback);
+
+ return this;
+};
+
+/**
+ * Merges another Query or conditions object into this one.
+ *
+ * When a Query is passed, conditions, field selection and options are merged.
+ *
+ * @param {Query|Object} source
+ * @return {Query} this
+ */
+
+Query.prototype.merge = function(source) {
+ if (!source) {
+ return this;
+ }
+
+ const opts = { overwrite: true };
+
+ if (source instanceof Query) {
+ // if source has a feature, apply it to ourselves
+
+ if (source._conditions) {
+ utils.merge(this._conditions, source._conditions, opts);
+ }
+
+ if (source._fields) {
+ this._fields || (this._fields = {});
+ utils.merge(this._fields, source._fields, opts);
+ }
+
+ if (source.options) {
+ this.options || (this.options = {});
+ utils.merge(this.options, source.options, opts);
+ }
+
+ if (source._update) {
+ this._update || (this._update = {});
+ utils.mergeClone(this._update, source._update);
+ }
+
+ if (source._distinct) {
+ this._distinct = source._distinct;
+ }
+
+ utils.merge(this._mongooseOptions, source._mongooseOptions);
+
+ return this;
+ }
+
+ // plain object
+ utils.merge(this._conditions, source, opts);
+
+ return this;
+};
+
+/**
+ * Adds a collation to this op (MongoDB 3.4 and up)
+ *
+ * @param {Object} value
+ * @return {Query} this
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/method/cursor.collation/#cursor.collation
+ * @api public
+ */
+
+Query.prototype.collation = function(value) {
+ if (this.options == null) {
+ this.options = {};
+ }
+ this.options.collation = value;
+ return this;
+};
+
+/**
+ * Hydrate a single doc from `findOne()`, `findOneAndUpdate()`, etc.
+ *
+ * @api private
+ */
+
+Query.prototype._completeOne = function(doc, res, callback) {
+ if (!doc && !this.options.rawResult) {
+ return callback(null, null);
+ }
+
+ const model = this.model;
+ const projection = utils.clone(this._fields);
+ const userProvidedFields = this._userProvidedFields || {};
+ // `populate`, `lean`
+ const mongooseOptions = this._mongooseOptions;
+ // `rawResult`
+ const options = this.options;
+
+ if (options.explain) {
+ return callback(null, doc);
+ }
+
+ if (!mongooseOptions.populate) {
+ return mongooseOptions.lean ?
+ _completeOneLean(doc, res, options, callback) :
+ completeOne(model, doc, res, options, projection, userProvidedFields,
+ null, callback);
+ }
+
+ const pop = helpers.preparePopulationOptionsMQ(this, this._mongooseOptions);
+ model.populate(doc, pop, (err, doc) => {
+ if (err) {
+ return callback(err);
+ }
+ return mongooseOptions.lean ?
+ _completeOneLean(doc, res, options, callback) :
+ completeOne(model, doc, res, options, projection, userProvidedFields,
+ pop, callback);
+ });
+};
+
+/**
+ * Thunk around findOne()
+ *
+ * @param {Function} [callback]
+ * @see findOne http://docs.mongodb.org/manual/reference/method/db.collection.findOne/
+ * @api private
+ */
+
+Query.prototype._findOne = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error()) {
+ callback(this.error());
+ return null;
+ }
+
+ this._applyPaths();
+ this._fields = this._castFields(this._fields);
+
+ applyGlobalMaxTimeMS(this.options, this.model);
+
+ // don't pass in the conditions because we already merged them in
+ Query.base.findOne.call(this, {}, (err, doc) => {
+ if (err) {
+ callback(err);
+ return null;
+ }
+
+ this._completeOne(doc, null, _wrapThunkCallback(this, callback));
+ });
+});
+
+/**
+ * Declares the query a findOne operation. When executed, the first found document is passed to the callback.
+ *
+ * Passing a `callback` executes the query. The result of the query is a single document.
+ *
+ * * *Note:* `conditions` is optional, and if `conditions` is null or undefined,
+ * mongoose will send an empty `findOne` command to MongoDB, which will return
+ * an arbitrary document. If you're querying by `_id`, use `Model.findById()`
+ * instead.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOne()`
+ *
+ * ####Example
+ *
+ * var query = Kitten.where({ color: 'white' });
+ * query.findOne(function (err, kitten) {
+ * if (err) return handleError(err);
+ * if (kitten) {
+ * // doc may be null if no document matched
+ * }
+ * });
+ *
+ * @param {Object} [filter] mongodb selector
+ * @param {Object} [projection] optional fields to return
+ * @param {Object} [options] see [`setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback] optional params are (error, document)
+ * @return {Query} this
+ * @see findOne http://docs.mongodb.org/manual/reference/method/db.collection.findOne/
+ * @see Query.select #query_Query-select
+ * @api public
+ */
+
+Query.prototype.findOne = function(conditions, projection, options, callback) {
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = null;
+ projection = null;
+ options = null;
+ } else if (typeof projection === 'function') {
+ callback = projection;
+ options = null;
+ projection = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ // make sure we don't send in the whole Document to merge()
+ conditions = utils.toObject(conditions);
+
+ this.op = 'findOne';
+
+ if (options) {
+ this.setOptions(options);
+ }
+
+ if (projection) {
+ this.select(projection);
+ }
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (conditions != null) {
+ this.error(new ObjectParameterError(conditions, 'filter', 'findOne'));
+ }
+
+ if (!callback) {
+ // already merged in the conditions, don't need to send them in.
+ return Query.base.findOne.call(this);
+ }
+
+ this._findOne(callback);
+
+ return this;
+};
+
+/**
+ * Thunk around count()
+ *
+ * @param {Function} [callback]
+ * @see count http://docs.mongodb.org/manual/reference/method/db.collection.count/
+ * @api private
+ */
+
+Query.prototype._count = wrapThunk(function(callback) {
+ try {
+ this.cast(this.model);
+ } catch (err) {
+ this.error(err);
+ }
+
+ if (this.error()) {
+ return callback(this.error());
+ }
+
+ const conds = this._conditions;
+ const options = this._optionsForExec();
+
+ this._collection.count(conds, options, utils.tick(callback));
+});
+
+/**
+ * Thunk around countDocuments()
+ *
+ * @param {Function} [callback]
+ * @see countDocuments http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments
+ * @api private
+ */
+
+Query.prototype._countDocuments = wrapThunk(function(callback) {
+ try {
+ this.cast(this.model);
+ } catch (err) {
+ this.error(err);
+ }
+
+ if (this.error()) {
+ return callback(this.error());
+ }
+
+ const conds = this._conditions;
+ const options = this._optionsForExec();
+
+ this._collection.collection.countDocuments(conds, options, utils.tick(callback));
+});
+
+/**
+ * Thunk around estimatedDocumentCount()
+ *
+ * @param {Function} [callback]
+ * @see estimatedDocumentCount http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#estimatedDocumentCount
+ * @api private
+ */
+
+Query.prototype._estimatedDocumentCount = wrapThunk(function(callback) {
+ if (this.error()) {
+ return callback(this.error());
+ }
+
+ const options = this._optionsForExec();
+
+ this._collection.collection.estimatedDocumentCount(options, utils.tick(callback));
+});
+
+/**
+ * Specifies this query as a `count` query.
+ *
+ * This method is deprecated. If you want to count the number of documents in
+ * a collection, e.g. `count({})`, use the [`estimatedDocumentCount()` function](/docs/api.html#query_Query-estimatedDocumentCount)
+ * instead. Otherwise, use the [`countDocuments()`](/docs/api.html#query_Query-countDocuments) function instead.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `count()`
+ *
+ * ####Example:
+ *
+ * var countQuery = model.where({ 'color': 'black' }).count();
+ *
+ * query.count({ color: 'black' }).count(callback)
+ *
+ * query.count({ color: 'black' }, callback)
+ *
+ * query.where('color', 'black').count(function (err, count) {
+ * if (err) return handleError(err);
+ * console.log('there are %d kittens', count);
+ * })
+ *
+ * @deprecated
+ * @param {Object} [filter] count documents that match this object
+ * @param {Function} [callback] optional params are (error, count)
+ * @return {Query} this
+ * @see count http://docs.mongodb.org/manual/reference/method/db.collection.count/
+ * @api public
+ */
+
+Query.prototype.count = function(filter, callback) {
+ if (typeof filter === 'function') {
+ callback = filter;
+ filter = undefined;
+ }
+
+ filter = utils.toObject(filter);
+
+ if (mquery.canMerge(filter)) {
+ this.merge(filter);
+ }
+
+ this.op = 'count';
+ if (!callback) {
+ return this;
+ }
+
+ this._count(callback);
+
+ return this;
+};
+
+/**
+ * Specifies this query as a `estimatedDocumentCount()` query. Faster than
+ * using `countDocuments()` for large collections because
+ * `estimatedDocumentCount()` uses collection metadata rather than scanning
+ * the entire collection.
+ *
+ * `estimatedDocumentCount()` does **not** accept a filter. `Model.find({ foo: bar }).estimatedDocumentCount()`
+ * is equivalent to `Model.find().estimatedDocumentCount()`
+ *
+ * This function triggers the following middleware.
+ *
+ * - `estimatedDocumentCount()`
+ *
+ * ####Example:
+ *
+ * await Model.find().estimatedDocumentCount();
+ *
+ * @param {Object} [options] passed transparently to the [MongoDB driver](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#estimatedDocumentCount)
+ * @param {Function} [callback] optional params are (error, count)
+ * @return {Query} this
+ * @see estimatedDocumentCount http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#estimatedDocumentCount
+ * @api public
+ */
+
+Query.prototype.estimatedDocumentCount = function(options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = undefined;
+ }
+
+ if (typeof options === 'object' && options != null) {
+ this.setOptions(options);
+ }
+
+ this.op = 'estimatedDocumentCount';
+ if (!callback) {
+ return this;
+ }
+
+ this._estimatedDocumentCount(callback);
+
+ return this;
+};
+
+/**
+ * Specifies this query as a `countDocuments()` query. Behaves like `count()`,
+ * except it always does a full collection scan when passed an empty filter `{}`.
+ *
+ * There are also minor differences in how `countDocuments()` handles
+ * [`$where` and a couple geospatial operators](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments).
+ * versus `count()`.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `countDocuments()`
+ *
+ * ####Example:
+ *
+ * const countQuery = model.where({ 'color': 'black' }).countDocuments();
+ *
+ * query.countDocuments({ color: 'black' }).count(callback);
+ *
+ * query.countDocuments({ color: 'black' }, callback);
+ *
+ * query.where('color', 'black').countDocuments(function(err, count) {
+ * if (err) return handleError(err);
+ * console.log('there are %d kittens', count);
+ * });
+ *
+ * The `countDocuments()` function is similar to `count()`, but there are a
+ * [few operators that `countDocuments()` does not support](https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments).
+ * Below are the operators that `count()` supports but `countDocuments()` does not,
+ * and the suggested replacement:
+ *
+ * - `$where`: [`$expr`](https://docs.mongodb.com/manual/reference/operator/query/expr/)
+ * - `$near`: [`$geoWithin`](https://docs.mongodb.com/manual/reference/operator/query/geoWithin/) with [`$center`](https://docs.mongodb.com/manual/reference/operator/query/center/#op._S_center)
+ * - `$nearSphere`: [`$geoWithin`](https://docs.mongodb.com/manual/reference/operator/query/geoWithin/) with [`$centerSphere`](https://docs.mongodb.com/manual/reference/operator/query/centerSphere/#op._S_centerSphere)
+ *
+ * @param {Object} [filter] mongodb selector
+ * @param {Function} [callback] optional params are (error, count)
+ * @return {Query} this
+ * @see countDocuments http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments
+ * @api public
+ */
+
+Query.prototype.countDocuments = function(conditions, callback) {
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = undefined;
+ }
+
+ conditions = utils.toObject(conditions);
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+ }
+
+ this.op = 'countDocuments';
+ if (!callback) {
+ return this;
+ }
+
+ this._countDocuments(callback);
+
+ return this;
+};
+
+/**
+ * Thunk around findOne()
+ *
+ * @param {Function} [callback]
+ * @see findOne http://docs.mongodb.org/manual/reference/method/db.collection.findOne/
+ * @api private
+ */
+
+Query.prototype.__distinct = wrapThunk(function __distinct(callback) {
+ this._castConditions();
+
+ if (this.error()) {
+ callback(this.error());
+ return null;
+ }
+
+ // don't pass in the conditions because we already merged them in
+ this._collection.collection.
+ distinct(this._distinct, this._conditions, callback);
+});
+
+/**
+ * Declares or executes a distinct() operation.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * This function does not trigger any middleware.
+ *
+ * ####Example
+ *
+ * distinct(field, conditions, callback)
+ * distinct(field, conditions)
+ * distinct(field, callback)
+ * distinct(field)
+ * distinct(callback)
+ * distinct()
+ *
+ * @param {String} [field]
+ * @param {Object|Query} [filter]
+ * @param {Function} [callback] optional params are (error, arr)
+ * @return {Query} this
+ * @see distinct http://docs.mongodb.org/manual/reference/method/db.collection.distinct/
+ * @api public
+ */
+
+Query.prototype.distinct = function(field, conditions, callback) {
+ if (!callback) {
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = undefined;
+ } else if (typeof field === 'function') {
+ callback = field;
+ field = undefined;
+ conditions = undefined;
+ }
+ }
+
+ conditions = utils.toObject(conditions);
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (conditions != null) {
+ this.error(new ObjectParameterError(conditions, 'filter', 'distinct'));
+ }
+
+ if (field != null) {
+ this._distinct = field;
+ }
+ this.op = 'distinct';
+
+ if (callback != null) {
+ this.__distinct(callback);
+ }
+
+ return this;
+};
+
+/**
+ * Sets the sort order
+ *
+ * If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
+ *
+ * If a string is passed, it must be a space delimited list of path names. The
+ * sort order of each path is ascending unless the path name is prefixed with `-`
+ * which will be treated as descending.
+ *
+ * ####Example
+ *
+ * // sort by "field" ascending and "test" descending
+ * query.sort({ field: 'asc', test: -1 });
+ *
+ * // equivalent
+ * query.sort('field -test');
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @param {Object|String} arg
+ * @return {Query} this
+ * @see cursor.sort http://docs.mongodb.org/manual/reference/method/cursor.sort/
+ * @api public
+ */
+
+Query.prototype.sort = function(arg) {
+ if (arguments.length > 1) {
+ throw new Error('sort() only takes 1 Argument');
+ }
+
+ return Query.base.sort.call(this, arg);
+};
+
+/**
+ * Declare and/or execute this query as a remove() operation. `remove()` is
+ * deprecated, you should use [`deleteOne()`](#query_Query-deleteOne)
+ * or [`deleteMany()`](#query_Query-deleteMany) instead.
+ *
+ * This function does not trigger any middleware
+ *
+ * ####Example
+ *
+ * Character.remove({ name: /Stark/ }, callback);
+ *
+ * This function calls the MongoDB driver's [`Collection#remove()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#remove).
+ * The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
+ * object that contains 3 properties:
+ *
+ * - `ok`: `1` if no errors occurred
+ * - `deletedCount`: the number of documents deleted
+ * - `n`: the number of documents deleted. Equal to `deletedCount`.
+ *
+ * ####Example
+ *
+ * const res = await Character.remove({ name: /Stark/ });
+ * // Number of docs deleted
+ * res.deletedCount;
+ *
+ * ####Note
+ *
+ * Calling `remove()` creates a [Mongoose query](./queries.html), and a query
+ * does not execute until you either pass a callback, call [`Query#then()`](#query_Query-then),
+ * or call [`Query#exec()`](#query_Query-exec).
+ *
+ * // not executed
+ * const query = Character.remove({ name: /Stark/ });
+ *
+ * // executed
+ * Character.remove({ name: /Stark/ }, callback);
+ * Character.remove({ name: /Stark/ }).remove(callback);
+ *
+ * // executed without a callback
+ * Character.exec();
+ *
+ * @param {Object|Query} [filter] mongodb selector
+ * @param {Function} [callback] optional params are (error, mongooseDeleteResult)
+ * @return {Query} this
+ * @deprecated
+ * @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
+ * @see MongoDB driver remove http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#remove
+ * @api public
+ */
+
+Query.prototype.remove = function(filter, callback) {
+ if (typeof filter === 'function') {
+ callback = filter;
+ filter = null;
+ }
+
+ filter = utils.toObject(filter);
+
+ if (mquery.canMerge(filter)) {
+ this.merge(filter);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (filter != null) {
+ this.error(new ObjectParameterError(filter, 'filter', 'remove'));
+ }
+
+ if (!callback) {
+ return Query.base.remove.call(this);
+ }
+
+ this._remove(callback);
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+Query.prototype._remove = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return this;
+ }
+
+ callback = _wrapThunkCallback(this, callback);
+
+ return Query.base.remove.call(this, helpers.handleDeleteWriteOpResult(callback));
+});
+
+/**
+ * Declare and/or execute this query as a `deleteOne()` operation. Works like
+ * remove, except it deletes at most one document regardless of the `single`
+ * option.
+ *
+ * This function does not trigger any middleware.
+ *
+ * ####Example
+ *
+ * Character.deleteOne({ name: 'Eddard Stark' }, callback);
+ * Character.deleteOne({ name: 'Eddard Stark' }).then(next);
+ *
+ * This function calls the MongoDB driver's [`Collection#deleteOne()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteOne).
+ * The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
+ * object that contains 3 properties:
+ *
+ * - `ok`: `1` if no errors occurred
+ * - `deletedCount`: the number of documents deleted
+ * - `n`: the number of documents deleted. Equal to `deletedCount`.
+ *
+ * ####Example
+ *
+ * const res = await Character.deleteOne({ name: 'Eddard Stark' });
+ * // `1` if MongoDB deleted a doc, `0` if no docs matched the filter `{ name: ... }`
+ * res.deletedCount;
+ *
+ * @param {Object|Query} [filter] mongodb selector
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback] optional params are (error, mongooseDeleteResult)
+ * @return {Query} this
+ * @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
+ * @see MongoDB Driver deleteOne http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteOne
+ * @api public
+ */
+
+Query.prototype.deleteOne = function(filter, options, callback) {
+ if (typeof filter === 'function') {
+ callback = filter;
+ filter = null;
+ options = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ } else {
+ this.setOptions(options);
+ }
+
+ filter = utils.toObject(filter);
+
+ if (mquery.canMerge(filter)) {
+ this.merge(filter);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (filter != null) {
+ this.error(new ObjectParameterError(filter, 'filter', 'deleteOne'));
+ }
+
+ if (!callback) {
+ return Query.base.deleteOne.call(this);
+ }
+
+ this._deleteOne.call(this, callback);
+
+ return this;
+};
+
+/*!
+ * Internal thunk for `deleteOne()`
+ */
+
+Query.prototype._deleteOne = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return this;
+ }
+
+ callback = _wrapThunkCallback(this, callback);
+
+ return Query.base.deleteOne.call(this, helpers.handleDeleteWriteOpResult(callback));
+});
+
+/**
+ * Declare and/or execute this query as a `deleteMany()` operation. Works like
+ * remove, except it deletes _every_ document that matches `filter` in the
+ * collection, regardless of the value of `single`.
+ *
+ * This function does not trigger any middleware
+ *
+ * ####Example
+ *
+ * Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, callback)
+ * Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }).then(next)
+ *
+ * This function calls the MongoDB driver's [`Collection#deleteMany()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteMany).
+ * The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
+ * object that contains 3 properties:
+ *
+ * - `ok`: `1` if no errors occurred
+ * - `deletedCount`: the number of documents deleted
+ * - `n`: the number of documents deleted. Equal to `deletedCount`.
+ *
+ * ####Example
+ *
+ * const res = await Character.deleteMany({ name: /Stark/, age: { $gte: 18 } });
+ * // `0` if no docs matched the filter, number of docs deleted otherwise
+ * res.deletedCount;
+ *
+ * @param {Object|Query} [filter] mongodb selector
+ * @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
+ * @param {Function} [callback] optional params are (error, mongooseDeleteResult)
+ * @return {Query} this
+ * @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
+ * @see MongoDB Driver deleteMany http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteMany
+ * @api public
+ */
+
+Query.prototype.deleteMany = function(filter, options, callback) {
+ if (typeof filter === 'function') {
+ callback = filter;
+ filter = null;
+ options = null;
+ } else if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ } else {
+ this.setOptions(options);
+ }
+
+ filter = utils.toObject(filter);
+
+ if (mquery.canMerge(filter)) {
+ this.merge(filter);
+
+ prepareDiscriminatorCriteria(this);
+ } else if (filter != null) {
+ this.error(new ObjectParameterError(filter, 'filter', 'deleteMany'));
+ }
+
+ if (!callback) {
+ return Query.base.deleteMany.call(this);
+ }
+
+ this._deleteMany.call(this, callback);
+
+ return this;
+};
+
+/*!
+ * Internal thunk around `deleteMany()`
+ */
+
+Query.prototype._deleteMany = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return this;
+ }
+
+ callback = _wrapThunkCallback(this, callback);
+
+ return Query.base.deleteMany.call(this, helpers.handleDeleteWriteOpResult(callback));
+});
+
+/*!
+ * hydrates a document
+ *
+ * @param {Model} model
+ * @param {Document} doc
+ * @param {Object} res 3rd parameter to callback
+ * @param {Object} fields
+ * @param {Query} self
+ * @param {Array} [pop] array of paths used in population
+ * @param {Function} callback
+ */
+
+function completeOne(model, doc, res, options, fields, userProvidedFields, pop, callback) {
+ const opts = pop ?
+ { populated: pop }
+ : undefined;
+
+ if (options.rawResult && doc == null) {
+ _init(null);
+ return null;
+ }
+
+ const casted = helpers.createModel(model, doc, fields, userProvidedFields);
+ try {
+ casted.init(doc, opts, _init);
+ } catch (error) {
+ _init(error);
+ }
+
+ function _init(err) {
+ if (err) {
+ return process.nextTick(() => callback(err));
+ }
+
+
+ if (options.rawResult) {
+ if (doc && casted) {
+ casted.$session(options.session);
+ res.value = casted;
+ } else {
+ res.value = null;
+ }
+ return process.nextTick(() => callback(null, res));
+ }
+ casted.$session(options.session);
+ process.nextTick(() => callback(null, casted));
+ }
+}
+
+/*!
+ * If the model is a discriminator type and not root, then add the key & value to the criteria.
+ */
+
+function prepareDiscriminatorCriteria(query) {
+ if (!query || !query.model || !query.model.schema) {
+ return;
+ }
+
+ const schema = query.model.schema;
+
+ if (schema && schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
+ query._conditions[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
+ }
+}
+
+/**
+ * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) update command.
+ *
+ * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found
+ * document (if any) to the callback. The query executes if
+ * `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndUpdate()`
+ *
+ * ####Available options
+ *
+ * - `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
+ * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
+ * - `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate()`
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * - `context` (string) if set to 'query' and `runValidators` is on, `this` will refer to the query in custom validator functions that update validation runs. Does nothing if `runValidators` is false.
+ *
+ * ####Callback Signature
+ * function(error, doc) {
+ * // error: any errors that occurred
+ * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
+ * }
+ *
+ * ####Examples
+ *
+ * query.findOneAndUpdate(conditions, update, options, callback) // executes
+ * query.findOneAndUpdate(conditions, update, options) // returns Query
+ * query.findOneAndUpdate(conditions, update, callback) // executes
+ * query.findOneAndUpdate(conditions, update) // returns Query
+ * query.findOneAndUpdate(update, callback) // returns Query
+ * query.findOneAndUpdate(update) // returns Query
+ * query.findOneAndUpdate(callback) // executes
+ * query.findOneAndUpdate() // returns Query
+ *
+ * @method findOneAndUpdate
+ * @memberOf Query
+ * @instance
+ * @param {Object|Query} [filter]
+ * @param {Object} [doc]
+ * @param {Object} [options]
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](http://mongoosejs.com/docs/api.html#query_Query-lean).
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] optional params are (error, doc), _unless_ `rawResult` is used, in which case params are (error, writeOpResult)
+ * @see Tutorial /docs/tutorials/findoneandupdate.html
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
+ this.op = 'findOneAndUpdate';
+ this._validate();
+
+ switch (arguments.length) {
+ case 3:
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ break;
+ case 2:
+ if (typeof doc === 'function') {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ options = undefined;
+ break;
+ case 1:
+ if (typeof criteria === 'function') {
+ callback = criteria;
+ criteria = options = doc = undefined;
+ } else {
+ doc = criteria;
+ criteria = options = undefined;
+ }
+ }
+
+ if (mquery.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ // apply doc
+ if (doc) {
+ this._mergeUpdate(doc);
+ }
+
+ if (options) {
+ options = utils.clone(options);
+ if (options.projection) {
+ this.select(options.projection);
+ delete options.projection;
+ }
+ if (options.fields) {
+ this.select(options.fields);
+ delete options.fields;
+ }
+
+ this.setOptions(options);
+ }
+
+ if (!callback) {
+ return this;
+ }
+
+ this._findOneAndUpdate(callback);
+
+ return this;
+};
+
+/*!
+ * Thunk around findOneAndUpdate()
+ *
+ * @param {Function} [callback]
+ * @api private
+ */
+
+Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
+ if (this.error() != null) {
+ return callback(this.error());
+ }
+
+ this._findAndModify('update', callback);
+});
+
+/**
+ * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command.
+ *
+ * Finds a matching document, removes it, passing the found document (if any) to
+ * the callback. Executes if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndRemove()`
+ *
+ * ####Available options
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ *
+ * ####Callback Signature
+ * function(error, doc) {
+ * // error: any errors that occurred
+ * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
+ * }
+ *
+ * ####Examples
+ *
+ * A.where().findOneAndRemove(conditions, options, callback) // executes
+ * A.where().findOneAndRemove(conditions, options) // return Query
+ * A.where().findOneAndRemove(conditions, callback) // executes
+ * A.where().findOneAndRemove(conditions) // returns Query
+ * A.where().findOneAndRemove(callback) // executes
+ * A.where().findOneAndRemove() // returns Query
+ *
+ * @method findOneAndRemove
+ * @memberOf Query
+ * @instance
+ * @param {Object} [conditions]
+ * @param {Object} [options]
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Function} [callback] optional params are (error, document)
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Query.prototype.findOneAndRemove = function(conditions, options, callback) {
+ this.op = 'findOneAndRemove';
+ this._validate();
+
+ switch (arguments.length) {
+ case 2:
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ break;
+ case 1:
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = undefined;
+ options = undefined;
+ }
+ break;
+ }
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+ }
+
+ options && this.setOptions(options);
+
+ if (!callback) {
+ return this;
+ }
+
+ this._findOneAndRemove(callback);
+
+ return this;
+};
+
+/**
+ * Issues a MongoDB [findOneAndDelete](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndDelete/) command.
+ *
+ * Finds a matching document, removes it, and passes the found document (if any)
+ * to the callback. Executes if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndDelete()`
+ *
+ * This function differs slightly from `Model.findOneAndRemove()` in that
+ * `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/),
+ * as opposed to a `findOneAndDelete()` command. For most mongoose use cases,
+ * this distinction is purely pedantic. You should use `findOneAndDelete()`
+ * unless you have a good reason not to.
+ *
+ * ####Available options
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ *
+ * ####Callback Signature
+ * function(error, doc) {
+ * // error: any errors that occurred
+ * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
+ * }
+ *
+ * ####Examples
+ *
+ * A.where().findOneAndDelete(conditions, options, callback) // executes
+ * A.where().findOneAndDelete(conditions, options) // return Query
+ * A.where().findOneAndDelete(conditions, callback) // executes
+ * A.where().findOneAndDelete(conditions) // returns Query
+ * A.where().findOneAndDelete(callback) // executes
+ * A.where().findOneAndDelete() // returns Query
+ *
+ * @method findOneAndDelete
+ * @memberOf Query
+ * @param {Object} [conditions]
+ * @param {Object} [options]
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Function} [callback] optional params are (error, document)
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Query.prototype.findOneAndDelete = function(conditions, options, callback) {
+ this.op = 'findOneAndDelete';
+ this._validate();
+
+ switch (arguments.length) {
+ case 2:
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ break;
+ case 1:
+ if (typeof conditions === 'function') {
+ callback = conditions;
+ conditions = undefined;
+ options = undefined;
+ }
+ break;
+ }
+
+ if (mquery.canMerge(conditions)) {
+ this.merge(conditions);
+ }
+
+ options && this.setOptions(options);
+
+ if (!callback) {
+ return this;
+ }
+
+ this._findOneAndDelete(callback);
+
+ return this;
+};
+
+/*!
+ * Thunk around findOneAndDelete()
+ *
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api private
+ */
+Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return null;
+ }
+
+ const filter = this._conditions;
+ const options = this._optionsForExec();
+ let fields = null;
+
+ if (this._fields != null) {
+ options.projection = this._castFields(utils.clone(this._fields));
+ fields = options.projection;
+ if (fields instanceof Error) {
+ callback(fields);
+ return null;
+ }
+ }
+
+ this._collection.collection.findOneAndDelete(filter, options, _wrapThunkCallback(this, (err, res) => {
+ if (err) {
+ return callback(err);
+ }
+
+ const doc = res.value;
+
+ return this._completeOne(doc, res, callback);
+ }));
+});
+
+/**
+ * Issues a MongoDB [findOneAndReplace](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndReplace/) command.
+ *
+ * Finds a matching document, removes it, and passes the found document (if any)
+ * to the callback. Executes if `callback` is passed.
+ *
+ * This function triggers the following middleware.
+ *
+ * - `findOneAndReplace()`
+ *
+ * ####Available options
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ *
+ * ####Callback Signature
+ * function(error, doc) {
+ * // error: any errors that occurred
+ * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
+ * }
+ *
+ * ####Examples
+ *
+ * A.where().findOneAndReplace(filter, replacement, options, callback); // executes
+ * A.where().findOneAndReplace(filter, replacement, options); // return Query
+ * A.where().findOneAndReplace(filter, replacement, callback); // executes
+ * A.where().findOneAndReplace(filter); // returns Query
+ * A.where().findOneAndReplace(callback); // executes
+ * A.where().findOneAndReplace(); // returns Query
+ *
+ * @method findOneAndReplace
+ * @memberOf Query
+ * @param {Object} [filter]
+ * @param {Object} [replacement]
+ * @param {Object} [options]
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
+ * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](http://mongoosejs.com/docs/api.html#query_Query-lean).
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Function} [callback] optional params are (error, document)
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
+ this.op = 'findOneAndReplace';
+ this._validate();
+
+ switch (arguments.length) {
+ case 3:
+ if (typeof options === 'function') {
+ callback = options;
+ options = void 0;
+ }
+ break;
+ case 2:
+ if (typeof replacement === 'function') {
+ callback = replacement;
+ replacement = void 0;
+ }
+ break;
+ case 1:
+ if (typeof filter === 'function') {
+ callback = filter;
+ filter = void 0;
+ replacement = void 0;
+ options = void 0;
+ }
+ break;
+ }
+
+ if (mquery.canMerge(filter)) {
+ this.merge(filter);
+ }
+
+ if (replacement != null) {
+ if (hasDollarKeys(replacement)) {
+ throw new Error('The replacement document must not contain atomic operators.');
+ }
+ this._mergeUpdate(replacement);
+ }
+
+ options && this.setOptions(options);
+
+ if (!callback) {
+ return this;
+ }
+
+ this._findOneAndReplace(callback);
+
+ return this;
+};
+
+/*!
+ * Thunk around findOneAndReplace()
+ *
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api private
+ */
+Query.prototype._findOneAndReplace = wrapThunk(function(callback) {
+ this._castConditions();
+
+ if (this.error() != null) {
+ callback(this.error());
+ return null;
+ }
+
+ const filter = this._conditions;
+ const options = this._optionsForExec();
+ convertNewToReturnOriginal(options);
+ let fields = null;
+
+ let castedDoc = new this.model(this._update, null, true);
+ this._update = castedDoc;
+
+ this._applyPaths();
+ if (this._fields != null) {
+ options.projection = this._castFields(utils.clone(this._fields));
+ fields = options.projection;
+ if (fields instanceof Error) {
+ callback(fields);
+ return null;
+ }
+ }
+
+ castedDoc.validate(err => {
+ if (err != null) {
+ return callback(err);
+ }
+
+ if (castedDoc.toBSON) {
+ castedDoc = castedDoc.toBSON();
+ }
+
+ this._collection.collection.findOneAndReplace(filter, castedDoc, options, _wrapThunkCallback(this, (err, res) => {
+ if (err) {
+ return callback(err);
+ }
+
+ const doc = res.value;
+
+ return this._completeOne(doc, res, callback);
+ }));
+ });
+});
+
+/*!
+ * Support the `new` option as an alternative to `returnOriginal` for backwards
+ * compat.
+ */
+
+function convertNewToReturnOriginal(options) {
+ if ('new' in options) {
+ options.returnOriginal = !options['new'];
+ delete options['new'];
+ }
+}
+
+/*!
+ * Thunk around findOneAndRemove()
+ *
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api private
+ */
+Query.prototype._findOneAndRemove = wrapThunk(function(callback) {
+ if (this.error() != null) {
+ callback(this.error());
+ return;
+ }
+
+ this._findAndModify('remove', callback);
+});
+
+/*!
+ * Get options from query opts, falling back to the base mongoose object.
+ */
+
+function _getOption(query, option, def) {
+ const opts = query._optionsForExec(query.model);
+
+ if (option in opts) {
+ return opts[option];
+ }
+ if (option in query.model.base.options) {
+ return query.model.base.options[option];
+ }
+ return def;
+}
+
+/*!
+ * Override mquery.prototype._findAndModify to provide casting etc.
+ *
+ * @param {String} type - either "remove" or "update"
+ * @param {Function} callback
+ * @api private
+ */
+
+Query.prototype._findAndModify = function(type, callback) {
+ if (typeof callback !== 'function') {
+ throw new Error('Expected callback in _findAndModify');
+ }
+
+ const model = this.model;
+ const schema = model.schema;
+ const _this = this;
+ let fields;
+
+ const castedQuery = castQuery(this);
+ if (castedQuery instanceof Error) {
+ return callback(castedQuery);
+ }
+
+ _castArrayFilters(this);
+
+ const opts = this._optionsForExec(model);
+
+ if ('strict' in opts) {
+ this._mongooseOptions.strict = opts.strict;
+ }
+
+ const isOverwriting = this.options.overwrite && !hasDollarKeys(this._update);
+ if (isOverwriting) {
+ this._update = new this.model(this._update, null, true);
+ }
+
+ if (type === 'remove') {
+ opts.remove = true;
+ } else {
+ if (!('new' in opts) && !('returnOriginal' in opts)) {
+ opts.new = false;
+ }
+ if (!('upsert' in opts)) {
+ opts.upsert = false;
+ }
+ if (opts.upsert || opts['new']) {
+ opts.remove = false;
+ }
+
+ if (!isOverwriting) {
+ this._update = castDoc(this, opts.overwrite);
+ this._update = setDefaultsOnInsert(this._conditions, schema, this._update, opts);
+ if (!this._update) {
+ if (opts.upsert) {
+ // still need to do the upsert to empty doc
+ const doc = utils.clone(castedQuery);
+ delete doc._id;
+ this._update = { $set: doc };
+ } else {
+ this.findOne(callback);
+ return this;
+ }
+ } else if (this._update instanceof Error) {
+ return callback(this._update);
+ } else {
+ // In order to make MongoDB 2.6 happy (see
+ // https://jira.mongodb.org/browse/SERVER-12266 and related issues)
+ // if we have an actual update document but $set is empty, junk the $set.
+ if (this._update.$set && Object.keys(this._update.$set).length === 0) {
+ delete this._update.$set;
+ }
+ }
+ }
+ }
+
+ this._applyPaths();
+
+ const options = this._mongooseOptions;
+
+ if (this._fields) {
+ fields = utils.clone(this._fields);
+ opts.projection = this._castFields(fields);
+ if (opts.projection instanceof Error) {
+ return callback(opts.projection);
+ }
+ }
+
+ if (opts.sort) convertSortToArray(opts);
+
+ const cb = function(err, doc, res) {
+ if (err) {
+ return callback(err);
+ }
+
+ _this._completeOne(doc, res, callback);
+ };
+
+ let useFindAndModify = true;
+ const runValidators = _getOption(this, 'runValidators', false);
+ const base = _this.model && _this.model.base;
+ const conn = get(model, 'collection.conn', {});
+ if ('useFindAndModify' in base.options) {
+ useFindAndModify = base.get('useFindAndModify');
+ }
+ if ('useFindAndModify' in conn.config) {
+ useFindAndModify = conn.config.useFindAndModify;
+ }
+ if ('useFindAndModify' in options) {
+ useFindAndModify = options.useFindAndModify;
+ }
+ if (useFindAndModify === false) {
+ // Bypass mquery
+ const collection = _this._collection.collection;
+ convertNewToReturnOriginal(opts);
+
+ if (type === 'remove') {
+ collection.findOneAndDelete(castedQuery, opts, _wrapThunkCallback(_this, function(error, res) {
+ return cb(error, res ? res.value : res, res);
+ }));
+
+ return this;
+ }
+
+ // honors legacy overwrite option for backward compatibility
+ const updateMethod = isOverwriting ? 'findOneAndReplace' : 'findOneAndUpdate';
+
+ if (runValidators) {
+ this.validate(this._update, opts, isOverwriting, error => {
+ if (error) {
+ return callback(error);
+ }
+ if (this._update && this._update.toBSON) {
+ this._update = this._update.toBSON();
+ }
+
+ collection[updateMethod](castedQuery, this._update, opts, _wrapThunkCallback(_this, function(error, res) {
+ return cb(error, res ? res.value : res, res);
+ }));
+ });
+ } else {
+ if (this._update && this._update.toBSON) {
+ this._update = this._update.toBSON();
+ }
+ collection[updateMethod](castedQuery, this._update, opts, _wrapThunkCallback(_this, function(error, res) {
+ return cb(error, res ? res.value : res, res);
+ }));
+ }
+
+ return this;
+ }
+
+ if (runValidators) {
+ this.validate(this._update, opts, isOverwriting, function(error) {
+ if (error) {
+ return callback(error);
+ }
+ _legacyFindAndModify.call(_this, castedQuery, _this._update, opts, cb);
+ });
+ } else {
+ _legacyFindAndModify.call(_this, castedQuery, _this._update, opts, cb);
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+function _completeOneLean(doc, res, opts, callback) {
+ if (opts.rawResult) {
+ return callback(null, res);
+ }
+ return callback(null, doc);
+}
+
+
+/*!
+ * ignore
+ */
+
+const _legacyFindAndModify = util.deprecate(function(filter, update, opts, cb) {
+ if (update && update.toBSON) {
+ update = update.toBSON();
+ }
+ const collection = this._collection;
+ const sort = opts != null && Array.isArray(opts.sort) ? opts.sort : [];
+ const _cb = _wrapThunkCallback(this, function(error, res) {
+ return cb(error, res ? res.value : res, res);
+ });
+ collection.collection._findAndModify(filter, sort, update, opts, _cb);
+}, 'Mongoose: `findOneAndUpdate()` and `findOneAndDelete()` without the ' +
+ '`useFindAndModify` option set to false are deprecated. See: ' +
+ 'https://mongoosejs.com/docs/deprecations.html#findandmodify');
+
+/*!
+ * Override mquery.prototype._mergeUpdate to handle mongoose objects in
+ * updates.
+ *
+ * @param {Object} doc
+ * @api private
+ */
+
+Query.prototype._mergeUpdate = function(doc) {
+ if (doc == null || (typeof doc === 'object' && Object.keys(doc).length === 0)) {
+ return;
+ }
+
+ if (!this._update) {
+ this._update = Array.isArray(doc) ? [] : {};
+ }
+ if (doc instanceof Query) {
+ if (Array.isArray(this._update)) {
+ throw new Error('Cannot mix array and object updates');
+ }
+ if (doc._update) {
+ utils.mergeClone(this._update, doc._update);
+ }
+ } else if (Array.isArray(doc)) {
+ if (!Array.isArray(this._update)) {
+ throw new Error('Cannot mix array and object updates');
+ }
+ this._update = this._update.concat(doc);
+ } else {
+ if (Array.isArray(this._update)) {
+ throw new Error('Cannot mix array and object updates');
+ }
+ utils.mergeClone(this._update, doc);
+ }
+};
+
+/*!
+ * The mongodb driver 1.3.23 only supports the nested array sort
+ * syntax. We must convert it or sorting findAndModify will not work.
+ */
+
+function convertSortToArray(opts) {
+ if (Array.isArray(opts.sort)) {
+ return;
+ }
+ if (!utils.isObject(opts.sort)) {
+ return;
+ }
+
+ const sort = [];
+
+ for (const key in opts.sort) {
+ if (utils.object.hasOwnProperty(opts.sort, key)) {
+ sort.push([key, opts.sort[key]]);
+ }
+ }
+
+ opts.sort = sort;
+}
+
+/*!
+ * ignore
+ */
+
+function _updateThunk(op, callback) {
+ this._castConditions();
+
+ _castArrayFilters(this);
+
+ if (this.error() != null) {
+ callback(this.error());
+ return null;
+ }
+
+ callback = _wrapThunkCallback(this, callback);
+
+ const castedQuery = this._conditions;
+ const options = this._optionsForExec(this.model);
+
+ ++this._executionCount;
+
+ this._update = utils.clone(this._update, options);
+ const isOverwriting = this.options.overwrite && !hasDollarKeys(this._update);
+ if (isOverwriting) {
+ if (op === 'updateOne' || op === 'updateMany') {
+ return callback(new MongooseError('The MongoDB server disallows ' +
+ 'overwriting documents using `' + op + '`. See: ' +
+ 'https://mongoosejs.com/docs/deprecations.html#update'));
+ }
+ this._update = new this.model(this._update, null, true);
+ } else {
+ this._update = castDoc(this, options.overwrite);
+
+ if (this._update instanceof Error) {
+ callback(this._update);
+ return null;
+ }
+
+ if (this._update == null || Object.keys(this._update).length === 0) {
+ callback(null, 0);
+ return null;
+ }
+
+ this._update = setDefaultsOnInsert(this._conditions, this.model.schema,
+ this._update, options);
+ }
+
+ const runValidators = _getOption(this, 'runValidators', false);
+ if (runValidators) {
+ this.validate(this._update, options, isOverwriting, err => {
+ if (err) {
+ return callback(err);
+ }
+
+ if (this._update.toBSON) {
+ this._update = this._update.toBSON();
+ }
+ this._collection[op](castedQuery, this._update, options, callback);
+ });
+ return null;
+ }
+
+ if (this._update.toBSON) {
+ this._update = this._update.toBSON();
+ }
+
+ this._collection[op](castedQuery, this._update, options, callback);
+ return null;
+}
+
+/*!
+ * Mongoose calls this function internally to validate the query if
+ * `runValidators` is set
+ *
+ * @param {Object} castedDoc the update, after casting
+ * @param {Object} options the options from `_optionsForExec()`
+ * @param {Function} callback
+ * @api private
+ */
+
+Query.prototype.validate = function validate(castedDoc, options, isOverwriting, callback) {
+ return promiseOrCallback(callback, cb => {
+ try {
+ if (isOverwriting) {
+ castedDoc.validate(cb);
+ } else {
+ updateValidators(this, this.model.schema, castedDoc, options, cb);
+ }
+ } catch (err) {
+ process.nextTick(function() {
+ cb(err);
+ });
+ }
+ });
+};
+
+/*!
+ * Internal thunk for .update()
+ *
+ * @param {Function} callback
+ * @see Model.update #model_Model.update
+ * @api private
+ */
+Query.prototype._execUpdate = wrapThunk(function(callback) {
+ return _updateThunk.call(this, 'update', callback);
+});
+
+/*!
+ * Internal thunk for .updateMany()
+ *
+ * @param {Function} callback
+ * @see Model.update #model_Model.update
+ * @api private
+ */
+Query.prototype._updateMany = wrapThunk(function(callback) {
+ return _updateThunk.call(this, 'updateMany', callback);
+});
+
+/*!
+ * Internal thunk for .updateOne()
+ *
+ * @param {Function} callback
+ * @see Model.update #model_Model.update
+ * @api private
+ */
+Query.prototype._updateOne = wrapThunk(function(callback) {
+ return _updateThunk.call(this, 'updateOne', callback);
+});
+
+/*!
+ * Internal thunk for .replaceOne()
+ *
+ * @param {Function} callback
+ * @see Model.replaceOne #model_Model.replaceOne
+ * @api private
+ */
+Query.prototype._replaceOne = wrapThunk(function(callback) {
+ return _updateThunk.call(this, 'replaceOne', callback);
+});
+
+/**
+ * Declare and/or execute this query as an update() operation.
+ *
+ * _All paths passed that are not [atomic](https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/#pattern) operations will become `$set` ops._
+ *
+ * This function triggers the following middleware.
+ *
+ * - `update()`
+ *
+ * ####Example
+ *
+ * Model.where({ _id: id }).update({ title: 'words' })
+ *
+ * // becomes
+ *
+ * Model.where({ _id: id }).update({ $set: { title: 'words' }})
+ *
+ * ####Valid options:
+ *
+ * - `upsert` (boolean) whether to create the doc if it doesn't match (false)
+ * - `multi` (boolean) whether multiple documents should be updated (false)
+ * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
+ * - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
+ * - `strict` (boolean) overrides the `strict` option for this update
+ * - `overwrite` (boolean) disables update-only mode, allowing you to overwrite the doc (false)
+ * - `context` (string) if set to 'query' and `runValidators` is on, `this` will refer to the query in custom validator functions that update validation runs. Does nothing if `runValidators` is false.
+ * - `read`
+ * - `writeConcern`
+ *
+ * ####Note
+ *
+ * Passing an empty object `{}` as the doc will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option set, the update operation will be ignored and the callback executed without sending the command to MongoDB so as to prevent accidently overwritting documents in the collection.
+ *
+ * ####Note
+ *
+ * The operation is only executed when a callback is passed. To force execution without a callback, we must first call update() and then execute it by using the `exec()` method.
+ *
+ * var q = Model.where({ _id: id });
+ * q.update({ $set: { name: 'bob' }}).update(); // not executed
+ *
+ * q.update({ $set: { name: 'bob' }}).exec(); // executed
+ *
+ * // keys that are not [atomic](https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/#pattern) ops become `$set`.
+ * // this executes the same command as the previous example.
+ * q.update({ name: 'bob' }).exec();
+ *
+ * // overwriting with empty docs
+ * var q = Model.where({ _id: id }).setOptions({ overwrite: true })
+ * q.update({ }, callback); // executes
+ *
+ * // multi update with overwrite to empty doc
+ * var q = Model.where({ _id: id });
+ * q.setOptions({ multi: true, overwrite: true })
+ * q.update({ });
+ * q.update(callback); // executed
+ *
+ * // multi updates
+ * Model.where()
+ * .update({ name: /^match/ }, { $set: { arr: [] }}, { multi: true }, callback)
+ *
+ * // more multi updates
+ * Model.where()
+ * .setOptions({ multi: true })
+ * .update({ $set: { arr: [] }}, callback)
+ *
+ * // single update by default
+ * Model.where({ email: 'address@example.com' })
+ * .update({ $inc: { counter: 1 }}, callback)
+ *
+ * API summary
+ *
+ * update(filter, doc, options, cb) // executes
+ * update(filter, doc, options)
+ * update(filter, doc, cb) // executes
+ * update(filter, doc)
+ * update(doc, cb) // executes
+ * update(doc)
+ * update(cb) // executes
+ * update(true) // executes
+ * update()
+ *
+ * @param {Object} [filter]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @return {Query} this
+ * @see Model.update #model_Model.update
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @api public
+ */
+
+Query.prototype.update = function(conditions, doc, options, callback) {
+ if (typeof options === 'function') {
+ // .update(conditions, doc, callback)
+ callback = options;
+ options = null;
+ } else if (typeof doc === 'function') {
+ // .update(doc, callback);
+ callback = doc;
+ doc = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof conditions === 'function') {
+ // .update(callback)
+ callback = conditions;
+ conditions = undefined;
+ doc = undefined;
+ options = undefined;
+ } else if (typeof conditions === 'object' && !doc && !options && !callback) {
+ // .update(doc)
+ doc = conditions;
+ conditions = undefined;
+ options = undefined;
+ callback = undefined;
+ }
+
+ return _update(this, 'update', conditions, doc, options, callback);
+};
+
+/**
+ * Declare and/or execute this query as an updateMany() operation. Same as
+ * `update()`, except MongoDB will update _all_ documents that match
+ * `filter` (as opposed to just the first one) regardless of the value of
+ * the `multi` option.
+ *
+ * **Note** updateMany will _not_ fire update middleware. Use `pre('updateMany')`
+ * and `post('updateMany')` instead.
+ *
+ * ####Example:
+ * const res = await Person.updateMany({ name: /Stark$/ }, { isDeleted: true });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `updateMany()`
+ *
+ * @param {Object} [filter]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @return {Query} this
+ * @see Model.update #model_Model.update
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @api public
+ */
+
+Query.prototype.updateMany = function(conditions, doc, options, callback) {
+ if (typeof options === 'function') {
+ // .update(conditions, doc, callback)
+ callback = options;
+ options = null;
+ } else if (typeof doc === 'function') {
+ // .update(doc, callback);
+ callback = doc;
+ doc = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof conditions === 'function') {
+ // .update(callback)
+ callback = conditions;
+ conditions = undefined;
+ doc = undefined;
+ options = undefined;
+ } else if (typeof conditions === 'object' && !doc && !options && !callback) {
+ // .update(doc)
+ doc = conditions;
+ conditions = undefined;
+ options = undefined;
+ callback = undefined;
+ }
+
+ return _update(this, 'updateMany', conditions, doc, options, callback);
+};
+
+/**
+ * Declare and/or execute this query as an updateOne() operation. Same as
+ * `update()`, except it does not support the `multi` or `overwrite` options.
+ *
+ * - MongoDB will update _only_ the first document that matches `filter` regardless of the value of the `multi` option.
+ * - Use `replaceOne()` if you want to overwrite an entire document rather than using [atomic](https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/#pattern) operators like `$set`.
+ *
+ * **Note** updateOne will _not_ fire update middleware. Use `pre('updateOne')`
+ * and `post('updateOne')` instead.
+ *
+ * ####Example:
+ * const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `updateOne()`
+ *
+ * @param {Object} [filter]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @return {Query} this
+ * @see Model.update #model_Model.update
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @api public
+ */
+
+Query.prototype.updateOne = function(conditions, doc, options, callback) {
+ if (typeof options === 'function') {
+ // .update(conditions, doc, callback)
+ callback = options;
+ options = null;
+ } else if (typeof doc === 'function') {
+ // .update(doc, callback);
+ callback = doc;
+ doc = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof conditions === 'function') {
+ // .update(callback)
+ callback = conditions;
+ conditions = undefined;
+ doc = undefined;
+ options = undefined;
+ } else if (typeof conditions === 'object' && !doc && !options && !callback) {
+ // .update(doc)
+ doc = conditions;
+ conditions = undefined;
+ options = undefined;
+ callback = undefined;
+ }
+
+ return _update(this, 'updateOne', conditions, doc, options, callback);
+};
+
+/**
+ * Declare and/or execute this query as a replaceOne() operation. Same as
+ * `update()`, except MongoDB will replace the existing document and will
+ * not accept any [atomic](https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/#pattern) operators (`$set`, etc.)
+ *
+ * **Note** replaceOne will _not_ fire update middleware. Use `pre('replaceOne')`
+ * and `post('replaceOne')` instead.
+ *
+ * ####Example:
+ * const res = await Person.replaceOne({ _id: 24601 }, { name: 'Jean Valjean' });
+ * res.n; // Number of documents matched
+ * res.nModified; // Number of documents modified
+ *
+ * This function triggers the following middleware.
+ *
+ * - `replaceOne()`
+ *
+ * @param {Object} [filter]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
+ * @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
+ * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
+ * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
+ * @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
+ * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
+ * @param {Function} [callback] params are (error, writeOpResult)
+ * @return {Query} this
+ * @see Model.update #model_Model.update
+ * @see Query docs https://mongoosejs.com/docs/queries.html
+ * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/
+ * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
+ * @api public
+ */
+
+Query.prototype.replaceOne = function(conditions, doc, options, callback) {
+ if (typeof options === 'function') {
+ // .update(conditions, doc, callback)
+ callback = options;
+ options = null;
+ } else if (typeof doc === 'function') {
+ // .update(doc, callback);
+ callback = doc;
+ doc = conditions;
+ conditions = {};
+ options = null;
+ } else if (typeof conditions === 'function') {
+ // .update(callback)
+ callback = conditions;
+ conditions = undefined;
+ doc = undefined;
+ options = undefined;
+ } else if (typeof conditions === 'object' && !doc && !options && !callback) {
+ // .update(doc)
+ doc = conditions;
+ conditions = undefined;
+ options = undefined;
+ callback = undefined;
+ }
+
+ this.setOptions({ overwrite: true });
+ return _update(this, 'replaceOne', conditions, doc, options, callback);
+};
+
+/*!
+ * Internal helper for update, updateMany, updateOne, replaceOne
+ */
+
+function _update(query, op, filter, doc, options, callback) {
+ // make sure we don't send in the whole Document to merge()
+ query.op = op;
+ filter = utils.toObject(filter);
+ doc = doc || {};
+
+ const oldCb = callback;
+ if (oldCb) {
+ if (typeof oldCb === 'function') {
+ callback = function(error, result) {
+ oldCb(error, result ? result.result : { ok: 0, n: 0, nModified: 0 });
+ };
+ } else {
+ throw new Error('Invalid callback() argument.');
+ }
+ }
+
+ // strict is an option used in the update checking, make sure it gets set
+ if (options != null) {
+ if ('strict' in options) {
+ query._mongooseOptions.strict = options.strict;
+ }
+ }
+
+ if (!(filter instanceof Query) &&
+ filter != null &&
+ filter.toString() !== '[object Object]') {
+ query.error(new ObjectParameterError(filter, 'filter', op));
+ } else {
+ query.merge(filter);
+ }
+
+ if (utils.isObject(options)) {
+ query.setOptions(options);
+ }
+
+ query._mergeUpdate(doc);
+
+ // Hooks
+ if (callback) {
+ if (op === 'update') {
+ query._execUpdate(callback);
+ return query;
+ }
+ query['_' + op](callback);
+ return query;
+ }
+
+ return Query.base[op].call(query, filter, void 0, options, callback);
+}
+
+/**
+ * Runs a function `fn` and treats the return value of `fn` as the new value
+ * for the query to resolve to.
+ *
+ * Any functions you pass to `map()` will run **after** any post hooks.
+ *
+ * ####Example:
+ *
+ * const res = await MyModel.findOne().map(res => {
+ * // Sets a `loadedAt` property on the doc that tells you the time the
+ * // document was loaded.
+ * return res == null ?
+ * res :
+ * Object.assign(res, { loadedAt: new Date() });
+ * });
+ *
+ * @method map
+ * @memberOf Query
+ * @instance
+ * @param {Function} fn function to run to transform the query result
+ * @return {Query} this
+ */
+
+Query.prototype.map = function(fn) {
+ this._transforms.push(fn);
+ return this;
+};
+
+/**
+ * Make this query throw an error if no documents match the given `filter`.
+ * This is handy for integrating with async/await, because `orFail()` saves you
+ * an extra `if` statement to check if no document was found.
+ *
+ * ####Example:
+ *
+ * // Throws if no doc returned
+ * await Model.findOne({ foo: 'bar' }).orFail();
+ *
+ * // Throws if no document was updated
+ * await Model.updateOne({ foo: 'bar' }, { name: 'test' }).orFail();
+ *
+ * // Throws "No docs found!" error if no docs match `{ foo: 'bar' }`
+ * await Model.find({ foo: 'bar' }).orFail(new Error('No docs found!'));
+ *
+ * // Throws "Not found" error if no document was found
+ * await Model.findOneAndUpdate({ foo: 'bar' }, { name: 'test' }).
+ * orFail(() => Error('Not found'));
+ *
+ * @method orFail
+ * @memberOf Query
+ * @instance
+ * @param {Function|Error} [err] optional error to throw if no docs match `filter`. If not specified, `orFail()` will throw a `DocumentNotFoundError`
+ * @return {Query} this
+ */
+
+Query.prototype.orFail = function(err) {
+ this.map(res => {
+ switch (this.op) {
+ case 'find':
+ if (res.length === 0) {
+ throw _orFailError(err, this);
+ }
+ break;
+ case 'findOne':
+ if (res == null) {
+ throw _orFailError(err, this);
+ }
+ break;
+ case 'update':
+ case 'updateMany':
+ case 'updateOne':
+ if (get(res, 'result.nModified') === 0) {
+ throw _orFailError(err, this);
+ }
+ break;
+ case 'findOneAndDelete':
+ if (get(res, 'lastErrorObject.n') === 0) {
+ throw _orFailError(err, this);
+ }
+ break;
+ case 'findOneAndUpdate':
+ case 'findOneAndReplace':
+ if (get(res, 'lastErrorObject.updatedExisting') === false) {
+ throw _orFailError(err, this);
+ }
+ break;
+ case 'deleteMany':
+ case 'deleteOne':
+ case 'remove':
+ if (res.n === 0) {
+ throw _orFailError(err, this);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return res;
+ });
+ return this;
+};
+
+/*!
+ * Get the error to throw for `orFail()`
+ */
+
+function _orFailError(err, query) {
+ if (typeof err === 'function') {
+ err = err.call(query);
+ }
+
+ if (err == null) {
+ err = new DocumentNotFoundError(query.getQuery(), query.model.modelName);
+ }
+
+ return err;
+}
+
+/**
+ * Executes the query
+ *
+ * ####Examples:
+ *
+ * var promise = query.exec();
+ * var promise = query.exec('update');
+ *
+ * query.exec(callback);
+ * query.exec('find', callback);
+ *
+ * @param {String|Function} [operation]
+ * @param {Function} [callback] optional params depend on the function being called
+ * @return {Promise}
+ * @api public
+ */
+
+Query.prototype.exec = function exec(op, callback) {
+ const _this = this;
+
+ if (typeof op === 'function') {
+ callback = op;
+ op = null;
+ } else if (typeof op === 'string') {
+ this.op = op;
+ }
+
+ callback = this.model.$handleCallbackError(callback);
+
+ return promiseOrCallback(callback, (cb) => {
+ cb = this.model.$wrapCallback(cb);
+
+ if (!_this.op) {
+ cb();
+ return;
+ }
+
+ this._hooks.execPre('exec', this, [], (error) => {
+ if (error != null) {
+ return cb(error);
+ }
+ this[this.op].call(this, (error, res) => {
+ if (error) {
+ return cb(error);
+ }
+
+ this._hooks.execPost('exec', this, [], {}, (error) => {
+ if (error) {
+ return cb(error);
+ }
+
+ cb(null, res);
+ });
+ });
+ });
+ }, this.model.events);
+};
+
+/*!
+ * ignore
+ */
+
+function _wrapThunkCallback(query, cb) {
+ return function(error, res) {
+ if (error != null) {
+ return cb(error);
+ }
+
+ for (const fn of query._transforms) {
+ try {
+ res = fn(res);
+ } catch (error) {
+ return cb(error);
+ }
+ }
+
+ return cb(null, res);
+ };
+}
+
+/**
+ * Executes the query returning a `Promise` which will be
+ * resolved with either the doc(s) or rejected with the error.
+ *
+ * @param {Function} [resolve]
+ * @param {Function} [reject]
+ * @return {Promise}
+ * @api public
+ */
+
+Query.prototype.then = function(resolve, reject) {
+ return this.exec().then(resolve, reject);
+};
+
+/**
+ * Executes the query returning a `Promise` which will be
+ * resolved with either the doc(s) or rejected with the error.
+ * Like `.then()`, but only takes a rejection handler.
+ *
+ * @param {Function} [reject]
+ * @return {Promise}
+ * @api public
+ */
+
+Query.prototype.catch = function(reject) {
+ return this.exec().then(null, reject);
+};
+
+/*!
+ * ignore
+ */
+
+Query.prototype._pre = function(fn) {
+ this._hooks.pre('exec', fn);
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+Query.prototype._post = function(fn) {
+ this._hooks.post('exec', fn);
+ return this;
+};
+
+/*!
+ * Casts obj for an update command.
+ *
+ * @param {Object} obj
+ * @return {Object} obj after casting its values
+ * @api private
+ */
+
+Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
+ let strict;
+ if ('strict' in this._mongooseOptions) {
+ strict = this._mongooseOptions.strict;
+ } else if (this.schema && this.schema.options) {
+ strict = this.schema.options.strict;
+ } else {
+ strict = true;
+ }
+
+ let omitUndefined = false;
+ if ('omitUndefined' in this._mongooseOptions) {
+ omitUndefined = this._mongooseOptions.omitUndefined;
+ }
+
+ let useNestedStrict;
+ if ('useNestedStrict' in this.options) {
+ useNestedStrict = this.options.useNestedStrict;
+ }
+
+ let schema = this.schema;
+ const filter = this._conditions;
+ if (schema != null &&
+ utils.hasUserDefinedProperty(filter, schema.options.discriminatorKey) &&
+ typeof filter[schema.options.discriminatorKey] !== 'object' &&
+ schema.discriminators != null) {
+ const discriminatorValue = filter[schema.options.discriminatorKey];
+ const byValue = getDiscriminatorByValue(this.model, discriminatorValue);
+ schema = schema.discriminators[discriminatorValue] ||
+ (byValue && byValue.schema) ||
+ schema;
+ }
+
+ return castUpdate(schema, obj, {
+ overwrite: overwrite,
+ strict: strict,
+ omitUndefined,
+ useNestedStrict: useNestedStrict
+ }, this, this._conditions);
+};
+
+/*!
+ * castQuery
+ * @api private
+ */
+
+function castQuery(query) {
+ try {
+ return query.cast(query.model);
+ } catch (err) {
+ return err;
+ }
+}
+
+/*!
+ * castDoc
+ * @api private
+ */
+
+function castDoc(query, overwrite) {
+ try {
+ return query._castUpdate(query._update, overwrite);
+ } catch (err) {
+ return err;
+ }
+}
+
+/**
+ * Specifies paths which should be populated with other documents.
+ *
+ * ####Example:
+ *
+ * let book = await Book.findOne().populate('authors');
+ * book.title; // 'Node.js in Action'
+ * book.authors[0].name; // 'TJ Holowaychuk'
+ * book.authors[1].name; // 'Nathan Rajlich'
+ *
+ * let books = await Book.find().populate({
+ * path: 'authors',
+ * // `match` and `sort` apply to the Author model,
+ * // not the Book model. These options do not affect
+ * // which documents are in `books`, just the order and
+ * // contents of each book document's `authors`.
+ * match: { name: new RegExp('.*h.*', 'i') },
+ * sort: { name: -1 }
+ * });
+ * books[0].title; // 'Node.js in Action'
+ * // Each book's `authors` are sorted by name, descending.
+ * books[0].authors[0].name; // 'TJ Holowaychuk'
+ * books[0].authors[1].name; // 'Marc Harter'
+ *
+ * books[1].title; // 'Professional AngularJS'
+ * // Empty array, no authors' name has the letter 'h'
+ * books[1].authors; // []
+ *
+ * Paths are populated after the query executes and a response is received. A
+ * separate query is then executed for each path specified for population. After
+ * a response for each query has also been returned, the results are passed to
+ * the callback.
+ *
+ * @param {Object|String} path either the path to populate or an object specifying all parameters
+ * @param {Object|String} [select] Field selection for the population query
+ * @param {Model} [model] The model you wish to use for population. If not specified, populate will look up the model by the name in the Schema's `ref` field.
+ * @param {Object} [match] Conditions for the population query
+ * @param {Object} [options] Options for the population query (sort, etc)
+ * @param {String} [options.path=null] The path to populate.
+ * @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
+ * @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](/docs/schematypes.html#schematype-options).
+ * @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
+ * @param {Object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://docs.mongodb.com/manual/tutorial/query-documents/), or a function that returns a filter object.
+ * @param {Object} [options.options=null] Additional options like `limit` and `lean`.
+ * @see population ./populate.html
+ * @see Query#select #query_Query-select
+ * @see Model.populate #model_Model.populate
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.populate = function() {
+ // Bail when given no truthy arguments
+ if (!Array.from(arguments).some(Boolean)) {
+ return this;
+ }
+
+ const res = utils.populate.apply(null, arguments);
+
+ // Propagate readConcern and readPreference and lean from parent query,
+ // unless one already specified
+ if (this.options != null) {
+ const readConcern = this.options.readConcern;
+ const readPref = this.options.readPreference;
+
+ for (let i = 0; i < res.length; ++i) {
+ if (readConcern != null && get(res[i], 'options.readConcern') == null) {
+ res[i].options = res[i].options || {};
+ res[i].options.readConcern = readConcern;
+ }
+ if (readPref != null && get(res[i], 'options.readPreference') == null) {
+ res[i].options = res[i].options || {};
+ res[i].options.readPreference = readPref;
+ }
+ }
+ }
+
+ const opts = this._mongooseOptions;
+
+ if (opts.lean != null) {
+ const lean = opts.lean;
+ for (let i = 0; i < res.length; ++i) {
+ if (get(res[i], 'options.lean') == null) {
+ res[i].options = res[i].options || {};
+ res[i].options.lean = lean;
+ }
+ }
+ }
+
+ if (!utils.isObject(opts.populate)) {
+ opts.populate = {};
+ }
+
+ const pop = opts.populate;
+
+ for (let i = 0; i < res.length; ++i) {
+ const path = res[i].path;
+ if (pop[path] && pop[path].populate && res[i].populate) {
+ res[i].populate = pop[path].populate.concat(res[i].populate);
+ }
+ pop[res[i].path] = res[i];
+ }
+
+ return this;
+};
+
+/**
+ * Gets a list of paths to be populated by this query
+ *
+ * ####Example:
+ * bookSchema.pre('findOne', function() {
+ * let keys = this.getPopulatedPaths(); // ['author']
+ * });
+ * ...
+ * Book.findOne({}).populate('author');
+ *
+ * ####Example:
+ * // Deep populate
+ * const q = L1.find().populate({
+ * path: 'level2',
+ * populate: { path: 'level3' }
+ * });
+ * q.getPopulatedPaths(); // ['level2', 'level2.level3']
+ *
+ * @return {Array} an array of strings representing populated paths
+ * @api public
+ */
+
+Query.prototype.getPopulatedPaths = function getPopulatedPaths() {
+ const obj = this._mongooseOptions.populate || {};
+ const ret = Object.keys(obj);
+ for (const path of Object.keys(obj)) {
+ const pop = obj[path];
+ if (!Array.isArray(pop.populate)) {
+ continue;
+ }
+ _getPopulatedPaths(ret, pop.populate, path + '.');
+ }
+ return ret;
+};
+
+/*!
+ * ignore
+ */
+
+function _getPopulatedPaths(list, arr, prefix) {
+ for (const pop of arr) {
+ list.push(prefix + pop.path);
+ if (!Array.isArray(pop.populate)) {
+ continue;
+ }
+ _getPopulatedPaths(list, pop.populate, prefix + pop.path + '.');
+ }
+}
+
+/**
+ * Casts this query to the schema of `model`
+ *
+ * ####Note
+ *
+ * If `obj` is present, it is cast instead of this query.
+ *
+ * @param {Model} [model] the model to cast to. If not set, defaults to `this.model`
+ * @param {Object} [obj]
+ * @return {Object}
+ * @api public
+ */
+
+Query.prototype.cast = function(model, obj) {
+ obj || (obj = this._conditions);
+
+ model = model || this.model;
+
+ try {
+ return cast(model.schema, obj, {
+ upsert: this.options && this.options.upsert,
+ strict: (this.options && 'strict' in this.options) ?
+ this.options.strict :
+ get(model, 'schema.options.strict', null),
+ strictQuery: (this.options && this.options.strictQuery) ||
+ get(model, 'schema.options.strictQuery', null)
+ }, this);
+ } catch (err) {
+ // CastError, assign model
+ if (typeof err.setModel === 'function') {
+ err.setModel(model);
+ }
+ throw err;
+ }
+};
+
+/**
+ * Casts selected field arguments for field selection with mongo 2.2
+ *
+ * query.select({ ids: { $elemMatch: { $in: [hexString] }})
+ *
+ * @param {Object} fields
+ * @see https://github.com/Automattic/mongoose/issues/1091
+ * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/
+ * @api private
+ */
+
+Query.prototype._castFields = function _castFields(fields) {
+ let selected,
+ elemMatchKeys,
+ keys,
+ key,
+ out,
+ i;
+
+ if (fields) {
+ keys = Object.keys(fields);
+ elemMatchKeys = [];
+ i = keys.length;
+
+ // collect $elemMatch args
+ while (i--) {
+ key = keys[i];
+ if (fields[key].$elemMatch) {
+ selected || (selected = {});
+ selected[key] = fields[key];
+ elemMatchKeys.push(key);
+ }
+ }
+ }
+
+ if (selected) {
+ // they passed $elemMatch, cast em
+ try {
+ out = this.cast(this.model, selected);
+ } catch (err) {
+ return err;
+ }
+
+ // apply the casted field args
+ i = elemMatchKeys.length;
+ while (i--) {
+ key = elemMatchKeys[i];
+ fields[key] = out[key];
+ }
+ }
+
+ return fields;
+};
+
+/**
+ * Applies schematype selected options to this query.
+ * @api private
+ */
+
+Query.prototype._applyPaths = function applyPaths() {
+ this._fields = this._fields || {};
+ helpers.applyPaths(this._fields, this.model.schema);
+
+ let _selectPopulatedPaths = true;
+
+ if ('selectPopulatedPaths' in this.model.base.options) {
+ _selectPopulatedPaths = this.model.base.options.selectPopulatedPaths;
+ }
+ if ('selectPopulatedPaths' in this.model.schema.options) {
+ _selectPopulatedPaths = this.model.schema.options.selectPopulatedPaths;
+ }
+
+ if (_selectPopulatedPaths) {
+ selectPopulatedFields(this);
+ }
+};
+
+/**
+ * Returns a wrapper around a [mongodb driver cursor](http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html).
+ * A QueryCursor exposes a Streams3 interface, as well as a `.next()` function.
+ *
+ * The `.cursor()` function triggers pre find hooks, but **not** post find hooks.
+ *
+ * ####Example
+ *
+ * // There are 2 ways to use a cursor. First, as a stream:
+ * Thing.
+ * find({ name: /^hello/ }).
+ * cursor().
+ * on('data', function(doc) { console.log(doc); }).
+ * on('end', function() { console.log('Done!'); });
+ *
+ * // Or you can use `.next()` to manually get the next doc in the stream.
+ * // `.next()` returns a promise, so you can use promises or callbacks.
+ * var cursor = Thing.find({ name: /^hello/ }).cursor();
+ * cursor.next(function(error, doc) {
+ * console.log(doc);
+ * });
+ *
+ * // Because `.next()` returns a promise, you can use co
+ * // to easily iterate through all documents without loading them
+ * // all into memory.
+ * co(function*() {
+ * const cursor = Thing.find({ name: /^hello/ }).cursor();
+ * for (let doc = yield cursor.next(); doc != null; doc = yield cursor.next()) {
+ * console.log(doc);
+ * }
+ * });
+ *
+ * ####Valid options
+ *
+ * - `transform`: optional function which accepts a mongoose document. The return value of the function will be emitted on `data` and returned by `.next()`.
+ *
+ * @return {QueryCursor}
+ * @param {Object} [options]
+ * @see QueryCursor
+ * @api public
+ */
+
+Query.prototype.cursor = function cursor(opts) {
+ this._applyPaths();
+ this._fields = this._castFields(this._fields);
+ this.setOptions({ projection: this._fieldsForExec() });
+ if (opts) {
+ this.setOptions(opts);
+ }
+
+ const options = Object.assign({}, this._optionsForExec(), {
+ projection: this.projection()
+ });
+ try {
+ this.cast(this.model);
+ } catch (err) {
+ return (new QueryCursor(this, options))._markError(err);
+ }
+
+ return new QueryCursor(this, options);
+};
+
+// the rest of these are basically to support older Mongoose syntax with mquery
+
+/**
+ * _DEPRECATED_ Alias of `maxScan`
+ *
+ * @deprecated
+ * @see maxScan #query_Query-maxScan
+ * @method maxscan
+ * @memberOf Query
+ * @instance
+ */
+
+Query.prototype.maxscan = Query.base.maxScan;
+
+/**
+ * Sets the tailable option (for use with capped collections).
+ *
+ * ####Example
+ *
+ * query.tailable() // true
+ * query.tailable(true)
+ * query.tailable(false)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @param {Boolean} bool defaults to true
+ * @param {Object} [opts] options to set
+ * @param {Number} [opts.numberOfRetries] if cursor is exhausted, retry this many times before giving up
+ * @param {Number} [opts.tailableRetryInterval] if cursor is exhausted, wait this many milliseconds before retrying
+ * @see tailable http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/
+ * @api public
+ */
+
+Query.prototype.tailable = function(val, opts) {
+ // we need to support the tailable({ awaitdata : true }) as well as the
+ // tailable(true, {awaitdata :true}) syntax that mquery does not support
+ if (val && val.constructor.name === 'Object') {
+ opts = val;
+ val = true;
+ }
+
+ if (val === undefined) {
+ val = true;
+ }
+
+ if (opts && typeof opts === 'object') {
+ for (const key in opts) {
+ if (key === 'awaitdata') {
+ // For backwards compatibility
+ this.options[key] = !!opts[key];
+ } else {
+ this.options[key] = opts[key];
+ }
+ }
+ }
+
+ return Query.base.tailable.call(this, val);
+};
+
+/**
+ * Declares an intersects query for `geometry()`.
+ *
+ * ####Example
+ *
+ * query.where('path').intersects().geometry({
+ * type: 'LineString'
+ * , coordinates: [[180.0, 11.0], [180, 9.0]]
+ * })
+ *
+ * query.where('path').intersects({
+ * type: 'LineString'
+ * , coordinates: [[180.0, 11.0], [180, 9.0]]
+ * })
+ *
+ * ####NOTE:
+ *
+ * **MUST** be used after `where()`.
+ *
+ * ####NOTE:
+ *
+ * In Mongoose 3.7, `intersects` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within).
+ *
+ * @method intersects
+ * @memberOf Query
+ * @instance
+ * @param {Object} [arg]
+ * @return {Query} this
+ * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/
+ * @see geoIntersects http://docs.mongodb.org/manual/reference/operator/geoIntersects/
+ * @api public
+ */
+
+/**
+ * Specifies a `$geometry` condition
+ *
+ * ####Example
+ *
+ * var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
+ * query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
+ *
+ * // or
+ * var polyB = [[ 0, 0 ], [ 1, 1 ]]
+ * query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
+ *
+ * // or
+ * var polyC = [ 0, 0 ]
+ * query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
+ *
+ * // or
+ * query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
+ *
+ * The argument is assigned to the most recent path passed to `where()`.
+ *
+ * ####NOTE:
+ *
+ * `geometry()` **must** come after either `intersects()` or `within()`.
+ *
+ * The `object` argument must contain `type` and `coordinates` properties.
+ * - type {String}
+ * - coordinates {Array}
+ *
+ * @method geometry
+ * @memberOf Query
+ * @instance
+ * @param {Object} object Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples.
+ * @return {Query} this
+ * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/
+ * @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+/**
+ * Specifies a `$near` or `$nearSphere` condition
+ *
+ * These operators return documents sorted by distance.
+ *
+ * ####Example
+ *
+ * query.where('loc').near({ center: [10, 10] });
+ * query.where('loc').near({ center: [10, 10], maxDistance: 5 });
+ * query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true });
+ * query.near('loc', { center: [10, 10], maxDistance: 5 });
+ *
+ * @method near
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Object} val
+ * @return {Query} this
+ * @see $near http://docs.mongodb.org/manual/reference/operator/near/
+ * @see $nearSphere http://docs.mongodb.org/manual/reference/operator/nearSphere/
+ * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+/*!
+ * Overwriting mquery is needed to support a couple different near() forms found in older
+ * versions of mongoose
+ * near([1,1])
+ * near(1,1)
+ * near(field, [1,2])
+ * near(field, 1, 2)
+ * In addition to all of the normal forms supported by mquery
+ */
+
+Query.prototype.near = function() {
+ const params = [];
+ const sphere = this._mongooseOptions.nearSphere;
+
+ // TODO refactor
+
+ if (arguments.length === 1) {
+ if (Array.isArray(arguments[0])) {
+ params.push({ center: arguments[0], spherical: sphere });
+ } else if (typeof arguments[0] === 'string') {
+ // just passing a path
+ params.push(arguments[0]);
+ } else if (utils.isObject(arguments[0])) {
+ if (typeof arguments[0].spherical !== 'boolean') {
+ arguments[0].spherical = sphere;
+ }
+ params.push(arguments[0]);
+ } else {
+ throw new TypeError('invalid argument');
+ }
+ } else if (arguments.length === 2) {
+ if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
+ params.push({ center: [arguments[0], arguments[1]], spherical: sphere });
+ } else if (typeof arguments[0] === 'string' && Array.isArray(arguments[1])) {
+ params.push(arguments[0]);
+ params.push({ center: arguments[1], spherical: sphere });
+ } else if (typeof arguments[0] === 'string' && utils.isObject(arguments[1])) {
+ params.push(arguments[0]);
+ if (typeof arguments[1].spherical !== 'boolean') {
+ arguments[1].spherical = sphere;
+ }
+ params.push(arguments[1]);
+ } else {
+ throw new TypeError('invalid argument');
+ }
+ } else if (arguments.length === 3) {
+ if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number'
+ && typeof arguments[2] === 'number') {
+ params.push(arguments[0]);
+ params.push({ center: [arguments[1], arguments[2]], spherical: sphere });
+ } else {
+ throw new TypeError('invalid argument');
+ }
+ } else {
+ throw new TypeError('invalid argument');
+ }
+
+ return Query.base.near.apply(this, params);
+};
+
+/**
+ * _DEPRECATED_ Specifies a `$nearSphere` condition
+ *
+ * ####Example
+ *
+ * query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 });
+ *
+ * **Deprecated.** Use `query.near()` instead with the `spherical` option set to `true`.
+ *
+ * ####Example
+ *
+ * query.where('loc').near({ center: [10, 10], spherical: true });
+ *
+ * @deprecated
+ * @see near() #query_Query-near
+ * @see $near http://docs.mongodb.org/manual/reference/operator/near/
+ * @see $nearSphere http://docs.mongodb.org/manual/reference/operator/nearSphere/
+ * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/
+ */
+
+Query.prototype.nearSphere = function() {
+ this._mongooseOptions.nearSphere = true;
+ this.near.apply(this, arguments);
+ return this;
+};
+
+/**
+ * Returns an asyncIterator for use with [`for/await/of` loops](http://bit.ly/async-iterators)
+ * This function *only* works for `find()` queries.
+ * You do not need to call this function explicitly, the JavaScript runtime
+ * will call it for you.
+ *
+ * ####Example
+ *
+ * for await (const doc of Model.aggregate([{ $sort: { name: 1 } }])) {
+ * console.log(doc.name);
+ * }
+ *
+ * Node.js 10.x supports async iterators natively without any flags. You can
+ * enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).
+ *
+ * **Note:** This function is not if `Symbol.asyncIterator` is undefined. If
+ * `Symbol.asyncIterator` is undefined, that means your Node.js version does not
+ * support async iterators.
+ *
+ * @method Symbol.asyncIterator
+ * @memberOf Query
+ * @instance
+ * @api public
+ */
+
+if (Symbol.asyncIterator != null) {
+ Query.prototype[Symbol.asyncIterator] = function() {
+ return this.cursor().transformNull().map(doc => {
+ return doc == null ? { done: true } : { value: doc, done: false };
+ });
+ };
+}
+
+/**
+ * Specifies a `$polygon` condition
+ *
+ * ####Example
+ *
+ * query.where('loc').within().polygon([10,20], [13, 25], [7,15])
+ * query.polygon('loc', [10,20], [13, 25], [7,15])
+ *
+ * @method polygon
+ * @memberOf Query
+ * @instance
+ * @param {String|Array} [path]
+ * @param {Array|Object} [coordinatePairs...]
+ * @return {Query} this
+ * @see $polygon http://docs.mongodb.org/manual/reference/operator/polygon/
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+/**
+ * Specifies a `$box` condition
+ *
+ * ####Example
+ *
+ * var lowerLeft = [40.73083, -73.99756]
+ * var upperRight= [40.741404, -73.988135]
+ *
+ * query.where('loc').within().box(lowerLeft, upperRight)
+ * query.box({ ll : lowerLeft, ur : upperRight })
+ *
+ * @method box
+ * @memberOf Query
+ * @instance
+ * @see $box http://docs.mongodb.org/manual/reference/operator/box/
+ * @see within() Query#within #query_Query-within
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @param {Object} val
+ * @param [Array] Upper Right Coords
+ * @return {Query} this
+ * @api public
+ */
+
+/*!
+ * this is needed to support the mongoose syntax of:
+ * box(field, { ll : [x,y], ur : [x2,y2] })
+ * box({ ll : [x,y], ur : [x2,y2] })
+ */
+
+Query.prototype.box = function(ll, ur) {
+ if (!Array.isArray(ll) && utils.isObject(ll)) {
+ ur = ll.ur;
+ ll = ll.ll;
+ }
+ return Query.base.box.call(this, ll, ur);
+};
+
+/**
+ * Specifies a `$center` or `$centerSphere` condition.
+ *
+ * ####Example
+ *
+ * var area = { center: [50, 50], radius: 10, unique: true }
+ * query.where('loc').within().circle(area)
+ * // alternatively
+ * query.circle('loc', area);
+ *
+ * // spherical calculations
+ * var area = { center: [50, 50], radius: 10, unique: true, spherical: true }
+ * query.where('loc').within().circle(area)
+ * // alternatively
+ * query.circle('loc', area);
+ *
+ * @method circle
+ * @memberOf Query
+ * @instance
+ * @param {String} [path]
+ * @param {Object} area
+ * @return {Query} this
+ * @see $center http://docs.mongodb.org/manual/reference/operator/center/
+ * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/
+ * @see $geoWithin http://docs.mongodb.org/manual/reference/operator/geoWithin/
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+/**
+ * _DEPRECATED_ Alias for [circle](#query_Query-circle)
+ *
+ * **Deprecated.** Use [circle](#query_Query-circle) instead.
+ *
+ * @deprecated
+ * @method center
+ * @memberOf Query
+ * @instance
+ * @api public
+ */
+
+Query.prototype.center = Query.base.circle;
+
+/**
+ * _DEPRECATED_ Specifies a `$centerSphere` condition
+ *
+ * **Deprecated.** Use [circle](#query_Query-circle) instead.
+ *
+ * ####Example
+ *
+ * var area = { center: [50, 50], radius: 10 };
+ * query.where('loc').within().centerSphere(area);
+ *
+ * @deprecated
+ * @param {String} [path]
+ * @param {Object} val
+ * @return {Query} this
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/
+ * @api public
+ */
+
+Query.prototype.centerSphere = function() {
+ if (arguments[0] && arguments[0].constructor.name === 'Object') {
+ arguments[0].spherical = true;
+ }
+
+ if (arguments[1] && arguments[1].constructor.name === 'Object') {
+ arguments[1].spherical = true;
+ }
+
+ Query.base.circle.apply(this, arguments);
+};
+
+/**
+ * Determines if field selection has been made.
+ *
+ * @method selected
+ * @memberOf Query
+ * @instance
+ * @return {Boolean}
+ * @api public
+ */
+
+/**
+ * Determines if inclusive field selection has been made.
+ *
+ * query.selectedInclusively() // false
+ * query.select('name')
+ * query.selectedInclusively() // true
+ *
+ * @method selectedInclusively
+ * @memberOf Query
+ * @instance
+ * @return {Boolean}
+ * @api public
+ */
+
+Query.prototype.selectedInclusively = function selectedInclusively() {
+ return isInclusive(this._fields);
+};
+
+/**
+ * Determines if exclusive field selection has been made.
+ *
+ * query.selectedExclusively() // false
+ * query.select('-name')
+ * query.selectedExclusively() // true
+ * query.selectedInclusively() // false
+ *
+ * @method selectedExclusively
+ * @memberOf Query
+ * @instance
+ * @return {Boolean}
+ * @api public
+ */
+
+Query.prototype.selectedExclusively = function selectedExclusively() {
+ if (!this._fields) {
+ return false;
+ }
+
+ const keys = Object.keys(this._fields);
+ if (keys.length === 0) {
+ return false;
+ }
+
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ if (key === '_id') {
+ continue;
+ }
+ if (this._fields[key] === 0 || this._fields[key] === false) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/*!
+ * Export
+ */
+
+module.exports = Query;
diff --git a/node_modules/mongoose/lib/queryhelpers.js b/node_modules/mongoose/lib/queryhelpers.js
new file mode 100644
index 0000000..343c3b1
--- /dev/null
+++ b/node_modules/mongoose/lib/queryhelpers.js
@@ -0,0 +1,307 @@
+'use strict';
+
+/*!
+ * Module dependencies
+ */
+
+const checkEmbeddedDiscriminatorKeyProjection =
+ require('./helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection');
+const get = require('./helpers/get');
+const getDiscriminatorByValue =
+ require('./helpers/discriminator/getDiscriminatorByValue');
+const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
+const clone = require('./helpers/clone');
+
+/*!
+ * Prepare a set of path options for query population.
+ *
+ * @param {Query} query
+ * @param {Object} options
+ * @return {Array}
+ */
+
+exports.preparePopulationOptions = function preparePopulationOptions(query, options) {
+ const _populate = query.options.populate;
+ const pop = Object.keys(_populate).reduce((vals, key) => vals.concat([_populate[key]]), []);
+
+ // lean options should trickle through all queries
+ if (options.lean != null) {
+ pop.
+ filter(p => get(p, 'options.lean') == null).
+ forEach(makeLean(options.lean));
+ }
+
+ return pop;
+};
+
+/*!
+ * Prepare a set of path options for query population. This is the MongooseQuery
+ * version
+ *
+ * @param {Query} query
+ * @param {Object} options
+ * @return {Array}
+ */
+
+exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query, options) {
+ const _populate = query._mongooseOptions.populate;
+ const pop = Object.keys(_populate).reduce((vals, key) => vals.concat([_populate[key]]), []);
+
+ // lean options should trickle through all queries
+ if (options.lean != null) {
+ pop.
+ filter(p => get(p, 'options.lean') == null).
+ forEach(makeLean(options.lean));
+ }
+
+ const session = get(query, 'options.session', null);
+ if (session != null) {
+ pop.forEach(path => {
+ if (path.options == null) {
+ path.options = { session: session };
+ return;
+ }
+ if (!('session' in path.options)) {
+ path.options.session = session;
+ }
+ });
+ }
+
+ const projection = query._fieldsForExec();
+ pop.forEach(p => {
+ p._queryProjection = projection;
+ });
+
+ return pop;
+};
+
+/*!
+ * If the document is a mapped discriminator type, it returns a model instance for that type, otherwise,
+ * it returns an instance of the given model.
+ *
+ * @param {Model} model
+ * @param {Object} doc
+ * @param {Object} fields
+ *
+ * @return {Document}
+ */
+exports.createModel = function createModel(model, doc, fields, userProvidedFields) {
+ model.hooks.execPreSync('createModel', doc);
+ const discriminatorMapping = model.schema ?
+ model.schema.discriminatorMapping :
+ null;
+
+ const key = discriminatorMapping && discriminatorMapping.isRoot ?
+ discriminatorMapping.key :
+ null;
+
+ const value = doc[key];
+ if (key && value && model.discriminators) {
+ const discriminator = model.discriminators[value] || getDiscriminatorByValue(model, value);
+ if (discriminator) {
+ const _fields = clone(userProvidedFields);
+ exports.applyPaths(_fields, discriminator.schema);
+ return new discriminator(undefined, _fields, true);
+ }
+ }
+
+ return new model(undefined, fields, {
+ skipId: true,
+ isNew: false,
+ willInit: true
+ });
+};
+
+/*!
+ * ignore
+ */
+
+exports.applyPaths = function applyPaths(fields, schema) {
+ // determine if query is selecting or excluding fields
+ let exclude;
+ let keys;
+ let ki;
+ let field;
+
+ if (fields) {
+ keys = Object.keys(fields);
+ ki = keys.length;
+
+ while (ki--) {
+ if (keys[ki][0] === '+') {
+ continue;
+ }
+ field = fields[keys[ki]];
+ // Skip `$meta` and `$slice`
+ if (!isDefiningProjection(field)) {
+ continue;
+ }
+ exclude = field === 0;
+ break;
+ }
+ }
+
+ // if selecting, apply default schematype select:true fields
+ // if excluding, apply schematype select:false fields
+
+ const selected = [];
+ const excluded = [];
+ const stack = [];
+
+ const analyzePath = function(path, type) {
+ const plusPath = '+' + path;
+ const hasPlusPath = fields && plusPath in fields;
+ if (hasPlusPath) {
+ // forced inclusion
+ delete fields[plusPath];
+ }
+
+ if (typeof type.selected !== 'boolean') return;
+
+ if (hasPlusPath) {
+ // forced inclusion
+ delete fields[plusPath];
+
+ // if there are other fields being included, add this one
+ // if no other included fields, leave this out (implied inclusion)
+ if (exclude === false && keys.length > 1 && !~keys.indexOf(path)) {
+ fields[path] = 1;
+ }
+
+ return;
+ }
+
+ // check for parent exclusions
+ const pieces = path.split('.');
+ let cur = '';
+ for (let i = 0; i < pieces.length; ++i) {
+ cur += cur.length ? '.' + pieces[i] : pieces[i];
+ if (excluded.indexOf(cur) !== -1) {
+ return;
+ }
+ }
+
+ // Special case: if user has included a parent path of a discriminator key,
+ // don't explicitly project in the discriminator key because that will
+ // project out everything else under the parent path
+ if (!exclude && get(type, 'options.$skipDiscriminatorCheck', false)) {
+ let cur = '';
+ for (let i = 0; i < pieces.length; ++i) {
+ cur += (cur.length === 0 ? '' : '.') + pieces[i];
+ const projection = get(fields, cur, false);
+ if (projection && typeof projection !== 'object') {
+ return;
+ }
+ }
+ }
+
+ (type.selected ? selected : excluded).push(path);
+ return path;
+ };
+
+ analyzeSchema(schema);
+
+ switch (exclude) {
+ case true:
+ for (let i = 0; i < excluded.length; ++i) {
+ fields[excluded[i]] = 0;
+ }
+ break;
+ case false:
+ if (schema &&
+ schema.paths['_id'] &&
+ schema.paths['_id'].options &&
+ schema.paths['_id'].options.select === false) {
+ fields._id = 0;
+ }
+ for (let i = 0; i < selected.length; ++i) {
+ fields[selected[i]] = 1;
+ }
+ break;
+ case undefined:
+ if (fields == null) {
+ break;
+ }
+ // Any leftover plus paths must in the schema, so delete them (gh-7017)
+ for (const key of Object.keys(fields || {})) {
+ if (key.startsWith('+')) {
+ delete fields[key];
+ }
+ }
+
+ // user didn't specify fields, implies returning all fields.
+ // only need to apply excluded fields and delete any plus paths
+ for (let i = 0; i < excluded.length; ++i) {
+ fields[excluded[i]] = 0;
+ }
+ break;
+ }
+
+ function analyzeSchema(schema, prefix) {
+ prefix || (prefix = '');
+
+ // avoid recursion
+ if (stack.indexOf(schema) !== -1) {
+ return [];
+ }
+ stack.push(schema);
+
+ const addedPaths = [];
+ schema.eachPath(function(path, type) {
+ if (prefix) path = prefix + '.' + path;
+
+ const addedPath = analyzePath(path, type);
+ if (addedPath != null) {
+ addedPaths.push(addedPath);
+ }
+
+ // nested schemas
+ if (type.schema) {
+ const _addedPaths = analyzeSchema(type.schema, path);
+
+ // Special case: if discriminator key is the only field that would
+ // be projected in, remove it.
+ if (exclude === false) {
+ checkEmbeddedDiscriminatorKeyProjection(fields, path, type.schema,
+ selected, _addedPaths);
+ }
+ }
+ });
+
+ stack.pop();
+ return addedPaths;
+ }
+};
+
+/*!
+ * Set each path query option to lean
+ *
+ * @param {Object} option
+ */
+
+function makeLean(val) {
+ return function(option) {
+ option.options || (option.options = {});
+ option.options.lean = val;
+ };
+}
+
+/*!
+ * Handle the `WriteOpResult` from the server
+ */
+
+exports.handleDeleteWriteOpResult = function handleDeleteWriteOpResult(callback) {
+ return function _handleDeleteWriteOpResult(error, res) {
+ if (error) {
+ return callback(error);
+ }
+ const mongooseResult = Object.assign({}, res.result);
+ if (get(res, 'result.n', null) != null) {
+ mongooseResult.deletedCount = res.result.n;
+ }
+ if (res.deletedCount != null) {
+ mongooseResult.deletedCount = res.deletedCount;
+ }
+ return callback(null, mongooseResult);
+ };
+};
diff --git a/node_modules/mongoose/lib/schema.js b/node_modules/mongoose/lib/schema.js
new file mode 100644
index 0000000..16b0ad4
--- /dev/null
+++ b/node_modules/mongoose/lib/schema.js
@@ -0,0 +1,2193 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const EventEmitter = require('events').EventEmitter;
+const Kareem = require('kareem');
+const MongooseError = require('./error/mongooseError');
+const SchemaType = require('./schematype');
+const SchemaTypeOptions = require('./options/SchemaTypeOptions');
+const VirtualOptions = require('./options/VirtualOptions');
+const VirtualType = require('./virtualtype');
+const addAutoId = require('./helpers/schema/addAutoId');
+const applyTimestampsToChildren = require('./helpers/update/applyTimestampsToChildren');
+const applyTimestampsToUpdate = require('./helpers/update/applyTimestampsToUpdate');
+const arrayParentSymbol = require('./helpers/symbols').arrayParentSymbol;
+const get = require('./helpers/get');
+const getIndexes = require('./helpers/schema/getIndexes');
+const handleTimestampOption = require('./helpers/schema/handleTimestampOption');
+const merge = require('./helpers/schema/merge');
+const mpath = require('mpath');
+const readPref = require('./driver').get().ReadPreference;
+const symbols = require('./schema/symbols');
+const util = require('util');
+const utils = require('./utils');
+const validateRef = require('./helpers/populate/validateRef');
+
+let MongooseTypes;
+
+const queryHooks = require('./helpers/query/applyQueryMiddleware').
+ middlewareFunctions;
+const documentHooks = require('./helpers/model/applyHooks').middlewareFunctions;
+const hookNames = queryHooks.concat(documentHooks).
+ reduce((s, hook) => s.add(hook), new Set());
+
+let id = 0;
+
+/**
+ * Schema constructor.
+ *
+ * ####Example:
+ *
+ * var child = new Schema({ name: String });
+ * var schema = new Schema({ name: String, age: Number, children: [child] });
+ * var Tree = mongoose.model('Tree', schema);
+ *
+ * // setting schema options
+ * new Schema({ name: String }, { _id: false, autoIndex: false })
+ *
+ * ####Options:
+ *
+ * - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to null (which means use the connection's autoIndex option)
+ * - [autoCreate](/docs/guide.html#autoCreate): bool - defaults to null (which means use the connection's autoCreate option)
+ * - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
+ * - [capped](/docs/guide.html#capped): bool - defaults to false
+ * - [collection](/docs/guide.html#collection): string - no default
+ * - [id](/docs/guide.html#id): bool - defaults to true
+ * - [_id](/docs/guide.html#_id): bool - defaults to true
+ * - [minimize](/docs/guide.html#minimize): bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
+ * - [read](/docs/guide.html#read): string
+ * - [writeConcern](/docs/guide.html#writeConcern): object - defaults to null, use to override [the MongoDB server's default write concern settings](https://docs.mongodb.com/manual/reference/write-concern/)
+ * - [shardKey](/docs/guide.html#shardKey): object - defaults to `null`
+ * - [strict](/docs/guide.html#strict): bool - defaults to true
+ * - [strictQuery](/docs/guide.html#strictQuery): bool - defaults to false
+ * - [toJSON](/docs/guide.html#toJSON) - object - no default
+ * - [toObject](/docs/guide.html#toObject) - object - no default
+ * - [typeKey](/docs/guide.html#typeKey) - string - defaults to 'type'
+ * - [typePojoToMixed](/docs/guide.html#typePojoToMixed) - boolean - defaults to true. Determines whether a type set to a POJO becomes a Mixed path or a Subdocument
+ * - [useNestedStrict](/docs/guide.html#useNestedStrict) - boolean - defaults to false
+ * - [validateBeforeSave](/docs/guide.html#validateBeforeSave) - bool - defaults to `true`
+ * - [versionKey](/docs/guide.html#versionKey): string - defaults to "__v"
+ * - [collation](/docs/guide.html#collation): object - defaults to null (which means use no collation)
+ * - [selectPopulatedPaths](/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
+ * - [skipVersioning](/docs/guide.html#skipVersioning): object - paths to exclude from versioning
+ * - [timestamps](/docs/guide.html#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
+ * - [storeSubdocValidationError](/docs/guide.html#storeSubdocValidationError): boolean - Defaults to true. If false, Mongoose will wrap validation errors in single nested document subpaths into a single validation error on the single nested subdoc's path.
+ *
+ * ####Options for Nested Schemas:
+ * - `excludeIndexes`: bool - defaults to `false`. If `true`, skip building indexes on this schema's paths.
+ *
+ * ####Note:
+ *
+ * _When nesting schemas, (`children` in the example above), always declare the child schema first before passing it into its parent._
+ *
+ * @param {Object|Schema|Array} [definition] Can be one of: object describing schema paths, or schema to copy, or array of objects and schemas
+ * @param {Object} [options]
+ * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
+ * @event `init`: Emitted after the schema is compiled into a `Model`.
+ * @api public
+ */
+
+function Schema(obj, options) {
+ if (!(this instanceof Schema)) {
+ return new Schema(obj, options);
+ }
+
+ this.obj = obj;
+ this.paths = {};
+ this.aliases = {};
+ this.subpaths = {};
+ this.virtuals = {};
+ this.singleNestedPaths = {};
+ this.nested = {};
+ this.inherits = {};
+ this.callQueue = [];
+ this._indexes = [];
+ this.methods = {};
+ this.methodOptions = {};
+ this.statics = {};
+ this.tree = {};
+ this.query = {};
+ this.childSchemas = [];
+ this.plugins = [];
+ // For internal debugging. Do not use this to try to save a schema in MDB.
+ this.$id = ++id;
+
+ this.s = {
+ hooks: new Kareem()
+ };
+
+ this.options = this.defaultOptions(options);
+
+ // build paths
+ if (Array.isArray(obj)) {
+ for (const definition of obj) {
+ this.add(definition);
+ }
+ } else if (obj) {
+ this.add(obj);
+ }
+
+ // check if _id's value is a subdocument (gh-2276)
+ const _idSubDoc = obj && obj._id && utils.isObject(obj._id);
+
+ // ensure the documents get an auto _id unless disabled
+ const auto_id = !this.paths['_id'] &&
+ (!this.options.noId && this.options._id) && !_idSubDoc;
+
+ if (auto_id) {
+ addAutoId(this);
+ }
+
+ this.setupTimestamp(this.options.timestamps);
+}
+
+/*!
+ * Create virtual properties with alias field
+ */
+function aliasFields(schema, paths) {
+ paths = paths || Object.keys(schema.paths);
+ for (const path of paths) {
+ const options = get(schema.paths[path], 'options');
+ if (options == null) {
+ continue;
+ }
+
+ const prop = schema.paths[path].path;
+ const alias = options.alias;
+
+ if (!alias) {
+ continue;
+ }
+
+ if (typeof alias !== 'string') {
+ throw new Error('Invalid value for alias option on ' + prop + ', got ' + alias);
+ }
+
+ schema.aliases[alias] = prop;
+
+ schema.
+ virtual(alias).
+ get((function(p) {
+ return function() {
+ if (typeof this.get === 'function') {
+ return this.get(p);
+ }
+ return this[p];
+ };
+ })(prop)).
+ set((function(p) {
+ return function(v) {
+ return this.set(p, v);
+ };
+ })(prop));
+ }
+}
+
+/*!
+ * Inherit from EventEmitter.
+ */
+Schema.prototype = Object.create(EventEmitter.prototype);
+Schema.prototype.constructor = Schema;
+Schema.prototype.instanceOfSchema = true;
+
+/*!
+ * ignore
+ */
+
+Object.defineProperty(Schema.prototype, '$schemaType', {
+ configurable: false,
+ enumerable: false,
+ writable: true
+});
+
+/**
+ * Array of child schemas (from document arrays and single nested subdocs)
+ * and their corresponding compiled models. Each element of the array is
+ * an object with 2 properties: `schema` and `model`.
+ *
+ * This property is typically only useful for plugin authors and advanced users.
+ * You do not need to interact with this property at all to use mongoose.
+ *
+ * @api public
+ * @property childSchemas
+ * @memberOf Schema
+ * @instance
+ */
+
+Object.defineProperty(Schema.prototype, 'childSchemas', {
+ configurable: false,
+ enumerable: true,
+ writable: true
+});
+
+/**
+ * The original object passed to the schema constructor
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ a: String }).add({ b: String });
+ * schema.obj; // { a: String }
+ *
+ * @api public
+ * @property obj
+ * @memberOf Schema
+ * @instance
+ */
+
+Schema.prototype.obj;
+
+/**
+ * The paths defined on this schema. The keys are the top-level paths
+ * in this schema, and the values are instances of the SchemaType class.
+ *
+ * ####Example:
+ * const schema = new Schema({ name: String }, { _id: false });
+ * schema.paths; // { name: SchemaString { ... } }
+ *
+ * schema.add({ age: Number });
+ * schema.paths; // { name: SchemaString { ... }, age: SchemaNumber { ... } }
+ *
+ * @api public
+ * @property paths
+ * @memberOf Schema
+ * @instance
+ */
+
+Schema.prototype.paths;
+
+/**
+ * Schema as a tree
+ *
+ * ####Example:
+ * {
+ * '_id' : ObjectId
+ * , 'nested' : {
+ * 'key' : String
+ * }
+ * }
+ *
+ * @api private
+ * @property tree
+ * @memberOf Schema
+ * @instance
+ */
+
+Schema.prototype.tree;
+
+/**
+ * Returns a deep copy of the schema
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: String });
+ * const clone = schema.clone();
+ * clone === schema; // false
+ * clone.path('name'); // SchemaString { ... }
+ *
+ * @return {Schema} the cloned schema
+ * @api public
+ * @memberOf Schema
+ * @instance
+ */
+
+Schema.prototype.clone = function() {
+ const s = new Schema({}, this._userProvidedOptions);
+ s.base = this.base;
+ s.obj = this.obj;
+ s.options = utils.clone(this.options);
+ s.callQueue = this.callQueue.map(function(f) { return f; });
+ s.methods = utils.clone(this.methods);
+ s.methodOptions = utils.clone(this.methodOptions);
+ s.statics = utils.clone(this.statics);
+ s.query = utils.clone(this.query);
+ s.plugins = Array.prototype.slice.call(this.plugins);
+ s._indexes = utils.clone(this._indexes);
+ s.s.hooks = this.s.hooks.clone();
+
+ s.tree = utils.clone(this.tree);
+ s.paths = utils.clone(this.paths);
+ s.nested = utils.clone(this.nested);
+ s.subpaths = utils.clone(this.subpaths);
+ s.singleNestedPaths = utils.clone(this.singleNestedPaths);
+ s.childSchemas = gatherChildSchemas(s);
+
+ s.virtuals = utils.clone(this.virtuals);
+ s.$globalPluginsApplied = this.$globalPluginsApplied;
+ s.$isRootDiscriminator = this.$isRootDiscriminator;
+ s.$implicitlyCreated = this.$implicitlyCreated;
+
+ if (this.discriminatorMapping != null) {
+ s.discriminatorMapping = Object.assign({}, this.discriminatorMapping);
+ }
+ if (this.discriminators != null) {
+ s.discriminators = Object.assign({}, this.discriminators);
+ }
+
+ s.aliases = Object.assign({}, this.aliases);
+
+ // Bubble up `init` for backwards compat
+ s.on('init', v => this.emit('init', v));
+
+ return s;
+};
+
+/**
+ * Returns a new schema that has the picked `paths` from this schema.
+ *
+ * This method is analagous to [Lodash's `pick()` function](https://lodash.com/docs/4.17.15#pick) for Mongoose schemas.
+ *
+ * ####Example:
+ *
+ * const schema = Schema({ name: String, age: Number });
+ * // Creates a new schema with the same `name` path as `schema`,
+ * // but no `age` path.
+ * const newSchema = schema.pick(['name']);
+ *
+ * newSchema.path('name'); // SchemaString { ... }
+ * newSchema.path('age'); // undefined
+ *
+ * @param {Array} paths list of paths to pick
+ * @param {Object} [options] options to pass to the schema constructor. Defaults to `this.options` if not set.
+ * @return {Schema}
+ * @api public
+ */
+
+Schema.prototype.pick = function(paths, options) {
+ const newSchema = new Schema({}, options || this.options);
+ if (!Array.isArray(paths)) {
+ throw new MongooseError('Schema#pick() only accepts an array argument, ' +
+ 'got "' + typeof paths + '"');
+ }
+
+ for (const path of paths) {
+ if (this.nested[path]) {
+ newSchema.add({ [path]: get(this.tree, path) });
+ } else {
+ const schematype = this.path(path);
+ if (schematype == null) {
+ throw new MongooseError('Path `' + path + '` is not in the schema');
+ }
+ newSchema.add({ [path]: schematype });
+ }
+ }
+
+ return newSchema;
+};
+
+/**
+ * Returns default options for this schema, merged with `options`.
+ *
+ * @param {Object} options
+ * @return {Object}
+ * @api private
+ */
+
+Schema.prototype.defaultOptions = function(options) {
+ if (options && options.safe === false) {
+ options.safe = { w: 0 };
+ }
+
+ if (options && options.safe && options.safe.w === 0) {
+ // if you turn off safe writes, then versioning goes off as well
+ options.versionKey = false;
+ }
+
+ this._userProvidedOptions = options == null ? {} : utils.clone(options);
+
+ const baseOptions = get(this, 'base.options', {});
+ options = utils.options({
+ strict: 'strict' in baseOptions ? baseOptions.strict : true,
+ bufferCommands: true,
+ capped: false, // { size, max, autoIndexId }
+ versionKey: '__v',
+ discriminatorKey: '__t',
+ minimize: true,
+ autoIndex: null,
+ shardKey: null,
+ read: null,
+ validateBeforeSave: true,
+ // the following are only applied at construction time
+ noId: false, // deprecated, use { _id: false }
+ _id: true,
+ noVirtualId: false, // deprecated, use { id: false }
+ id: true,
+ typeKey: 'type',
+ typePojoToMixed: 'typePojoToMixed' in baseOptions ? baseOptions.typePojoToMixed : true
+ }, utils.clone(options));
+
+ if (options.read) {
+ options.read = readPref(options.read);
+ }
+
+ return options;
+};
+
+/**
+ * Adds key path / schema type pairs to this schema.
+ *
+ * ####Example:
+ *
+ * const ToySchema = new Schema();
+ * ToySchema.add({ name: 'string', color: 'string', price: 'number' });
+ *
+ * const TurboManSchema = new Schema();
+ * // You can also `add()` another schema and copy over all paths, virtuals,
+ * // getters, setters, indexes, methods, and statics.
+ * TurboManSchema.add(ToySchema).add({ year: Number });
+ *
+ * @param {Object|Schema} obj plain object with paths to add, or another schema
+ * @param {String} [prefix] path to prefix the newly added paths with
+ * @return {Schema} the Schema instance
+ * @api public
+ */
+
+Schema.prototype.add = function add(obj, prefix) {
+ if (obj instanceof Schema) {
+ merge(this, obj);
+ return this;
+ }
+
+ // Special case: setting top-level `_id` to false should convert to disabling
+ // the `_id` option. This behavior never worked before 5.4.11 but numerous
+ // codebases use it (see gh-7516, gh-7512).
+ if (obj._id === false && prefix == null) {
+ this.options._id = false;
+ }
+
+ prefix = prefix || '';
+ const keys = Object.keys(obj);
+
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ const fullPath = prefix + key;
+
+ if (obj[key] == null) {
+ throw new TypeError('Invalid value for schema path `' + fullPath +
+ '`, got value "' + obj[key] + '"');
+ }
+ // Retain `_id: false` but don't set it as a path, re: gh-8274.
+ if (key === '_id' && obj[key] === false) {
+ continue;
+ }
+ if (obj[key] instanceof VirtualType) {
+ this.virtual(obj[key]);
+ continue;
+ }
+
+ if (Array.isArray(obj[key]) && obj[key].length === 1 && obj[key][0] == null) {
+ throw new TypeError('Invalid value for schema Array path `' + fullPath +
+ '`, got value "' + obj[key][0] + '"');
+ }
+
+ if (!(utils.isPOJO(obj[key]) || obj[key] instanceof SchemaTypeOptions)) {
+ // Special-case: Non-options definitely a path so leaf at this node
+ // Examples: Schema instances, SchemaType instances
+ if (prefix) {
+ this.nested[prefix.substr(0, prefix.length - 1)] = true;
+ }
+ this.path(prefix + key, obj[key]);
+ } else if (Object.keys(obj[key]).length < 1) {
+ // Special-case: {} always interpreted as Mixed path so leaf at this node
+ if (prefix) {
+ this.nested[prefix.substr(0, prefix.length - 1)] = true;
+ }
+ this.path(fullPath, obj[key]); // mixed type
+ } else if (!obj[key][this.options.typeKey] || (this.options.typeKey === 'type' && obj[key].type.type)) {
+ // Special-case: POJO with no bona-fide type key - interpret as tree of deep paths so recurse
+ // nested object { last: { name: String }}
+ this.nested[fullPath] = true;
+ this.add(obj[key], fullPath + '.');
+ } else {
+ // There IS a bona-fide type key that may also be a POJO
+ if (!this.options.typePojoToMixed && utils.isPOJO(obj[key][this.options.typeKey])) {
+ // If a POJO is the value of a type key, make it a subdocument
+ if (prefix) {
+ this.nested[prefix.substr(0, prefix.length - 1)] = true;
+ }
+ // Propage `typePojoToMixed` to implicitly created schemas
+ const opts = { typePojoToMixed: false };
+ const _schema = new Schema(obj[key][this.options.typeKey], opts);
+ const schemaWrappedPath = Object.assign({}, obj[key], { type: _schema });
+ this.path(prefix + key, schemaWrappedPath);
+ } else {
+ // Either the type is non-POJO or we interpret it as Mixed anyway
+ if (prefix) {
+ this.nested[prefix.substr(0, prefix.length - 1)] = true;
+ }
+ this.path(prefix + key, obj[key]);
+ }
+ }
+ }
+
+ const addedKeys = Object.keys(obj).
+ map(key => prefix ? prefix + key : key);
+ aliasFields(this, addedKeys);
+ return this;
+};
+
+/**
+ * Reserved document keys.
+ *
+ * Keys in this object are names that are rejected in schema declarations
+ * because they conflict with Mongoose functionality. If you create a schema
+ * using `new Schema()` with one of these property names, Mongoose will throw
+ * an error.
+ *
+ * - prototype
+ * - emit
+ * - on
+ * - once
+ * - listeners
+ * - removeListener
+ * - collection
+ * - db
+ * - errors
+ * - init
+ * - isModified
+ * - isNew
+ * - get
+ * - modelName
+ * - save
+ * - schema
+ * - toObject
+ * - validate
+ * - remove
+ * - populated
+ * - _pres
+ * - _posts
+ *
+ * _NOTE:_ Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on.
+ *
+ * var schema = new Schema(..);
+ * schema.methods.init = function () {} // potentially breaking
+ */
+
+Schema.reserved = Object.create(null);
+Schema.prototype.reserved = Schema.reserved;
+const reserved = Schema.reserved;
+// Core object
+reserved['prototype'] =
+// EventEmitter
+reserved.emit =
+reserved.on =
+reserved.once =
+reserved.listeners =
+reserved.removeListener =
+// document properties and functions
+reserved.collection =
+reserved.db =
+reserved.errors =
+reserved.init =
+reserved.isModified =
+reserved.isNew =
+reserved.get =
+reserved.modelName =
+reserved.save =
+reserved.schema =
+reserved.toObject =
+reserved.validate =
+reserved.remove =
+reserved.populated = 1;
+
+/*!
+ * Document keys to print warnings for
+ */
+
+const warnings = {};
+warnings.increment = '`increment` should not be used as a schema path name ' +
+ 'unless you have disabled versioning.';
+
+/**
+ * Gets/sets schema paths.
+ *
+ * Sets a path (if arity 2)
+ * Gets a path (if arity 1)
+ *
+ * ####Example
+ *
+ * schema.path('name') // returns a SchemaType
+ * schema.path('name', Number) // changes the schemaType of `name` to Number
+ *
+ * @param {String} path
+ * @param {Object} constructor
+ * @api public
+ */
+
+Schema.prototype.path = function(path, obj) {
+ // Convert to '.$' to check subpaths re: gh-6405
+ const cleanPath = _pathToPositionalSyntax(path);
+ if (obj === undefined) {
+ let schematype = _getPath(this, path, cleanPath);
+ if (schematype != null) {
+ return schematype;
+ }
+
+ // Look for maps
+ const mapPath = getMapPath(this, path);
+ if (mapPath != null) {
+ return mapPath;
+ }
+
+ // Look if a parent of this path is mixed
+ schematype = this.hasMixedParent(cleanPath);
+ if (schematype != null) {
+ return schematype;
+ }
+
+ // subpaths?
+ return /\.\d+\.?.*$/.test(path)
+ ? getPositionalPath(this, path)
+ : undefined;
+ }
+
+ // some path names conflict with document methods
+ if (reserved[path]) {
+ throw new Error('`' + path + '` may not be used as a schema pathname');
+ }
+
+ if (warnings[path]) {
+ console.log('WARN: ' + warnings[path]);
+ }
+
+ if (typeof obj === 'object' && utils.hasUserDefinedProperty(obj, 'ref')) {
+ validateRef(obj.ref, path);
+ }
+
+ // update the tree
+ const subpaths = path.split(/\./);
+ const last = subpaths.pop();
+ let branch = this.tree;
+
+ subpaths.forEach(function(sub, i) {
+ if (!branch[sub]) {
+ branch[sub] = {};
+ }
+ if (typeof branch[sub] !== 'object') {
+ const msg = 'Cannot set nested path `' + path + '`. '
+ + 'Parent path `'
+ + subpaths.slice(0, i).concat([sub]).join('.')
+ + '` already set to type ' + branch[sub].name
+ + '.';
+ throw new Error(msg);
+ }
+ branch = branch[sub];
+ });
+
+ branch[last] = utils.clone(obj);
+
+ this.paths[path] = this.interpretAsType(path, obj, this.options);
+ const schemaType = this.paths[path];
+
+ if (schemaType.$isSchemaMap) {
+ // Maps can have arbitrary keys, so `$*` is internal shorthand for "any key"
+ // The '$' is to imply this path should never be stored in MongoDB so we
+ // can easily build a regexp out of this path, and '*' to imply "any key."
+ const mapPath = path + '.$*';
+ let _mapType = { type: {} };
+ if (utils.hasUserDefinedProperty(obj, 'of')) {
+ const isInlineSchema = utils.isPOJO(obj.of) &&
+ Object.keys(obj.of).length > 0 &&
+ !utils.hasUserDefinedProperty(obj.of, this.options.typeKey);
+ _mapType = isInlineSchema ? new Schema(obj.of) : obj.of;
+ }
+ this.paths[mapPath] = this.interpretAsType(mapPath,
+ _mapType, this.options);
+ schemaType.$__schemaType = this.paths[mapPath];
+ }
+
+ if (schemaType.$isSingleNested) {
+ for (const key in schemaType.schema.paths) {
+ this.singleNestedPaths[path + '.' + key] = schemaType.schema.paths[key];
+ }
+ for (const key in schemaType.schema.singleNestedPaths) {
+ this.singleNestedPaths[path + '.' + key] =
+ schemaType.schema.singleNestedPaths[key];
+ }
+ for (const key in schemaType.schema.subpaths) {
+ this.singleNestedPaths[path + '.' + key] =
+ schemaType.schema.subpaths[key];
+ }
+
+ Object.defineProperty(schemaType.schema, 'base', {
+ configurable: true,
+ enumerable: false,
+ writable: false,
+ value: this.base
+ });
+
+ schemaType.caster.base = this.base;
+ this.childSchemas.push({
+ schema: schemaType.schema,
+ model: schemaType.caster
+ });
+ } else if (schemaType.$isMongooseDocumentArray) {
+ Object.defineProperty(schemaType.schema, 'base', {
+ configurable: true,
+ enumerable: false,
+ writable: false,
+ value: this.base
+ });
+
+ schemaType.casterConstructor.base = this.base;
+ this.childSchemas.push({
+ schema: schemaType.schema,
+ model: schemaType.casterConstructor
+ });
+ }
+
+ if (schemaType.$isMongooseArray && schemaType.caster instanceof SchemaType) {
+ let arrayPath = path;
+ let _schemaType = schemaType;
+
+ const toAdd = [];
+ while (_schemaType.$isMongooseArray) {
+ arrayPath = arrayPath + '.$';
+
+ // Skip arrays of document arrays
+ if (_schemaType.$isMongooseDocumentArray) {
+ _schemaType = _schemaType.$embeddedSchemaType.clone();
+ } else {
+ _schemaType = _schemaType.caster.clone();
+ }
+
+ _schemaType.path = arrayPath;
+ toAdd.push(_schemaType);
+ }
+
+ for (const _schemaType of toAdd) {
+ this.subpaths[_schemaType.path] = _schemaType;
+ }
+ }
+
+ if (schemaType.$isMongooseDocumentArray) {
+ for (const key of Object.keys(schemaType.schema.paths)) {
+ this.subpaths[path + '.' + key] = schemaType.schema.paths[key];
+ schemaType.schema.paths[key].$isUnderneathDocArray = true;
+ }
+ for (const key of Object.keys(schemaType.schema.subpaths)) {
+ this.subpaths[path + '.' + key] = schemaType.schema.subpaths[key];
+ schemaType.schema.subpaths[key].$isUnderneathDocArray = true;
+ }
+ for (const key of Object.keys(schemaType.schema.singleNestedPaths)) {
+ this.subpaths[path + '.' + key] = schemaType.schema.singleNestedPaths[key];
+ schemaType.schema.singleNestedPaths[key].$isUnderneathDocArray = true;
+ }
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+function gatherChildSchemas(schema) {
+ const childSchemas = [];
+
+ for (const path of Object.keys(schema.paths)) {
+ const schematype = schema.paths[path];
+ if (schematype.$isMongooseDocumentArray || schematype.$isSingleNested) {
+ childSchemas.push({ schema: schematype.schema, model: schematype.caster });
+ }
+ }
+
+ return childSchemas;
+}
+
+/*!
+ * ignore
+ */
+
+function _getPath(schema, path, cleanPath) {
+ if (schema.paths.hasOwnProperty(path)) {
+ return schema.paths[path];
+ }
+ if (schema.subpaths.hasOwnProperty(cleanPath)) {
+ return schema.subpaths[cleanPath];
+ }
+ if (schema.singleNestedPaths.hasOwnProperty(cleanPath)) {
+ return schema.singleNestedPaths[cleanPath];
+ }
+
+ return null;
+}
+
+/*!
+ * ignore
+ */
+
+function _pathToPositionalSyntax(path) {
+ if (!/\.\d+/.test(path)) {
+ return path;
+ }
+ return path.replace(/\.\d+\./g, '.$.').replace(/\.\d+$/, '.$');
+}
+
+/*!
+ * ignore
+ */
+
+function getMapPath(schema, path) {
+ for (const _path of Object.keys(schema.paths)) {
+ if (!_path.includes('.$*')) {
+ continue;
+ }
+ const re = new RegExp('^' + _path.replace(/\.\$\*/g, '\\.[^.]+') + '$');
+ if (re.test(path)) {
+ return schema.paths[_path];
+ }
+ }
+
+ return null;
+}
+
+/**
+ * The Mongoose instance this schema is associated with
+ *
+ * @property base
+ * @api private
+ */
+
+Object.defineProperty(Schema.prototype, 'base', {
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ value: null
+});
+
+/**
+ * Converts type arguments into Mongoose Types.
+ *
+ * @param {String} path
+ * @param {Object} obj constructor
+ * @api private
+ */
+
+Schema.prototype.interpretAsType = function(path, obj, options) {
+ if (obj instanceof SchemaType) {
+ return obj;
+ }
+
+ // If this schema has an associated Mongoose object, use the Mongoose object's
+ // copy of SchemaTypes re: gh-7158 gh-6933
+ const MongooseTypes = this.base != null ? this.base.Schema.Types : Schema.Types;
+
+ if (!utils.isPOJO(obj) && !(obj instanceof SchemaTypeOptions)) {
+ const constructorName = utils.getFunctionName(obj.constructor);
+ if (constructorName !== 'Object') {
+ const oldObj = obj;
+ obj = {};
+ obj[options.typeKey] = oldObj;
+ }
+ }
+
+ // Get the type making sure to allow keys named "type"
+ // and default to mixed if not specified.
+ // { type: { type: String, default: 'freshcut' } }
+ let type = obj[options.typeKey] && (options.typeKey !== 'type' || !obj.type.type)
+ ? obj[options.typeKey]
+ : {};
+ let name;
+
+ if (utils.isPOJO(type) || type === 'mixed') {
+ return new MongooseTypes.Mixed(path, obj);
+ }
+
+ if (Array.isArray(type) || Array === type || type === 'array') {
+ // if it was specified through { type } look for `cast`
+ let cast = (Array === type || type === 'array')
+ ? obj.cast
+ : type[0];
+
+ if (cast && cast.instanceOfSchema) {
+ return new MongooseTypes.DocumentArray(path, cast, obj);
+ }
+ if (cast &&
+ cast[options.typeKey] &&
+ cast[options.typeKey].instanceOfSchema) {
+ return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast);
+ }
+
+ if (Array.isArray(cast)) {
+ return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj);
+ }
+
+ if (typeof cast === 'string') {
+ cast = MongooseTypes[cast.charAt(0).toUpperCase() + cast.substring(1)];
+ } else if (cast && (!cast[options.typeKey] || (options.typeKey === 'type' && cast.type.type))
+ && utils.isPOJO(cast)) {
+ if (Object.keys(cast).length) {
+ // The `minimize` and `typeKey` options propagate to child schemas
+ // declared inline, like `{ arr: [{ val: { $type: String } }] }`.
+ // See gh-3560
+ const childSchemaOptions = { minimize: options.minimize };
+ if (options.typeKey) {
+ childSchemaOptions.typeKey = options.typeKey;
+ }
+ //propagate 'strict' option to child schema
+ if (options.hasOwnProperty('strict')) {
+ childSchemaOptions.strict = options.strict;
+ }
+ if (options.hasOwnProperty('typePojoToMixed')) {
+ childSchemaOptions.typePojoToMixed = options.typePojoToMixed;
+ }
+ const childSchema = new Schema(cast, childSchemaOptions);
+ childSchema.$implicitlyCreated = true;
+ return new MongooseTypes.DocumentArray(path, childSchema, obj);
+ } else {
+ // Special case: empty object becomes mixed
+ return new MongooseTypes.Array(path, MongooseTypes.Mixed, obj);
+ }
+ }
+
+ if (cast) {
+ type = cast[options.typeKey] && (options.typeKey !== 'type' || !cast.type.type)
+ ? cast[options.typeKey]
+ : cast;
+
+ name = typeof type === 'string'
+ ? type
+ : type.schemaName || utils.getFunctionName(type);
+
+ if (!MongooseTypes.hasOwnProperty(name)) {
+ throw new TypeError('Invalid schema configuration: ' +
+ `\`${name}\` is not a valid type within the array \`${path}\`.` +
+ 'See http://bit.ly/mongoose-schematypes for a list of valid schema types.');
+ }
+ }
+
+ return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options);
+ }
+
+ if (type && type.instanceOfSchema) {
+ return new MongooseTypes.Embedded(type, path, obj);
+ }
+
+ if (Buffer.isBuffer(type)) {
+ name = 'Buffer';
+ } else if (typeof type === 'function' || typeof type === 'object') {
+ name = type.schemaName || utils.getFunctionName(type);
+ } else {
+ name = type == null ? '' + type : type.toString();
+ }
+
+ if (name) {
+ name = name.charAt(0).toUpperCase() + name.substring(1);
+ }
+ // Special case re: gh-7049 because the bson `ObjectID` class' capitalization
+ // doesn't line up with Mongoose's.
+ if (name === 'ObjectID') {
+ name = 'ObjectId';
+ }
+
+ if (MongooseTypes[name] == null) {
+ throw new TypeError(`Invalid schema configuration: \`${name}\` is not ` +
+ `a valid type at path \`${path}\`. See ` +
+ 'http://bit.ly/mongoose-schematypes for a list of valid schema types.');
+ }
+
+ return new MongooseTypes[name](path, obj);
+};
+
+/**
+ * Iterates the schemas paths similar to Array#forEach.
+ *
+ * The callback is passed the pathname and the schemaType instance.
+ *
+ * ####Example:
+ *
+ * const userSchema = new Schema({ name: String, registeredAt: Date });
+ * userSchema.eachPath((pathname, schematype) => {
+ * // Prints twice:
+ * // name SchemaString { ... }
+ * // registeredAt SchemaDate { ... }
+ * console.log(pathname, schematype);
+ * });
+ *
+ * @param {Function} fn callback function
+ * @return {Schema} this
+ * @api public
+ */
+
+Schema.prototype.eachPath = function(fn) {
+ const keys = Object.keys(this.paths);
+ const len = keys.length;
+
+ for (let i = 0; i < len; ++i) {
+ fn(keys[i], this.paths[keys[i]]);
+ }
+
+ return this;
+};
+
+/**
+ * Returns an Array of path strings that are required by this schema.
+ *
+ * ####Example:
+ * const s = new Schema({
+ * name: { type: String, required: true },
+ * age: { type: String, required: true },
+ * notes: String
+ * });
+ * s.requiredPaths(); // [ 'age', 'name' ]
+ *
+ * @api public
+ * @param {Boolean} invalidate refresh the cache
+ * @return {Array}
+ */
+
+Schema.prototype.requiredPaths = function requiredPaths(invalidate) {
+ if (this._requiredpaths && !invalidate) {
+ return this._requiredpaths;
+ }
+
+ const paths = Object.keys(this.paths);
+ let i = paths.length;
+ const ret = [];
+
+ while (i--) {
+ const path = paths[i];
+ if (this.paths[path].isRequired) {
+ ret.push(path);
+ }
+ }
+ this._requiredpaths = ret;
+ return this._requiredpaths;
+};
+
+/**
+ * Returns indexes from fields and schema-level indexes (cached).
+ *
+ * @api private
+ * @return {Array}
+ */
+
+Schema.prototype.indexedPaths = function indexedPaths() {
+ if (this._indexedpaths) {
+ return this._indexedpaths;
+ }
+ this._indexedpaths = this.indexes();
+ return this._indexedpaths;
+};
+
+/**
+ * Returns the pathType of `path` for this schema.
+ *
+ * Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.
+ *
+ * ####Example:
+ * const s = new Schema({ name: String, nested: { foo: String } });
+ * s.virtual('foo').get(() => 42);
+ * s.pathType('name'); // "real"
+ * s.pathType('nested'); // "nested"
+ * s.pathType('foo'); // "virtual"
+ * s.pathType('fail'); // "adhocOrUndefined"
+ *
+ * @param {String} path
+ * @return {String}
+ * @api public
+ */
+
+Schema.prototype.pathType = function(path) {
+ // Convert to '.$' to check subpaths re: gh-6405
+ const cleanPath = _pathToPositionalSyntax(path);
+
+ if (this.paths.hasOwnProperty(path)) {
+ return 'real';
+ }
+ if (this.virtuals.hasOwnProperty(path)) {
+ return 'virtual';
+ }
+ if (this.nested.hasOwnProperty(path)) {
+ return 'nested';
+ }
+ if (this.subpaths.hasOwnProperty(cleanPath) || this.subpaths.hasOwnProperty(path)) {
+ return 'real';
+ }
+ if (this.singleNestedPaths.hasOwnProperty(cleanPath) || this.singleNestedPaths.hasOwnProperty(path)) {
+ return 'real';
+ }
+
+ // Look for maps
+ const mapPath = getMapPath(this, path);
+ if (mapPath != null) {
+ return 'real';
+ }
+
+ if (/\.\d+\.|\.\d+$/.test(path)) {
+ return getPositionalPathType(this, path);
+ }
+ return 'adhocOrUndefined';
+};
+
+/**
+ * Returns true iff this path is a child of a mixed schema.
+ *
+ * @param {String} path
+ * @return {Boolean}
+ * @api private
+ */
+
+Schema.prototype.hasMixedParent = function(path) {
+ const subpaths = path.split(/\./g);
+ path = '';
+ for (let i = 0; i < subpaths.length; ++i) {
+ path = i > 0 ? path + '.' + subpaths[i] : subpaths[i];
+ if (path in this.paths &&
+ this.paths[path] instanceof MongooseTypes.Mixed) {
+ return this.paths[path];
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Setup updatedAt and createdAt timestamps to documents if enabled
+ *
+ * @param {Boolean|Object} timestamps timestamps options
+ * @api private
+ */
+Schema.prototype.setupTimestamp = function(timestamps) {
+ const childHasTimestamp = this.childSchemas.find(withTimestamp);
+
+ function withTimestamp(s) {
+ const ts = s.schema.options.timestamps;
+ return !!ts;
+ }
+
+ if (!timestamps && !childHasTimestamp) {
+ return;
+ }
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ const currentTime = timestamps != null && timestamps.hasOwnProperty('currentTime') ?
+ timestamps.currentTime :
+ null;
+ const schemaAdditions = {};
+
+ this.$timestamps = { createdAt: createdAt, updatedAt: updatedAt };
+
+ if (updatedAt && !this.paths[updatedAt]) {
+ schemaAdditions[updatedAt] = Date;
+ }
+
+ if (createdAt && !this.paths[createdAt]) {
+ schemaAdditions[createdAt] = Date;
+ }
+
+ this.add(schemaAdditions);
+
+ this.pre('save', function(next) {
+ const timestampOption = get(this, '$__.saveOptions.timestamps');
+ if (timestampOption === false) {
+ return next();
+ }
+
+ const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
+ const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
+
+ const defaultTimestamp = currentTime != null ?
+ currentTime() :
+ (this.ownerDocument ? this.ownerDocument() : this).constructor.base.now();
+ const auto_id = this._id && this._id.auto;
+
+ if (!skipCreatedAt && createdAt && !this.get(createdAt) && this.isSelected(createdAt)) {
+ this.set(createdAt, auto_id ? this._id.getTimestamp() : defaultTimestamp);
+ }
+
+ if (!skipUpdatedAt && updatedAt && (this.isNew || this.isModified())) {
+ let ts = defaultTimestamp;
+ if (this.isNew) {
+ if (createdAt != null) {
+ ts = this.$__getValue(createdAt);
+ } else if (auto_id) {
+ ts = this._id.getTimestamp();
+ }
+ }
+ this.set(updatedAt, ts);
+ }
+
+ next();
+ });
+
+ this.methods.initializeTimestamps = function() {
+ const ts = currentTime != null ?
+ currentTime() :
+ this.constructor.base.now();
+ if (createdAt && !this.get(createdAt)) {
+ this.set(createdAt, ts);
+ }
+ if (updatedAt && !this.get(updatedAt)) {
+ this.set(updatedAt, ts);
+ }
+ return this;
+ };
+
+ _setTimestampsOnUpdate[symbols.builtInMiddleware] = true;
+
+ const opts = { query: true, model: false };
+ this.pre('findOneAndUpdate', opts, _setTimestampsOnUpdate);
+ this.pre('replaceOne', opts, _setTimestampsOnUpdate);
+ this.pre('update', opts, _setTimestampsOnUpdate);
+ this.pre('updateOne', opts, _setTimestampsOnUpdate);
+ this.pre('updateMany', opts, _setTimestampsOnUpdate);
+
+ function _setTimestampsOnUpdate(next) {
+ const now = currentTime != null ?
+ currentTime() :
+ this.model.base.now();
+ applyTimestampsToUpdate(now, createdAt, updatedAt, this.getUpdate(),
+ this.options, this.schema);
+ applyTimestampsToChildren(now, this.getUpdate(), this.model.schema);
+ next();
+ }
+};
+
+/*!
+ * ignore. Deprecated re: #6405
+ */
+
+function getPositionalPathType(self, path) {
+ const subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
+ if (subpaths.length < 2) {
+ return self.paths.hasOwnProperty(subpaths[0]) ?
+ self.paths[subpaths[0]] :
+ 'adhocOrUndefined';
+ }
+
+ let val = self.path(subpaths[0]);
+ let isNested = false;
+ if (!val) {
+ return 'adhocOrUndefined';
+ }
+
+ const last = subpaths.length - 1;
+
+ for (let i = 1; i < subpaths.length; ++i) {
+ isNested = false;
+ const subpath = subpaths[i];
+
+ if (i === last && val && !/\D/.test(subpath)) {
+ if (val.$isMongooseDocumentArray) {
+ val = val.$embeddedSchemaType;
+ } else if (val instanceof MongooseTypes.Array) {
+ // StringSchema, NumberSchema, etc
+ val = val.caster;
+ } else {
+ val = undefined;
+ }
+ break;
+ }
+
+ // ignore if its just a position segment: path.0.subpath
+ if (!/\D/.test(subpath)) {
+ // Nested array
+ if (val instanceof MongooseTypes.Array && i !== last) {
+ val = val.caster;
+ }
+ continue;
+ }
+
+ if (!(val && val.schema)) {
+ val = undefined;
+ break;
+ }
+
+ const type = val.schema.pathType(subpath);
+ isNested = (type === 'nested');
+ val = val.schema.path(subpath);
+ }
+
+ self.subpaths[path] = val;
+ if (val) {
+ return 'real';
+ }
+ if (isNested) {
+ return 'nested';
+ }
+ return 'adhocOrUndefined';
+}
+
+
+/*!
+ * ignore
+ */
+
+function getPositionalPath(self, path) {
+ getPositionalPathType(self, path);
+ return self.subpaths[path];
+}
+
+/**
+ * Adds a method call to the queue.
+ *
+ * ####Example:
+ *
+ * schema.methods.print = function() { console.log(this); };
+ * schema.queue('print', []); // Print the doc every one is instantiated
+ *
+ * const Model = mongoose.model('Test', schema);
+ * new Model({ name: 'test' }); // Prints '{"_id": ..., "name": "test" }'
+ *
+ * @param {String} name name of the document method to call later
+ * @param {Array} args arguments to pass to the method
+ * @api public
+ */
+
+Schema.prototype.queue = function(name, args) {
+ this.callQueue.push([name, args]);
+ return this;
+};
+
+/**
+ * Defines a pre hook for the document.
+ *
+ * ####Example
+ *
+ * var toySchema = new Schema({ name: String, created: Date });
+ *
+ * toySchema.pre('save', function(next) {
+ * if (!this.created) this.created = new Date;
+ * next();
+ * });
+ *
+ * toySchema.pre('validate', function(next) {
+ * if (this.name !== 'Woody') this.name = 'Woody';
+ * next();
+ * });
+ *
+ * // Equivalent to calling `pre()` on `find`, `findOne`, `findOneAndUpdate`.
+ * toySchema.pre(/^find/, function(next) {
+ * console.log(this.getFilter());
+ * });
+ *
+ * // Equivalent to calling `pre()` on `updateOne`, `findOneAndUpdate`.
+ * toySchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
+ * console.log(this.getFilter());
+ * });
+ *
+ * toySchema.pre('deleteOne', function() {
+ * // Runs when you call `Toy.deleteOne()`
+ * });
+ *
+ * toySchema.pre('deleteOne', { document: true }, function() {
+ * // Runs when you call `doc.deleteOne()`
+ * });
+ *
+ * @param {String|RegExp} The method name or regular expression to match method name
+ * @param {Object} [options]
+ * @param {Boolean} [options.document] If `name` is a hook for both document and query middleware, set to `true` to run on document middleware. For example, set `options.document` to `true` to apply this hook to `Document#deleteOne()` rather than `Query#deleteOne()`.
+ * @param {Boolean} [options.query] If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.
+ * @param {Function} callback
+ * @api public
+ */
+
+Schema.prototype.pre = function(name) {
+ if (name instanceof RegExp) {
+ const remainingArgs = Array.prototype.slice.call(arguments, 1);
+ for (const fn of hookNames) {
+ if (name.test(fn)) {
+ this.pre.apply(this, [fn].concat(remainingArgs));
+ }
+ }
+ return this;
+ }
+ if (Array.isArray(name)) {
+ const remainingArgs = Array.prototype.slice.call(arguments, 1);
+ for (const el of name) {
+ this.pre.apply(this, [el].concat(remainingArgs));
+ }
+ return this;
+ }
+ this.s.hooks.pre.apply(this.s.hooks, arguments);
+ return this;
+};
+
+/**
+ * Defines a post hook for the document
+ *
+ * var schema = new Schema(..);
+ * schema.post('save', function (doc) {
+ * console.log('this fired after a document was saved');
+ * });
+ *
+ * schema.post('find', function(docs) {
+ * console.log('this fired after you ran a find query');
+ * });
+ *
+ * schema.post(/Many$/, function(res) {
+ * console.log('this fired after you ran `updateMany()` or `deleteMany()`);
+ * });
+ *
+ * var Model = mongoose.model('Model', schema);
+ *
+ * var m = new Model(..);
+ * m.save(function(err) {
+ * console.log('this fires after the `post` hook');
+ * });
+ *
+ * m.find(function(err, docs) {
+ * console.log('this fires after the post find hook');
+ * });
+ *
+ * @param {String|RegExp} The method name or regular expression to match method name
+ * @param {Object} [options]
+ * @param {Boolean} [options.document] If `name` is a hook for both document and query middleware, set to `true` to run on document middleware.
+ * @param {Boolean} [options.query] If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.
+ * @param {Function} fn callback
+ * @see middleware http://mongoosejs.com/docs/middleware.html
+ * @see kareem http://npmjs.org/package/kareem
+ * @api public
+ */
+
+Schema.prototype.post = function(name) {
+ if (name instanceof RegExp) {
+ const remainingArgs = Array.prototype.slice.call(arguments, 1);
+ for (const fn of hookNames) {
+ if (name.test(fn)) {
+ this.post.apply(this, [fn].concat(remainingArgs));
+ }
+ }
+ return this;
+ }
+ if (Array.isArray(name)) {
+ const remainingArgs = Array.prototype.slice.call(arguments, 1);
+ for (const el of name) {
+ this.post.apply(this, [el].concat(remainingArgs));
+ }
+ return this;
+ }
+ this.s.hooks.post.apply(this.s.hooks, arguments);
+ return this;
+};
+
+/**
+ * Registers a plugin for this schema.
+ *
+ * ####Example:
+ *
+ * const s = new Schema({ name: String });
+ * s.plugin(schema => console.log(schema.path('name').path));
+ * mongoose.model('Test', s); // Prints 'name'
+ *
+ * @param {Function} plugin callback
+ * @param {Object} [opts]
+ * @see plugins
+ * @api public
+ */
+
+Schema.prototype.plugin = function(fn, opts) {
+ if (typeof fn !== 'function') {
+ throw new Error('First param to `schema.plugin()` must be a function, ' +
+ 'got "' + (typeof fn) + '"');
+ }
+
+ if (opts &&
+ opts.deduplicate) {
+ for (let i = 0; i < this.plugins.length; ++i) {
+ if (this.plugins[i].fn === fn) {
+ return this;
+ }
+ }
+ }
+ this.plugins.push({ fn: fn, opts: opts });
+
+ fn(this, opts);
+ return this;
+};
+
+/**
+ * Adds an instance method to documents constructed from Models compiled from this schema.
+ *
+ * ####Example
+ *
+ * var schema = kittySchema = new Schema(..);
+ *
+ * schema.method('meow', function () {
+ * console.log('meeeeeoooooooooooow');
+ * })
+ *
+ * var Kitty = mongoose.model('Kitty', schema);
+ *
+ * var fizz = new Kitty;
+ * fizz.meow(); // meeeeeooooooooooooow
+ *
+ * If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.
+ *
+ * schema.method({
+ * purr: function () {}
+ * , scratch: function () {}
+ * });
+ *
+ * // later
+ * fizz.purr();
+ * fizz.scratch();
+ *
+ * NOTE: `Schema.method()` adds instance methods to the `Schema.methods` object. You can also add instance methods directly to the `Schema.methods` object as seen in the [guide](./guide.html#methods)
+ *
+ * @param {String|Object} method name
+ * @param {Function} [fn]
+ * @api public
+ */
+
+Schema.prototype.method = function(name, fn, options) {
+ if (typeof name !== 'string') {
+ for (const i in name) {
+ this.methods[i] = name[i];
+ this.methodOptions[i] = utils.clone(options);
+ }
+ } else {
+ this.methods[name] = fn;
+ this.methodOptions[name] = utils.clone(options);
+ }
+ return this;
+};
+
+/**
+ * Adds static "class" methods to Models compiled from this schema.
+ *
+ * ####Example
+ *
+ * const schema = new Schema(..);
+ * // Equivalent to `schema.statics.findByName = function(name) {}`;
+ * schema.static('findByName', function(name) {
+ * return this.find({ name: name });
+ * });
+ *
+ * const Drink = mongoose.model('Drink', schema);
+ * await Drink.findByName('LaCroix');
+ *
+ * If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
+ *
+ * @param {String|Object} name
+ * @param {Function} [fn]
+ * @api public
+ * @see Statics /docs/guide.html#statics
+ */
+
+Schema.prototype.static = function(name, fn) {
+ if (typeof name !== 'string') {
+ for (const i in name) {
+ this.statics[i] = name[i];
+ }
+ } else {
+ this.statics[name] = fn;
+ }
+ return this;
+};
+
+/**
+ * Defines an index (most likely compound) for this schema.
+ *
+ * ####Example
+ *
+ * schema.index({ first: 1, last: -1 })
+ *
+ * @param {Object} fields
+ * @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndex)
+ * @param {String} [options.expires=null] Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert `expires` option into seconds for the `expireAfterSeconds` in the above link.
+ * @api public
+ */
+
+Schema.prototype.index = function(fields, options) {
+ fields || (fields = {});
+ options || (options = {});
+
+ if (options.expires) {
+ utils.expires(options);
+ }
+
+ this._indexes.push([fields, options]);
+ return this;
+};
+
+/**
+ * Sets/gets a schema option.
+ *
+ * ####Example
+ *
+ * schema.set('strict'); // 'true' by default
+ * schema.set('strict', false); // Sets 'strict' to false
+ * schema.set('strict'); // 'false'
+ *
+ * @param {String} key option name
+ * @param {Object} [value] if not passed, the current option value is returned
+ * @see Schema ./
+ * @api public
+ */
+
+Schema.prototype.set = function(key, value, _tags) {
+ if (arguments.length === 1) {
+ return this.options[key];
+ }
+
+ switch (key) {
+ case 'read':
+ this.options[key] = readPref(value, _tags);
+ this._userProvidedOptions[key] = this.options[key];
+ break;
+ case 'safe':
+ setSafe(this.options, value);
+ this._userProvidedOptions[key] = this.options[key];
+ break;
+ case 'timestamps':
+ this.setupTimestamp(value);
+ this.options[key] = value;
+ this._userProvidedOptions[key] = this.options[key];
+ break;
+ default:
+ this.options[key] = value;
+ this._userProvidedOptions[key] = this.options[key];
+ break;
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+const safeDeprecationWarning = 'Mongoose: The `safe` option for schemas is ' +
+ 'deprecated. Use the `writeConcern` option instead: ' +
+ 'http://bit.ly/mongoose-write-concern';
+
+const setSafe = util.deprecate(function setSafe(options, value) {
+ options.safe = value === false ?
+ { w: 0 } :
+ value;
+}, safeDeprecationWarning);
+
+/**
+ * Gets a schema option.
+ *
+ * ####Example:
+ *
+ * schema.get('strict'); // true
+ * schema.set('strict', false);
+ * schema.get('strict'); // false
+ *
+ * @param {String} key option name
+ * @api public
+ * @return {Any} the option's value
+ */
+
+Schema.prototype.get = function(key) {
+ return this.options[key];
+};
+
+/**
+ * The allowed index types
+ *
+ * @receiver Schema
+ * @static indexTypes
+ * @api public
+ */
+
+const indexTypes = '2d 2dsphere hashed text'.split(' ');
+
+Object.defineProperty(Schema, 'indexTypes', {
+ get: function() {
+ return indexTypes;
+ },
+ set: function() {
+ throw new Error('Cannot overwrite Schema.indexTypes');
+ }
+});
+
+/**
+ * Returns a list of indexes that this schema declares, via `schema.index()`
+ * or by `index: true` in a path's options.
+ *
+ * ####Example:
+ *
+ * const userSchema = new Schema({
+ * email: { type: String, required: true, unique: true },
+ * registeredAt: { type: Date, index: true }
+ * });
+ *
+ * // [ [ { email: 1 }, { unique: true, background: true } ],
+ * // [ { registeredAt: 1 }, { background: true } ] ]
+ * userSchema.indexes();
+ *
+ * @api public
+ * @return {Array} list of indexes defined in the schema
+ */
+
+Schema.prototype.indexes = function() {
+ return getIndexes(this);
+};
+
+/**
+ * Creates a virtual type with the given name.
+ *
+ * @param {String} name
+ * @param {Object} [options]
+ * @param {String|Model} [options.ref] model name or model instance. Marks this as a [populate virtual](populate.html#populate-virtuals).
+ * @param {String|Function} [options.localField] Required for populate virtuals. See [populate virtual docs](populate.html#populate-virtuals) for more information.
+ * @param {String|Function} [options.foreignField] Required for populate virtuals. See [populate virtual docs](populate.html#populate-virtuals) for more information.
+ * @param {Boolean|Function} [options.justOne=false] Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), will be a single doc or `null`. Otherwise, the populate virtual will be an array.
+ * @param {Boolean} [options.count=false] Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), this populate virtual will contain the number of documents rather than the documents themselves when you `populate()`.
+ * @return {VirtualType}
+ */
+
+Schema.prototype.virtual = function(name, options) {
+ if (name instanceof VirtualType) {
+ return this.virtual(name.path, name.options);
+ }
+
+ options = new VirtualOptions(options);
+
+ if (utils.hasUserDefinedProperty(options, ['ref', 'refPath'])) {
+ if (options.localField == null) {
+ throw new Error('Reference virtuals require `localField` option');
+ }
+
+ if (options.foreignField == null) {
+ throw new Error('Reference virtuals require `foreignField` option');
+ }
+
+ this.pre('init', function(obj) {
+ if (mpath.has(name, obj)) {
+ const _v = mpath.get(name, obj);
+ if (!this.$$populatedVirtuals) {
+ this.$$populatedVirtuals = {};
+ }
+
+ if (options.justOne || options.count) {
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
+ _v[0] :
+ _v;
+ } else {
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
+ _v :
+ _v == null ? [] : [_v];
+ }
+
+ mpath.unset(name, obj);
+ }
+ });
+
+ const virtual = this.virtual(name);
+ virtual.options = options;
+ return virtual.
+ get(function() {
+ if (!this.$$populatedVirtuals) {
+ this.$$populatedVirtuals = {};
+ }
+ if (this.$$populatedVirtuals.hasOwnProperty(name)) {
+ return this.$$populatedVirtuals[name];
+ }
+ return void 0;
+ }).
+ set(function(_v) {
+ if (!this.$$populatedVirtuals) {
+ this.$$populatedVirtuals = {};
+ }
+
+ if (options.justOne || options.count) {
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
+ _v[0] :
+ _v;
+
+ if (typeof this.$$populatedVirtuals[name] !== 'object') {
+ this.$$populatedVirtuals[name] = options.count ? _v : null;
+ }
+ } else {
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
+ _v :
+ _v == null ? [] : [_v];
+
+ this.$$populatedVirtuals[name] = this.$$populatedVirtuals[name].filter(function(doc) {
+ return doc && typeof doc === 'object';
+ });
+ }
+ });
+ }
+
+ const virtuals = this.virtuals;
+ const parts = name.split('.');
+
+ if (this.pathType(name) === 'real') {
+ throw new Error('Virtual path "' + name + '"' +
+ ' conflicts with a real path in the schema');
+ }
+
+ virtuals[name] = parts.reduce(function(mem, part, i) {
+ mem[part] || (mem[part] = (i === parts.length - 1)
+ ? new VirtualType(options, name)
+ : {});
+ return mem[part];
+ }, this.tree);
+
+ // Workaround for gh-8198: if virtual is under document array, make a fake
+ // virtual. See gh-8210
+ let cur = parts[0];
+ for (let i = 0; i < parts.length - 1; ++i) {
+ if (this.paths[cur] != null && this.paths[cur].$isMongooseDocumentArray) {
+ const remnant = parts.slice(i + 1).join('.');
+ const v = this.paths[cur].schema.virtual(remnant);
+ v.get((v, virtual, doc) => {
+ const parent = doc.__parentArray[arrayParentSymbol];
+ const path = cur + '.' + doc.__index + '.' + remnant;
+ return parent.get(path);
+ });
+ break;
+ }
+
+ cur += '.' + parts[i + 1];
+ }
+
+ return virtuals[name];
+};
+
+/**
+ * Returns the virtual type with the given `name`.
+ *
+ * @param {String} name
+ * @return {VirtualType}
+ */
+
+Schema.prototype.virtualpath = function(name) {
+ return this.virtuals.hasOwnProperty(name) ? this.virtuals[name] : null;
+};
+
+/**
+ * Removes the given `path` (or [`paths`]).
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: String, age: Number });
+ * schema.remove('name');
+ * schema.path('name'); // Undefined
+ * schema.path('age'); // SchemaNumber { ... }
+ *
+ * @param {String|Array} path
+ * @return {Schema} the Schema instance
+ * @api public
+ */
+Schema.prototype.remove = function(path) {
+ if (typeof path === 'string') {
+ path = [path];
+ }
+ if (Array.isArray(path)) {
+ path.forEach(function(name) {
+ if (this.path(name) == null && !this.nested[name]) {
+ return;
+ }
+ if (this.nested[name]) {
+ const allKeys = Object.keys(this.paths).
+ concat(Object.keys(this.nested));
+ for (const path of allKeys) {
+ if (path.startsWith(name + '.')) {
+ delete this.paths[path];
+ delete this.nested[path];
+ _deletePath(this, path);
+ }
+ }
+
+ delete this.nested[name];
+ _deletePath(this, name);
+ return;
+ }
+
+ delete this.paths[name];
+ _deletePath(this, name);
+ }, this);
+ }
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+function _deletePath(schema, name) {
+ const pieces = name.split('.');
+ const last = pieces.pop();
+ let branch = schema.tree;
+ for (let i = 0; i < pieces.length; ++i) {
+ branch = branch[pieces[i]];
+ }
+ delete branch[last];
+}
+
+/**
+ * Loads an ES6 class into a schema. Maps [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) + [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get), [static methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static),
+ * and [instance methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Class_body_and_method_definitions)
+ * to schema [virtuals](http://mongoosejs.com/docs/guide.html#virtuals),
+ * [statics](http://mongoosejs.com/docs/guide.html#statics), and
+ * [methods](http://mongoosejs.com/docs/guide.html#methods).
+ *
+ * ####Example:
+ *
+ * ```javascript
+ * const md5 = require('md5');
+ * const userSchema = new Schema({ email: String });
+ * class UserClass {
+ * // `gravatarImage` becomes a virtual
+ * get gravatarImage() {
+ * const hash = md5(this.email.toLowerCase());
+ * return `https://www.gravatar.com/avatar/${hash}`;
+ * }
+ *
+ * // `getProfileUrl()` becomes a document method
+ * getProfileUrl() {
+ * return `https://mysite.com/${this.email}`;
+ * }
+ *
+ * // `findByEmail()` becomes a static
+ * static findByEmail(email) {
+ * return this.findOne({ email });
+ * }
+ * }
+ *
+ * // `schema` will now have a `gravatarImage` virtual, a `getProfileUrl()` method,
+ * // and a `findByEmail()` static
+ * userSchema.loadClass(UserClass);
+ * ```
+ *
+ * @param {Function} model
+ * @param {Boolean} [virtualsOnly] if truthy, only pulls virtuals from the class, not methods or statics
+ */
+Schema.prototype.loadClass = function(model, virtualsOnly) {
+ if (model === Object.prototype ||
+ model === Function.prototype ||
+ model.prototype.hasOwnProperty('$isMongooseModelPrototype')) {
+ return this;
+ }
+
+ this.loadClass(Object.getPrototypeOf(model));
+
+ // Add static methods
+ if (!virtualsOnly) {
+ Object.getOwnPropertyNames(model).forEach(function(name) {
+ if (name.match(/^(length|name|prototype)$/)) {
+ return;
+ }
+ const method = Object.getOwnPropertyDescriptor(model, name);
+ if (typeof method.value === 'function') {
+ this.static(name, method.value);
+ }
+ }, this);
+ }
+
+ // Add methods and virtuals
+ Object.getOwnPropertyNames(model.prototype).forEach(function(name) {
+ if (name.match(/^(constructor)$/)) {
+ return;
+ }
+ const method = Object.getOwnPropertyDescriptor(model.prototype, name);
+ if (!virtualsOnly) {
+ if (typeof method.value === 'function') {
+ this.method(name, method.value);
+ }
+ }
+ if (typeof method.get === 'function') {
+ this.virtual(name).get(method.get);
+ }
+ if (typeof method.set === 'function') {
+ this.virtual(name).set(method.set);
+ }
+ }, this);
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+Schema.prototype._getSchema = function(path) {
+ const _this = this;
+ const pathschema = _this.path(path);
+ const resultPath = [];
+
+ if (pathschema) {
+ pathschema.$fullPath = path;
+ return pathschema;
+ }
+
+ function search(parts, schema) {
+ let p = parts.length + 1;
+ let foundschema;
+ let trypath;
+
+ while (p--) {
+ trypath = parts.slice(0, p).join('.');
+ foundschema = schema.path(trypath);
+ if (foundschema) {
+ resultPath.push(trypath);
+
+ if (foundschema.caster) {
+ // array of Mixed?
+ if (foundschema.caster instanceof MongooseTypes.Mixed) {
+ foundschema.caster.$fullPath = resultPath.join('.');
+ return foundschema.caster;
+ }
+
+ // Now that we found the array, we need to check if there
+ // are remaining document paths to look up for casting.
+ // Also we need to handle array.$.path since schema.path
+ // doesn't work for that.
+ // If there is no foundschema.schema we are dealing with
+ // a path like array.$
+ if (p !== parts.length && foundschema.schema) {
+ let ret;
+ if (parts[p] === '$' || isArrayFilter(parts[p])) {
+ if (p + 1 === parts.length) {
+ // comments.$
+ return foundschema;
+ }
+ // comments.$.comments.$.title
+ ret = search(parts.slice(p + 1), foundschema.schema);
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+ return ret;
+ }
+ // this is the last path of the selector
+ ret = search(parts.slice(p), foundschema.schema);
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+ return ret;
+ }
+ }
+
+ foundschema.$fullPath = resultPath.join('.');
+
+ return foundschema;
+ }
+ }
+ }
+
+ // look for arrays
+ const parts = path.split('.');
+ for (let i = 0; i < parts.length; ++i) {
+ if (parts[i] === '$' || isArrayFilter(parts[i])) {
+ // Re: gh-5628, because `schema.path()` doesn't take $ into account.
+ parts[i] = '0';
+ }
+ }
+ return search(parts, _this);
+};
+
+/*!
+ * ignore
+ */
+
+Schema.prototype._getPathType = function(path) {
+ const _this = this;
+ const pathschema = _this.path(path);
+
+ if (pathschema) {
+ return 'real';
+ }
+
+ function search(parts, schema) {
+ let p = parts.length + 1,
+ foundschema,
+ trypath;
+
+ while (p--) {
+ trypath = parts.slice(0, p).join('.');
+ foundschema = schema.path(trypath);
+ if (foundschema) {
+ if (foundschema.caster) {
+ // array of Mixed?
+ if (foundschema.caster instanceof MongooseTypes.Mixed) {
+ return { schema: foundschema, pathType: 'mixed' };
+ }
+
+ // Now that we found the array, we need to check if there
+ // are remaining document paths to look up for casting.
+ // Also we need to handle array.$.path since schema.path
+ // doesn't work for that.
+ // If there is no foundschema.schema we are dealing with
+ // a path like array.$
+ if (p !== parts.length && foundschema.schema) {
+ if (parts[p] === '$' || isArrayFilter(parts[p])) {
+ if (p === parts.length - 1) {
+ return { schema: foundschema, pathType: 'nested' };
+ }
+ // comments.$.comments.$.title
+ return search(parts.slice(p + 1), foundschema.schema);
+ }
+ // this is the last path of the selector
+ return search(parts.slice(p), foundschema.schema);
+ }
+ return {
+ schema: foundschema,
+ pathType: foundschema.$isSingleNested ? 'nested' : 'array'
+ };
+ }
+ return { schema: foundschema, pathType: 'real' };
+ } else if (p === parts.length && schema.nested[trypath]) {
+ return { schema: schema, pathType: 'nested' };
+ }
+ }
+ return { schema: foundschema || schema, pathType: 'undefined' };
+ }
+
+ // look for arrays
+ return search(path.split('.'), _this);
+};
+
+/*!
+ * ignore
+ */
+
+function isArrayFilter(piece) {
+ return piece.startsWith('$[') && piece.endsWith(']');
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = Schema;
+
+// require down here because of reference issues
+
+/**
+ * The various built-in Mongoose Schema Types.
+ *
+ * ####Example:
+ *
+ * var mongoose = require('mongoose');
+ * var ObjectId = mongoose.Schema.Types.ObjectId;
+ *
+ * ####Types:
+ *
+ * - [String](#schema-string-js)
+ * - [Number](#schema-number-js)
+ * - [Boolean](#schema-boolean-js) | Bool
+ * - [Array](#schema-array-js)
+ * - [Buffer](#schema-buffer-js)
+ * - [Date](#schema-date-js)
+ * - [ObjectId](#schema-objectid-js) | Oid
+ * - [Mixed](#schema-mixed-js)
+ *
+ * Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.
+ *
+ * var Mixed = mongoose.Schema.Types.Mixed;
+ * new mongoose.Schema({ _user: Mixed })
+ *
+ * @api public
+ */
+
+Schema.Types = MongooseTypes = require('./schema/index');
+
+/*!
+ * ignore
+ */
+
+exports.ObjectId = MongooseTypes.ObjectId;
diff --git a/node_modules/mongoose/lib/schema/SingleNestedPath.js b/node_modules/mongoose/lib/schema/SingleNestedPath.js
new file mode 100644
index 0000000..9ac2971
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/SingleNestedPath.js
@@ -0,0 +1,310 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const CastError = require('../error/cast');
+const EventEmitter = require('events').EventEmitter;
+const ObjectExpectedError = require('../error/objectExpected');
+const SchemaSingleNestedOptions = require('../options/SchemaSingleNestedOptions');
+const SchemaType = require('../schematype');
+const $exists = require('./operators/exists');
+const castToNumber = require('./operators/helpers').castToNumber;
+const discriminator = require('../helpers/model/discriminator');
+const geospatial = require('./operators/geospatial');
+const get = require('../helpers/get');
+const getConstructor = require('../helpers/discriminator/getConstructor');
+const handleIdOption = require('../helpers/schema/handleIdOption');
+const internalToObjectOptions = require('../options').internalToObjectOptions;
+
+let Subdocument;
+
+module.exports = SingleNestedPath;
+
+/**
+ * Single nested subdocument SchemaType constructor.
+ *
+ * @param {Schema} schema
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SingleNestedPath(schema, path, options) {
+ schema = handleIdOption(schema, options);
+
+ this.caster = _createConstructor(schema);
+ this.caster.path = path;
+ this.caster.prototype.$basePath = path;
+ this.schema = schema;
+ this.$isSingleNested = true;
+ SchemaType.call(this, path, options, 'Embedded');
+}
+
+/*!
+ * ignore
+ */
+
+SingleNestedPath.prototype = Object.create(SchemaType.prototype);
+SingleNestedPath.prototype.constructor = SingleNestedPath;
+SingleNestedPath.prototype.OptionsConstructor = SchemaSingleNestedOptions;
+
+/*!
+ * ignore
+ */
+
+function _createConstructor(schema, baseClass) {
+ // lazy load
+ Subdocument || (Subdocument = require('../types/subdocument'));
+
+ const _embedded = function SingleNested(value, path, parent) {
+ const _this = this;
+
+ this.$parent = parent;
+ Subdocument.apply(this, arguments);
+
+ this.$session(this.ownerDocument().$session());
+
+ if (parent) {
+ parent.on('save', function() {
+ _this.emit('save', _this);
+ _this.constructor.emit('save', _this);
+ });
+
+ parent.on('isNew', function(val) {
+ _this.isNew = val;
+ _this.emit('isNew', val);
+ _this.constructor.emit('isNew', val);
+ });
+ }
+ };
+
+ const proto = baseClass != null ? baseClass.prototype : Subdocument.prototype;
+ _embedded.prototype = Object.create(proto);
+ _embedded.prototype.$__setSchema(schema);
+ _embedded.prototype.constructor = _embedded;
+ _embedded.schema = schema;
+ _embedded.$isSingleNested = true;
+ _embedded.events = new EventEmitter();
+ _embedded.prototype.toBSON = function() {
+ return this.toObject(internalToObjectOptions);
+ };
+
+ // apply methods
+ for (const i in schema.methods) {
+ _embedded.prototype[i] = schema.methods[i];
+ }
+
+ // apply statics
+ for (const i in schema.statics) {
+ _embedded[i] = schema.statics[i];
+ }
+
+ for (const i in EventEmitter.prototype) {
+ _embedded[i] = EventEmitter.prototype[i];
+ }
+
+ return _embedded;
+}
+
+/*!
+ * Special case for when users use a common location schema to represent
+ * locations for use with $geoWithin.
+ * https://docs.mongodb.org/manual/reference/operator/query/geoWithin/
+ *
+ * @param {Object} val
+ * @api private
+ */
+
+SingleNestedPath.prototype.$conditionalHandlers.$geoWithin = function handle$geoWithin(val) {
+ return { $geometry: this.castForQuery(val.$geometry) };
+};
+
+/*!
+ * ignore
+ */
+
+SingleNestedPath.prototype.$conditionalHandlers.$near =
+SingleNestedPath.prototype.$conditionalHandlers.$nearSphere = geospatial.cast$near;
+
+SingleNestedPath.prototype.$conditionalHandlers.$within =
+SingleNestedPath.prototype.$conditionalHandlers.$geoWithin = geospatial.cast$within;
+
+SingleNestedPath.prototype.$conditionalHandlers.$geoIntersects =
+ geospatial.cast$geoIntersects;
+
+SingleNestedPath.prototype.$conditionalHandlers.$minDistance = castToNumber;
+SingleNestedPath.prototype.$conditionalHandlers.$maxDistance = castToNumber;
+
+SingleNestedPath.prototype.$conditionalHandlers.$exists = $exists;
+
+/**
+ * Casts contents
+ *
+ * @param {Object} value
+ * @api private
+ */
+
+SingleNestedPath.prototype.cast = function(val, doc, init, priorVal) {
+ if (val && val.$isSingleNested && val.parent === doc) {
+ return val;
+ }
+
+ if (val != null && (typeof val !== 'object' || Array.isArray(val))) {
+ throw new ObjectExpectedError(this.path, val);
+ }
+
+ const Constructor = getConstructor(this.caster, val);
+
+ let subdoc;
+
+ // Only pull relevant selected paths and pull out the base path
+ const parentSelected = get(doc, '$__.selected', {});
+ const path = this.path;
+ const selected = Object.keys(parentSelected).reduce((obj, key) => {
+ if (key.startsWith(path + '.')) {
+ obj[key.substr(path.length + 1)] = parentSelected[key];
+ }
+ return obj;
+ }, {});
+
+ if (init) {
+ subdoc = new Constructor(void 0, selected, doc);
+ subdoc.init(val);
+ } else {
+ if (Object.keys(val).length === 0) {
+ return new Constructor({}, selected, doc);
+ }
+
+ return new Constructor(val, selected, doc, undefined, { priorDoc: priorVal });
+ }
+
+ return subdoc;
+};
+
+/**
+ * Casts contents for query
+ *
+ * @param {string} [$conditional] optional query operator (like `$eq` or `$in`)
+ * @param {any} value
+ * @api private
+ */
+
+SingleNestedPath.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional);
+ }
+ return handler.call(this, val);
+ }
+ val = $conditional;
+ if (val == null) {
+ return val;
+ }
+
+ if (this.options.runSetters) {
+ val = this._applySetters(val);
+ }
+
+ const Constructor = getConstructor(this.caster, val);
+
+ try {
+ val = new Constructor(val);
+ } catch (error) {
+ // Make sure we always wrap in a CastError (gh-6803)
+ if (!(error instanceof CastError)) {
+ throw new CastError('Embedded', val, this.path, error, this);
+ }
+ throw error;
+ }
+ return val;
+};
+
+/**
+ * Async validation on this single nested doc.
+ *
+ * @api private
+ */
+
+SingleNestedPath.prototype.doValidate = function(value, fn, scope, options) {
+ const Constructor = getConstructor(this.caster, value);
+
+ if (options && options.skipSchemaValidators) {
+ if (!(value instanceof Constructor)) {
+ value = new Constructor(value, null, scope);
+ }
+ return value.validate(fn);
+ }
+
+ SchemaType.prototype.doValidate.call(this, value, function(error) {
+ if (error) {
+ return fn(error);
+ }
+ if (!value) {
+ return fn(null);
+ }
+
+ value.validate(fn);
+ }, scope, options);
+};
+
+/**
+ * Synchronously validate this single nested doc
+ *
+ * @api private
+ */
+
+SingleNestedPath.prototype.doValidateSync = function(value, scope, options) {
+ if (!options || !options.skipSchemaValidators) {
+ const schemaTypeError = SchemaType.prototype.doValidateSync.call(this, value, scope);
+ if (schemaTypeError) {
+ return schemaTypeError;
+ }
+ }
+ if (!value) {
+ return;
+ }
+ return value.validateSync();
+};
+
+/**
+ * Adds a discriminator to this single nested subdocument.
+ *
+ * ####Example:
+ * const shapeSchema = Schema({ name: String }, { discriminatorKey: 'kind' });
+ * const schema = Schema({ shape: shapeSchema });
+ *
+ * const singleNestedPath = parentSchema.path('shape');
+ * singleNestedPath.discriminator('Circle', Schema({ radius: Number }));
+ *
+ * @param {String} name
+ * @param {Schema} schema fields to add to the schema for instances of this sub-class
+ * @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ * @return {Function} the constructor Mongoose will use for creating instances of this discriminator model
+ * @see discriminators /docs/discriminators.html
+ * @api public
+ */
+
+SingleNestedPath.prototype.discriminator = function(name, schema, value) {
+ schema = discriminator(this.caster, name, schema, value);
+
+ this.caster.discriminators[name] = _createConstructor(schema, this.caster);
+
+ return this.caster.discriminators[name];
+};
+
+/*!
+ * ignore
+ */
+
+SingleNestedPath.prototype.clone = function() {
+ const options = Object.assign({}, this.options);
+ const schematype = new this.constructor(this.schema, this.path, options);
+ schematype.validators = this.validators.slice();
+ schematype.caster.discriminators = Object.assign({}, this.caster.discriminators);
+ return schematype;
+};
diff --git a/node_modules/mongoose/lib/schema/array.js b/node_modules/mongoose/lib/schema/array.js
new file mode 100644
index 0000000..86589f1
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/array.js
@@ -0,0 +1,568 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const $exists = require('./operators/exists');
+const $type = require('./operators/type');
+const MongooseError = require('../error/mongooseError');
+const SchemaArrayOptions = require('../options/SchemaArrayOptions');
+const SchemaType = require('../schematype');
+const CastError = SchemaType.CastError;
+const Mixed = require('./mixed');
+const arrayDepth = require('../helpers/arrayDepth');
+const cast = require('../cast');
+const get = require('../helpers/get');
+const isOperator = require('../helpers/query/isOperator');
+const util = require('util');
+const utils = require('../utils');
+const castToNumber = require('./operators/helpers').castToNumber;
+const geospatial = require('./operators/geospatial');
+const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminatorByValue');
+
+let MongooseArray;
+let EmbeddedDoc;
+
+const isNestedArraySymbol = Symbol('mongoose#isNestedArray');
+
+/**
+ * Array SchemaType constructor
+ *
+ * @param {String} key
+ * @param {SchemaType} cast
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaArray(key, cast, options, schemaOptions) {
+ // lazy load
+ EmbeddedDoc || (EmbeddedDoc = require('../types').Embedded);
+
+ let typeKey = 'type';
+ if (schemaOptions && schemaOptions.typeKey) {
+ typeKey = schemaOptions.typeKey;
+ }
+ this.schemaOptions = schemaOptions;
+
+ if (cast) {
+ let castOptions = {};
+
+ if (utils.isPOJO(cast)) {
+ if (cast[typeKey]) {
+ // support { type: Woot }
+ castOptions = utils.clone(cast); // do not alter user arguments
+ delete castOptions[typeKey];
+ cast = cast[typeKey];
+ } else {
+ cast = Mixed;
+ }
+ }
+
+ if (cast === Object) {
+ cast = Mixed;
+ }
+
+ // support { type: 'String' }
+ const name = typeof cast === 'string'
+ ? cast
+ : utils.getFunctionName(cast);
+
+ const Types = require('./index.js');
+ const caster = Types.hasOwnProperty(name) ? Types[name] : cast;
+
+ this.casterConstructor = caster;
+
+ if (this.casterConstructor instanceof SchemaArray) {
+ this.casterConstructor[isNestedArraySymbol] = true;
+ }
+
+ if (typeof caster === 'function' &&
+ !caster.$isArraySubdocument &&
+ !caster.$isSchemaMap) {
+ this.caster = new caster(null, castOptions);
+ } else {
+ this.caster = caster;
+ }
+
+ this.$embeddedSchemaType = this.caster;
+
+ if (!(this.caster instanceof EmbeddedDoc)) {
+ this.caster.path = key;
+ }
+ }
+
+ this.$isMongooseArray = true;
+
+ SchemaType.call(this, key, options, 'Array');
+
+ let defaultArr;
+ let fn;
+
+ if (this.defaultValue != null) {
+ defaultArr = this.defaultValue;
+ fn = typeof defaultArr === 'function';
+ }
+
+ if (!('defaultValue' in this) || this.defaultValue !== void 0) {
+ const defaultFn = function() {
+ let arr = [];
+ if (fn) {
+ arr = defaultArr.call(this);
+ } else if (defaultArr != null) {
+ arr = arr.concat(defaultArr);
+ }
+ // Leave it up to `cast()` to convert the array
+ return arr;
+ };
+ defaultFn.$runBeforeSetters = true;
+ this.default(defaultFn);
+ }
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaArray.schemaName = 'Array';
+
+
+/**
+ * Options for all arrays.
+ *
+ * - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
+ *
+ * @static options
+ * @api public
+ */
+
+SchemaArray.options = { castNonArrays: true };
+
+SchemaArray.defaultOptions = {};
+
+/**
+ * Sets a default option for all Array instances.
+ *
+ * ####Example:
+ *
+ * // Make all Array instances have `required` of true by default.
+ * mongoose.Schema.Array.set('required', true);
+ *
+ * const User = mongoose.model('User', new Schema({ test: Array }));
+ * new User({ }).validateSync().errors.test.message; // Path `test` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+SchemaArray.set = SchemaType.set;
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaArray.prototype = Object.create(SchemaType.prototype);
+SchemaArray.prototype.constructor = SchemaArray;
+SchemaArray.prototype.OptionsConstructor = SchemaArrayOptions;
+
+/*!
+ * ignore
+ */
+
+SchemaArray._checkRequired = SchemaType.prototype.checkRequired;
+
+/**
+ * Override the function the required validator uses to check whether an array
+ * passes the `required` check.
+ *
+ * ####Example:
+ *
+ * // Require non-empty array to pass `required` check
+ * mongoose.Schema.Types.Array.checkRequired(v => Array.isArray(v) && v.length);
+ *
+ * const M = mongoose.model({ arr: { type: Array, required: true } });
+ * new M({ arr: [] }).validateSync(); // `null`, validation fails!
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaArray.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies the `required` validator.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ SchemaArray.checkRequired();
+
+ return _checkRequired(value);
+};
+
+/**
+ * Adds an enum validator if this is an array of strings or numbers. Equivalent to
+ * `SchemaString.prototype.enum()` or `SchemaNumber.prototype.enum()`
+ *
+ * @param {String|Object} [args...] enumeration values
+ * @return {SchemaArray} this
+ */
+
+SchemaArray.prototype.enum = function() {
+ let arr = this;
+ while (true) {
+ const instance = get(arr, 'caster.instance');
+ if (instance === 'Array') {
+ arr = arr.caster;
+ continue;
+ }
+ if (instance !== 'String' && instance !== 'Number') {
+ throw new Error('`enum` can only be set on an array of strings or numbers ' +
+ ', not ' + instance);
+ }
+ break;
+ }
+ arr.caster.enum.apply(arr.caster, arguments);
+ return this;
+};
+
+/**
+ * Overrides the getters application for the population special-case
+ *
+ * @param {Object} value
+ * @param {Object} scope
+ * @api private
+ */
+
+SchemaArray.prototype.applyGetters = function(value, scope) {
+ if (this.caster.options && this.caster.options.ref) {
+ // means the object id was populated
+ return value;
+ }
+
+ return SchemaType.prototype.applyGetters.call(this, value, scope);
+};
+
+SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
+ if (this.casterConstructor instanceof SchemaArray &&
+ SchemaArray.options.castNonArrays &&
+ !this[isNestedArraySymbol]) {
+ // Check nesting levels and wrap in array if necessary
+ let depth = 0;
+ let arr = this;
+ while (arr != null &&
+ arr instanceof SchemaArray &&
+ !arr.$isMongooseDocumentArray) {
+ ++depth;
+ arr = arr.casterConstructor;
+ }
+
+ // No need to wrap empty arrays
+ if (value != null && value.length > 0) {
+ const valueDepth = arrayDepth(value);
+ if (valueDepth.min === valueDepth.max && valueDepth.max < depth) {
+ for (let i = valueDepth.max; i < depth; ++i) {
+ value = [value];
+ }
+ }
+ }
+ }
+
+ return SchemaType.prototype._applySetters.call(this, value, scope, init, priorVal);
+};
+
+/**
+ * Casts values for set().
+ *
+ * @param {Object} value
+ * @param {Document} doc document that triggers the casting
+ * @param {Boolean} init whether this is an initialization cast
+ * @api private
+ */
+
+SchemaArray.prototype.cast = function(value, doc, init) {
+ // lazy load
+ MongooseArray || (MongooseArray = require('../types').Array);
+
+ let i;
+ let l;
+
+ if (Array.isArray(value)) {
+ if (!value.length && doc) {
+ const indexes = doc.schema.indexedPaths();
+
+ const arrayPath = this.path;
+ for (i = 0, l = indexes.length; i < l; ++i) {
+ const pathIndex = indexes[i][0][arrayPath];
+ if (pathIndex === '2dsphere' || pathIndex === '2d') {
+ return;
+ }
+ }
+
+ // Special case: if this index is on the parent of what looks like
+ // GeoJSON, skip setting the default to empty array re: #1668, #3233
+ const arrayGeojsonPath = this.path.endsWith('.coordinates') ?
+ this.path.substr(0, this.path.lastIndexOf('.')) : null;
+ if (arrayGeojsonPath != null) {
+ for (i = 0, l = indexes.length; i < l; ++i) {
+ const pathIndex = indexes[i][0][arrayGeojsonPath];
+ if (pathIndex === '2dsphere') {
+ return;
+ }
+ }
+ }
+ }
+
+ if (!(value && value.isMongooseArray)) {
+ value = new MongooseArray(value, this.path, doc);
+ } else if (value && value.isMongooseArray) {
+ // We need to create a new array, otherwise change tracking will
+ // update the old doc (gh-4449)
+ value = new MongooseArray(value, this.path, doc);
+ }
+
+ const isPopulated = doc != null && doc.$__ != null && doc.populated(this.path);
+ if (isPopulated) {
+ return value;
+ }
+
+ if (this.caster && this.casterConstructor !== Mixed) {
+ try {
+ for (i = 0, l = value.length; i < l; i++) {
+ value[i] = this.caster.cast(value[i], doc, init);
+ }
+ } catch (e) {
+ // rethrow
+ throw new CastError('[' + e.kind + ']', util.inspect(value), this.path, e, this);
+ }
+ }
+
+ return value;
+ }
+
+ if (init || SchemaArray.options.castNonArrays) {
+ // gh-2442: if we're loading this from the db and its not an array, mark
+ // the whole array as modified.
+ if (!!doc && !!init) {
+ doc.markModified(this.path);
+ }
+ return this.cast([value], doc, init);
+ }
+
+ throw new CastError('Array', util.inspect(value), this.path, null, this);
+};
+
+/*!
+ * Ignore
+ */
+
+SchemaArray.prototype.discriminator = function(name, schema) {
+ let arr = this; // eslint-disable-line consistent-this
+ while (arr.$isMongooseArray && !arr.$isMongooseDocumentArray) {
+ arr = arr.casterConstructor;
+ if (arr == null || typeof arr === 'function') {
+ throw new MongooseError('You can only add an embedded discriminator on ' +
+ 'a document array, ' + this.path + ' is a plain array');
+ }
+ }
+ return arr.discriminator(name, schema);
+};
+
+/*!
+ * ignore
+ */
+
+SchemaArray.prototype.clone = function() {
+ const options = Object.assign({}, this.options);
+ const schematype = new this.constructor(this.path, this.caster, options, this.schemaOptions);
+ schematype.validators = this.validators.slice();
+ return schematype;
+};
+
+/**
+ * Casts values for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} [value]
+ * @api private
+ */
+
+SchemaArray.prototype.castForQuery = function($conditional, value) {
+ let handler;
+ let val;
+
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional + ' with Array.');
+ }
+
+ val = handler.call(this, value);
+ } else {
+ val = $conditional;
+ let Constructor = this.casterConstructor;
+
+ if (val &&
+ Constructor.discriminators &&
+ Constructor.schema &&
+ Constructor.schema.options &&
+ Constructor.schema.options.discriminatorKey) {
+ if (typeof val[Constructor.schema.options.discriminatorKey] === 'string' &&
+ Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]]) {
+ Constructor = Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]];
+ } else {
+ const constructorByValue = getDiscriminatorByValue(Constructor, val[Constructor.schema.options.discriminatorKey]);
+ if (constructorByValue) {
+ Constructor = constructorByValue;
+ }
+ }
+ }
+
+ const proto = this.casterConstructor.prototype;
+ let method = proto && (proto.castForQuery || proto.cast);
+ if (!method && Constructor.castForQuery) {
+ method = Constructor.castForQuery;
+ }
+ const caster = this.caster;
+
+ if (Array.isArray(val)) {
+ this.setters.reverse().forEach(setter => {
+ val = setter.call(this, val, this);
+ });
+ val = val.map(function(v) {
+ if (utils.isObject(v) && v.$elemMatch) {
+ return v;
+ }
+ if (method) {
+ v = method.call(caster, v);
+ return v;
+ }
+ if (v != null) {
+ v = new Constructor(v);
+ return v;
+ }
+ return v;
+ });
+ } else if (method) {
+ val = method.call(caster, val);
+ } else if (val != null) {
+ val = new Constructor(val);
+ }
+ }
+
+ return val;
+};
+
+function cast$all(val) {
+ if (!Array.isArray(val)) {
+ val = [val];
+ }
+
+ val = val.map(function(v) {
+ if (utils.isObject(v)) {
+ const o = {};
+ o[this.path] = v;
+ return cast(this.casterConstructor.schema, o)[this.path];
+ }
+ return v;
+ }, this);
+
+ return this.castForQuery(val);
+}
+
+function cast$elemMatch(val) {
+ const keys = Object.keys(val);
+ const numKeys = keys.length;
+ for (let i = 0; i < numKeys; ++i) {
+ const key = keys[i];
+ const value = val[key];
+ if (isOperator(key) && value != null) {
+ val[key] = this.castForQuery(key, value);
+ }
+ }
+
+ // Is this an embedded discriminator and is the discriminator key set?
+ // If so, use the discriminator schema. See gh-7449
+ const discriminatorKey = get(this,
+ 'casterConstructor.schema.options.discriminatorKey');
+ const discriminators = get(this, 'casterConstructor.schema.discriminators', {});
+ if (discriminatorKey != null &&
+ val[discriminatorKey] != null &&
+ discriminators[val[discriminatorKey]] != null) {
+ return cast(discriminators[val[discriminatorKey]], val);
+ }
+
+ return cast(this.casterConstructor.schema, val);
+}
+
+const handle = SchemaArray.prototype.$conditionalHandlers = {};
+
+handle.$all = cast$all;
+handle.$options = String;
+handle.$elemMatch = cast$elemMatch;
+handle.$geoIntersects = geospatial.cast$geoIntersects;
+handle.$or = handle.$and = function(val) {
+ if (!Array.isArray(val)) {
+ throw new TypeError('conditional $or/$and require array');
+ }
+
+ const ret = [];
+ for (let i = 0; i < val.length; ++i) {
+ ret.push(cast(this.casterConstructor.schema, val[i]));
+ }
+
+ return ret;
+};
+
+handle.$near =
+handle.$nearSphere = geospatial.cast$near;
+
+handle.$within =
+handle.$geoWithin = geospatial.cast$within;
+
+handle.$size =
+handle.$minDistance =
+handle.$maxDistance = castToNumber;
+
+handle.$exists = $exists;
+handle.$type = $type;
+
+handle.$eq =
+handle.$gt =
+handle.$gte =
+handle.$lt =
+handle.$lte =
+handle.$ne =
+handle.$regex = SchemaArray.prototype.castForQuery;
+
+// `$in` is special because you can also include an empty array in the query
+// like `$in: [1, []]`, see gh-5913
+handle.$nin = SchemaType.prototype.$conditionalHandlers.$nin;
+handle.$in = SchemaType.prototype.$conditionalHandlers.$in;
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaArray;
diff --git a/node_modules/mongoose/lib/schema/boolean.js b/node_modules/mongoose/lib/schema/boolean.js
new file mode 100644
index 0000000..4280d94
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/boolean.js
@@ -0,0 +1,231 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const CastError = require('../error/cast');
+const SchemaType = require('../schematype');
+const castBoolean = require('../cast/boolean');
+const utils = require('../utils');
+
+/**
+ * Boolean SchemaType constructor.
+ *
+ * @param {String} path
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaBoolean(path, options) {
+ SchemaType.call(this, path, options, 'Boolean');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaBoolean.schemaName = 'Boolean';
+
+SchemaBoolean.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaBoolean.prototype = Object.create(SchemaType.prototype);
+SchemaBoolean.prototype.constructor = SchemaBoolean;
+
+/*!
+ * ignore
+ */
+
+SchemaBoolean._cast = castBoolean;
+
+/**
+ * Sets a default option for all Boolean instances.
+ *
+ * ####Example:
+ *
+ * // Make all booleans have `default` of false.
+ * mongoose.Schema.Boolean.set('default', false);
+ *
+ * const Order = mongoose.model('Order', new Schema({ isPaid: Boolean }));
+ * new Order({ }).isPaid; // false
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+SchemaBoolean.set = SchemaType.set;
+
+/**
+ * Get/set the function used to cast arbitrary values to booleans.
+ *
+ * ####Example:
+ *
+ * // Make Mongoose cast empty string '' to false.
+ * const original = mongoose.Schema.Boolean.cast();
+ * mongoose.Schema.Boolean.cast(v => {
+ * if (v === '') {
+ * return false;
+ * }
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.Schema.Boolean.cast(false);
+ *
+ * @param {Function} caster
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaBoolean.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (v != null && typeof v !== 'boolean') {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/*!
+ * ignore
+ */
+
+SchemaBoolean._checkRequired = v => v === true || v === false;
+
+/**
+ * Override the function the required validator uses to check whether a boolean
+ * passes the `required` check.
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaBoolean.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator. For a boolean
+ * to satisfy a required validator, it must be strictly equal to true or to
+ * false.
+ *
+ * @param {Any} value
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaBoolean.prototype.checkRequired = function(value) {
+ return this.constructor._checkRequired(value);
+};
+
+/**
+ * Configure which values get casted to `true`.
+ *
+ * ####Example:
+ *
+ * const M = mongoose.model('Test', new Schema({ b: Boolean }));
+ * new M({ b: 'affirmative' }).b; // undefined
+ * mongoose.Schema.Boolean.convertToTrue.add('affirmative');
+ * new M({ b: 'affirmative' }).b; // true
+ *
+ * @property convertToTrue
+ * @type Set
+ * @api public
+ */
+
+Object.defineProperty(SchemaBoolean, 'convertToTrue', {
+ get: () => castBoolean.convertToTrue,
+ set: v => { castBoolean.convertToTrue = v; }
+});
+
+/**
+ * Configure which values get casted to `false`.
+ *
+ * ####Example:
+ *
+ * const M = mongoose.model('Test', new Schema({ b: Boolean }));
+ * new M({ b: 'nay' }).b; // undefined
+ * mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
+ * new M({ b: 'nay' }).b; // false
+ *
+ * @property convertToFalse
+ * @type Set
+ * @api public
+ */
+
+Object.defineProperty(SchemaBoolean, 'convertToFalse', {
+ get: () => castBoolean.convertToFalse,
+ set: v => { castBoolean.convertToFalse = v; }
+});
+
+/**
+ * Casts to boolean
+ *
+ * @param {Object} value
+ * @param {Object} model - this value is optional
+ * @api private
+ */
+
+SchemaBoolean.prototype.cast = function(value) {
+ const castBoolean = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ SchemaBoolean.cast();
+ try {
+ return castBoolean(value);
+ } catch (error) {
+ throw new CastError('Boolean', value, this.path, error, this);
+ }
+};
+
+SchemaBoolean.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {});
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} val
+ * @api private
+ */
+
+SchemaBoolean.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = SchemaBoolean.$conditionalHandlers[$conditional];
+
+ if (handler) {
+ return handler.call(this, val);
+ }
+
+ return this._castForQuery(val);
+ }
+
+ return this._castForQuery($conditional);
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaBoolean;
diff --git a/node_modules/mongoose/lib/schema/buffer.js b/node_modules/mongoose/lib/schema/buffer.js
new file mode 100644
index 0000000..81f0300
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/buffer.js
@@ -0,0 +1,276 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const MongooseBuffer = require('../types/buffer');
+const SchemaBufferOptions = require('../options/SchemaBufferOptions');
+const SchemaType = require('../schematype');
+const handleBitwiseOperator = require('./operators/bitwise');
+const utils = require('../utils');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+const Binary = MongooseBuffer.Binary;
+const CastError = SchemaType.CastError;
+let Document;
+
+/**
+ * Buffer SchemaType constructor
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaBuffer(key, options) {
+ SchemaType.call(this, key, options, 'Buffer');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaBuffer.schemaName = 'Buffer';
+
+SchemaBuffer.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaBuffer.prototype = Object.create(SchemaType.prototype);
+SchemaBuffer.prototype.constructor = SchemaBuffer;
+SchemaBuffer.prototype.OptionsConstructor = SchemaBufferOptions;
+
+/*!
+ * ignore
+ */
+
+SchemaBuffer._checkRequired = v => !!(v && v.length);
+
+/**
+ * Sets a default option for all Buffer instances.
+ *
+ * ####Example:
+ *
+ * // Make all buffers have `required` of true by default.
+ * mongoose.Schema.Buffer.set('required', true);
+ *
+ * const User = mongoose.model('User', new Schema({ test: Buffer }));
+ * new User({ }).validateSync().errors.test.message; // Path `test` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+SchemaBuffer.set = SchemaType.set;
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * ####Example:
+ *
+ * // Allow empty strings to pass `required` check
+ * mongoose.Schema.Types.String.checkRequired(v => v != null);
+ *
+ * const M = mongoose.model({ buf: { type: Buffer, required: true } });
+ * new M({ buf: Buffer.from('') }).validateSync(); // validation passes!
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaBuffer.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator. To satisfy a
+ * required validator, a buffer must not be null or undefined and have
+ * non-zero length.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaBuffer.prototype.checkRequired = function(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+ return this.constructor._checkRequired(value);
+};
+
+/**
+ * Casts contents
+ *
+ * @param {Object} value
+ * @param {Document} doc document that triggers the casting
+ * @param {Boolean} init
+ * @api private
+ */
+
+SchemaBuffer.prototype.cast = function(value, doc, init) {
+ let ret;
+ if (SchemaType._isRef(this, value, doc, init)) {
+ // wait! we may need to cast this to a document
+
+ if (value === null || value === undefined) {
+ return value;
+ }
+
+ // lazy load
+ Document || (Document = require('./../document'));
+
+ if (value instanceof Document) {
+ value.$__.wasPopulated = true;
+ return value;
+ }
+
+ // setting a populated path
+ if (Buffer.isBuffer(value)) {
+ return value;
+ } else if (!utils.isObject(value)) {
+ throw new CastError('buffer', value, this.path, null, this);
+ }
+
+ // Handle the case where user directly sets a populated
+ // path to a plain object; cast to the Model used in
+ // the population query.
+ const path = doc.$__fullPath(this.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ const pop = owner.populated(path, true);
+ ret = new pop.options[populateModelSymbol](value);
+ ret.$__.wasPopulated = true;
+ return ret;
+ }
+
+ // documents
+ if (value && value._id) {
+ value = value._id;
+ }
+
+ if (value && value.isMongooseBuffer) {
+ return value;
+ }
+
+ if (Buffer.isBuffer(value)) {
+ if (!value || !value.isMongooseBuffer) {
+ value = new MongooseBuffer(value, [this.path, doc]);
+ if (this.options.subtype != null) {
+ value._subtype = this.options.subtype;
+ }
+ }
+ return value;
+ }
+
+ if (value instanceof Binary) {
+ ret = new MongooseBuffer(value.value(true), [this.path, doc]);
+ if (typeof value.sub_type !== 'number') {
+ throw new CastError('buffer', value, this.path, null, this);
+ }
+ ret._subtype = value.sub_type;
+ return ret;
+ }
+
+ if (value === null) {
+ return value;
+ }
+
+
+ const type = typeof value;
+ if (
+ type === 'string' || type === 'number' || Array.isArray(value) ||
+ (type === 'object' && value.type === 'Buffer' && Array.isArray(value.data)) // gh-6863
+ ) {
+ if (type === 'number') {
+ value = [value];
+ }
+ ret = new MongooseBuffer(value, [this.path, doc]);
+ if (this.options.subtype != null) {
+ ret._subtype = this.options.subtype;
+ }
+ return ret;
+ }
+
+ throw new CastError('buffer', value, this.path, null, this);
+};
+
+/**
+ * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
+ * for this buffer. You can find a [list of allowed subtypes here](http://api.mongodb.com/python/current/api/bson/binary.html).
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ uuid: { type: Buffer, subtype: 4 });
+ * var M = db.model('M', s);
+ * var m = new M({ uuid: 'test string' });
+ * m.uuid._subtype; // 4
+ *
+ * @param {Number} subtype the default subtype
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaBuffer.prototype.subtype = function(subtype) {
+ this.options.subtype = subtype;
+ return this;
+};
+
+/*!
+ * ignore
+ */
+function handleSingle(val) {
+ return this.castForQuery(val);
+}
+
+SchemaBuffer.prototype.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $bitsAllClear: handleBitwiseOperator,
+ $bitsAnyClear: handleBitwiseOperator,
+ $bitsAllSet: handleBitwiseOperator,
+ $bitsAnySet: handleBitwiseOperator,
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle
+ });
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} [value]
+ * @api private
+ */
+
+SchemaBuffer.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
+ }
+ return handler.call(this, val);
+ }
+ val = $conditional;
+ const casted = this._castForQuery(val);
+ return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaBuffer;
diff --git a/node_modules/mongoose/lib/schema/date.js b/node_modules/mongoose/lib/schema/date.js
new file mode 100644
index 0000000..ebeaf47
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/date.js
@@ -0,0 +1,390 @@
+/*!
+ * Module requirements.
+ */
+
+'use strict';
+
+const MongooseError = require('../error/index');
+const SchemaDateOptions = require('../options/SchemaDateOptions');
+const SchemaType = require('../schematype');
+const castDate = require('../cast/date');
+const utils = require('../utils');
+
+const CastError = SchemaType.CastError;
+
+/**
+ * Date SchemaType constructor.
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaDate(key, options) {
+ SchemaType.call(this, key, options, 'Date');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaDate.schemaName = 'Date';
+
+SchemaDate.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaDate.prototype = Object.create(SchemaType.prototype);
+SchemaDate.prototype.constructor = SchemaDate;
+SchemaDate.prototype.OptionsConstructor = SchemaDateOptions;
+
+/*!
+ * ignore
+ */
+
+SchemaDate._cast = castDate;
+
+/**
+ * Sets a default option for all Date instances.
+ *
+ * ####Example:
+ *
+ * // Make all dates have `required` of true by default.
+ * mongoose.Schema.Date.set('required', true);
+ *
+ * const User = mongoose.model('User', new Schema({ test: Date }));
+ * new User({ }).validateSync().errors.test.message; // Path `test` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+SchemaDate.set = SchemaType.set;
+
+/**
+ * Get/set the function used to cast arbitrary values to dates.
+ *
+ * ####Example:
+ *
+ * // Mongoose converts empty string '' into `null` for date types. You
+ * // can create a custom caster to disable it.
+ * const original = mongoose.Schema.Types.Date.cast();
+ * mongoose.Schema.Types.Date.cast(v => {
+ * assert.ok(v !== '');
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.Schema.Types.Date.cast(false);
+ *
+ * @param {Function} caster
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaDate.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (v != null && !(v instanceof Date)) {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/**
+ * Declares a TTL index (rounded to the nearest second) for _Date_ types only.
+ *
+ * This sets the `expireAfterSeconds` index option available in MongoDB >= 2.1.2.
+ * This index type is only compatible with Date types.
+ *
+ * ####Example:
+ *
+ * // expire in 24 hours
+ * new Schema({ createdAt: { type: Date, expires: 60*60*24 }});
+ *
+ * `expires` utilizes the `ms` module from [guille](https://github.com/guille/) allowing us to use a friendlier syntax:
+ *
+ * ####Example:
+ *
+ * // expire in 24 hours
+ * new Schema({ createdAt: { type: Date, expires: '24h' }});
+ *
+ * // expire in 1.5 hours
+ * new Schema({ createdAt: { type: Date, expires: '1.5h' }});
+ *
+ * // expire in 7 days
+ * var schema = new Schema({ createdAt: Date });
+ * schema.path('createdAt').expires('7d');
+ *
+ * @param {Number|String} when
+ * @added 3.0.0
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaDate.prototype.expires = function(when) {
+ if (!this._index || this._index.constructor.name !== 'Object') {
+ this._index = {};
+ }
+
+ this._index.expires = when;
+ utils.expires(this._index);
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+SchemaDate._checkRequired = v => v instanceof Date;
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * ####Example:
+ *
+ * // Allow empty strings to pass `required` check
+ * mongoose.Schema.Types.String.checkRequired(v => v != null);
+ *
+ * const M = mongoose.model({ str: { type: String, required: true } });
+ * new M({ str: '' }).validateSync(); // `null`, validation passes!
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaDate.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator. To satisfy
+ * a required validator, the given value must be an instance of `Date`.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaDate.prototype.checkRequired = function(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ SchemaDate.checkRequired();
+ return _checkRequired(value);
+};
+
+/**
+ * Sets a minimum date validator.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ d: { type: Date, min: Date('1970-01-01') })
+ * var M = db.model('M', s)
+ * var m = new M({ d: Date('1969-12-31') })
+ * m.save(function (err) {
+ * console.error(err) // validator error
+ * m.d = Date('2014-12-08');
+ * m.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MIN} token which will be replaced with the invalid value
+ * var min = [Date('1970-01-01'), 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'];
+ * var schema = new Schema({ d: { type: Date, min: min })
+ * var M = mongoose.model('M', schema);
+ * var s= new M({ d: Date('1969-12-31') });
+ * s.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `d` (1969-12-31) is before the limit (1970-01-01).
+ * })
+ *
+ * @param {Date} value minimum date
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaDate.prototype.min = function(value, message) {
+ if (this.minValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.minValidator;
+ }, this);
+ }
+
+ if (value) {
+ let msg = message || MongooseError.messages.Date.min;
+ if (typeof msg === 'string') {
+ msg = msg.replace(/{MIN}/, (value === Date.now ? 'Date.now()' : value.toString()));
+ }
+ const _this = this;
+ this.validators.push({
+ validator: this.minValidator = function(val) {
+ let _value = value;
+ if (typeof value === 'function' && value !== Date.now) {
+ _value = _value.call(this);
+ }
+ const min = (_value === Date.now ? _value() : _this.cast(_value));
+ return val === null || val.valueOf() >= min.valueOf();
+ },
+ message: msg,
+ type: 'min',
+ min: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Sets a maximum date validator.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ d: { type: Date, max: Date('2014-01-01') })
+ * var M = db.model('M', s)
+ * var m = new M({ d: Date('2014-12-08') })
+ * m.save(function (err) {
+ * console.error(err) // validator error
+ * m.d = Date('2013-12-31');
+ * m.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MAX} token which will be replaced with the invalid value
+ * var max = [Date('2014-01-01'), 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).'];
+ * var schema = new Schema({ d: { type: Date, max: max })
+ * var M = mongoose.model('M', schema);
+ * var s= new M({ d: Date('2014-12-08') });
+ * s.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `d` (2014-12-08) exceeds the limit (2014-01-01).
+ * })
+ *
+ * @param {Date} maximum date
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaDate.prototype.max = function(value, message) {
+ if (this.maxValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.maxValidator;
+ }, this);
+ }
+
+ if (value) {
+ let msg = message || MongooseError.messages.Date.max;
+ if (typeof msg === 'string') {
+ msg = msg.replace(/{MAX}/, (value === Date.now ? 'Date.now()' : value.toString()));
+ }
+ const _this = this;
+ this.validators.push({
+ validator: this.maxValidator = function(val) {
+ let _value = value;
+ if (typeof _value === 'function' && _value !== Date.now) {
+ _value = _value.call(this);
+ }
+ const max = (_value === Date.now ? _value() : _this.cast(_value));
+ return val === null || val.valueOf() <= max.valueOf();
+ },
+ message: msg,
+ type: 'max',
+ max: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Casts to date
+ *
+ * @param {Object} value to cast
+ * @api private
+ */
+
+SchemaDate.prototype.cast = function(value) {
+ const castDate = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ SchemaDate.cast();
+ try {
+ return castDate(value);
+ } catch (error) {
+ throw new CastError('date', value, this.path, error, this);
+ }
+};
+
+/*!
+ * Date Query casting.
+ *
+ * @api private
+ */
+
+function handleSingle(val) {
+ return this.cast(val);
+}
+
+SchemaDate.prototype.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle
+ });
+
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} [value]
+ * @api private
+ */
+
+SchemaDate.prototype.castForQuery = function($conditional, val) {
+ if (arguments.length !== 2) {
+ return this._castForQuery($conditional);
+ }
+
+ const handler = this.$conditionalHandlers[$conditional];
+
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional + ' with Date.');
+ }
+
+ return handler.call(this, val);
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaDate;
diff --git a/node_modules/mongoose/lib/schema/decimal128.js b/node_modules/mongoose/lib/schema/decimal128.js
new file mode 100644
index 0000000..ca9bcb4
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/decimal128.js
@@ -0,0 +1,235 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const SchemaType = require('../schematype');
+const CastError = SchemaType.CastError;
+const Decimal128Type = require('../types/decimal128');
+const castDecimal128 = require('../cast/decimal128');
+const utils = require('../utils');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+let Document;
+
+/**
+ * Decimal128 SchemaType constructor.
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function Decimal128(key, options) {
+ SchemaType.call(this, key, options, 'Decimal128');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+Decimal128.schemaName = 'Decimal128';
+
+Decimal128.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+Decimal128.prototype = Object.create(SchemaType.prototype);
+Decimal128.prototype.constructor = Decimal128;
+
+/*!
+ * ignore
+ */
+
+Decimal128._cast = castDecimal128;
+
+/**
+ * Sets a default option for all Decimal128 instances.
+ *
+ * ####Example:
+ *
+ * // Make all decimal 128s have `required` of true by default.
+ * mongoose.Schema.Decimal128.set('required', true);
+ *
+ * const User = mongoose.model('User', new Schema({ test: mongoose.Decimal128 }));
+ * new User({ }).validateSync().errors.test.message; // Path `test` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+Decimal128.set = SchemaType.set;
+
+/**
+ * Get/set the function used to cast arbitrary values to decimals.
+ *
+ * ####Example:
+ *
+ * // Make Mongoose only refuse to cast numbers as decimal128
+ * const original = mongoose.Schema.Types.Decimal128.cast();
+ * mongoose.Decimal128.cast(v => {
+ * assert.ok(typeof v !== 'number');
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.Decimal128.cast(false);
+ *
+ * @param {Function} [caster]
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+Decimal128.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (v != null && !(v instanceof Decimal128Type)) {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/*!
+ * ignore
+ */
+
+Decimal128._checkRequired = v => v instanceof Decimal128Type;
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+Decimal128.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+Decimal128.prototype.checkRequired = function checkRequired(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ Decimal128.checkRequired();
+
+ return _checkRequired(value);
+};
+
+/**
+ * Casts to Decimal128
+ *
+ * @param {Object} value
+ * @param {Object} doc
+ * @param {Boolean} init whether this is an initialization cast
+ * @api private
+ */
+
+Decimal128.prototype.cast = function(value, doc, init) {
+ if (SchemaType._isRef(this, value, doc, init)) {
+ // wait! we may need to cast this to a document
+
+ if (value === null || value === undefined) {
+ return value;
+ }
+
+ // lazy load
+ Document || (Document = require('./../document'));
+
+ if (value instanceof Document) {
+ value.$__.wasPopulated = true;
+ return value;
+ }
+
+ // setting a populated path
+ if (value instanceof Decimal128Type) {
+ return value;
+ } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
+ throw new CastError('Decimal128', value, this.path, null, this);
+ }
+
+ // Handle the case where user directly sets a populated
+ // path to a plain object; cast to the Model used in
+ // the population query.
+ const path = doc.$__fullPath(this.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ const pop = owner.populated(path, true);
+ let ret = value;
+ if (!doc.$__.populated ||
+ !doc.$__.populated[path] ||
+ !doc.$__.populated[path].options ||
+ !doc.$__.populated[path].options.options ||
+ !doc.$__.populated[path].options.options.lean) {
+ ret = new pop.options[populateModelSymbol](value);
+ ret.$__.wasPopulated = true;
+ }
+
+ return ret;
+ }
+
+ const castDecimal128 = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ Decimal128.cast();
+ try {
+ return castDecimal128(value);
+ } catch (error) {
+ throw new CastError('Decimal128', value, this.path, error, this);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function handleSingle(val) {
+ return this.cast(val);
+}
+
+Decimal128.prototype.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle
+ });
+
+/*!
+ * Module exports.
+ */
+
+module.exports = Decimal128;
diff --git a/node_modules/mongoose/lib/schema/documentarray.js b/node_modules/mongoose/lib/schema/documentarray.js
new file mode 100644
index 0000000..3ec0e3c
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/documentarray.js
@@ -0,0 +1,512 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const ArrayType = require('./array');
+const CastError = require('../error/cast');
+const EventEmitter = require('events').EventEmitter;
+const SchemaDocumentArrayOptions =
+ require('../options/SchemaDocumentArrayOptions');
+const SchemaType = require('../schematype');
+const ValidationError = require('../error/validation');
+const discriminator = require('../helpers/model/discriminator');
+const get = require('../helpers/get');
+const handleIdOption = require('../helpers/schema/handleIdOption');
+const util = require('util');
+const utils = require('../utils');
+const getConstructor = require('../helpers/discriminator/getConstructor');
+
+const arrayPathSymbol = require('../helpers/symbols').arrayPathSymbol;
+const documentArrayParent = require('../helpers/symbols').documentArrayParent;
+
+let MongooseDocumentArray;
+let Subdocument;
+
+/**
+ * SubdocsArray SchemaType constructor
+ *
+ * @param {String} key
+ * @param {Schema} schema
+ * @param {Object} options
+ * @inherits SchemaArray
+ * @api public
+ */
+
+function DocumentArrayPath(key, schema, options, schemaOptions) {
+ if (schemaOptions != null && schemaOptions._id != null) {
+ schema = handleIdOption(schema, schemaOptions);
+ } else if (options != null && options._id != null) {
+ schema = handleIdOption(schema, options);
+ }
+
+ const EmbeddedDocument = _createConstructor(schema, options);
+ EmbeddedDocument.prototype.$basePath = key;
+
+ ArrayType.call(this, key, EmbeddedDocument, options);
+
+ this.schema = schema;
+ this.schemaOptions = schemaOptions || {};
+ this.$isMongooseDocumentArray = true;
+ this.Constructor = EmbeddedDocument;
+
+ EmbeddedDocument.base = schema.base;
+
+ const fn = this.defaultValue;
+
+ if (!('defaultValue' in this) || fn !== void 0) {
+ this.default(function() {
+ let arr = fn.call(this);
+ if (!Array.isArray(arr)) {
+ arr = [arr];
+ }
+ // Leave it up to `cast()` to convert this to a documentarray
+ return arr;
+ });
+ }
+
+ const parentSchemaType = this;
+ this.$embeddedSchemaType = new SchemaType(key + '.$', {
+ required: get(this, 'schemaOptions.required', false)
+ });
+ this.$embeddedSchemaType.cast = function(value, doc, init) {
+ return parentSchemaType.cast(value, doc, init)[0];
+ };
+ this.$embeddedSchemaType.$isMongooseDocumentArrayElement = true;
+ this.$embeddedSchemaType.caster = this.Constructor;
+ this.$embeddedSchemaType.schema = this.schema;
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+DocumentArrayPath.schemaName = 'DocumentArray';
+
+/**
+ * Options for all document arrays.
+ *
+ * - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
+ *
+ * @api public
+ */
+
+DocumentArrayPath.options = { castNonArrays: true };
+
+/*!
+ * Inherits from ArrayType.
+ */
+DocumentArrayPath.prototype = Object.create(ArrayType.prototype);
+DocumentArrayPath.prototype.constructor = DocumentArrayPath;
+DocumentArrayPath.prototype.OptionsConstructor = SchemaDocumentArrayOptions;
+
+/*!
+ * Ignore
+ */
+
+function _createConstructor(schema, options, baseClass) {
+ Subdocument || (Subdocument = require('../types/embedded'));
+
+ // compile an embedded document for this schema
+ function EmbeddedDocument() {
+ Subdocument.apply(this, arguments);
+
+ this.$session(this.ownerDocument().$session());
+ }
+
+ const proto = baseClass != null ? baseClass.prototype : Subdocument.prototype;
+ EmbeddedDocument.prototype = Object.create(proto);
+ EmbeddedDocument.prototype.$__setSchema(schema);
+ EmbeddedDocument.schema = schema;
+ EmbeddedDocument.prototype.constructor = EmbeddedDocument;
+ EmbeddedDocument.$isArraySubdocument = true;
+ EmbeddedDocument.events = new EventEmitter();
+
+ // apply methods
+ for (const i in schema.methods) {
+ EmbeddedDocument.prototype[i] = schema.methods[i];
+ }
+
+ // apply statics
+ for (const i in schema.statics) {
+ EmbeddedDocument[i] = schema.statics[i];
+ }
+
+ for (const i in EventEmitter.prototype) {
+ EmbeddedDocument[i] = EventEmitter.prototype[i];
+ }
+
+ EmbeddedDocument.options = options;
+
+ return EmbeddedDocument;
+}
+
+/**
+ * Adds a discriminator to this document array.
+ *
+ * ####Example:
+ * const shapeSchema = Schema({ name: String }, { discriminatorKey: 'kind' });
+ * const schema = Schema({ shapes: [shapeSchema] });
+ *
+ * const docArrayPath = parentSchema.path('shapes');
+ * docArrayPath.discriminator('Circle', Schema({ radius: Number }));
+ *
+ * @param {String} name
+ * @param {Schema} schema fields to add to the schema for instances of this sub-class
+ * @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
+ * @see discriminators /docs/discriminators.html
+ * @return {Function} the constructor Mongoose will use for creating instances of this discriminator model
+ * @api public
+ */
+
+DocumentArrayPath.prototype.discriminator = function(name, schema, tiedValue) {
+ if (typeof name === 'function') {
+ name = utils.getFunctionName(name);
+ }
+
+ schema = discriminator(this.casterConstructor, name, schema, tiedValue);
+
+ const EmbeddedDocument = _createConstructor(schema, null, this.casterConstructor);
+ EmbeddedDocument.baseCasterConstructor = this.casterConstructor;
+
+ try {
+ Object.defineProperty(EmbeddedDocument, 'name', {
+ value: name
+ });
+ } catch (error) {
+ // Ignore error, only happens on old versions of node
+ }
+
+ this.casterConstructor.discriminators[name] = EmbeddedDocument;
+
+ return this.casterConstructor.discriminators[name];
+};
+
+/**
+ * Performs local validations first, then validations on each embedded doc
+ *
+ * @api private
+ */
+
+DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
+ // lazy load
+ MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentarray'));
+
+ const _this = this;
+ try {
+ SchemaType.prototype.doValidate.call(this, array, cb, scope);
+ } catch (err) {
+ err.$isArrayValidatorError = true;
+ return fn(err);
+ }
+
+ function cb(err) {
+ if (err) {
+ err.$isArrayValidatorError = true;
+ return fn(err);
+ }
+
+ let count = array && array.length;
+ let error;
+
+ if (!count) {
+ return fn();
+ }
+ if (options && options.updateValidator) {
+ return fn();
+ }
+ if (!array.isMongooseDocumentArray) {
+ array = new MongooseDocumentArray(array, _this.path, scope);
+ }
+
+ // handle sparse arrays, do not use array.forEach which does not
+ // iterate over sparse elements yet reports array.length including
+ // them :(
+
+ function callback(err) {
+ if (err != null) {
+ error = err;
+ if (!(error instanceof ValidationError)) {
+ error.$isArrayValidatorError = true;
+ }
+ }
+ --count || fn(error);
+ }
+
+ for (let i = 0, len = count; i < len; ++i) {
+ // sidestep sparse entries
+ let doc = array[i];
+ if (doc == null) {
+ --count || fn(error);
+ continue;
+ }
+
+ // If you set the array index directly, the doc might not yet be
+ // a full fledged mongoose subdoc, so make it into one.
+ if (!(doc instanceof Subdocument)) {
+ const Constructor = getConstructor(_this.casterConstructor, array[i]);
+ doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
+ }
+
+ doc.$__validate(callback);
+ }
+ }
+};
+
+/**
+ * Performs local validations first, then validations on each embedded doc.
+ *
+ * ####Note:
+ *
+ * This method ignores the asynchronous validators.
+ *
+ * @return {MongooseError|undefined}
+ * @api private
+ */
+
+DocumentArrayPath.prototype.doValidateSync = function(array, scope) {
+ const schemaTypeError = SchemaType.prototype.doValidateSync.call(this, array, scope);
+ if (schemaTypeError != null) {
+ schemaTypeError.$isArrayValidatorError = true;
+ return schemaTypeError;
+ }
+
+ const count = array && array.length;
+ let resultError = null;
+
+ if (!count) {
+ return;
+ }
+
+ // handle sparse arrays, do not use array.forEach which does not
+ // iterate over sparse elements yet reports array.length including
+ // them :(
+
+ for (let i = 0, len = count; i < len; ++i) {
+ // sidestep sparse entries
+ let doc = array[i];
+ if (!doc) {
+ continue;
+ }
+
+ // If you set the array index directly, the doc might not yet be
+ // a full fledged mongoose subdoc, so make it into one.
+ if (!(doc instanceof Subdocument)) {
+ const Constructor = getConstructor(this.casterConstructor, array[i]);
+ doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
+ }
+
+ const subdocValidateError = doc.validateSync();
+
+ if (subdocValidateError && resultError == null) {
+ resultError = subdocValidateError;
+ }
+ }
+
+ return resultError;
+};
+
+/*!
+ * ignore
+ */
+
+DocumentArrayPath.prototype.getDefault = function(scope) {
+ let ret = typeof this.defaultValue === 'function'
+ ? this.defaultValue.call(scope)
+ : this.defaultValue;
+
+ if (ret == null) {
+ return ret;
+ }
+
+ // lazy load
+ MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentarray'));
+
+ if (!Array.isArray(ret)) {
+ ret = [ret];
+ }
+
+ ret = new MongooseDocumentArray(ret, this.path, scope);
+
+ for (let i = 0; i < ret.length; ++i) {
+ const Constructor = getConstructor(this.casterConstructor, ret[i]);
+ const _subdoc = new Constructor({}, ret, undefined,
+ undefined, i);
+ _subdoc.init(ret[i]);
+ _subdoc.isNew = true;
+
+ // Make sure all paths in the subdoc are set to `default` instead
+ // of `init` since we used `init`.
+ Object.assign(_subdoc.$__.activePaths.default, _subdoc.$__.activePaths.init);
+ _subdoc.$__.activePaths.init = {};
+
+ ret[i] = _subdoc;
+ }
+
+ return ret;
+};
+
+/**
+ * Casts contents
+ *
+ * @param {Object} value
+ * @param {Document} document that triggers the casting
+ * @api private
+ */
+
+DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
+ // lazy load
+ MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentarray'));
+
+ let selected;
+ let subdoc;
+ const _opts = { transform: false, virtuals: false };
+
+ if (!Array.isArray(value)) {
+ if (!init && !DocumentArrayPath.options.castNonArrays) {
+ throw new CastError('DocumentArray', util.inspect(value), this.path, null, this);
+ }
+ // gh-2442 mark whole array as modified if we're initializing a doc from
+ // the db and the path isn't an array in the document
+ if (!!doc && init) {
+ doc.markModified(this.path);
+ }
+ return this.cast([value], doc, init, prev);
+ }
+
+ if (!(value && value.isMongooseDocumentArray) &&
+ (!options || !options.skipDocumentArrayCast)) {
+ value = new MongooseDocumentArray(value, this.path, doc);
+ } else if (value && value.isMongooseDocumentArray) {
+ // We need to create a new array, otherwise change tracking will
+ // update the old doc (gh-4449)
+ value = new MongooseDocumentArray(value, this.path, doc);
+ }
+
+ const len = value.length;
+
+ for (let i = 0; i < len; ++i) {
+ if (!value[i]) {
+ continue;
+ }
+
+ const Constructor = getConstructor(this.casterConstructor, value[i]);
+
+ // Check if the document has a different schema (re gh-3701)
+ if ((value[i].$__) &&
+ (!(value[i] instanceof Constructor) || value[i][documentArrayParent] !== doc)) {
+ value[i] = value[i].toObject({
+ transform: false,
+ // Special case: if different model, but same schema, apply virtuals
+ // re: gh-7898
+ virtuals: value[i].schema === Constructor.schema
+ });
+ }
+
+ if (value[i] instanceof Subdocument) {
+ // Might not have the correct index yet, so ensure it does.
+ if (value[i].__index == null) {
+ value[i].$setIndex(i);
+ }
+ } else if (value[i] != null) {
+ if (init) {
+ if (doc) {
+ selected || (selected = scopePaths(this, doc.$__.selected, init));
+ } else {
+ selected = true;
+ }
+
+ subdoc = new Constructor(null, value, true, selected, i);
+ value[i] = subdoc.init(value[i]);
+ } else {
+ if (prev && typeof prev.id === 'function') {
+ subdoc = prev.id(value[i]._id);
+ }
+
+ if (prev && subdoc && utils.deepEqual(subdoc.toObject(_opts), value[i])) {
+ // handle resetting doc with existing id and same data
+ subdoc.set(value[i]);
+ // if set() is hooked it will have no return value
+ // see gh-746
+ value[i] = subdoc;
+ } else {
+ try {
+ subdoc = new Constructor(value[i], value, undefined,
+ undefined, i);
+ // if set() is hooked it will have no return value
+ // see gh-746
+ value[i] = subdoc;
+ } catch (error) {
+ const valueInErrorMessage = util.inspect(value[i]);
+ throw new CastError('embedded', valueInErrorMessage,
+ value[arrayPathSymbol], error, this);
+ }
+ }
+ }
+ }
+ }
+
+ return value;
+};
+
+/*!
+ * ignore
+ */
+
+DocumentArrayPath.prototype.clone = function() {
+ const options = Object.assign({}, this.options);
+ const schematype = new this.constructor(this.path, this.schema, options, this.schemaOptions);
+ schematype.validators = this.validators.slice();
+ schematype.Constructor.discriminators = Object.assign({},
+ this.Constructor.discriminators);
+ return schematype;
+};
+
+/*!
+ * Scopes paths selected in a query to this array.
+ * Necessary for proper default application of subdocument values.
+ *
+ * @param {DocumentArrayPath} array - the array to scope `fields` paths
+ * @param {Object|undefined} fields - the root fields selected in the query
+ * @param {Boolean|undefined} init - if we are being created part of a query result
+ */
+
+function scopePaths(array, fields, init) {
+ if (!(init && fields)) {
+ return undefined;
+ }
+
+ const path = array.path + '.';
+ const keys = Object.keys(fields);
+ let i = keys.length;
+ const selected = {};
+ let hasKeys;
+ let key;
+ let sub;
+
+ while (i--) {
+ key = keys[i];
+ if (key.startsWith(path)) {
+ sub = key.substring(path.length);
+ if (sub === '$') {
+ continue;
+ }
+ if (sub.startsWith('$.')) {
+ sub = sub.substr(2);
+ }
+ hasKeys || (hasKeys = true);
+ selected[sub] = fields[key];
+ }
+ }
+
+ return hasKeys && selected || undefined;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = DocumentArrayPath;
diff --git a/node_modules/mongoose/lib/schema/index.js b/node_modules/mongoose/lib/schema/index.js
new file mode 100644
index 0000000..f33b084
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/index.js
@@ -0,0 +1,37 @@
+
+/*!
+ * Module exports.
+ */
+
+'use strict';
+
+exports.String = require('./string');
+
+exports.Number = require('./number');
+
+exports.Boolean = require('./boolean');
+
+exports.DocumentArray = require('./documentarray');
+
+exports.Embedded = require('./SingleNestedPath');
+
+exports.Array = require('./array');
+
+exports.Buffer = require('./buffer');
+
+exports.Date = require('./date');
+
+exports.ObjectId = require('./objectid');
+
+exports.Mixed = require('./mixed');
+
+exports.Decimal128 = exports.Decimal = require('./decimal128');
+
+exports.Map = require('./map');
+
+// alias
+
+exports.Oid = exports.ObjectId;
+exports.Object = exports.Mixed;
+exports.Bool = exports.Boolean;
+exports.ObjectID = exports.ObjectId;
diff --git a/node_modules/mongoose/lib/schema/map.js b/node_modules/mongoose/lib/schema/map.js
new file mode 100644
index 0000000..468faea
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/map.js
@@ -0,0 +1,62 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+const MongooseMap = require('../types/map');
+const SchemaMapOptions = require('../options/SchemaMapOptions');
+const SchemaType = require('../schematype');
+/*!
+ * ignore
+ */
+
+class Map extends SchemaType {
+ constructor(key, options) {
+ super(key, options, 'Map');
+ this.$isSchemaMap = true;
+ }
+
+ set(option, value) {
+ return SchemaType.set(option, value);
+ }
+
+ cast(val, doc, init) {
+ if (val instanceof MongooseMap) {
+ return val;
+ }
+
+ if (init) {
+ const map = new MongooseMap({}, this.path, doc, this.$__schemaType);
+
+ if (val instanceof global.Map) {
+ for (const key of val.keys()) {
+ map.$init(key, map.$__schemaType.cast(val.get(key), doc, true));
+ }
+ } else {
+ for (const key of Object.keys(val)) {
+ map.$init(key, map.$__schemaType.cast(val[key], doc, true));
+ }
+ }
+
+ return map;
+ }
+
+ return new MongooseMap(val, this.path, doc, this.$__schemaType);
+ }
+
+ clone() {
+ const schematype = super.clone();
+
+ if (this.$__schemaType != null) {
+ schematype.$__schemaType = this.$__schemaType.clone();
+ }
+ return schematype;
+ }
+}
+
+Map.prototype.OptionsConstructor = SchemaMapOptions;
+
+Map.defaultOptions = {};
+
+module.exports = Map;
diff --git a/node_modules/mongoose/lib/schema/mixed.js b/node_modules/mongoose/lib/schema/mixed.js
new file mode 100644
index 0000000..88e4db6
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/mixed.js
@@ -0,0 +1,128 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const SchemaType = require('../schematype');
+const symbols = require('./symbols');
+const isObject = require('../helpers/isObject');
+
+/**
+ * Mixed SchemaType constructor.
+ *
+ * @param {String} path
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function Mixed(path, options) {
+ if (options && options.default) {
+ const def = options.default;
+ if (Array.isArray(def) && def.length === 0) {
+ // make sure empty array defaults are handled
+ options.default = Array;
+ } else if (!options.shared && isObject(def) && Object.keys(def).length === 0) {
+ // prevent odd "shared" objects between documents
+ options.default = function() {
+ return {};
+ };
+ }
+ }
+
+ SchemaType.call(this, path, options, 'Mixed');
+
+ this[symbols.schemaMixedSymbol] = true;
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+Mixed.schemaName = 'Mixed';
+
+Mixed.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+Mixed.prototype = Object.create(SchemaType.prototype);
+Mixed.prototype.constructor = Mixed;
+
+/**
+ * Attaches a getter for all Mixed paths.
+ *
+ * ####Example:
+ *
+ * // Hide the 'hidden' path
+ * mongoose.Schema.Mixed.get(v => Object.assign({}, v, { hidden: null }));
+ *
+ * const Model = mongoose.model('Test', new Schema({ test: {} }));
+ * new Model({ test: { hidden: 'Secret!' } }).test.hidden; // null
+ *
+ * @param {Function} getter
+ * @return {this}
+ * @function get
+ * @static
+ * @api public
+ */
+
+Mixed.get = SchemaType.get;
+
+/**
+ * Sets a default option for all Mixed instances.
+ *
+ * ####Example:
+ *
+ * // Make all mixed instances have `required` of true by default.
+ * mongoose.Schema.Mixed.set('required', true);
+ *
+ * const User = mongoose.model('User', new Schema({ test: mongoose.Mixed }));
+ * new User({ }).validateSync().errors.test.message; // Path `test` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+Mixed.set = SchemaType.set;
+
+/**
+ * Casts `val` for Mixed.
+ *
+ * _this is a no-op_
+ *
+ * @param {Object} value to cast
+ * @api private
+ */
+
+Mixed.prototype.cast = function(val) {
+ return val;
+};
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $cond
+ * @param {any} [val]
+ * @api private
+ */
+
+Mixed.prototype.castForQuery = function($cond, val) {
+ if (arguments.length === 2) {
+ return val;
+ }
+ return $cond;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = Mixed;
diff --git a/node_modules/mongoose/lib/schema/number.js b/node_modules/mongoose/lib/schema/number.js
new file mode 100644
index 0000000..d868b4e
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/number.js
@@ -0,0 +1,444 @@
+'use strict';
+
+/*!
+ * Module requirements.
+ */
+
+const MongooseError = require('../error/index');
+const SchemaNumberOptions = require('../options/SchemaNumberOptions');
+const SchemaType = require('../schematype');
+const castNumber = require('../cast/number');
+const handleBitwiseOperator = require('./operators/bitwise');
+const utils = require('../utils');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+const CastError = SchemaType.CastError;
+let Document;
+
+/**
+ * Number SchemaType constructor.
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaNumber(key, options) {
+ SchemaType.call(this, key, options, 'Number');
+}
+
+/**
+ * Attaches a getter for all Number instances.
+ *
+ * ####Example:
+ *
+ * // Make all numbers round down
+ * mongoose.Number.get(function(v) { return Math.floor(v); });
+ *
+ * const Model = mongoose.model('Test', new Schema({ test: Number }));
+ * new Model({ test: 3.14 }).test; // 3
+ *
+ * @param {Function} getter
+ * @return {this}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaNumber.get = SchemaType.get;
+
+/**
+ * Sets a default option for all Number instances.
+ *
+ * ####Example:
+ *
+ * // Make all numbers have option `min` equal to 0.
+ * mongoose.Schema.Number.set('min', 0);
+ *
+ * const Order = mongoose.model('Order', new Schema({ amount: Number }));
+ * new Order({ amount: -10 }).validateSync().errors.amount.message; // Path `amount` must be larger than 0.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+SchemaNumber.set = SchemaType.set;
+
+/*!
+ * ignore
+ */
+
+SchemaNumber._cast = castNumber;
+
+/**
+ * Get/set the function used to cast arbitrary values to numbers.
+ *
+ * ####Example:
+ *
+ * // Make Mongoose cast empty strings '' to 0 for paths declared as numbers
+ * const original = mongoose.Number.cast();
+ * mongoose.Number.cast(v => {
+ * if (v === '') { return 0; }
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.Number.cast(false);
+ *
+ * @param {Function} caster
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaNumber.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (typeof v !== 'number') {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaNumber.schemaName = 'Number';
+
+SchemaNumber.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaNumber.prototype = Object.create(SchemaType.prototype);
+SchemaNumber.prototype.constructor = SchemaNumber;
+SchemaNumber.prototype.OptionsConstructor = SchemaNumberOptions;
+
+/*!
+ * ignore
+ */
+
+SchemaNumber._checkRequired = v => typeof v === 'number' || v instanceof Number;
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaNumber.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaNumber.prototype.checkRequired = function checkRequired(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ SchemaNumber.checkRequired();
+
+ return _checkRequired(value);
+};
+
+/**
+ * Sets a minimum number validator.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ n: { type: Number, min: 10 })
+ * var M = db.model('M', s)
+ * var m = new M({ n: 9 })
+ * m.save(function (err) {
+ * console.error(err) // validator error
+ * m.n = 10;
+ * m.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MIN} token which will be replaced with the invalid value
+ * var min = [10, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).'];
+ * var schema = new Schema({ n: { type: Number, min: min })
+ * var M = mongoose.model('Measurement', schema);
+ * var s= new M({ n: 4 });
+ * s.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `n` (4) is beneath the limit (10).
+ * })
+ *
+ * @param {Number} value minimum number
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaNumber.prototype.min = function(value, message) {
+ if (this.minValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.minValidator;
+ }, this);
+ }
+
+ if (value !== null && value !== undefined) {
+ let msg = message || MongooseError.messages.Number.min;
+ msg = msg.replace(/{MIN}/, value);
+ this.validators.push({
+ validator: this.minValidator = function(v) {
+ return v == null || v >= value;
+ },
+ message: msg,
+ type: 'min',
+ min: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Sets a maximum number validator.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ n: { type: Number, max: 10 })
+ * var M = db.model('M', s)
+ * var m = new M({ n: 11 })
+ * m.save(function (err) {
+ * console.error(err) // validator error
+ * m.n = 10;
+ * m.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MAX} token which will be replaced with the invalid value
+ * var max = [10, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).'];
+ * var schema = new Schema({ n: { type: Number, max: max })
+ * var M = mongoose.model('Measurement', schema);
+ * var s= new M({ n: 4 });
+ * s.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `n` (4) exceeds the limit (10).
+ * })
+ *
+ * @param {Number} maximum number
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaNumber.prototype.max = function(value, message) {
+ if (this.maxValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.maxValidator;
+ }, this);
+ }
+
+ if (value !== null && value !== undefined) {
+ let msg = message || MongooseError.messages.Number.max;
+ msg = msg.replace(/{MAX}/, value);
+ this.validators.push({
+ validator: this.maxValidator = function(v) {
+ return v == null || v <= value;
+ },
+ message: msg,
+ type: 'max',
+ max: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Sets a enum validator
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ n: { type: Number, enum: [1, 2, 3] });
+ * var M = db.model('M', s);
+ *
+ * var m = new M({ n: 4 });
+ * await m.save(); // throws validation error
+ *
+ * m.n = 3;
+ * await m.save(); // succeeds
+ *
+ * @param {Array} values allowed values
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaNumber.prototype.enum = function(values, message) {
+ if (this.enumValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.enumValidator;
+ }, this);
+ }
+
+ if (!Array.isArray(values)) {
+ values = Array.prototype.slice.call(arguments);
+ message = MongooseError.messages.Number.enum;
+ }
+
+ message = message == null ? MongooseError.messages.Number.enum : message;
+
+ this.enumValidator = v => v == null || values.indexOf(v) !== -1;
+ this.validators.push({
+ validator: this.enumValidator,
+ message: message,
+ type: 'enum',
+ enumValues: values
+ });
+
+ return this;
+};
+
+/**
+ * Casts to number
+ *
+ * @param {Object} value value to cast
+ * @param {Document} doc document that triggers the casting
+ * @param {Boolean} init
+ * @api private
+ */
+
+SchemaNumber.prototype.cast = function(value, doc, init) {
+ if (SchemaType._isRef(this, value, doc, init)) {
+ // wait! we may need to cast this to a document
+
+ if (value === null || value === undefined) {
+ return value;
+ }
+
+ // lazy load
+ Document || (Document = require('./../document'));
+
+ if (value instanceof Document) {
+ value.$__.wasPopulated = true;
+ return value;
+ }
+
+ // setting a populated path
+ if (typeof value === 'number') {
+ return value;
+ } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
+ throw new CastError('number', value, this.path, null, this);
+ }
+
+ // Handle the case where user directly sets a populated
+ // path to a plain object; cast to the Model used in
+ // the population query.
+ const path = doc.$__fullPath(this.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ const pop = owner.populated(path, true);
+ const ret = new pop.options[populateModelSymbol](value);
+ ret.$__.wasPopulated = true;
+ return ret;
+ }
+
+ const val = value && typeof value._id !== 'undefined' ?
+ value._id : // documents
+ value;
+
+ const castNumber = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ SchemaNumber.cast();
+ try {
+ return castNumber(val);
+ } catch (err) {
+ throw new CastError('number', val, this.path, err, this);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function handleSingle(val) {
+ return this.cast(val);
+}
+
+function handleArray(val) {
+ const _this = this;
+ if (!Array.isArray(val)) {
+ return [this.cast(val)];
+ }
+ return val.map(function(m) {
+ return _this.cast(m);
+ });
+}
+
+SchemaNumber.prototype.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $bitsAllClear: handleBitwiseOperator,
+ $bitsAnyClear: handleBitwiseOperator,
+ $bitsAllSet: handleBitwiseOperator,
+ $bitsAnySet: handleBitwiseOperator,
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle,
+ $mod: handleArray
+ });
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} [value]
+ * @api private
+ */
+
+SchemaNumber.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+ if (!handler) {
+ throw new CastError('number', val, this.path, null, this);
+ }
+ return handler.call(this, val);
+ }
+ val = this._castForQuery($conditional);
+ return val;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaNumber;
diff --git a/node_modules/mongoose/lib/schema/objectid.js b/node_modules/mongoose/lib/schema/objectid.js
new file mode 100644
index 0000000..aa7b4fb
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/objectid.js
@@ -0,0 +1,319 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const SchemaObjectIdOptions = require('../options/SchemaObjectIdOptions');
+const SchemaType = require('../schematype');
+const castObjectId = require('../cast/objectid');
+const oid = require('../types/objectid');
+const utils = require('../utils');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+const CastError = SchemaType.CastError;
+let Document;
+
+/**
+ * ObjectId SchemaType constructor.
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function ObjectId(key, options) {
+ const isKeyHexStr = typeof key === 'string' && key.length === 24 && /^[a-f0-9]+$/i.test(key);
+ const suppressWarning = options && options.suppressWarning;
+ if ((isKeyHexStr || typeof key === 'undefined') && !suppressWarning) {
+ console.warn('mongoose: To create a new ObjectId please try ' +
+ '`Mongoose.Types.ObjectId` instead of using ' +
+ '`Mongoose.Schema.ObjectId`. Set the `suppressWarning` option if ' +
+ 'you\'re trying to create a hex char path in your schema.');
+ console.trace();
+ }
+ SchemaType.call(this, key, options, 'ObjectID');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+ObjectId.schemaName = 'ObjectId';
+
+ObjectId.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+ObjectId.prototype = Object.create(SchemaType.prototype);
+ObjectId.prototype.constructor = ObjectId;
+ObjectId.prototype.OptionsConstructor = SchemaObjectIdOptions;
+
+/**
+ * Attaches a getter for all ObjectId instances
+ *
+ * ####Example:
+ *
+ * // Always convert to string when getting an ObjectId
+ * mongoose.ObjectId.get(v => v.toString());
+ *
+ * const Model = mongoose.model('Test', new Schema({}));
+ * typeof (new Model({})._id); // 'string'
+ *
+ * @param {Function} getter
+ * @return {this}
+ * @function get
+ * @static
+ * @api public
+ */
+
+ObjectId.get = SchemaType.get;
+
+/**
+ * Sets a default option for all ObjectId instances.
+ *
+ * ####Example:
+ *
+ * // Make all object ids have option `required` equal to true.
+ * mongoose.Schema.ObjectId.set('required', true);
+ *
+ * const Order = mongoose.model('Order', new Schema({ userId: ObjectId }));
+ * new Order({ }).validateSync().errors.userId.message; // Path `userId` is required.
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+ObjectId.set = SchemaType.set;
+
+/**
+ * Adds an auto-generated ObjectId default if turnOn is true.
+ * @param {Boolean} turnOn auto generated ObjectId defaults
+ * @api public
+ * @return {SchemaType} this
+ */
+
+ObjectId.prototype.auto = function(turnOn) {
+ if (turnOn) {
+ this.default(defaultId);
+ this.set(resetId);
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+ObjectId._checkRequired = v => v instanceof oid;
+
+/*!
+ * ignore
+ */
+
+ObjectId._cast = castObjectId;
+
+/**
+ * Get/set the function used to cast arbitrary values to objectids.
+ *
+ * ####Example:
+ *
+ * // Make Mongoose only try to cast length 24 strings. By default, any 12
+ * // char string is a valid ObjectId.
+ * const original = mongoose.ObjectId.cast();
+ * mongoose.ObjectId.cast(v => {
+ * assert.ok(typeof v !== 'string' || v.length === 24);
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.ObjectId.cast(false);
+ *
+ * @param {Function} caster
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+ObjectId.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (!(v instanceof oid)) {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * ####Example:
+ *
+ * // Allow empty strings to pass `required` check
+ * mongoose.Schema.Types.String.checkRequired(v => v != null);
+ *
+ * const M = mongoose.model({ str: { type: String, required: true } });
+ * new M({ str: '' }).validateSync(); // `null`, validation passes!
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+ObjectId.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Check if the given value satisfies a required validator.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+ObjectId.prototype.checkRequired = function checkRequired(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ ObjectId.checkRequired();
+
+ return _checkRequired(value);
+};
+
+/**
+ * Casts to ObjectId
+ *
+ * @param {Object} value
+ * @param {Object} doc
+ * @param {Boolean} init whether this is an initialization cast
+ * @api private
+ */
+
+ObjectId.prototype.cast = function(value, doc, init) {
+ if (SchemaType._isRef(this, value, doc, init)) {
+ // wait! we may need to cast this to a document
+
+ if (value === null || value === undefined) {
+ return value;
+ }
+
+ // lazy load
+ Document || (Document = require('./../document'));
+
+ if (value instanceof Document) {
+ value.$__.wasPopulated = true;
+ return value;
+ }
+
+ // setting a populated path
+ if (value instanceof oid) {
+ return value;
+ } else if ((value.constructor.name || '').toLowerCase() === 'objectid') {
+ return new oid(value.toHexString());
+ } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
+ throw new CastError('ObjectId', value, this.path, null, this);
+ }
+
+ // Handle the case where user directly sets a populated
+ // path to a plain object; cast to the Model used in
+ // the population query.
+ const path = doc.$__fullPath(this.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ const pop = owner.populated(path, true);
+ let ret = value;
+ if (!doc.$__.populated ||
+ !doc.$__.populated[path] ||
+ !doc.$__.populated[path].options ||
+ !doc.$__.populated[path].options.options ||
+ !doc.$__.populated[path].options.options.lean) {
+ ret = new pop.options[populateModelSymbol](value);
+ ret.$__.wasPopulated = true;
+ }
+
+ return ret;
+ }
+
+ const castObjectId = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ ObjectId.cast();
+ try {
+ return castObjectId(value);
+ } catch (error) {
+ throw new CastError('ObjectId', value, this.path, error, this);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function handleSingle(val) {
+ return this.cast(val);
+}
+
+ObjectId.prototype.$conditionalHandlers =
+ utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle
+ });
+
+/*!
+ * ignore
+ */
+
+function defaultId() {
+ return new oid();
+}
+
+defaultId.$runBeforeSetters = true;
+
+function resetId(v) {
+ Document || (Document = require('./../document'));
+
+ if (this instanceof Document) {
+ if (v === void 0) {
+ const _v = new oid;
+ this.$__._id = _v;
+ return _v;
+ }
+
+ this.$__._id = v;
+ }
+
+ return v;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = ObjectId;
diff --git a/node_modules/mongoose/lib/schema/operators/bitwise.js b/node_modules/mongoose/lib/schema/operators/bitwise.js
new file mode 100644
index 0000000..07e18cd
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/bitwise.js
@@ -0,0 +1,38 @@
+/*!
+ * Module requirements.
+ */
+
+'use strict';
+
+const CastError = require('../../error/cast');
+
+/*!
+ * ignore
+ */
+
+function handleBitwiseOperator(val) {
+ const _this = this;
+ if (Array.isArray(val)) {
+ return val.map(function(v) {
+ return _castNumber(_this.path, v);
+ });
+ } else if (Buffer.isBuffer(val)) {
+ return val;
+ }
+ // Assume trying to cast to number
+ return _castNumber(_this.path, val);
+}
+
+/*!
+ * ignore
+ */
+
+function _castNumber(path, num) {
+ const v = Number(num);
+ if (isNaN(v)) {
+ throw new CastError('number', num, path);
+ }
+ return v;
+}
+
+module.exports = handleBitwiseOperator;
diff --git a/node_modules/mongoose/lib/schema/operators/exists.js b/node_modules/mongoose/lib/schema/operators/exists.js
new file mode 100644
index 0000000..916b4cb
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/exists.js
@@ -0,0 +1,12 @@
+'use strict';
+
+const castBoolean = require('../../cast/boolean');
+
+/*!
+ * ignore
+ */
+
+module.exports = function(val) {
+ const path = this != null ? this.path : null;
+ return castBoolean(val, path);
+};
diff --git a/node_modules/mongoose/lib/schema/operators/geospatial.js b/node_modules/mongoose/lib/schema/operators/geospatial.js
new file mode 100644
index 0000000..73e38f8
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/geospatial.js
@@ -0,0 +1,102 @@
+/*!
+ * Module requirements.
+ */
+
+'use strict';
+
+const castArraysOfNumbers = require('./helpers').castArraysOfNumbers;
+const castToNumber = require('./helpers').castToNumber;
+
+/*!
+ * ignore
+ */
+
+exports.cast$geoIntersects = cast$geoIntersects;
+exports.cast$near = cast$near;
+exports.cast$within = cast$within;
+
+function cast$near(val) {
+ const SchemaArray = require('../array');
+
+ if (Array.isArray(val)) {
+ castArraysOfNumbers(val, this);
+ return val;
+ }
+
+ _castMinMaxDistance(this, val);
+
+ if (val && val.$geometry) {
+ return cast$geometry(val, this);
+ }
+
+ return SchemaArray.prototype.castForQuery.call(this, val);
+}
+
+function cast$geometry(val, self) {
+ switch (val.$geometry.type) {
+ case 'Polygon':
+ case 'LineString':
+ case 'Point':
+ castArraysOfNumbers(val.$geometry.coordinates, self);
+ break;
+ default:
+ // ignore unknowns
+ break;
+ }
+
+ _castMinMaxDistance(self, val);
+
+ return val;
+}
+
+function cast$within(val) {
+ _castMinMaxDistance(this, val);
+
+ if (val.$box || val.$polygon) {
+ const type = val.$box ? '$box' : '$polygon';
+ val[type].forEach(arr => {
+ if (!Array.isArray(arr)) {
+ const msg = 'Invalid $within $box argument. '
+ + 'Expected an array, received ' + arr;
+ throw new TypeError(msg);
+ }
+ arr.forEach((v, i) => {
+ arr[i] = castToNumber.call(this, v);
+ });
+ });
+ } else if (val.$center || val.$centerSphere) {
+ const type = val.$center ? '$center' : '$centerSphere';
+ val[type].forEach((item, i) => {
+ if (Array.isArray(item)) {
+ item.forEach((v, j) => {
+ item[j] = castToNumber.call(this, v);
+ });
+ } else {
+ val[type][i] = castToNumber.call(this, item);
+ }
+ });
+ } else if (val.$geometry) {
+ cast$geometry(val, this);
+ }
+
+ return val;
+}
+
+function cast$geoIntersects(val) {
+ const geo = val.$geometry;
+ if (!geo) {
+ return;
+ }
+
+ cast$geometry(val, this);
+ return val;
+}
+
+function _castMinMaxDistance(self, val) {
+ if (val.$maxDistance) {
+ val.$maxDistance = castToNumber.call(self, val.$maxDistance);
+ }
+ if (val.$minDistance) {
+ val.$minDistance = castToNumber.call(self, val.$minDistance);
+ }
+}
diff --git a/node_modules/mongoose/lib/schema/operators/helpers.js b/node_modules/mongoose/lib/schema/operators/helpers.js
new file mode 100644
index 0000000..a17951c
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/helpers.js
@@ -0,0 +1,32 @@
+'use strict';
+
+/*!
+ * Module requirements.
+ */
+
+const SchemaNumber = require('../number');
+
+/*!
+ * @ignore
+ */
+
+exports.castToNumber = castToNumber;
+exports.castArraysOfNumbers = castArraysOfNumbers;
+
+/*!
+ * @ignore
+ */
+
+function castToNumber(val) {
+ return SchemaNumber.cast()(val);
+}
+
+function castArraysOfNumbers(arr, self) {
+ arr.forEach(function(v, i) {
+ if (Array.isArray(v)) {
+ castArraysOfNumbers(v, self);
+ } else {
+ arr[i] = castToNumber.call(self, v);
+ }
+ });
+}
diff --git a/node_modules/mongoose/lib/schema/operators/text.js b/node_modules/mongoose/lib/schema/operators/text.js
new file mode 100644
index 0000000..4b95916
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/text.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const CastError = require('../../error/cast');
+const castBoolean = require('../../cast/boolean');
+const castString = require('../../cast/string');
+
+/*!
+ * Casts val to an object suitable for `$text`. Throws an error if the object
+ * can't be casted.
+ *
+ * @param {Any} val value to cast
+ * @param {String} [path] path to associate with any errors that occured
+ * @return {Object} casted object
+ * @see https://docs.mongodb.com/manual/reference/operator/query/text/
+ * @api private
+ */
+
+module.exports = function(val, path) {
+ if (val == null || typeof val !== 'object') {
+ throw new CastError('$text', val, path);
+ }
+
+ if (val.$search != null) {
+ val.$search = castString(val.$search, path + '.$search');
+ }
+ if (val.$language != null) {
+ val.$language = castString(val.$language, path + '.$language');
+ }
+ if (val.$caseSensitive != null) {
+ val.$caseSensitive = castBoolean(val.$caseSensitive,
+ path + '.$castSensitive');
+ }
+ if (val.$diacriticSensitive != null) {
+ val.$diacriticSensitive = castBoolean(val.$diacriticSensitive,
+ path + '.$diacriticSensitive');
+ }
+
+ return val;
+};
diff --git a/node_modules/mongoose/lib/schema/operators/type.js b/node_modules/mongoose/lib/schema/operators/type.js
new file mode 100644
index 0000000..c8e391a
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/operators/type.js
@@ -0,0 +1,13 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function(val) {
+ if (typeof val !== 'number' && typeof val !== 'string') {
+ throw new Error('$type parameter must be number or string');
+ }
+
+ return val;
+};
diff --git a/node_modules/mongoose/lib/schema/string.js b/node_modules/mongoose/lib/schema/string.js
new file mode 100644
index 0000000..e0771be
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/string.js
@@ -0,0 +1,675 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const SchemaType = require('../schematype');
+const MongooseError = require('../error/index');
+const SchemaStringOptions = require('../options/SchemaStringOptions');
+const castString = require('../cast/string');
+const utils = require('../utils');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+const CastError = SchemaType.CastError;
+let Document;
+
+/**
+ * String SchemaType constructor.
+ *
+ * @param {String} key
+ * @param {Object} options
+ * @inherits SchemaType
+ * @api public
+ */
+
+function SchemaString(key, options) {
+ this.enumValues = [];
+ this.regExp = null;
+ SchemaType.call(this, key, options, 'String');
+}
+
+/**
+ * This schema type's name, to defend against minifiers that mangle
+ * function names.
+ *
+ * @api public
+ */
+SchemaString.schemaName = 'String';
+
+SchemaString.defaultOptions = {};
+
+/*!
+ * Inherits from SchemaType.
+ */
+SchemaString.prototype = Object.create(SchemaType.prototype);
+SchemaString.prototype.constructor = SchemaString;
+Object.defineProperty(SchemaString.prototype, 'OptionsConstructor', {
+ configurable: false,
+ enumerable: false,
+ writable: false,
+ value: SchemaStringOptions
+});
+
+/*!
+ * ignore
+ */
+
+SchemaString._cast = castString;
+
+/**
+ * Get/set the function used to cast arbitrary values to strings.
+ *
+ * ####Example:
+ *
+ * // Throw an error if you pass in an object. Normally, Mongoose allows
+ * // objects with custom `toString()` functions.
+ * const original = mongoose.Schema.Types.String.cast();
+ * mongoose.Schema.Types.String.cast(v => {
+ * assert.ok(v == null || typeof v !== 'object');
+ * return original(v);
+ * });
+ *
+ * // Or disable casting entirely
+ * mongoose.Schema.Types.String.cast(false);
+ *
+ * @param {Function} caster
+ * @return {Function}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaString.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => {
+ if (v != null && typeof v !== 'string') {
+ throw new Error();
+ }
+ return v;
+ };
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/**
+ * Attaches a getter for all String instances.
+ *
+ * ####Example:
+ *
+ * // Make all numbers round down
+ * mongoose.Schema.String.get(v => v.toLowerCase());
+ *
+ * const Model = mongoose.model('Test', new Schema({ test: String }));
+ * new Model({ test: 'FOO' }).test; // 'foo'
+ *
+ * @param {Function} getter
+ * @return {this}
+ * @function get
+ * @static
+ * @api public
+ */
+
+SchemaString.get = SchemaType.get;
+
+/**
+ * Sets a default option for all String instances.
+ *
+ * ####Example:
+ *
+ * // Make all strings have option `trim` equal to true.
+ * mongoose.Schema.String.set('trim', true);
+ *
+ * const User = mongoose.model('User', new Schema({ name: String }));
+ * new User({ name: ' John Doe ' }).name; // 'John Doe'
+ *
+ * @param {String} option - The option you'd like to set the value for
+ * @param {*} value - value for option
+ * @return {undefined}
+ * @function set
+ * @static
+ * @api public
+ */
+
+SchemaString.set = SchemaType.set;
+
+/*!
+ * ignore
+ */
+
+SchemaString._checkRequired = v => (v instanceof String || typeof v === 'string') && v.length;
+
+/**
+ * Override the function the required validator uses to check whether a string
+ * passes the `required` check.
+ *
+ * ####Example:
+ *
+ * // Allow empty strings to pass `required` check
+ * mongoose.Schema.Types.String.checkRequired(v => v != null);
+ *
+ * const M = mongoose.model({ str: { type: String, required: true } });
+ * new M({ str: '' }).validateSync(); // `null`, validation passes!
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @function checkRequired
+ * @static
+ * @api public
+ */
+
+SchemaString.checkRequired = SchemaType.checkRequired;
+
+/**
+ * Adds an enum validator
+ *
+ * ####Example:
+ *
+ * var states = ['opening', 'open', 'closing', 'closed']
+ * var s = new Schema({ state: { type: String, enum: states }})
+ * var M = db.model('M', s)
+ * var m = new M({ state: 'invalid' })
+ * m.save(function (err) {
+ * console.error(String(err)) // ValidationError: `invalid` is not a valid enum value for path `state`.
+ * m.state = 'open'
+ * m.save(callback) // success
+ * })
+ *
+ * // or with custom error messages
+ * var enum = {
+ * values: ['opening', 'open', 'closing', 'closed'],
+ * message: 'enum validator failed for path `{PATH}` with value `{VALUE}`'
+ * }
+ * var s = new Schema({ state: { type: String, enum: enum })
+ * var M = db.model('M', s)
+ * var m = new M({ state: 'invalid' })
+ * m.save(function (err) {
+ * console.error(String(err)) // ValidationError: enum validator failed for path `state` with value `invalid`
+ * m.state = 'open'
+ * m.save(callback) // success
+ * })
+ *
+ * @param {String|Object} [args...] enumeration values
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaString.prototype.enum = function() {
+ if (this.enumValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.enumValidator;
+ }, this);
+ this.enumValidator = false;
+ }
+
+ if (arguments[0] === void 0 || arguments[0] === false) {
+ return this;
+ }
+
+ let values;
+ let errorMessage;
+
+ if (utils.isObject(arguments[0])) {
+ values = arguments[0].values;
+ errorMessage = arguments[0].message;
+ } else {
+ values = arguments;
+ errorMessage = MongooseError.messages.String.enum;
+ }
+
+ for (let i = 0; i < values.length; i++) {
+ if (undefined !== values[i]) {
+ this.enumValues.push(this.cast(values[i]));
+ }
+ }
+
+ const vals = this.enumValues;
+ this.enumValidator = function(v) {
+ return undefined === v || ~vals.indexOf(v);
+ };
+ this.validators.push({
+ validator: this.enumValidator,
+ message: errorMessage,
+ type: 'enum',
+ enumValues: vals
+ });
+
+ return this;
+};
+
+/**
+ * Adds a lowercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ email: { type: String, lowercase: true }})
+ * var M = db.model('M', s);
+ * var m = new M({ email: 'SomeEmail@example.COM' });
+ * console.log(m.email) // someemail@example.com
+ * M.find({ email: 'SomeEmail@example.com' }); // Queries by 'someemail@example.com'
+ *
+ * Note that `lowercase` does **not** affect regular expression queries:
+ *
+ * ####Example:
+ * // Still queries for documents whose `email` matches the regular
+ * // expression /SomeEmail/. Mongoose does **not** convert the RegExp
+ * // to lowercase.
+ * M.find({ email: /SomeEmail/ });
+ *
+ * @api public
+ * @return {SchemaType} this
+ */
+
+SchemaString.prototype.lowercase = function(shouldApply) {
+ if (arguments.length > 0 && !shouldApply) {
+ return this;
+ }
+ return this.set(function(v, self) {
+ if (typeof v !== 'string') {
+ v = self.cast(v);
+ }
+ if (v) {
+ return v.toLowerCase();
+ }
+ return v;
+ });
+};
+
+/**
+ * Adds an uppercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ caps: { type: String, uppercase: true }})
+ * var M = db.model('M', s);
+ * var m = new M({ caps: 'an example' });
+ * console.log(m.caps) // AN EXAMPLE
+ * M.find({ caps: 'an example' }) // Matches documents where caps = 'AN EXAMPLE'
+ *
+ * Note that `uppercase` does **not** affect regular expression queries:
+ *
+ * ####Example:
+ * // Mongoose does **not** convert the RegExp to uppercase.
+ * M.find({ email: /an example/ });
+ *
+ * @api public
+ * @return {SchemaType} this
+ */
+
+SchemaString.prototype.uppercase = function(shouldApply) {
+ if (arguments.length > 0 && !shouldApply) {
+ return this;
+ }
+ return this.set(function(v, self) {
+ if (typeof v !== 'string') {
+ v = self.cast(v);
+ }
+ if (v) {
+ return v.toUpperCase();
+ }
+ return v;
+ });
+};
+
+/**
+ * Adds a trim [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
+ *
+ * The string value will be trimmed when set.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ name: { type: String, trim: true }});
+ * var M = db.model('M', s);
+ * var string = ' some name ';
+ * console.log(string.length); // 11
+ * var m = new M({ name: string });
+ * console.log(m.name.length); // 9
+ *
+ * // Equivalent to `findOne({ name: string.trim() })`
+ * M.findOne({ name: string });
+ *
+ * Note that `trim` does **not** affect regular expression queries:
+ *
+ * ####Example:
+ * // Mongoose does **not** trim whitespace from the RegExp.
+ * M.find({ name: / some name / });
+ *
+ * @api public
+ * @return {SchemaType} this
+ */
+
+SchemaString.prototype.trim = function(shouldTrim) {
+ if (arguments.length > 0 && !shouldTrim) {
+ return this;
+ }
+ return this.set(function(v, self) {
+ if (typeof v !== 'string') {
+ v = self.cast(v);
+ }
+ if (v) {
+ return v.trim();
+ }
+ return v;
+ });
+};
+
+/**
+ * Sets a minimum length validator.
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ postalCode: { type: String, minlength: 5 })
+ * var Address = db.model('Address', schema)
+ * var address = new Address({ postalCode: '9512' })
+ * address.save(function (err) {
+ * console.error(err) // validator error
+ * address.postalCode = '95125';
+ * address.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MINLENGTH} token which will be replaced with the minimum allowed length
+ * var minlength = [5, 'The value of path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).'];
+ * var schema = new Schema({ postalCode: { type: String, minlength: minlength })
+ * var Address = mongoose.model('Address', schema);
+ * var address = new Address({ postalCode: '9512' });
+ * address.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `postalCode` (`9512`) is shorter than the minimum length (5).
+ * })
+ *
+ * @param {Number} value minimum string length
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaString.prototype.minlength = function(value, message) {
+ if (this.minlengthValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.minlengthValidator;
+ }, this);
+ }
+
+ if (value !== null && value !== undefined) {
+ let msg = message || MongooseError.messages.String.minlength;
+ msg = msg.replace(/{MINLENGTH}/, value);
+ this.validators.push({
+ validator: this.minlengthValidator = function(v) {
+ return v === null || v.length >= value;
+ },
+ message: msg,
+ type: 'minlength',
+ minlength: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Sets a maximum length validator.
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ postalCode: { type: String, maxlength: 9 })
+ * var Address = db.model('Address', schema)
+ * var address = new Address({ postalCode: '9512512345' })
+ * address.save(function (err) {
+ * console.error(err) // validator error
+ * address.postalCode = '95125';
+ * address.save() // success
+ * })
+ *
+ * // custom error messages
+ * // We can also use the special {MAXLENGTH} token which will be replaced with the maximum allowed length
+ * var maxlength = [9, 'The value of path `{PATH}` (`{VALUE}`) exceeds the maximum allowed length ({MAXLENGTH}).'];
+ * var schema = new Schema({ postalCode: { type: String, maxlength: maxlength })
+ * var Address = mongoose.model('Address', schema);
+ * var address = new Address({ postalCode: '9512512345' });
+ * address.validate(function (err) {
+ * console.log(String(err)) // ValidationError: The value of path `postalCode` (`9512512345`) exceeds the maximum allowed length (9).
+ * })
+ *
+ * @param {Number} value maximum string length
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaString.prototype.maxlength = function(value, message) {
+ if (this.maxlengthValidator) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.maxlengthValidator;
+ }, this);
+ }
+
+ if (value !== null && value !== undefined) {
+ let msg = message || MongooseError.messages.String.maxlength;
+ msg = msg.replace(/{MAXLENGTH}/, value);
+ this.validators.push({
+ validator: this.maxlengthValidator = function(v) {
+ return v === null || v.length <= value;
+ },
+ message: msg,
+ type: 'maxlength',
+ maxlength: value
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Sets a regexp validator.
+ *
+ * Any value that does not pass `regExp`.test(val) will fail validation.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ name: { type: String, match: /^a/ }})
+ * var M = db.model('M', s)
+ * var m = new M({ name: 'I am invalid' })
+ * m.validate(function (err) {
+ * console.error(String(err)) // "ValidationError: Path `name` is invalid (I am invalid)."
+ * m.name = 'apples'
+ * m.validate(function (err) {
+ * assert.ok(err) // success
+ * })
+ * })
+ *
+ * // using a custom error message
+ * var match = [ /\.html$/, "That file doesn't end in .html ({VALUE})" ];
+ * var s = new Schema({ file: { type: String, match: match }})
+ * var M = db.model('M', s);
+ * var m = new M({ file: 'invalid' });
+ * m.validate(function (err) {
+ * console.log(String(err)) // "ValidationError: That file doesn't end in .html (invalid)"
+ * })
+ *
+ * Empty strings, `undefined`, and `null` values always pass the match validator. If you require these values, enable the `required` validator also.
+ *
+ * var s = new Schema({ name: { type: String, match: /^a/, required: true }})
+ *
+ * @param {RegExp} regExp regular expression to test against
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @api public
+ */
+
+SchemaString.prototype.match = function match(regExp, message) {
+ // yes, we allow multiple match validators
+
+ const msg = message || MongooseError.messages.String.match;
+
+ const matchValidator = function(v) {
+ if (!regExp) {
+ return false;
+ }
+
+ const ret = ((v != null && v !== '')
+ ? regExp.test(v)
+ : true);
+ return ret;
+ };
+
+ this.validators.push({
+ validator: matchValidator,
+ message: msg,
+ type: 'regexp',
+ regexp: regExp
+ });
+ return this;
+};
+
+/**
+ * Check if the given value satisfies the `required` validator. The value is
+ * considered valid if it is a string (that is, not `null` or `undefined`) and
+ * has positive length. The `required` validator **will** fail for empty
+ * strings.
+ *
+ * @param {Any} value
+ * @param {Document} doc
+ * @return {Boolean}
+ * @api public
+ */
+
+SchemaString.prototype.checkRequired = function checkRequired(value, doc) {
+ if (SchemaType._isRef(this, value, doc, true)) {
+ return !!value;
+ }
+
+ // `require('util').inherits()` does **not** copy static properties, and
+ // plugins like mongoose-float use `inherits()` for pre-ES6.
+ const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
+ this.constructor.checkRequired() :
+ SchemaString.checkRequired();
+
+ return _checkRequired(value);
+};
+
+/**
+ * Casts to String
+ *
+ * @api private
+ */
+
+SchemaString.prototype.cast = function(value, doc, init) {
+ if (SchemaType._isRef(this, value, doc, init)) {
+ // wait! we may need to cast this to a document
+
+ if (value === null || value === undefined) {
+ return value;
+ }
+
+ // lazy load
+ Document || (Document = require('./../document'));
+
+ if (value instanceof Document) {
+ value.$__.wasPopulated = true;
+ return value;
+ }
+
+ // setting a populated path
+ if (typeof value === 'string') {
+ return value;
+ } else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
+ throw new CastError('string', value, this.path, null, this);
+ }
+
+ // Handle the case where user directly sets a populated
+ // path to a plain object; cast to the Model used in
+ // the population query.
+ const path = doc.$__fullPath(this.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ const pop = owner.populated(path, true);
+ const ret = new pop.options[populateModelSymbol](value);
+ ret.$__.wasPopulated = true;
+ return ret;
+ }
+
+ const castString = typeof this.constructor.cast === 'function' ?
+ this.constructor.cast() :
+ SchemaString.cast();
+ try {
+ return castString(value);
+ } catch (error) {
+ throw new CastError('string', value, this.path, null, this);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function handleSingle(val) {
+ return this.castForQuery(val);
+}
+
+function handleArray(val) {
+ const _this = this;
+ if (!Array.isArray(val)) {
+ return [this.castForQuery(val)];
+ }
+ return val.map(function(m) {
+ return _this.castForQuery(m);
+ });
+}
+
+const $conditionalHandlers = utils.options(SchemaType.prototype.$conditionalHandlers, {
+ $all: handleArray,
+ $gt: handleSingle,
+ $gte: handleSingle,
+ $lt: handleSingle,
+ $lte: handleSingle,
+ $options: String,
+ $regex: handleSingle,
+ $not: handleSingle
+});
+
+Object.defineProperty(SchemaString.prototype, '$conditionalHandlers', {
+ configurable: false,
+ enumerable: false,
+ writable: false,
+ value: Object.freeze($conditionalHandlers)
+});
+
+/**
+ * Casts contents for queries.
+ *
+ * @param {String} $conditional
+ * @param {any} [val]
+ * @api private
+ */
+
+SchemaString.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional + ' with String.');
+ }
+ return handler.call(this, val);
+ }
+ val = $conditional;
+ if (Object.prototype.toString.call(val) === '[object RegExp]') {
+ return val;
+ }
+
+ return this._castForQuery(val);
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = SchemaString;
diff --git a/node_modules/mongoose/lib/schema/symbols.js b/node_modules/mongoose/lib/schema/symbols.js
new file mode 100644
index 0000000..08d1d27
--- /dev/null
+++ b/node_modules/mongoose/lib/schema/symbols.js
@@ -0,0 +1,5 @@
+'use strict';
+
+exports.schemaMixedSymbol = Symbol.for('mongoose:schema_mixed');
+
+exports.builtInMiddleware = Symbol.for('mongoose:built-in-middleware');
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/schematype.js b/node_modules/mongoose/lib/schematype.js
new file mode 100644
index 0000000..c1e197b
--- /dev/null
+++ b/node_modules/mongoose/lib/schematype.js
@@ -0,0 +1,1495 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const MongooseError = require('./error/index');
+const SchemaTypeOptions = require('./options/SchemaTypeOptions');
+const $exists = require('./schema/operators/exists');
+const $type = require('./schema/operators/type');
+const get = require('./helpers/get');
+const handleImmutable = require('./helpers/schematype/handleImmutable');
+const immediate = require('./helpers/immediate');
+const schemaTypeSymbol = require('./helpers/symbols').schemaTypeSymbol;
+const util = require('util');
+const utils = require('./utils');
+const validatorErrorSymbol = require('./helpers/symbols').validatorErrorSymbol;
+
+const CastError = MongooseError.CastError;
+const ValidatorError = MongooseError.ValidatorError;
+
+/**
+ * SchemaType constructor. Do **not** instantiate `SchemaType` directly.
+ * Mongoose converts your schema paths into SchemaTypes automatically.
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({ name: String });
+ * schema.path('name') instanceof SchemaType; // true
+ *
+ * @param {String} path
+ * @param {SchemaTypeOptions} [options] See [SchemaTypeOptions docs](/docs/api/schematypeoptions.html)
+ * @param {String} [instance]
+ * @api public
+ */
+
+function SchemaType(path, options, instance) {
+ this[schemaTypeSymbol] = true;
+ this.path = path;
+ this.instance = instance;
+ this.validators = [];
+ this.getters = this.constructor.hasOwnProperty('getters') ?
+ this.constructor.getters.slice() :
+ [];
+ this.setters = [];
+
+ options = options || {};
+ const defaultOptions = this.constructor.defaultOptions || {};
+ const defaultOptionsKeys = Object.keys(defaultOptions);
+
+ for (const option of defaultOptionsKeys) {
+ if (defaultOptions.hasOwnProperty(option) && !options.hasOwnProperty(option)) {
+ options[option] = defaultOptions[option];
+ }
+ }
+
+
+ const Options = this.OptionsConstructor || SchemaTypeOptions;
+ this.options = new Options(options);
+ this._index = null;
+ this.selected;
+ if (utils.hasUserDefinedProperty(this.options, 'immutable')) {
+ this.$immutable = this.options.immutable;
+
+ handleImmutable(this);
+ }
+
+ const keys = Object.keys(this.options);
+ for (const prop of keys) {
+ if (prop === 'cast') {
+ continue;
+ }
+ if (utils.hasUserDefinedProperty(this.options, prop) && typeof this[prop] === 'function') {
+ // { unique: true, index: true }
+ if (prop === 'index' && this._index) {
+ if (options.index === false) {
+ const index = this._index;
+ if (typeof index === 'object' && index != null) {
+ if (index.unique) {
+ throw new Error('Path "' + this.path + '" may not have `index` ' +
+ 'set to false and `unique` set to true');
+ }
+ if (index.sparse) {
+ throw new Error('Path "' + this.path + '" may not have `index` ' +
+ 'set to false and `sparse` set to true');
+ }
+ }
+
+ this._index = false;
+ }
+ continue;
+ }
+
+ const val = options[prop];
+ // Special case so we don't screw up array defaults, see gh-5780
+ if (prop === 'default') {
+ this.default(val);
+ continue;
+ }
+
+ const opts = Array.isArray(val) ? val : [val];
+
+ this[prop].apply(this, opts);
+ }
+ }
+
+ Object.defineProperty(this, '$$context', {
+ enumerable: false,
+ configurable: false,
+ writable: true,
+ value: null
+ });
+}
+
+/*!
+ * ignore
+ */
+
+SchemaType.prototype.OptionsConstructor = SchemaTypeOptions;
+
+/**
+ * Get/set the function used to cast arbitrary values to this type.
+ *
+ * ####Example:
+ *
+ * // Disallow `null` for numbers, and don't try to cast any values to
+ * // numbers, so even strings like '123' will cause a CastError.
+ * mongoose.Number.cast(function(v) {
+ * assert.ok(v === undefined || typeof v === 'number');
+ * return v;
+ * });
+ *
+ * @param {Function|false} caster Function that casts arbitrary values to this type, or throws an error if casting failed
+ * @return {Function}
+ * @static
+ * @receiver SchemaType
+ * @function cast
+ * @api public
+ */
+
+SchemaType.cast = function cast(caster) {
+ if (arguments.length === 0) {
+ return this._cast;
+ }
+ if (caster === false) {
+ caster = v => v;
+ }
+ this._cast = caster;
+
+ return this._cast;
+};
+
+/**
+ * Sets a default option for this schema type.
+ *
+ * ####Example:
+ *
+ * // Make all strings be trimmed by default
+ * mongoose.SchemaTypes.String.set('trim', true);
+ *
+ * @param {String} option The name of the option you'd like to set (e.g. trim, lowercase, etc...)
+ * @param {*} value The value of the option you'd like to set.
+ * @return {void}
+ * @static
+ * @receiver SchemaType
+ * @function set
+ * @api public
+ */
+
+SchemaType.set = function set(option, value) {
+ if (!this.hasOwnProperty('defaultOptions')) {
+ this.defaultOptions = Object.assign({}, this.defaultOptions);
+ }
+ this.defaultOptions[option] = value;
+};
+
+/**
+ * Attaches a getter for all instances of this schema type.
+ *
+ * ####Example:
+ *
+ * // Make all numbers round down
+ * mongoose.Number.get(function(v) { return Math.floor(v); });
+ *
+ * @param {Function} getter
+ * @return {this}
+ * @static
+ * @receiver SchemaType
+ * @function get
+ * @api public
+ */
+
+SchemaType.get = function(getter) {
+ this.getters = this.hasOwnProperty('getters') ? this.getters : [];
+ this.getters.push(getter);
+};
+
+/**
+ * Sets a default value for this SchemaType.
+ *
+ * ####Example:
+ *
+ * var schema = new Schema({ n: { type: Number, default: 10 })
+ * var M = db.model('M', schema)
+ * var m = new M;
+ * console.log(m.n) // 10
+ *
+ * Defaults can be either `functions` which return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation.
+ *
+ * ####Example:
+ *
+ * // values are cast:
+ * var schema = new Schema({ aNumber: { type: Number, default: 4.815162342 }})
+ * var M = db.model('M', schema)
+ * var m = new M;
+ * console.log(m.aNumber) // 4.815162342
+ *
+ * // default unique objects for Mixed types:
+ * var schema = new Schema({ mixed: Schema.Types.Mixed });
+ * schema.path('mixed').default(function () {
+ * return {};
+ * });
+ *
+ * // if we don't use a function to return object literals for Mixed defaults,
+ * // each document will receive a reference to the same object literal creating
+ * // a "shared" object instance:
+ * var schema = new Schema({ mixed: Schema.Types.Mixed });
+ * schema.path('mixed').default({});
+ * var M = db.model('M', schema);
+ * var m1 = new M;
+ * m1.mixed.added = 1;
+ * console.log(m1.mixed); // { added: 1 }
+ * var m2 = new M;
+ * console.log(m2.mixed); // { added: 1 }
+ *
+ * @param {Function|any} val the default value
+ * @return {defaultValue}
+ * @api public
+ */
+
+SchemaType.prototype.default = function(val) {
+ if (arguments.length === 1) {
+ if (val === void 0) {
+ this.defaultValue = void 0;
+ return void 0;
+ }
+ this.defaultValue = val;
+ return this.defaultValue;
+ } else if (arguments.length > 1) {
+ this.defaultValue = utils.args(arguments);
+ }
+ return this.defaultValue;
+};
+
+/**
+ * Declares the index options for this schematype.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ name: { type: String, index: true })
+ * var s = new Schema({ loc: { type: [Number], index: 'hashed' })
+ * var s = new Schema({ loc: { type: [Number], index: '2d', sparse: true })
+ * var s = new Schema({ loc: { type: [Number], index: { type: '2dsphere', sparse: true }})
+ * var s = new Schema({ date: { type: Date, index: { unique: true, expires: '1d' }})
+ * s.path('my.path').index(true);
+ * s.path('my.date').index({ expires: 60 });
+ * s.path('my.path').index({ unique: true, sparse: true });
+ *
+ * ####NOTE:
+ *
+ * _Indexes are created [in the background](https://docs.mongodb.com/manual/core/index-creation/#index-creation-background)
+ * by default. If `background` is set to `false`, MongoDB will not execute any
+ * read/write operations you send until the index build.
+ * Specify `background: false` to override Mongoose's default._
+ *
+ * @param {Object|Boolean|String} options
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.index = function(options) {
+ this._index = options;
+ utils.expires(this._index);
+ return this;
+};
+
+/**
+ * Declares an unique index.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ name: { type: String, unique: true }});
+ * s.path('name').index({ unique: true });
+ *
+ * _NOTE: violating the constraint returns an `E11000` error from MongoDB when saving, not a Mongoose validation error._
+ *
+ * @param {Boolean} bool
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.unique = function(bool) {
+ if (this._index === false) {
+ if (!bool) {
+ return;
+ }
+ throw new Error('Path "' + this.path + '" may not have `index` set to ' +
+ 'false and `unique` set to true');
+ }
+ if (this._index == null || this._index === true) {
+ this._index = {};
+ } else if (typeof this._index === 'string') {
+ this._index = { type: this._index };
+ }
+
+ this._index.unique = bool;
+ return this;
+};
+
+/**
+ * Declares a full text index.
+ *
+ * ###Example:
+ *
+ * var s = new Schema({name : {type: String, text : true })
+ * s.path('name').index({text : true});
+ * @param {Boolean} bool
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.text = function(bool) {
+ if (this._index === false) {
+ if (!bool) {
+ return;
+ }
+ throw new Error('Path "' + this.path + '" may not have `index` set to ' +
+ 'false and `text` set to true');
+ }
+
+ if (this._index === null || this._index === undefined ||
+ typeof this._index === 'boolean') {
+ this._index = {};
+ } else if (typeof this._index === 'string') {
+ this._index = { type: this._index };
+ }
+
+ this._index.text = bool;
+ return this;
+};
+
+/**
+ * Declares a sparse index.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ name: { type: String, sparse: true } });
+ * s.path('name').index({ sparse: true });
+ *
+ * @param {Boolean} bool
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.sparse = function(bool) {
+ if (this._index === false) {
+ if (!bool) {
+ return;
+ }
+ throw new Error('Path "' + this.path + '" may not have `index` set to ' +
+ 'false and `sparse` set to true');
+ }
+
+ if (this._index == null || typeof this._index === 'boolean') {
+ this._index = {};
+ } else if (typeof this._index === 'string') {
+ this._index = { type: this._index };
+ }
+
+ this._index.sparse = bool;
+ return this;
+};
+
+/**
+ * Defines this path as immutable. Mongoose prevents you from changing
+ * immutable paths unless the parent document has [`isNew: true`](/docs/api.html#document_Document-isNew).
+ *
+ * ####Example:
+ *
+ * const schema = new Schema({
+ * name: { type: String, immutable: true },
+ * age: Number
+ * });
+ * const Model = mongoose.model('Test', schema);
+ *
+ * await Model.create({ name: 'test' });
+ * const doc = await Model.findOne();
+ *
+ * doc.isNew; // false
+ * doc.name = 'new name';
+ * doc.name; // 'test', because `name` is immutable
+ *
+ * Mongoose also prevents changing immutable properties using `updateOne()`
+ * and `updateMany()` based on [strict mode](/docs/guide.html#strict).
+ *
+ * ####Example:
+ *
+ * // Mongoose will strip out the `name` update, because `name` is immutable
+ * Model.updateOne({}, { $set: { name: 'test2' }, $inc: { age: 1 } });
+ *
+ * // If `strict` is set to 'throw', Mongoose will throw an error if you
+ * // update `name`
+ * const err = await Model.updateOne({}, { name: 'test2' }, { strict: 'throw' }).
+ * then(() => null, err => err);
+ * err.name; // StrictModeError
+ *
+ * // If `strict` is `false`, Mongoose allows updating `name` even though
+ * // the property is immutable.
+ * Model.updateOne({}, { name: 'test2' }, { strict: false });
+ *
+ * @param {Boolean} bool
+ * @return {SchemaType} this
+ * @see isNew /docs/api.html#document_Document-isNew
+ * @api public
+ */
+
+SchemaType.prototype.immutable = function(bool) {
+ this.$immutable = bool;
+ handleImmutable(this);
+
+ return this;
+};
+
+/**
+ * Adds a setter to this schematype.
+ *
+ * ####Example:
+ *
+ * function capitalize (val) {
+ * if (typeof val !== 'string') val = '';
+ * return val.charAt(0).toUpperCase() + val.substring(1);
+ * }
+ *
+ * // defining within the schema
+ * var s = new Schema({ name: { type: String, set: capitalize }});
+ *
+ * // or with the SchemaType
+ * var s = new Schema({ name: String })
+ * s.path('name').set(capitalize);
+ *
+ * Setters allow you to transform the data before it gets to the raw mongodb
+ * document or query.
+ *
+ * Suppose you are implementing user registration for a website. Users provide
+ * an email and password, which gets saved to mongodb. The email is a string
+ * that you will want to normalize to lower case, in order to avoid one email
+ * having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM.
+ *
+ * You can set up email lower case normalization easily via a Mongoose setter.
+ *
+ * function toLower(v) {
+ * return v.toLowerCase();
+ * }
+ *
+ * var UserSchema = new Schema({
+ * email: { type: String, set: toLower }
+ * });
+ *
+ * var User = db.model('User', UserSchema);
+ *
+ * var user = new User({email: 'AVENUE@Q.COM'});
+ * console.log(user.email); // 'avenue@q.com'
+ *
+ * // or
+ * var user = new User();
+ * user.email = 'Avenue@Q.com';
+ * console.log(user.email); // 'avenue@q.com'
+ * User.updateOne({ _id: _id }, { $set: { email: 'AVENUE@Q.COM' } }); // update to 'avenue@q.com'
+ *
+ * As you can see above, setters allow you to transform the data before it
+ * stored in MongoDB, or before executing a query.
+ *
+ * _NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function._
+ *
+ * new Schema({ email: { type: String, lowercase: true }})
+ *
+ * Setters are also passed a second argument, the schematype on which the setter was defined. This allows for tailored behavior based on options passed in the schema.
+ *
+ * function inspector (val, schematype) {
+ * if (schematype.options.required) {
+ * return schematype.path + ' is required';
+ * } else {
+ * return val;
+ * }
+ * }
+ *
+ * var VirusSchema = new Schema({
+ * name: { type: String, required: true, set: inspector },
+ * taxonomy: { type: String, set: inspector }
+ * })
+ *
+ * var Virus = db.model('Virus', VirusSchema);
+ * var v = new Virus({ name: 'Parvoviridae', taxonomy: 'Parvovirinae' });
+ *
+ * console.log(v.name); // name is required
+ * console.log(v.taxonomy); // Parvovirinae
+ *
+ * You can also use setters to modify other properties on the document. If
+ * you're setting a property `name` on a document, the setter will run with
+ * `this` as the document. Be careful, in mongoose 5 setters will also run
+ * when querying by `name` with `this` as the query.
+ *
+ * ```javascript
+ * const nameSchema = new Schema({ name: String, keywords: [String] });
+ * nameSchema.path('name').set(function(v) {
+ * // Need to check if `this` is a document, because in mongoose 5
+ * // setters will also run on queries, in which case `this` will be a
+ * // mongoose query object.
+ * if (this instanceof Document && v != null) {
+ * this.keywords = v.split(' ');
+ * }
+ * return v;
+ * });
+ * ```
+ *
+ * @param {Function} fn
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.set = function(fn) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('A setter must be a function.');
+ }
+ this.setters.push(fn);
+ return this;
+};
+
+/**
+ * Adds a getter to this schematype.
+ *
+ * ####Example:
+ *
+ * function dob (val) {
+ * if (!val) return val;
+ * return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear();
+ * }
+ *
+ * // defining within the schema
+ * var s = new Schema({ born: { type: Date, get: dob })
+ *
+ * // or by retreiving its SchemaType
+ * var s = new Schema({ born: Date })
+ * s.path('born').get(dob)
+ *
+ * Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see.
+ *
+ * Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way:
+ *
+ * function obfuscate (cc) {
+ * return '****-****-****-' + cc.slice(cc.length-4, cc.length);
+ * }
+ *
+ * var AccountSchema = new Schema({
+ * creditCardNumber: { type: String, get: obfuscate }
+ * });
+ *
+ * var Account = db.model('Account', AccountSchema);
+ *
+ * Account.findById(id, function (err, found) {
+ * console.log(found.creditCardNumber); // '****-****-****-1234'
+ * });
+ *
+ * Getters are also passed a second argument, the schematype on which the getter was defined. This allows for tailored behavior based on options passed in the schema.
+ *
+ * function inspector (val, schematype) {
+ * if (schematype.options.required) {
+ * return schematype.path + ' is required';
+ * } else {
+ * return schematype.path + ' is not';
+ * }
+ * }
+ *
+ * var VirusSchema = new Schema({
+ * name: { type: String, required: true, get: inspector },
+ * taxonomy: { type: String, get: inspector }
+ * })
+ *
+ * var Virus = db.model('Virus', VirusSchema);
+ *
+ * Virus.findById(id, function (err, virus) {
+ * console.log(virus.name); // name is required
+ * console.log(virus.taxonomy); // taxonomy is not
+ * })
+ *
+ * @param {Function} fn
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.get = function(fn) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('A getter must be a function.');
+ }
+ this.getters.push(fn);
+ return this;
+};
+
+/**
+ * Adds validator(s) for this document path.
+ *
+ * Validators always receive the value to validate as their first argument and
+ * must return `Boolean`. Returning `false` or throwing an error means
+ * validation failed.
+ *
+ * The error message argument is optional. If not passed, the [default generic error message template](#error_messages_MongooseError-messages) will be used.
+ *
+ * ####Examples:
+ *
+ * // make sure every value is equal to "something"
+ * function validator (val) {
+ * return val == 'something';
+ * }
+ * new Schema({ name: { type: String, validate: validator }});
+ *
+ * // with a custom error message
+ *
+ * var custom = [validator, 'Uh oh, {PATH} does not equal "something".']
+ * new Schema({ name: { type: String, validate: custom }});
+ *
+ * // adding many validators at a time
+ *
+ * var many = [
+ * { validator: validator, msg: 'uh oh' }
+ * , { validator: anotherValidator, msg: 'failed' }
+ * ]
+ * new Schema({ name: { type: String, validate: many }});
+ *
+ * // or utilizing SchemaType methods directly:
+ *
+ * var schema = new Schema({ name: 'string' });
+ * schema.path('name').validate(validator, 'validation of `{PATH}` failed with value `{VALUE}`');
+ *
+ * ####Error message templates:
+ *
+ * From the examples above, you may have noticed that error messages support
+ * basic templating. There are a few other template keywords besides `{PATH}`
+ * and `{VALUE}` too. To find out more, details are available
+ * [here](#error_messages_MongooseError.messages).
+ *
+ * If Mongoose's built-in error message templating isn't enough, Mongoose
+ * supports setting the `message` property to a function.
+ *
+ * schema.path('name').validate({
+ * validator: function() { return v.length > 5; },
+ * // `errors['name']` will be "name must have length 5, got 'foo'"
+ * message: function(props) {
+ * return `${props.path} must have length 5, got '${props.value}'`;
+ * }
+ * });
+ *
+ * To bypass Mongoose's error messages and just copy the error message that
+ * the validator throws, do this:
+ *
+ * schema.path('name').validate({
+ * validator: function() { throw new Error('Oops!'); },
+ * // `errors['name']` will be "Oops!"
+ * message: function(props) { return props.reason.message; }
+ * });
+ *
+ * ####Asynchronous validation:
+ *
+ * Mongoose supports validators that return a promise. A validator that returns
+ * a promise is called an _async validator_. Async validators run in
+ * parallel, and `validate()` will wait until all async validators have settled.
+ *
+ * schema.path('name').validate({
+ * validator: function (value) {
+ * return new Promise(function (resolve, reject) {
+ * resolve(false); // validation failed
+ * });
+ * }
+ * });
+ *
+ * You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs.
+ *
+ * Validation occurs `pre('save')` or whenever you manually execute [document#validate](#document_Document-validate).
+ *
+ * If validation fails during `pre('save')` and no callback was passed to receive the error, an `error` event will be emitted on your Models associated db [connection](#connection_Connection), passing the validation error object along.
+ *
+ * var conn = mongoose.createConnection(..);
+ * conn.on('error', handleError);
+ *
+ * var Product = conn.model('Product', yourSchema);
+ * var dvd = new Product(..);
+ * dvd.save(); // emits error on the `conn` above
+ *
+ * If you want to handle these errors at the Model level, add an `error`
+ * listener to your Model as shown below.
+ *
+ * // registering an error listener on the Model lets us handle errors more locally
+ * Product.on('error', handleError);
+ *
+ * @param {RegExp|Function|Object} obj validator function, or hash describing options
+ * @param {Function} [obj.validator] validator function. If the validator function returns `undefined` or a truthy value, validation succeeds. If it returns [falsy](https://masteringjs.io/tutorials/fundamentals/falsy) (except `undefined`) or throws an error, validation fails.
+ * @param {String|Function} [obj.message] optional error message. If function, should return the error message as a string
+ * @param {Boolean} [obj.propsParameter=false] If true, Mongoose will pass the validator properties object (with the `validator` function, `message`, etc.) as the 2nd arg to the validator function. This is disabled by default because many validators [rely on positional args](https://github.com/chriso/validator.js#validators), so turning this on may cause unpredictable behavior in external validators.
+ * @param {String|Function} [errorMsg] optional error message. If function, should return the error message as a string
+ * @param {String} [type] optional validator type
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.validate = function(obj, message, type) {
+ if (typeof obj === 'function' || obj && utils.getFunctionName(obj.constructor) === 'RegExp') {
+ let properties;
+ if (typeof message === 'function') {
+ properties = { validator: obj, message: message };
+ properties.type = type || 'user defined';
+ } else if (message instanceof Object && !type) {
+ properties = utils.clone(message);
+ if (!properties.message) {
+ properties.message = properties.msg;
+ }
+ properties.validator = obj;
+ properties.type = properties.type || 'user defined';
+ } else {
+ if (message == null) {
+ message = MongooseError.messages.general.default;
+ }
+ if (!type) {
+ type = 'user defined';
+ }
+ properties = { message: message, type: type, validator: obj };
+ }
+
+ if (properties.isAsync) {
+ handleIsAsync();
+ }
+
+ this.validators.push(properties);
+ return this;
+ }
+
+ let i;
+ let length;
+ let arg;
+
+ for (i = 0, length = arguments.length; i < length; i++) {
+ arg = arguments[i];
+ if (!utils.isPOJO(arg)) {
+ const msg = 'Invalid validator. Received (' + typeof arg + ') '
+ + arg
+ + '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
+
+ throw new Error(msg);
+ }
+ this.validate(arg.validator, arg);
+ }
+
+ return this;
+};
+
+/*!
+ * ignore
+ */
+
+const handleIsAsync = util.deprecate(function handleIsAsync() {},
+ 'Mongoose: the `isAsync` option for custom validators is deprecated. Make ' +
+ 'your async validators return a promise instead: ' +
+ 'https://mongoosejs.com/docs/validation.html#async-custom-validators');
+
+/**
+ * Adds a required validator to this SchemaType. The validator gets added
+ * to the front of this SchemaType's validators array using `unshift()`.
+ *
+ * ####Example:
+ *
+ * var s = new Schema({ born: { type: Date, required: true })
+ *
+ * // or with custom error message
+ *
+ * var s = new Schema({ born: { type: Date, required: '{PATH} is required!' })
+ *
+ * // or with a function
+ *
+ * var s = new Schema({
+ * userId: ObjectId,
+ * username: {
+ * type: String,
+ * required: function() { return this.userId != null; }
+ * }
+ * })
+ *
+ * // or with a function and a custom message
+ * var s = new Schema({
+ * userId: ObjectId,
+ * username: {
+ * type: String,
+ * required: [
+ * function() { return this.userId != null; },
+ * 'username is required if id is specified'
+ * ]
+ * }
+ * })
+ *
+ * // or through the path API
+ *
+ * s.path('name').required(true);
+ *
+ * // with custom error messaging
+ *
+ * s.path('name').required(true, 'grrr :( ');
+ *
+ * // or make a path conditionally required based on a function
+ * var isOver18 = function() { return this.age >= 18; };
+ * s.path('voterRegistrationId').required(isOver18);
+ *
+ * The required validator uses the SchemaType's `checkRequired` function to
+ * determine whether a given value satisfies the required validator. By default,
+ * a value satisfies the required validator if `val != null` (that is, if
+ * the value is not null nor undefined). However, most built-in mongoose schema
+ * types override the default `checkRequired` function:
+ *
+ * @param {Boolean|Function|Object} required enable/disable the validator, or function that returns required boolean, or options object
+ * @param {Boolean|Function} [options.isRequired] enable/disable the validator, or function that returns required boolean
+ * @param {Function} [options.ErrorConstructor] custom error constructor. The constructor receives 1 parameter, an object containing the validator properties.
+ * @param {String} [message] optional custom error message
+ * @return {SchemaType} this
+ * @see Customized Error Messages #error_messages_MongooseError-messages
+ * @see SchemaArray#checkRequired #schema_array_SchemaArray.checkRequired
+ * @see SchemaBoolean#checkRequired #schema_boolean_SchemaBoolean-checkRequired
+ * @see SchemaBuffer#checkRequired #schema_buffer_SchemaBuffer.schemaName
+ * @see SchemaNumber#checkRequired #schema_number_SchemaNumber-min
+ * @see SchemaObjectId#checkRequired #schema_objectid_ObjectId-auto
+ * @see SchemaString#checkRequired #schema_string_SchemaString-checkRequired
+ * @api public
+ */
+
+SchemaType.prototype.required = function(required, message) {
+ let customOptions = {};
+
+ if (arguments.length > 0 && required == null) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.requiredValidator;
+ }, this);
+
+ this.isRequired = false;
+ delete this.originalRequiredValue;
+ return this;
+ }
+
+ if (typeof required === 'object') {
+ customOptions = required;
+ message = customOptions.message || message;
+ required = required.isRequired;
+ }
+
+ if (required === false) {
+ this.validators = this.validators.filter(function(v) {
+ return v.validator !== this.requiredValidator;
+ }, this);
+
+ this.isRequired = false;
+ delete this.originalRequiredValue;
+ return this;
+ }
+
+ const _this = this;
+ this.isRequired = true;
+
+ this.requiredValidator = function(v) {
+ const cachedRequired = get(this, '$__.cachedRequired');
+
+ // no validation when this path wasn't selected in the query.
+ if (cachedRequired != null && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
+ return true;
+ }
+
+ // `$cachedRequired` gets set in `_evaluateRequiredFunctions()` so we
+ // don't call required functions multiple times in one validate call
+ // See gh-6801
+ if (cachedRequired != null && _this.path in cachedRequired) {
+ const res = cachedRequired[_this.path] ?
+ _this.checkRequired(v, this) :
+ true;
+ delete cachedRequired[_this.path];
+ return res;
+ } else if (typeof required === 'function') {
+ return required.apply(this) ? _this.checkRequired(v, this) : true;
+ }
+
+ return _this.checkRequired(v, this);
+ };
+ this.originalRequiredValue = required;
+
+ if (typeof required === 'string') {
+ message = required;
+ required = undefined;
+ }
+
+ const msg = message || MongooseError.messages.general.required;
+ this.validators.unshift(Object.assign({}, customOptions, {
+ validator: this.requiredValidator,
+ message: msg,
+ type: 'required'
+ }));
+
+ return this;
+};
+
+/**
+ * Set the model that this path refers to. This is the option that [populate](https://mongoosejs.com/docs/populate.html)
+ * looks at to determine the foreign collection it should query.
+ *
+ * ####Example:
+ * const userSchema = new Schema({ name: String });
+ * const User = mongoose.model('User', userSchema);
+ *
+ * const postSchema = new Schema({ user: mongoose.ObjectId });
+ * postSchema.path('user').ref('User'); // By model name
+ * postSchema.path('user').ref(User); // Can pass the model as well
+ *
+ * // Or you can just declare the `ref` inline in your schema
+ * const postSchema2 = new Schema({
+ * user: { type: mongoose.ObjectId, ref: User }
+ * });
+ *
+ * @param {String|Model|Function} ref either a model name, a [Model](https://mongoosejs.com/docs/models.html), or a function that returns a model name or model.
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.ref = function(ref) {
+ this.options.ref = ref;
+ return this;
+};
+
+/**
+ * Gets the default value
+ *
+ * @param {Object} scope the scope which callback are executed
+ * @param {Boolean} init
+ * @api private
+ */
+
+SchemaType.prototype.getDefault = function(scope, init) {
+ let ret = typeof this.defaultValue === 'function'
+ ? this.defaultValue.call(scope)
+ : this.defaultValue;
+
+ if (ret !== null && ret !== undefined) {
+ if (typeof ret === 'object' && (!this.options || !this.options.shared)) {
+ ret = utils.clone(ret);
+ }
+
+ const casted = this.applySetters(ret, scope, init);
+ if (casted && casted.$isSingleNested) {
+ casted.$parent = scope;
+ }
+ return casted;
+ }
+ return ret;
+};
+
+/*!
+ * Applies setters without casting
+ *
+ * @api private
+ */
+
+SchemaType.prototype._applySetters = function(value, scope, init, priorVal) {
+ let v = value;
+ const setters = this.setters;
+ let len = setters.length;
+ const caster = this.caster;
+
+ while (len--) {
+ v = setters[len].call(scope, v, this);
+ }
+
+ if (Array.isArray(v) && caster && caster.setters) {
+ const newVal = [];
+ for (let i = 0; i < v.length; i++) {
+ newVal.push(caster.applySetters(v[i], scope, init, priorVal));
+ }
+ v = newVal;
+ }
+
+ return v;
+};
+
+/**
+ * Applies setters
+ *
+ * @param {Object} value
+ * @param {Object} scope
+ * @param {Boolean} init
+ * @api private
+ */
+
+SchemaType.prototype.applySetters = function(value, scope, init, priorVal, options) {
+ let v = this._applySetters(value, scope, init, priorVal, options);
+
+ if (v == null) {
+ return v;
+ }
+
+ // do not cast until all setters are applied #665
+ v = this.cast(v, scope, init, priorVal, options);
+
+ return v;
+};
+
+/**
+ * Applies getters to a value
+ *
+ * @param {Object} value
+ * @param {Object} scope
+ * @api private
+ */
+
+SchemaType.prototype.applyGetters = function(value, scope) {
+ let v = value;
+ const getters = this.getters;
+ const len = getters.length;
+
+ if (len === 0) {
+ return v;
+ }
+
+ for (let i = 0; i < len; ++i) {
+ v = getters[i].call(scope, v, this);
+ }
+
+ return v;
+};
+
+/**
+ * Sets default `select()` behavior for this path.
+ *
+ * Set to `true` if this path should always be included in the results, `false` if it should be excluded by default. This setting can be overridden at the query level.
+ *
+ * ####Example:
+ *
+ * T = db.model('T', new Schema({ x: { type: String, select: true }}));
+ * T.find(..); // field x will always be selected ..
+ * // .. unless overridden;
+ * T.find().select('-x').exec(callback);
+ *
+ * @param {Boolean} val
+ * @return {SchemaType} this
+ * @api public
+ */
+
+SchemaType.prototype.select = function select(val) {
+ this.selected = !!val;
+ return this;
+};
+
+/**
+ * Performs a validation of `value` using the validators declared for this SchemaType.
+ *
+ * @param {any} value
+ * @param {Function} callback
+ * @param {Object} scope
+ * @api private
+ */
+
+SchemaType.prototype.doValidate = function(value, fn, scope, options) {
+ let err = false;
+ const path = this.path;
+
+ // Avoid non-object `validators`
+ const validators = this.validators.
+ filter(v => v != null && typeof v === 'object');
+
+ let count = validators.length;
+
+ if (!count) {
+ return fn(null);
+ }
+
+ const validate = function(ok, validatorProperties) {
+ if (err) {
+ return;
+ }
+ if (ok === undefined || ok) {
+ if (--count <= 0) {
+ immediate(function() {
+ fn(null);
+ });
+ }
+ } else {
+ const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
+ err = new ErrorConstructor(validatorProperties);
+ err[validatorErrorSymbol] = true;
+ immediate(function() {
+ fn(err);
+ });
+ }
+ };
+
+ const _this = this;
+ validators.forEach(function(v) {
+ if (err) {
+ return;
+ }
+
+ const validator = v.validator;
+ let ok;
+
+ const validatorProperties = utils.clone(v);
+ validatorProperties.path = options && options.path ? options.path : path;
+ validatorProperties.value = value;
+
+ if (validator instanceof RegExp) {
+ validate(validator.test(value), validatorProperties);
+ } else if (typeof validator === 'function') {
+ if (value === undefined && validator !== _this.requiredValidator) {
+ validate(true, validatorProperties);
+ return;
+ }
+ if (validatorProperties.isAsync) {
+ asyncValidate(validator, scope, value, validatorProperties, validate);
+ } else {
+ try {
+ if (validatorProperties.propsParameter) {
+ ok = validator.call(scope, value, validatorProperties);
+ } else {
+ ok = validator.call(scope, value);
+ }
+ } catch (error) {
+ ok = false;
+ validatorProperties.reason = error;
+ if (error.message) {
+ validatorProperties.message = error.message;
+ }
+ }
+ if (ok != null && typeof ok.then === 'function') {
+ ok.then(
+ function(ok) { validate(ok, validatorProperties); },
+ function(error) {
+ validatorProperties.reason = error;
+ validatorProperties.message = error.message;
+ ok = false;
+ validate(ok, validatorProperties);
+ });
+ } else {
+ validate(ok, validatorProperties);
+ }
+ }
+ }
+ });
+};
+
+/*!
+ * Handle async validators
+ */
+
+function asyncValidate(validator, scope, value, props, cb) {
+ let called = false;
+ const returnVal = validator.call(scope, value, function(ok, customMsg) {
+ if (called) {
+ return;
+ }
+ called = true;
+ if (customMsg) {
+ props.message = customMsg;
+ }
+ cb(ok, props);
+ });
+ if (typeof returnVal === 'boolean') {
+ called = true;
+ cb(returnVal, props);
+ } else if (returnVal && typeof returnVal.then === 'function') {
+ // Promise
+ returnVal.then(
+ function(ok) {
+ if (called) {
+ return;
+ }
+ called = true;
+ cb(ok, props);
+ },
+ function(error) {
+ if (called) {
+ return;
+ }
+ called = true;
+
+ props.reason = error;
+ props.message = error.message;
+ cb(false, props);
+ });
+ }
+}
+
+/**
+ * Performs a validation of `value` using the validators declared for this SchemaType.
+ *
+ * ####Note:
+ *
+ * This method ignores the asynchronous validators.
+ *
+ * @param {any} value
+ * @param {Object} scope
+ * @return {MongooseError|undefined}
+ * @api private
+ */
+
+SchemaType.prototype.doValidateSync = function(value, scope, options) {
+ let err = null;
+ const path = this.path;
+ const count = this.validators.length;
+
+ if (!count) {
+ return null;
+ }
+
+ const validate = function(ok, validatorProperties) {
+ if (err) {
+ return;
+ }
+ if (ok !== undefined && !ok) {
+ const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
+ err = new ErrorConstructor(validatorProperties);
+ err[validatorErrorSymbol] = true;
+ }
+ };
+
+ let validators = this.validators;
+ if (value === void 0) {
+ if (this.validators.length > 0 && this.validators[0].type === 'required') {
+ validators = [this.validators[0]];
+ } else {
+ return null;
+ }
+ }
+
+ validators.forEach(function(v) {
+ if (err) {
+ return;
+ }
+
+ if (v == null || typeof v !== 'object') {
+ return;
+ }
+
+ const validator = v.validator;
+ const validatorProperties = utils.clone(v);
+ validatorProperties.path = options && options.path ? options.path : path;
+ validatorProperties.value = value;
+ let ok;
+
+ // Skip any explicit async validators. Validators that return a promise
+ // will still run, but won't trigger any errors.
+ if (validator.isAsync) {
+ return;
+ }
+
+ if (validator instanceof RegExp) {
+ validate(validator.test(value), validatorProperties);
+ } else if (typeof validator === 'function') {
+ try {
+ if (validatorProperties.propsParameter) {
+ ok = validator.call(scope, value, validatorProperties);
+ } else {
+ ok = validator.call(scope, value);
+ }
+ } catch (error) {
+ ok = false;
+ validatorProperties.reason = error;
+ }
+
+ // Skip any validators that return a promise, we can't handle those
+ // synchronously
+ if (ok != null && typeof ok.then === 'function') {
+ return;
+ }
+ validate(ok, validatorProperties);
+ }
+ });
+
+ return err;
+};
+
+/**
+ * Determines if value is a valid Reference.
+ *
+ * @param {SchemaType} self
+ * @param {Object} value
+ * @param {Document} doc
+ * @param {Boolean} init
+ * @return {Boolean}
+ * @api private
+ */
+
+SchemaType._isRef = function(self, value, doc, init) {
+ // fast path
+ let ref = init && self.options && (self.options.ref || self.options.refPath);
+
+ if (!ref && doc && doc.$__ != null) {
+ // checks for
+ // - this populated with adhoc model and no ref was set in schema OR
+ // - setting / pushing values after population
+ const path = doc.$__fullPath(self.path);
+ const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
+ ref = owner.populated(path) || doc.populated(self.path);
+ }
+
+ if (ref) {
+ if (value == null) {
+ return true;
+ }
+ if (!Buffer.isBuffer(value) && // buffers are objects too
+ value._bsontype !== 'Binary' // raw binary value from the db
+ && utils.isObject(value) // might have deselected _id in population query
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/*!
+ * ignore
+ */
+
+function handleSingle(val) {
+ return this.castForQuery(val);
+}
+
+/*!
+ * ignore
+ */
+
+function handleArray(val) {
+ const _this = this;
+ if (!Array.isArray(val)) {
+ return [this.castForQuery(val)];
+ }
+ return val.map(function(m) {
+ return _this.castForQuery(m);
+ });
+}
+
+/*!
+ * Just like handleArray, except also allows `[]` because surprisingly
+ * `$in: [1, []]` works fine
+ */
+
+function handle$in(val) {
+ const _this = this;
+ if (!Array.isArray(val)) {
+ return [this.castForQuery(val)];
+ }
+ return val.map(function(m) {
+ if (Array.isArray(m) && m.length === 0) {
+ return m;
+ }
+ return _this.castForQuery(m);
+ });
+}
+
+/*!
+ * ignore
+ */
+
+SchemaType.prototype.$conditionalHandlers = {
+ $all: handleArray,
+ $eq: handleSingle,
+ $in: handle$in,
+ $ne: handleSingle,
+ $nin: handle$in,
+ $exists: $exists,
+ $type: $type
+};
+
+/*!
+ * Wraps `castForQuery` to handle context
+ */
+
+SchemaType.prototype.castForQueryWrapper = function(params) {
+ this.$$context = params.context;
+ if ('$conditional' in params) {
+ return this.castForQuery(params.$conditional, params.val);
+ }
+ if (params.$skipQueryCastForUpdate || params.$applySetters) {
+ return this._castForQuery(params.val);
+ }
+ return this.castForQuery(params.val);
+};
+
+/**
+ * Cast the given value with the given optional query operator.
+ *
+ * @param {String} [$conditional] query operator, like `$eq` or `$in`
+ * @param {any} val
+ * @api private
+ */
+
+SchemaType.prototype.castForQuery = function($conditional, val) {
+ let handler;
+ if (arguments.length === 2) {
+ handler = this.$conditionalHandlers[$conditional];
+ if (!handler) {
+ throw new Error('Can\'t use ' + $conditional);
+ }
+ return handler.call(this, val);
+ }
+ val = $conditional;
+ return this._castForQuery(val);
+};
+
+/*!
+ * Internal switch for runSetters
+ *
+ * @api private
+ */
+
+SchemaType.prototype._castForQuery = function(val) {
+ return this.applySetters(val, this.$$context);
+};
+
+/**
+ * Override the function the required validator uses to check whether a value
+ * passes the `required` check. Override this on the individual SchemaType.
+ *
+ * ####Example:
+ *
+ * // Use this to allow empty strings to pass the `required` validator
+ * mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string');
+ *
+ * @param {Function} fn
+ * @return {Function}
+ * @static
+ * @receiver SchemaType
+ * @function checkRequired
+ * @api public
+ */
+
+SchemaType.checkRequired = function(fn) {
+ if (arguments.length > 0) {
+ this._checkRequired = fn;
+ }
+
+ return this._checkRequired;
+};
+
+/**
+ * Default check for if this path satisfies the `required` validator.
+ *
+ * @param {any} val
+ * @api private
+ */
+
+SchemaType.prototype.checkRequired = function(val) {
+ return val != null;
+};
+
+/*!
+ * ignore
+ */
+
+SchemaType.prototype.clone = function() {
+ const options = Object.assign({}, this.options);
+ const schematype = new this.constructor(this.path, options, this.instance);
+ schematype.validators = this.validators.slice();
+ if (this.requiredValidator !== undefined) schematype.requiredValidator = this.requiredValidator;
+ if (this.defaultValue !== undefined) schematype.defaultValue = this.defaultValue;
+ if (this.$immutable !== undefined && this.options.immutable === undefined) {
+ schematype.$immutable = this.$immutable;
+
+ handleImmutable(schematype);
+ }
+ if (this._index !== undefined) schematype._index = this._index;
+ if (this.selected !== undefined) schematype.selected = this.selected;
+ if (this.isRequired !== undefined) schematype.isRequired = this.isRequired;
+ if (this.originalRequiredValue !== undefined) schematype.originalRequiredValue = this.originalRequiredValue;
+ schematype.getters = this.getters.slice();
+ schematype.setters = this.setters.slice();
+ return schematype;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = SchemaType;
+
+exports.CastError = CastError;
+
+exports.ValidatorError = ValidatorError;
diff --git a/node_modules/mongoose/lib/statemachine.js b/node_modules/mongoose/lib/statemachine.js
new file mode 100644
index 0000000..7e36dc1
--- /dev/null
+++ b/node_modules/mongoose/lib/statemachine.js
@@ -0,0 +1,180 @@
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const utils = require('./utils');
+
+/*!
+ * StateMachine represents a minimal `interface` for the
+ * constructors it builds via StateMachine.ctor(...).
+ *
+ * @api private
+ */
+
+const StateMachine = module.exports = exports = function StateMachine() {
+};
+
+/*!
+ * StateMachine.ctor('state1', 'state2', ...)
+ * A factory method for subclassing StateMachine.
+ * The arguments are a list of states. For each state,
+ * the constructor's prototype gets state transition
+ * methods named after each state. These transition methods
+ * place their path argument into the given state.
+ *
+ * @param {String} state
+ * @param {String} [state]
+ * @return {Function} subclass constructor
+ * @private
+ */
+
+StateMachine.ctor = function() {
+ const states = utils.args(arguments);
+
+ const ctor = function() {
+ StateMachine.apply(this, arguments);
+ this.paths = {};
+ this.states = {};
+ this.stateNames = states;
+
+ let i = states.length,
+ state;
+
+ while (i--) {
+ state = states[i];
+ this.states[state] = {};
+ }
+ };
+
+ ctor.prototype = new StateMachine();
+
+ states.forEach(function(state) {
+ // Changes the `path`'s state to `state`.
+ ctor.prototype[state] = function(path) {
+ this._changeState(path, state);
+ };
+ });
+
+ return ctor;
+};
+
+/*!
+ * This function is wrapped by the state change functions:
+ *
+ * - `require(path)`
+ * - `modify(path)`
+ * - `init(path)`
+ *
+ * @api private
+ */
+
+StateMachine.prototype._changeState = function _changeState(path, nextState) {
+ const prevBucket = this.states[this.paths[path]];
+ if (prevBucket) delete prevBucket[path];
+
+ this.paths[path] = nextState;
+ this.states[nextState][path] = true;
+};
+
+/*!
+ * ignore
+ */
+
+StateMachine.prototype.clear = function clear(state) {
+ const keys = Object.keys(this.states[state]);
+ let i = keys.length;
+ let path;
+
+ while (i--) {
+ path = keys[i];
+ delete this.states[state][path];
+ delete this.paths[path];
+ }
+};
+
+/*!
+ * Checks to see if at least one path is in the states passed in via `arguments`
+ * e.g., this.some('required', 'inited')
+ *
+ * @param {String} state that we want to check for.
+ * @private
+ */
+
+StateMachine.prototype.some = function some() {
+ const _this = this;
+ const what = arguments.length ? arguments : this.stateNames;
+ return Array.prototype.some.call(what, function(state) {
+ return Object.keys(_this.states[state]).length;
+ });
+};
+
+/*!
+ * This function builds the functions that get assigned to `forEach` and `map`,
+ * since both of those methods share a lot of the same logic.
+ *
+ * @param {String} iterMethod is either 'forEach' or 'map'
+ * @return {Function}
+ * @api private
+ */
+
+StateMachine.prototype._iter = function _iter(iterMethod) {
+ return function() {
+ const numArgs = arguments.length;
+ let states = utils.args(arguments, 0, numArgs - 1);
+ const callback = arguments[numArgs - 1];
+
+ if (!states.length) states = this.stateNames;
+
+ const _this = this;
+
+ const paths = states.reduce(function(paths, state) {
+ return paths.concat(Object.keys(_this.states[state]));
+ }, []);
+
+ return paths[iterMethod](function(path, i, paths) {
+ return callback(path, i, paths);
+ });
+ };
+};
+
+/*!
+ * Iterates over the paths that belong to one of the parameter states.
+ *
+ * The function profile can look like:
+ * this.forEach(state1, fn); // iterates over all paths in state1
+ * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
+ * this.forEach(fn); // iterates over all paths in all states
+ *
+ * @param {String} [state]
+ * @param {String} [state]
+ * @param {Function} callback
+ * @private
+ */
+
+StateMachine.prototype.forEach = function forEach() {
+ this.forEach = this._iter('forEach');
+ return this.forEach.apply(this, arguments);
+};
+
+/*!
+ * Maps over the paths that belong to one of the parameter states.
+ *
+ * The function profile can look like:
+ * this.forEach(state1, fn); // iterates over all paths in state1
+ * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
+ * this.forEach(fn); // iterates over all paths in all states
+ *
+ * @param {String} [state]
+ * @param {String} [state]
+ * @param {Function} callback
+ * @return {Array}
+ * @private
+ */
+
+StateMachine.prototype.map = function map() {
+ this.map = this._iter('map');
+ return this.map.apply(this, arguments);
+};
diff --git a/node_modules/mongoose/lib/types/array.js b/node_modules/mongoose/lib/types/array.js
new file mode 100644
index 0000000..41c51e5
--- /dev/null
+++ b/node_modules/mongoose/lib/types/array.js
@@ -0,0 +1,66 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const CoreMongooseArray = require('./core_array');
+const Document = require('../document');
+
+const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
+const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
+const arrayPathSymbol = require('../helpers/symbols').arrayPathSymbol;
+const arraySchemaSymbol = require('../helpers/symbols').arraySchemaSymbol;
+
+const _basePush = Array.prototype.push;
+
+/**
+ * Mongoose Array constructor.
+ *
+ * ####NOTE:
+ *
+ * _Values always have to be passed to the constructor to initialize, otherwise `MongooseArray#push` will mark the array as modified._
+ *
+ * @param {Array} values
+ * @param {String} path
+ * @param {Document} doc parent document
+ * @api private
+ * @inherits Array
+ * @see http://bit.ly/f6CnZU
+ */
+
+function MongooseArray(values, path, doc) {
+ // TODO: replace this with `new CoreMongooseArray().concat()` when we remove
+ // support for node 4.x and 5.x, see https://i.imgur.com/UAAHk4S.png
+ const arr = new CoreMongooseArray();
+ arr[arrayAtomicsSymbol] = {};
+
+ if (Array.isArray(values)) {
+ const len = values.length;
+ for (let i = 0; i < len; ++i) {
+ _basePush.call(arr, values[i]);
+ }
+
+ arr[arrayAtomicsSymbol] = values[arrayAtomicsSymbol] || {};
+ }
+
+ arr[arrayPathSymbol] = path;
+ arr[arraySchemaSymbol] = void 0;
+
+ // Because doc comes from the context of another function, doc === global
+ // can happen if there was a null somewhere up the chain (see #3020)
+ // RB Jun 17, 2015 updated to check for presence of expected paths instead
+ // to make more proof against unusual node environments
+ if (doc && doc instanceof Document) {
+ arr[arrayParentSymbol] = doc;
+ arr[arraySchemaSymbol] = doc.schema.path(path);
+ }
+
+ return arr;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = exports = MongooseArray;
diff --git a/node_modules/mongoose/lib/types/buffer.js b/node_modules/mongoose/lib/types/buffer.js
new file mode 100644
index 0000000..5dbe2d4
--- /dev/null
+++ b/node_modules/mongoose/lib/types/buffer.js
@@ -0,0 +1,279 @@
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const Binary = require('../driver').get().Binary;
+const utils = require('../utils');
+const Buffer = require('safe-buffer').Buffer;
+
+// Yes this is weird. See https://github.com/feross/safe-buffer/pull/23
+const proto = Buffer.from('').constructor.prototype;
+
+/**
+ * Mongoose Buffer constructor.
+ *
+ * Values always have to be passed to the constructor to initialize.
+ *
+ * @param {Buffer} value
+ * @param {String} encode
+ * @param {Number} offset
+ * @api private
+ * @inherits Buffer
+ * @see http://bit.ly/f6CnZU
+ */
+
+function MongooseBuffer(value, encode, offset) {
+ const length = arguments.length;
+ let val;
+
+ if (length === 0 || arguments[0] === null || arguments[0] === undefined) {
+ val = 0;
+ } else {
+ val = value;
+ }
+
+ let encoding;
+ let path;
+ let doc;
+
+ if (Array.isArray(encode)) {
+ // internal casting
+ path = encode[0];
+ doc = encode[1];
+ } else {
+ encoding = encode;
+ }
+
+ let buf;
+ if (typeof val === 'number' || val instanceof Number) {
+ buf = Buffer.alloc(val);
+ } else { // string, array or object { type: 'Buffer', data: [...] }
+ buf = Buffer.from(val, encoding, offset);
+ }
+ utils.decorate(buf, MongooseBuffer.mixin);
+ buf.isMongooseBuffer = true;
+
+ // make sure these internal props don't show up in Object.keys()
+ buf[MongooseBuffer.pathSymbol] = path;
+ buf[parentSymbol] = doc;
+
+ buf._subtype = 0;
+ return buf;
+}
+
+const pathSymbol = Symbol.for('mongoose#Buffer#_path');
+const parentSymbol = Symbol.for('mongoose#Buffer#_parent');
+MongooseBuffer.pathSymbol = pathSymbol;
+
+/*!
+ * Inherit from Buffer.
+ */
+
+MongooseBuffer.mixin = {
+
+ /**
+ * Default subtype for the Binary representing this Buffer
+ *
+ * @api private
+ * @property _subtype
+ * @receiver MongooseBuffer
+ */
+
+ _subtype: undefined,
+
+ /**
+ * Marks this buffer as modified.
+ *
+ * @api private
+ * @method _markModified
+ * @receiver MongooseBuffer
+ */
+
+ _markModified: function() {
+ const parent = this[parentSymbol];
+
+ if (parent) {
+ parent.markModified(this[MongooseBuffer.pathSymbol]);
+ }
+ return this;
+ },
+
+ /**
+ * Writes the buffer.
+ *
+ * @api public
+ * @method write
+ * @receiver MongooseBuffer
+ */
+
+ write: function() {
+ const written = proto.write.apply(this, arguments);
+
+ if (written > 0) {
+ this._markModified();
+ }
+
+ return written;
+ },
+
+ /**
+ * Copies the buffer.
+ *
+ * ####Note:
+ *
+ * `Buffer#copy` does not mark `target` as modified so you must copy from a `MongooseBuffer` for it to work as expected. This is a work around since `copy` modifies the target, not this.
+ *
+ * @return {Number} The number of bytes copied.
+ * @param {Buffer} target
+ * @method copy
+ * @receiver MongooseBuffer
+ */
+
+ copy: function(target) {
+ const ret = proto.copy.apply(this, arguments);
+
+ if (target && target.isMongooseBuffer) {
+ target._markModified();
+ }
+
+ return ret;
+ }
+};
+
+/*!
+ * Compile other Buffer methods marking this buffer as modified.
+ */
+
+(
+// node < 0.5
+ ('writeUInt8 writeUInt16 writeUInt32 writeInt8 writeInt16 writeInt32 ' +
+ 'writeFloat writeDouble fill ' +
+ 'utf8Write binaryWrite asciiWrite set ' +
+
+ // node >= 0.5
+ 'writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE ' +
+ 'writeInt16LE writeInt16BE writeInt32LE writeInt32BE ' + 'writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE')
+).split(' ').forEach(function(method) {
+ if (!proto[method]) {
+ return;
+ }
+ MongooseBuffer.mixin[method] = function() {
+ const ret = proto[method].apply(this, arguments);
+ this._markModified();
+ return ret;
+ };
+});
+
+/**
+ * Converts this buffer to its Binary type representation.
+ *
+ * ####SubTypes:
+ *
+ * var bson = require('bson')
+ * bson.BSON_BINARY_SUBTYPE_DEFAULT
+ * bson.BSON_BINARY_SUBTYPE_FUNCTION
+ * bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
+ * bson.BSON_BINARY_SUBTYPE_UUID
+ * bson.BSON_BINARY_SUBTYPE_MD5
+ * bson.BSON_BINARY_SUBTYPE_USER_DEFINED
+ *
+ * doc.buffer.toObject(bson.BSON_BINARY_SUBTYPE_USER_DEFINED);
+ *
+ * @see http://bsonspec.org/#/specification
+ * @param {Hex} [subtype]
+ * @return {Binary}
+ * @api public
+ * @method toObject
+ * @receiver MongooseBuffer
+ */
+
+MongooseBuffer.mixin.toObject = function(options) {
+ const subtype = typeof options === 'number'
+ ? options
+ : (this._subtype || 0);
+ return new Binary(Buffer.from(this), subtype);
+};
+
+/**
+ * Converts this buffer for storage in MongoDB, including subtype
+ *
+ * @return {Binary}
+ * @api public
+ * @method toBSON
+ * @receiver MongooseBuffer
+ */
+
+MongooseBuffer.mixin.toBSON = function() {
+ return new Binary(this, this._subtype || 0);
+};
+
+/**
+ * Determines if this buffer is equals to `other` buffer
+ *
+ * @param {Buffer} other
+ * @return {Boolean}
+ * @method equals
+ * @receiver MongooseBuffer
+ */
+
+MongooseBuffer.mixin.equals = function(other) {
+ if (!Buffer.isBuffer(other)) {
+ return false;
+ }
+
+ if (this.length !== other.length) {
+ return false;
+ }
+
+ for (let i = 0; i < this.length; ++i) {
+ if (this[i] !== other[i]) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+/**
+ * Sets the subtype option and marks the buffer modified.
+ *
+ * ####SubTypes:
+ *
+ * var bson = require('bson')
+ * bson.BSON_BINARY_SUBTYPE_DEFAULT
+ * bson.BSON_BINARY_SUBTYPE_FUNCTION
+ * bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
+ * bson.BSON_BINARY_SUBTYPE_UUID
+ * bson.BSON_BINARY_SUBTYPE_MD5
+ * bson.BSON_BINARY_SUBTYPE_USER_DEFINED
+ *
+ * doc.buffer.subtype(bson.BSON_BINARY_SUBTYPE_UUID);
+ *
+ * @see http://bsonspec.org/#/specification
+ * @param {Hex} subtype
+ * @api public
+ * @method subtype
+ * @receiver MongooseBuffer
+ */
+
+MongooseBuffer.mixin.subtype = function(subtype) {
+ if (typeof subtype !== 'number') {
+ throw new TypeError('Invalid subtype. Expected a number');
+ }
+
+ if (this._subtype !== subtype) {
+ this._markModified();
+ }
+
+ this._subtype = subtype;
+};
+
+/*!
+ * Module exports.
+ */
+
+MongooseBuffer.Binary = Binary;
+
+module.exports = MongooseBuffer;
diff --git a/node_modules/mongoose/lib/types/core_array.js b/node_modules/mongoose/lib/types/core_array.js
new file mode 100644
index 0000000..a48bc40
--- /dev/null
+++ b/node_modules/mongoose/lib/types/core_array.js
@@ -0,0 +1,947 @@
+'use strict';
+
+const Document = require('../document');
+const EmbeddedDocument = require('./embedded');
+const MongooseError = require('../error/mongooseError');
+const ObjectId = require('./objectid');
+const cleanModifiedSubpaths = require('../helpers/document/cleanModifiedSubpaths');
+const get = require('../helpers/get');
+const internalToObjectOptions = require('../options').internalToObjectOptions;
+const utils = require('../utils');
+const util = require('util');
+
+const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
+const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
+const arrayPathSymbol = require('../helpers/symbols').arrayPathSymbol;
+const arraySchemaSymbol = require('../helpers/symbols').arraySchemaSymbol;
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+const _basePush = Array.prototype.push;
+
+const validatorsSymbol = Symbol('mongoose#MongooseCoreArray#validators');
+
+/*!
+ * ignore
+ */
+
+class CoreMongooseArray extends Array {
+ get isMongooseArray() {
+ return true;
+ }
+
+ get validators() {
+ return this[validatorsSymbol];
+ }
+
+ set validators(v) {
+ this[validatorsSymbol] = v;
+ }
+
+ /**
+ * Depopulates stored atomic operation values as necessary for direct insertion to MongoDB.
+ *
+ * If no atomics exist, we return all array values after conversion.
+ *
+ * @return {Array}
+ * @method $__getAtomics
+ * @memberOf MongooseArray
+ * @instance
+ * @api private
+ */
+
+ $__getAtomics() {
+ const ret = [];
+ const keys = Object.keys(this[arrayAtomicsSymbol]);
+ let i = keys.length;
+
+ const opts = Object.assign({}, internalToObjectOptions, { _isNested: true });
+
+ if (i === 0) {
+ ret[0] = ['$set', this.toObject(opts)];
+ return ret;
+ }
+
+ while (i--) {
+ const op = keys[i];
+ let val = this[arrayAtomicsSymbol][op];
+
+ // the atomic values which are arrays are not MongooseArrays. we
+ // need to convert their elements as if they were MongooseArrays
+ // to handle populated arrays versus DocumentArrays properly.
+ if (utils.isMongooseObject(val)) {
+ val = val.toObject(opts);
+ } else if (Array.isArray(val)) {
+ val = this.toObject.call(val, opts);
+ } else if (val != null && Array.isArray(val.$each)) {
+ val.$each = this.toObject.call(val.$each, opts);
+ } else if (val != null && typeof val.valueOf === 'function') {
+ val = val.valueOf();
+ }
+
+ if (op === '$addToSet') {
+ val = { $each: val };
+ }
+
+ ret.push([op, val]);
+ }
+
+ return ret;
+ }
+
+ /*!
+ * ignore
+ */
+
+ $atomics() {
+ return this[arrayAtomicsSymbol];
+ }
+
+ /*!
+ * ignore
+ */
+
+ $parent() {
+ return this[arrayParentSymbol];
+ }
+
+ /*!
+ * ignore
+ */
+
+ $path() {
+ return this[arrayPathSymbol];
+ }
+
+ /**
+ * Atomically shifts the array at most one time per document `save()`.
+ *
+ * ####NOTE:
+ *
+ * _Calling this multiple times on an array before saving sends the same command as calling it once._
+ * _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._
+ *
+ * doc.array = [1,2,3];
+ *
+ * var shifted = doc.array.$shift();
+ * console.log(shifted); // 1
+ * console.log(doc.array); // [2,3]
+ *
+ * // no affect
+ * shifted = doc.array.$shift();
+ * console.log(doc.array); // [2,3]
+ *
+ * doc.save(function (err) {
+ * if (err) return handleError(err);
+ *
+ * // we saved, now $shift works again
+ * shifted = doc.array.$shift();
+ * console.log(shifted ); // 2
+ * console.log(doc.array); // [3]
+ * })
+ *
+ * @api public
+ * @memberOf MongooseArray
+ * @instance
+ * @method $shift
+ * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop
+ */
+
+ $shift() {
+ this._registerAtomic('$pop', -1);
+ this._markModified();
+
+ // only allow shifting once
+ if (this._shifted) {
+ return;
+ }
+ this._shifted = true;
+
+ return [].shift.call(this);
+ }
+
+ /**
+ * Pops the array atomically at most one time per document `save()`.
+ *
+ * #### NOTE:
+ *
+ * _Calling this mulitple times on an array before saving sends the same command as calling it once._
+ * _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._
+ *
+ * doc.array = [1,2,3];
+ *
+ * var popped = doc.array.$pop();
+ * console.log(popped); // 3
+ * console.log(doc.array); // [1,2]
+ *
+ * // no affect
+ * popped = doc.array.$pop();
+ * console.log(doc.array); // [1,2]
+ *
+ * doc.save(function (err) {
+ * if (err) return handleError(err);
+ *
+ * // we saved, now $pop works again
+ * popped = doc.array.$pop();
+ * console.log(popped); // 2
+ * console.log(doc.array); // [1]
+ * })
+ *
+ * @api public
+ * @method $pop
+ * @memberOf MongooseArray
+ * @instance
+ * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop
+ * @method $pop
+ * @memberOf MongooseArray
+ */
+
+ $pop() {
+ this._registerAtomic('$pop', 1);
+ this._markModified();
+
+ // only allow popping once
+ if (this._popped) {
+ return;
+ }
+ this._popped = true;
+
+ return [].pop.call(this);
+ }
+
+ /*!
+ * ignore
+ */
+
+ $schema() {
+ return this[arraySchemaSymbol];
+ }
+
+ /**
+ * Casts a member based on this arrays schema.
+ *
+ * @param {any} value
+ * @return value the casted value
+ * @method _cast
+ * @api private
+ * @memberOf MongooseArray
+ */
+
+ _cast(value) {
+ let populated = false;
+ let Model;
+
+ if (this[arrayParentSymbol]) {
+ populated = this[arrayParentSymbol].populated(this[arrayPathSymbol], true);
+ }
+
+ if (populated && value !== null && value !== undefined) {
+ // cast to the populated Models schema
+ Model = populated.options[populateModelSymbol];
+
+ // only objects are permitted so we can safely assume that
+ // non-objects are to be interpreted as _id
+ if (Buffer.isBuffer(value) ||
+ value instanceof ObjectId || !utils.isObject(value)) {
+ value = { _id: value };
+ }
+
+ // gh-2399
+ // we should cast model only when it's not a discriminator
+ const isDisc = value.schema && value.schema.discriminatorMapping &&
+ value.schema.discriminatorMapping.key !== undefined;
+ if (!isDisc) {
+ value = new Model(value);
+ }
+ return this[arraySchemaSymbol].caster.applySetters(value, this[arrayParentSymbol], true);
+ }
+
+ return this[arraySchemaSymbol].caster.applySetters(value, this[arrayParentSymbol], false);
+ }
+
+ /**
+ * Internal helper for .map()
+ *
+ * @api private
+ * @return {Number}
+ * @method _mapCast
+ * @memberOf MongooseArray
+ */
+
+ _mapCast(val, index) {
+ return this._cast(val, this.length + index);
+ }
+
+ /**
+ * Marks this array as modified.
+ *
+ * If it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments)
+ *
+ * @param {EmbeddedDocument} embeddedDoc the embedded doc that invoked this method on the Array
+ * @param {String} embeddedPath the path which changed in the embeddedDoc
+ * @method _markModified
+ * @api private
+ * @memberOf MongooseArray
+ */
+
+ _markModified(elem, embeddedPath) {
+ const parent = this[arrayParentSymbol];
+ let dirtyPath;
+
+ if (parent) {
+ dirtyPath = this[arrayPathSymbol];
+
+ if (arguments.length) {
+ if (embeddedPath != null) {
+ // an embedded doc bubbled up the change
+ dirtyPath = dirtyPath + '.' + this.indexOf(elem) + '.' + embeddedPath;
+ } else {
+ // directly set an index
+ dirtyPath = dirtyPath + '.' + elem;
+ }
+ }
+
+ if (dirtyPath != null && dirtyPath.endsWith('.$')) {
+ return this;
+ }
+
+ parent.markModified(dirtyPath, arguments.length > 0 ? elem : parent);
+ }
+
+ return this;
+ }
+
+ /**
+ * Register an atomic operation with the parent.
+ *
+ * @param {Array} op operation
+ * @param {any} val
+ * @method _registerAtomic
+ * @api private
+ * @memberOf MongooseArray
+ */
+
+ _registerAtomic(op, val) {
+ if (op === '$set') {
+ // $set takes precedence over all other ops.
+ // mark entire array modified.
+ this[arrayAtomicsSymbol] = { $set: val };
+ cleanModifiedSubpaths(this[arrayParentSymbol], this[arrayPathSymbol]);
+ this._markModified();
+ return this;
+ }
+
+ const atomics = this[arrayAtomicsSymbol];
+
+ // reset pop/shift after save
+ if (op === '$pop' && !('$pop' in atomics)) {
+ const _this = this;
+ this[arrayParentSymbol].once('save', function() {
+ _this._popped = _this._shifted = null;
+ });
+ }
+
+ // check for impossible $atomic combos (Mongo denies more than one
+ // $atomic op on a single path
+ if (this[arrayAtomicsSymbol].$set || Object.keys(atomics).length && !(op in atomics)) {
+ // a different op was previously registered.
+ // save the entire thing.
+ this[arrayAtomicsSymbol] = { $set: this };
+ return this;
+ }
+
+ let selector;
+
+ if (op === '$pullAll' || op === '$addToSet') {
+ atomics[op] || (atomics[op] = []);
+ atomics[op] = atomics[op].concat(val);
+ } else if (op === '$pullDocs') {
+ const pullOp = atomics['$pull'] || (atomics['$pull'] = {});
+ if (val[0] instanceof EmbeddedDocument) {
+ selector = pullOp['$or'] || (pullOp['$or'] = []);
+ Array.prototype.push.apply(selector, val.map(function(v) {
+ return v.toObject({ transform: false, virtuals: false });
+ }));
+ } else {
+ selector = pullOp['_id'] || (pullOp['_id'] = { $in: [] });
+ selector['$in'] = selector['$in'].concat(val);
+ }
+ } else if (op === '$push') {
+ atomics.$push = atomics.$push || { $each: [] };
+ if (val != null && utils.hasUserDefinedProperty(val, '$each')) {
+ atomics.$push = val;
+ } else {
+ atomics.$push.$each = atomics.$push.$each.concat(val);
+ }
+ } else {
+ atomics[op] = val;
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds values to the array if not already present.
+ *
+ * ####Example:
+ *
+ * console.log(doc.array) // [2,3,4]
+ * var added = doc.array.addToSet(4,5);
+ * console.log(doc.array) // [2,3,4,5]
+ * console.log(added) // [5]
+ *
+ * @param {any} [args...]
+ * @return {Array} the values that were added
+ * @memberOf MongooseArray
+ * @api public
+ * @method addToSet
+ */
+
+ addToSet() {
+ _checkManualPopulation(this, arguments);
+
+ let values = [].map.call(arguments, this._mapCast, this);
+ values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
+ const added = [];
+ let type = '';
+ if (values[0] instanceof EmbeddedDocument) {
+ type = 'doc';
+ } else if (values[0] instanceof Date) {
+ type = 'date';
+ }
+
+ values.forEach(function(v) {
+ let found;
+ const val = +v;
+ switch (type) {
+ case 'doc':
+ found = this.some(function(doc) {
+ return doc.equals(v);
+ });
+ break;
+ case 'date':
+ found = this.some(function(d) {
+ return +d === val;
+ });
+ break;
+ default:
+ found = ~this.indexOf(v);
+ }
+
+ if (!found) {
+ [].push.call(this, v);
+ this._registerAtomic('$addToSet', v);
+ this._markModified();
+ [].push.call(added, v);
+ }
+ }, this);
+
+ return added;
+ }
+
+ /**
+ * Returns the number of pending atomic operations to send to the db for this array.
+ *
+ * @api private
+ * @return {Number}
+ * @method hasAtomics
+ * @memberOf MongooseArray
+ */
+
+ hasAtomics() {
+ if (!utils.isPOJO(this[arrayAtomicsSymbol])) {
+ return 0;
+ }
+
+ return Object.keys(this[arrayAtomicsSymbol]).length;
+ }
+
+ /**
+ * Return whether or not the `obj` is included in the array.
+ *
+ * @param {Object} obj the item to check
+ * @return {Boolean}
+ * @api public
+ * @method includes
+ * @memberOf MongooseArray
+ */
+
+ includes(obj, fromIndex) {
+ const ret = this.indexOf(obj, fromIndex);
+ return ret !== -1;
+ }
+
+ /**
+ * Return the index of `obj` or `-1` if not found.
+ *
+ * @param {Object} obj the item to look for
+ * @return {Number}
+ * @api public
+ * @method indexOf
+ * @memberOf MongooseArray
+ */
+
+ indexOf(obj, fromIndex) {
+ if (obj instanceof ObjectId) {
+ obj = obj.toString();
+ }
+
+ fromIndex = fromIndex == null ? 0 : fromIndex;
+ const len = this.length;
+ for (let i = fromIndex; i < len; ++i) {
+ if (obj == this[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Helper for console.log
+ *
+ * @api public
+ * @method inspect
+ * @memberOf MongooseArray
+ */
+
+ inspect() {
+ return JSON.stringify(this);
+ }
+
+ /**
+ * Pushes items to the array non-atomically.
+ *
+ * ####NOTE:
+ *
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @param {any} [args...]
+ * @api public
+ * @method nonAtomicPush
+ * @memberOf MongooseArray
+ */
+
+ nonAtomicPush() {
+ const values = [].map.call(arguments, this._mapCast, this);
+ const ret = [].push.apply(this, values);
+ this._registerAtomic('$set', this);
+ this._markModified();
+ return ret;
+ }
+
+ /**
+ * Wraps [`Array#pop`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking.
+ *
+ * ####Note:
+ *
+ * _marks the entire array as modified which will pass the entire thing to $set potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @see MongooseArray#$pop #types_array_MongooseArray-%24pop
+ * @api public
+ * @method pop
+ * @memberOf MongooseArray
+ */
+
+ pop() {
+ const ret = [].pop.call(this);
+ this._registerAtomic('$set', this);
+ this._markModified();
+ return ret;
+ }
+
+ /**
+ * Pulls items from the array atomically. Equality is determined by casting
+ * the provided value to an embedded document and comparing using
+ * [the `Document.equals()` function.](./api.html#document_Document-equals)
+ *
+ * ####Examples:
+ *
+ * doc.array.pull(ObjectId)
+ * doc.array.pull({ _id: 'someId' })
+ * doc.array.pull(36)
+ * doc.array.pull('tag 1', 'tag 2')
+ *
+ * To remove a document from a subdocument array we may pass an object with a matching `_id`.
+ *
+ * doc.subdocs.push({ _id: 4815162342 })
+ * doc.subdocs.pull({ _id: 4815162342 }) // removed
+ *
+ * Or we may passing the _id directly and let mongoose take care of it.
+ *
+ * doc.subdocs.push({ _id: 4815162342 })
+ * doc.subdocs.pull(4815162342); // works
+ *
+ * The first pull call will result in a atomic operation on the database, if pull is called repeatedly without saving the document, a $set operation is used on the complete array instead, overwriting possible changes that happened on the database in the meantime.
+ *
+ * @param {any} [args...]
+ * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull
+ * @api public
+ * @method pull
+ * @memberOf MongooseArray
+ */
+
+ pull() {
+ const values = [].map.call(arguments, this._cast, this);
+ const cur = this[arrayParentSymbol].get(this[arrayPathSymbol]);
+ let i = cur.length;
+ let mem;
+
+ while (i--) {
+ mem = cur[i];
+ if (mem instanceof Document) {
+ const some = values.some(function(v) {
+ return mem.equals(v);
+ });
+ if (some) {
+ [].splice.call(cur, i, 1);
+ }
+ } else if (~cur.indexOf.call(values, mem)) {
+ [].splice.call(cur, i, 1);
+ }
+ }
+
+ if (values[0] instanceof EmbeddedDocument) {
+ this._registerAtomic('$pullDocs', values.map(function(v) {
+ return v._id || v;
+ }));
+ } else {
+ this._registerAtomic('$pullAll', values);
+ }
+
+ this._markModified();
+
+ // Might have modified child paths and then pulled, like
+ // `doc.children[1].name = 'test';` followed by
+ // `doc.children.remove(doc.children[0]);`. In this case we fall back
+ // to a `$set` on the whole array. See #3511
+ if (cleanModifiedSubpaths(this[arrayParentSymbol], this[arrayPathSymbol]) > 0) {
+ this._registerAtomic('$set', this);
+ }
+
+ return this;
+ }
+
+ /**
+ * Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
+ *
+ * ####Example:
+ *
+ * const schema = Schema({ nums: [Number] });
+ * const Model = mongoose.model('Test', schema);
+ *
+ * const doc = await Model.create({ nums: [3, 4] });
+ * doc.nums.push(5); // Add 5 to the end of the array
+ * await doc.save();
+ *
+ * // You can also pass an object with `$each` as the
+ * // first parameter to use MongoDB's `$position`
+ * doc.nums.push({
+ * $each: [1, 2],
+ * $position: 0
+ * });
+ * doc.nums; // [1, 2, 3, 4, 5]
+ *
+ * @param {Object} [args...]
+ * @api public
+ * @method push
+ * @memberOf MongooseArray
+ */
+
+ push() {
+ let values = arguments;
+ let atomic = values;
+ const isOverwrite = values[0] != null &&
+ utils.hasUserDefinedProperty(values[0], '$each');
+ if (isOverwrite) {
+ atomic = values[0];
+ values = values[0].$each;
+ }
+
+ if (this[arraySchemaSymbol] == null) {
+ return _basePush.apply(this, values);
+ }
+
+ _checkManualPopulation(this, values);
+
+ const parent = this[arrayParentSymbol];
+ values = [].map.call(values, this._mapCast, this);
+ values = this[arraySchemaSymbol].applySetters(values, parent, undefined,
+ undefined, { skipDocumentArrayCast: true });
+ let ret;
+ const atomics = this[arrayAtomicsSymbol];
+
+ if (isOverwrite) {
+ atomic.$each = values;
+
+ if (get(atomics, '$push.$each.length', 0) > 0 &&
+ atomics.$push.$position != atomics.$position) {
+ throw new MongooseError('Cannot call `Array#push()` multiple times ' +
+ 'with different `$position`');
+ }
+
+ if (atomic.$position != null) {
+ [].splice.apply(this, [atomic.$position, 0].concat(values));
+ ret = this.length;
+ } else {
+ ret = [].push.apply(this, values);
+ }
+ } else {
+ if (get(atomics, '$push.$each.length', 0) > 0 &&
+ atomics.$push.$position != null) {
+ throw new MongooseError('Cannot call `Array#push()` multiple times ' +
+ 'with different `$position`');
+ }
+ atomic = values;
+ ret = [].push.apply(this, values);
+ }
+ this._registerAtomic('$push', atomic);
+ this._markModified();
+ return ret;
+ }
+
+ /**
+ * Alias of [pull](#types_array_MongooseArray-pull)
+ *
+ * @see MongooseArray#pull #types_array_MongooseArray-pull
+ * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull
+ * @api public
+ * @memberOf MongooseArray
+ * @instance
+ * @method remove
+ */
+
+ remove() {
+ return this.pull.apply(this, arguments);
+ }
+
+ /**
+ * Sets the casted `val` at index `i` and marks the array modified.
+ *
+ * ####Example:
+ *
+ * // given documents based on the following
+ * var Doc = mongoose.model('Doc', new Schema({ array: [Number] }));
+ *
+ * var doc = new Doc({ array: [2,3,4] })
+ *
+ * console.log(doc.array) // [2,3,4]
+ *
+ * doc.array.set(1,"5");
+ * console.log(doc.array); // [2,5,4] // properly cast to number
+ * doc.save() // the change is saved
+ *
+ * // VS not using array#set
+ * doc.array[1] = "5";
+ * console.log(doc.array); // [2,"5",4] // no casting
+ * doc.save() // change is not saved
+ *
+ * @return {Array} this
+ * @api public
+ * @method set
+ * @memberOf MongooseArray
+ */
+
+ set(i, val) {
+ const value = this._cast(val, i);
+ this[i] = value;
+ this._markModified(i);
+ return this;
+ }
+
+ /**
+ * Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
+ *
+ * ####Example:
+ *
+ * doc.array = [2,3];
+ * var res = doc.array.shift();
+ * console.log(res) // 2
+ * console.log(doc.array) // [3]
+ *
+ * ####Note:
+ *
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @api public
+ * @method shift
+ * @memberOf MongooseArray
+ */
+
+ shift() {
+ const ret = [].shift.call(this);
+ this._registerAtomic('$set', this);
+ this._markModified();
+ return ret;
+ }
+
+ /**
+ * Wraps [`Array#sort`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) with proper change tracking.
+ *
+ * ####NOTE:
+ *
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @api public
+ * @method sort
+ * @memberOf MongooseArray
+ * @see https://masteringjs.io/tutorials/fundamentals/array-sort
+ */
+
+ sort() {
+ const ret = [].sort.apply(this, arguments);
+ this._registerAtomic('$set', this);
+ return ret;
+ }
+
+ /**
+ * Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
+ *
+ * ####Note:
+ *
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @api public
+ * @method splice
+ * @memberOf MongooseArray
+ * @see https://masteringjs.io/tutorials/fundamentals/array-splice
+ */
+
+ splice() {
+ let ret;
+
+ _checkManualPopulation(this, Array.prototype.slice.call(arguments, 2));
+
+ if (arguments.length) {
+ let vals;
+ if (this[arraySchemaSymbol] == null) {
+ vals = arguments;
+ } else {
+ vals = [];
+ for (let i = 0; i < arguments.length; ++i) {
+ vals[i] = i < 2 ?
+ arguments[i] :
+ this._cast(arguments[i], arguments[0] + (i - 2));
+ }
+ }
+
+ ret = [].splice.apply(this, vals);
+ this._registerAtomic('$set', this);
+ }
+
+ return ret;
+ }
+
+ /*!
+ * ignore
+ */
+
+ slice() {
+ const ret = super.slice.apply(this, arguments);
+ ret[arrayParentSymbol] = this[arrayParentSymbol];
+ ret[arraySchemaSymbol] = this[arraySchemaSymbol];
+ ret[arrayAtomicsSymbol] = this[arrayAtomicsSymbol];
+ return ret;
+ }
+
+ /*!
+ * ignore
+ */
+
+ toBSON() {
+ return this.toObject(internalToObjectOptions);
+ }
+
+ /**
+ * Returns a native js Array.
+ *
+ * @param {Object} options
+ * @return {Array}
+ * @api public
+ * @method toObject
+ * @memberOf MongooseArray
+ */
+
+ toObject(options) {
+ if (options && options.depopulate) {
+ options = utils.clone(options);
+ options._isNested = true;
+ return this.map(function(doc) {
+ return doc instanceof Document
+ ? doc.toObject(options)
+ : doc;
+ });
+ }
+
+ return this.slice();
+ }
+
+ /**
+ * Wraps [`Array#unshift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
+ *
+ * ####Note:
+ *
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
+ *
+ * @api public
+ * @method unshift
+ * @memberOf MongooseArray
+ */
+
+ unshift() {
+ _checkManualPopulation(this, arguments);
+
+ let values = [].map.call(arguments, this._cast, this);
+ values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
+ [].unshift.apply(this, values);
+ this._registerAtomic('$set', this);
+ this._markModified();
+ return this.length;
+ }
+}
+
+if (util.inspect.custom) {
+ CoreMongooseArray.prototype[util.inspect.custom] =
+ CoreMongooseArray.prototype.inspect;
+}
+
+/*!
+ * ignore
+ */
+
+function _isAllSubdocs(docs, ref) {
+ if (!ref) {
+ return false;
+ }
+ for (let i = 0; i < docs.length; ++i) {
+ const arg = docs[i];
+ if (arg == null) {
+ return false;
+ }
+ const model = arg.constructor;
+ if (!(arg instanceof Document) ||
+ (model.modelName !== ref && model.baseModelName !== ref)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * ignore
+ */
+
+function _checkManualPopulation(arr, docs) {
+ const ref = arr == null ?
+ null :
+ get(arr[arraySchemaSymbol], 'caster.options.ref', null);
+ if (arr.length === 0 &&
+ docs.length > 0) {
+ if (_isAllSubdocs(docs, ref)) {
+ arr[arrayParentSymbol].populated(arr[arrayPathSymbol], [], {
+ [populateModelSymbol]: docs[0].constructor
+ });
+ }
+ }
+}
+
+module.exports = CoreMongooseArray;
\ No newline at end of file
diff --git a/node_modules/mongoose/lib/types/decimal128.js b/node_modules/mongoose/lib/types/decimal128.js
new file mode 100644
index 0000000..f0bae2a
--- /dev/null
+++ b/node_modules/mongoose/lib/types/decimal128.js
@@ -0,0 +1,13 @@
+/**
+ * ObjectId type constructor
+ *
+ * ####Example
+ *
+ * var id = new mongoose.Types.ObjectId;
+ *
+ * @constructor ObjectId
+ */
+
+'use strict';
+
+module.exports = require('../driver').get().Decimal128;
diff --git a/node_modules/mongoose/lib/types/documentarray.js b/node_modules/mongoose/lib/types/documentarray.js
new file mode 100644
index 0000000..2ad3a45
--- /dev/null
+++ b/node_modules/mongoose/lib/types/documentarray.js
@@ -0,0 +1,420 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const CoreMongooseArray = require('./core_array');
+const Document = require('../document');
+const ObjectId = require('./objectid');
+const castObjectId = require('../cast/objectid');
+const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminatorByValue');
+const internalToObjectOptions = require('../options').internalToObjectOptions;
+const util = require('util');
+const utils = require('../utils');
+
+const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
+const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
+const arrayPathSymbol = require('../helpers/symbols').arrayPathSymbol;
+const arraySchemaSymbol = require('../helpers/symbols').arraySchemaSymbol;
+const documentArrayParent = require('../helpers/symbols').documentArrayParent;
+
+const _basePush = Array.prototype.push;
+
+class CoreDocumentArray extends CoreMongooseArray {
+ get isMongooseDocumentArray() {
+ return true;
+ }
+
+ /*!
+ * ignore
+ */
+
+ toBSON() {
+ return this.toObject(internalToObjectOptions);
+ }
+
+ /*!
+ * ignore
+ */
+
+ map() {
+ const ret = super.map.apply(this, arguments);
+ ret[arraySchemaSymbol] = null;
+ ret[arrayPathSymbol] = null;
+ ret[arrayParentSymbol] = null;
+
+ return ret;
+ }
+
+ /**
+ * Overrides MongooseArray#cast
+ *
+ * @method _cast
+ * @api private
+ * @receiver MongooseDocumentArray
+ */
+
+ _cast(value, index) {
+ if (this[arraySchemaSymbol] == null) {
+ return value;
+ }
+ let Constructor = this[arraySchemaSymbol].casterConstructor;
+ const isInstance = Constructor.$isMongooseDocumentArray ?
+ value && value.isMongooseDocumentArray :
+ value instanceof Constructor;
+ if (isInstance ||
+ // Hack re: #5001, see #5005
+ (value && value.constructor && value.constructor.baseCasterConstructor === Constructor)) {
+ if (!(value[documentArrayParent] && value.__parentArray)) {
+ // value may have been created using array.create()
+ value[documentArrayParent] = this[arrayParentSymbol];
+ value.__parentArray = this;
+ }
+ value.$setIndex(index);
+ return value;
+ }
+
+ if (value === undefined || value === null) {
+ return null;
+ }
+
+ // handle cast('string') or cast(ObjectId) etc.
+ // only objects are permitted so we can safely assume that
+ // non-objects are to be interpreted as _id
+ if (Buffer.isBuffer(value) ||
+ value instanceof ObjectId || !utils.isObject(value)) {
+ value = { _id: value };
+ }
+
+ if (value &&
+ Constructor.discriminators &&
+ Constructor.schema &&
+ Constructor.schema.options &&
+ Constructor.schema.options.discriminatorKey) {
+ if (typeof value[Constructor.schema.options.discriminatorKey] === 'string' &&
+ Constructor.discriminators[value[Constructor.schema.options.discriminatorKey]]) {
+ Constructor = Constructor.discriminators[value[Constructor.schema.options.discriminatorKey]];
+ } else {
+ const constructorByValue = getDiscriminatorByValue(Constructor, value[Constructor.schema.options.discriminatorKey]);
+ if (constructorByValue) {
+ Constructor = constructorByValue;
+ }
+ }
+ }
+
+ if (Constructor.$isMongooseDocumentArray) {
+ return Constructor.cast(value, this, undefined, undefined, index);
+ }
+ return new Constructor(value, this, undefined, undefined, index);
+ }
+
+ /**
+ * Searches array items for the first document with a matching _id.
+ *
+ * ####Example:
+ *
+ * var embeddedDoc = m.array.id(some_id);
+ *
+ * @return {EmbeddedDocument|null} the subdocument or null if not found.
+ * @param {ObjectId|String|Number|Buffer} id
+ * @TODO cast to the _id based on schema for proper comparison
+ * @method id
+ * @api public
+ * @receiver MongooseDocumentArray
+ */
+
+ id(id) {
+ let casted;
+ let sid;
+ let _id;
+
+ try {
+ casted = castObjectId(id).toString();
+ } catch (e) {
+ casted = null;
+ }
+
+ for (let i = 0, l = this.length; i < l; i++) {
+ if (!this[i]) {
+ continue;
+ }
+ _id = this[i].get('_id');
+
+ if (_id === null || typeof _id === 'undefined') {
+ continue;
+ } else if (_id instanceof Document) {
+ sid || (sid = String(id));
+ if (sid == _id._id) {
+ return this[i];
+ }
+ } else if (!(id instanceof ObjectId) && !(_id instanceof ObjectId)) {
+ if (utils.deepEqual(id, _id)) {
+ return this[i];
+ }
+ } else if (casted == _id) {
+ return this[i];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a native js Array of plain js objects
+ *
+ * ####NOTE:
+ *
+ * _Each sub-document is converted to a plain object by calling its `#toObject` method._
+ *
+ * @param {Object} [options] optional options to pass to each documents `toObject` method call during conversion
+ * @return {Array}
+ * @method toObject
+ * @api public
+ * @receiver MongooseDocumentArray
+ */
+
+ toObject(options) {
+ // `[].concat` coerces the return value into a vanilla JS array, rather
+ // than a Mongoose array.
+ return [].concat(this.map(function(doc) {
+ if (doc == null) {
+ return null;
+ }
+ if (typeof doc.toObject !== 'function') {
+ return doc;
+ }
+ return doc.toObject(options);
+ }));
+ }
+
+ slice() {
+ const arr = super.slice.apply(this, arguments);
+ arr[arrayParentSymbol] = this[arrayParentSymbol];
+ arr[arrayPathSymbol] = this[arrayPathSymbol];
+
+ return arr;
+ }
+
+ /**
+ * Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
+ *
+ * @param {Object} [args...]
+ * @api public
+ * @method push
+ * @memberOf MongooseDocumentArray
+ */
+
+ push() {
+ const ret = super.push.apply(this, arguments);
+
+ _updateParentPopulated(this);
+
+ return ret;
+ }
+
+ /**
+ * Pulls items from the array atomically.
+ *
+ * @param {Object} [args...]
+ * @api public
+ * @method pull
+ * @memberOf MongooseDocumentArray
+ */
+
+ pull() {
+ const ret = super.pull.apply(this, arguments);
+
+ _updateParentPopulated(this);
+
+ return ret;
+ }
+
+ /**
+ * Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
+ */
+
+ shift() {
+ const ret = super.shift.apply(this, arguments);
+
+ _updateParentPopulated(this);
+
+ return ret;
+ }
+
+ /**
+ * Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
+ */
+
+ splice() {
+ const ret = super.splice.apply(this, arguments);
+
+ _updateParentPopulated(this);
+
+ return ret;
+ }
+
+ /**
+ * Helper for console.log
+ *
+ * @method inspect
+ * @api public
+ * @receiver MongooseDocumentArray
+ */
+
+ inspect() {
+ return this.toObject();
+ }
+
+ /**
+ * Creates a subdocument casted to this schema.
+ *
+ * This is the same subdocument constructor used for casting.
+ *
+ * @param {Object} obj the value to cast to this arrays SubDocument schema
+ * @method create
+ * @api public
+ * @receiver MongooseDocumentArray
+ */
+
+ create(obj) {
+ let Constructor = this[arraySchemaSymbol].casterConstructor;
+ if (obj &&
+ Constructor.discriminators &&
+ Constructor.schema &&
+ Constructor.schema.options &&
+ Constructor.schema.options.discriminatorKey) {
+ if (typeof obj[Constructor.schema.options.discriminatorKey] === 'string' &&
+ Constructor.discriminators[obj[Constructor.schema.options.discriminatorKey]]) {
+ Constructor = Constructor.discriminators[obj[Constructor.schema.options.discriminatorKey]];
+ } else {
+ const constructorByValue = getDiscriminatorByValue(Constructor, obj[Constructor.schema.options.discriminatorKey]);
+ if (constructorByValue) {
+ Constructor = constructorByValue;
+ }
+ }
+ }
+
+ return new Constructor(obj, this);
+ }
+
+ /*!
+ * ignore
+ */
+
+ notify(event) {
+ const _this = this;
+ return function notify(val, _arr) {
+ _arr = _arr || _this;
+ let i = _arr.length;
+ while (i--) {
+ if (_arr[i] == null) {
+ continue;
+ }
+ switch (event) {
+ // only swap for save event for now, we may change this to all event types later
+ case 'save':
+ val = _this[i];
+ break;
+ default:
+ // NO-OP
+ break;
+ }
+
+ if (_arr[i].isMongooseArray) {
+ notify(val, _arr[i]);
+ } else if (_arr[i]) {
+ _arr[i].emit(event, val);
+ }
+ }
+ };
+ }
+}
+
+if (util.inspect.custom) {
+ CoreDocumentArray.prototype[util.inspect.custom] =
+ CoreDocumentArray.prototype.inspect;
+}
+
+/*!
+ * If this is a document array, each element may contain single
+ * populated paths, so we need to modify the top-level document's
+ * populated cache. See gh-8247, gh-8265.
+ */
+
+function _updateParentPopulated(arr) {
+ const parent = arr[arrayParentSymbol];
+ if (!parent || parent.$__.populated == null) return;
+
+ const populatedPaths = Object.keys(parent.$__.populated).
+ filter(p => p.startsWith(arr[arrayPathSymbol] + '.'));
+
+ for (const path of populatedPaths) {
+ const remnant = path.slice((arr[arrayPathSymbol] + '.').length);
+ if (!Array.isArray(parent.$__.populated[path].value)) {
+ continue;
+ }
+
+ parent.$__.populated[path].value = arr.map(val => val.populated(remnant));
+ }
+}
+
+/**
+ * DocumentArray constructor
+ *
+ * @param {Array} values
+ * @param {String} path the path to this array
+ * @param {Document} doc parent document
+ * @api private
+ * @return {MongooseDocumentArray}
+ * @inherits MongooseArray
+ * @see http://bit.ly/f6CnZU
+ */
+
+function MongooseDocumentArray(values, path, doc) {
+ // TODO: replace this with `new CoreDocumentArray().concat()` when we remove
+ // support for node 4.x and 5.x, see https://i.imgur.com/UAAHk4S.png
+ const arr = new CoreDocumentArray();
+
+ arr[arrayAtomicsSymbol] = {};
+ arr[arraySchemaSymbol] = void 0;
+ if (Array.isArray(values)) {
+ if (values instanceof CoreDocumentArray &&
+ values[arrayPathSymbol] === path &&
+ values[arrayParentSymbol] === doc) {
+ arr[arrayAtomicsSymbol] = Object.assign({}, values[arrayAtomicsSymbol]);
+ }
+ values.forEach(v => {
+ _basePush.call(arr, v);
+ });
+ }
+ arr[arrayPathSymbol] = path;
+
+ // Because doc comes from the context of another function, doc === global
+ // can happen if there was a null somewhere up the chain (see #3020 && #3034)
+ // RB Jun 17, 2015 updated to check for presence of expected paths instead
+ // to make more proof against unusual node environments
+ if (doc && doc instanceof Document) {
+ arr[arrayParentSymbol] = doc;
+ arr[arraySchemaSymbol] = doc.schema.path(path);
+
+ // `schema.path()` doesn't drill into nested arrays properly yet, see
+ // gh-6398, gh-6602. This is a workaround because nested arrays are
+ // always plain non-document arrays, so once you get to a document array
+ // nesting is done. Matryoshka code.
+ while (arr != null &&
+ arr[arraySchemaSymbol] != null &&
+ arr[arraySchemaSymbol].$isMongooseArray &&
+ !arr[arraySchemaSymbol].$isMongooseDocumentArray) {
+ arr[arraySchemaSymbol] = arr[arraySchemaSymbol].casterConstructor;
+ }
+ }
+
+ return arr;
+}
+
+/*!
+ * Module exports.
+ */
+
+module.exports = MongooseDocumentArray;
diff --git a/node_modules/mongoose/lib/types/embedded.js b/node_modules/mongoose/lib/types/embedded.js
new file mode 100644
index 0000000..5e817bf
--- /dev/null
+++ b/node_modules/mongoose/lib/types/embedded.js
@@ -0,0 +1,445 @@
+/* eslint no-func-assign: 1 */
+
+/*!
+ * Module dependencies.
+ */
+
+'use strict';
+
+const Document = require('../document_provider')();
+const EventEmitter = require('events').EventEmitter;
+const ValidationError = require('../error/validation');
+const immediate = require('../helpers/immediate');
+const internalToObjectOptions = require('../options').internalToObjectOptions;
+const get = require('../helpers/get');
+const promiseOrCallback = require('../helpers/promiseOrCallback');
+const util = require('util');
+
+const documentArrayParent = require('../helpers/symbols').documentArrayParent;
+const validatorErrorSymbol = require('../helpers/symbols').validatorErrorSymbol;
+
+/**
+ * EmbeddedDocument constructor.
+ *
+ * @param {Object} obj js object returned from the db
+ * @param {MongooseDocumentArray} parentArr the parent array of this document
+ * @param {Boolean} skipId
+ * @inherits Document
+ * @api private
+ */
+
+function EmbeddedDocument(obj, parentArr, skipId, fields, index) {
+ if (parentArr != null && parentArr.isMongooseDocumentArray) {
+ this.__parentArray = parentArr;
+ this[documentArrayParent] = parentArr.$parent();
+ } else {
+ this.__parentArray = undefined;
+ this[documentArrayParent] = undefined;
+ }
+ this.$setIndex(index);
+ this.$isDocumentArrayElement = true;
+
+ Document.call(this, obj, fields, skipId);
+
+ const _this = this;
+ this.on('isNew', function(val) {
+ _this.isNew = val;
+ });
+
+ _this.on('save', function() {
+ _this.constructor.emit('save', _this);
+ });
+}
+
+/*!
+ * Inherit from Document
+ */
+EmbeddedDocument.prototype = Object.create(Document.prototype);
+EmbeddedDocument.prototype.constructor = EmbeddedDocument;
+
+for (const i in EventEmitter.prototype) {
+ EmbeddedDocument[i] = EventEmitter.prototype[i];
+}
+
+EmbeddedDocument.prototype.toBSON = function() {
+ return this.toObject(internalToObjectOptions);
+};
+
+/*!
+ * ignore
+ */
+
+EmbeddedDocument.prototype.$setIndex = function(index) {
+ this.__index = index;
+
+ if (get(this, '$__.validationError', null) != null) {
+ const keys = Object.keys(this.$__.validationError.errors);
+ for (const key of keys) {
+ this.invalidate(key, this.$__.validationError.errors[key]);
+ }
+ }
+};
+
+/**
+ * Marks the embedded doc modified.
+ *
+ * ####Example:
+ *
+ * var doc = blogpost.comments.id(hexstring);
+ * doc.mixed.type = 'changed';
+ * doc.markModified('mixed.type');
+ *
+ * @param {String} path the path which changed
+ * @api public
+ * @receiver EmbeddedDocument
+ */
+
+EmbeddedDocument.prototype.markModified = function(path) {
+ this.$__.activePaths.modify(path);
+ if (!this.__parentArray) {
+ return;
+ }
+
+ if (this.isNew) {
+ // Mark the WHOLE parent array as modified
+ // if this is a new document (i.e., we are initializing
+ // a document),
+ this.__parentArray._markModified();
+ } else {
+ this.__parentArray._markModified(this, path);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+EmbeddedDocument.prototype.populate = function() {
+ throw new Error('Mongoose does not support calling populate() on nested ' +
+ 'docs. Instead of `doc.arr[0].populate("path")`, use ' +
+ '`doc.populate("arr.0.path")`');
+};
+
+/**
+ * Used as a stub for [hooks.js](https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3)
+ *
+ * ####NOTE:
+ *
+ * _This is a no-op. Does not actually save the doc to the db._
+ *
+ * @param {Function} [fn]
+ * @return {Promise} resolved Promise
+ * @api private
+ */
+
+EmbeddedDocument.prototype.save = function(options, fn) {
+ if (typeof options === 'function') {
+ fn = options;
+ options = {};
+ }
+ options = options || {};
+
+ if (!options.suppressWarning) {
+ console.warn('mongoose: calling `save()` on a subdoc does **not** save ' +
+ 'the document to MongoDB, it only runs save middleware. ' +
+ 'Use `subdoc.save({ suppressWarning: true })` to hide this warning ' +
+ 'if you\'re sure this behavior is right for your app.');
+ }
+
+ return promiseOrCallback(fn, cb => {
+ this.$__save(cb);
+ });
+};
+
+/**
+ * Used as a stub for middleware
+ *
+ * ####NOTE:
+ *
+ * _This is a no-op. Does not actually save the doc to the db._
+ *
+ * @param {Function} [fn]
+ * @method $__save
+ * @api private
+ */
+
+EmbeddedDocument.prototype.$__save = function(fn) {
+ return immediate(() => fn(null, this));
+};
+
+/*!
+ * Registers remove event listeners for triggering
+ * on subdocuments.
+ *
+ * @param {EmbeddedDocument} sub
+ * @api private
+ */
+
+function registerRemoveListener(sub) {
+ let owner = sub.ownerDocument();
+
+ function emitRemove() {
+ owner.removeListener('save', emitRemove);
+ owner.removeListener('remove', emitRemove);
+ sub.emit('remove', sub);
+ sub.constructor.emit('remove', sub);
+ owner = sub = null;
+ }
+
+ owner.on('save', emitRemove);
+ owner.on('remove', emitRemove);
+}
+
+/*!
+ * no-op for hooks
+ */
+
+EmbeddedDocument.prototype.$__remove = function(cb) {
+ return cb(null, this);
+};
+
+/**
+ * Removes the subdocument from its parent array.
+ *
+ * @param {Object} [options]
+ * @param {Function} [fn]
+ * @api public
+ */
+
+EmbeddedDocument.prototype.remove = function(options, fn) {
+ if ( typeof options === 'function' && !fn ) {
+ fn = options;
+ options = undefined;
+ }
+ if (!this.__parentArray || (options && options.noop)) {
+ fn && fn(null);
+ return this;
+ }
+
+ let _id;
+ if (!this.willRemove) {
+ _id = this._doc._id;
+ if (!_id) {
+ throw new Error('For your own good, Mongoose does not know ' +
+ 'how to remove an EmbeddedDocument that has no _id');
+ }
+ this.__parentArray.pull({ _id: _id });
+ this.willRemove = true;
+ registerRemoveListener(this);
+ }
+
+ if (fn) {
+ fn(null);
+ }
+
+ return this;
+};
+
+/**
+ * Override #update method of parent documents.
+ * @api private
+ */
+
+EmbeddedDocument.prototype.update = function() {
+ throw new Error('The #update method is not available on EmbeddedDocuments');
+};
+
+/**
+ * Helper for console.log
+ *
+ * @api public
+ */
+
+EmbeddedDocument.prototype.inspect = function() {
+ return this.toObject({
+ transform: false,
+ virtuals: false,
+ flattenDecimals: false
+ });
+};
+
+if (util.inspect.custom) {
+ /*!
+ * Avoid Node deprecation warning DEP0079
+ */
+
+ EmbeddedDocument.prototype[util.inspect.custom] = EmbeddedDocument.prototype.inspect;
+}
+
+/**
+ * Marks a path as invalid, causing validation to fail.
+ *
+ * @param {String} path the field to invalidate
+ * @param {String|Error} err error which states the reason `path` was invalid
+ * @return {Boolean}
+ * @api public
+ */
+
+EmbeddedDocument.prototype.invalidate = function(path, err, val) {
+ Document.prototype.invalidate.call(this, path, err, val);
+
+ if (!this[documentArrayParent] || this.__index == null) {
+ if (err[validatorErrorSymbol] || err instanceof ValidationError) {
+ return true;
+ }
+ throw err;
+ }
+
+ const index = this.__index;
+ const parentPath = this.__parentArray.$path();
+ const fullPath = [parentPath, index, path].join('.');
+ this[documentArrayParent].invalidate(fullPath, err, val);
+
+ return true;
+};
+
+/**
+ * Marks a path as valid, removing existing validation errors.
+ *
+ * @param {String} path the field to mark as valid
+ * @api private
+ * @method $markValid
+ * @receiver EmbeddedDocument
+ */
+
+EmbeddedDocument.prototype.$markValid = function(path) {
+ if (!this[documentArrayParent]) {
+ return;
+ }
+
+ const index = this.__index;
+ if (typeof index !== 'undefined') {
+ const parentPath = this.__parentArray.$path();
+ const fullPath = [parentPath, index, path].join('.');
+ this[documentArrayParent].$markValid(fullPath);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+EmbeddedDocument.prototype.$ignore = function(path) {
+ Document.prototype.$ignore.call(this, path);
+
+ if (!this[documentArrayParent]) {
+ return;
+ }
+
+ const index = this.__index;
+ if (typeof index !== 'undefined') {
+ const parentPath = this.__parentArray.$path();
+ const fullPath = [parentPath, index, path].join('.');
+ this[documentArrayParent].$ignore(fullPath);
+ }
+};
+
+/**
+ * Checks if a path is invalid
+ *
+ * @param {String} path the field to check
+ * @api private
+ * @method $isValid
+ * @receiver EmbeddedDocument
+ */
+
+EmbeddedDocument.prototype.$isValid = function(path) {
+ const index = this.__index;
+ if (typeof index !== 'undefined' && this[documentArrayParent]) {
+ return !this[documentArrayParent].$__.validationError ||
+ !this[documentArrayParent].$__.validationError.errors[this.$__fullPath(path)];
+ }
+
+ return true;
+};
+
+/**
+ * Returns the top level document of this sub-document.
+ *
+ * @return {Document}
+ */
+
+EmbeddedDocument.prototype.ownerDocument = function() {
+ if (this.$__.ownerDocument) {
+ return this.$__.ownerDocument;
+ }
+
+ let parent = this[documentArrayParent];
+ if (!parent) {
+ return this;
+ }
+
+ while (parent[documentArrayParent] || parent.$parent) {
+ parent = parent[documentArrayParent] || parent.$parent;
+ }
+
+ this.$__.ownerDocument = parent;
+ return this.$__.ownerDocument;
+};
+
+/**
+ * Returns the full path to this document. If optional `path` is passed, it is appended to the full path.
+ *
+ * @param {String} [path]
+ * @return {String}
+ * @api private
+ * @method $__fullPath
+ * @memberOf EmbeddedDocument
+ * @instance
+ */
+
+EmbeddedDocument.prototype.$__fullPath = function(path) {
+ if (!this.$__.fullPath) {
+ let parent = this; // eslint-disable-line consistent-this
+ if (!parent[documentArrayParent]) {
+ return path;
+ }
+
+ const paths = [];
+ while (parent[documentArrayParent] || parent.$parent) {
+ if (parent[documentArrayParent]) {
+ paths.unshift(parent.__parentArray.$path());
+ } else {
+ paths.unshift(parent.$basePath);
+ }
+ parent = parent[documentArrayParent] || parent.$parent;
+ }
+
+ this.$__.fullPath = paths.join('.');
+
+ if (!this.$__.ownerDocument) {
+ // optimization
+ this.$__.ownerDocument = parent;
+ }
+ }
+
+ return path
+ ? this.$__.fullPath + '.' + path
+ : this.$__.fullPath;
+};
+
+/**
+ * Returns this sub-documents parent document.
+ *
+ * @api public
+ */
+
+EmbeddedDocument.prototype.parent = function() {
+ return this[documentArrayParent];
+};
+
+/**
+ * Returns this sub-documents parent array.
+ *
+ * @api public
+ */
+
+EmbeddedDocument.prototype.parentArray = function() {
+ return this.__parentArray;
+};
+
+/*!
+ * Module exports.
+ */
+
+module.exports = EmbeddedDocument;
diff --git a/node_modules/mongoose/lib/types/index.js b/node_modules/mongoose/lib/types/index.js
new file mode 100644
index 0000000..a1945a0
--- /dev/null
+++ b/node_modules/mongoose/lib/types/index.js
@@ -0,0 +1,20 @@
+
+/*!
+ * Module exports.
+ */
+
+'use strict';
+
+exports.Array = require('./array');
+exports.Buffer = require('./buffer');
+
+exports.Document = // @deprecate
+exports.Embedded = require('./embedded');
+
+exports.DocumentArray = require('./documentarray');
+exports.Decimal128 = require('./decimal128');
+exports.ObjectId = require('./objectid');
+
+exports.Map = require('./map');
+
+exports.Subdocument = require('./subdocument');
diff --git a/node_modules/mongoose/lib/types/map.js b/node_modules/mongoose/lib/types/map.js
new file mode 100644
index 0000000..dae044d
--- /dev/null
+++ b/node_modules/mongoose/lib/types/map.js
@@ -0,0 +1,206 @@
+'use strict';
+
+const Mixed = require('../schema/mixed');
+const deepEqual = require('../utils').deepEqual;
+const get = require('../helpers/get');
+const util = require('util');
+const specialProperties = require('../helpers/specialProperties');
+
+const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
+
+/*!
+ * ignore
+ */
+
+class MongooseMap extends Map {
+ constructor(v, path, doc, schemaType) {
+ if (v != null && v.constructor.name === 'Object') {
+ v = Object.keys(v).reduce((arr, key) => arr.concat([[key, v[key]]]), []);
+ }
+ super(v);
+
+ this.$__parent = doc != null && doc.$__ != null ? doc : null;
+ this.$__path = path;
+ this.$__schemaType = schemaType == null ? new Mixed(path) : schemaType;
+
+ this.$__runDeferred();
+ }
+
+ $init(key, value) {
+ checkValidKey(key);
+
+ super.set(key, value);
+
+ if (value != null && value.$isSingleNested) {
+ value.$basePath = this.$__path + '.' + key;
+ }
+ }
+
+ $__set(key, value) {
+ super.set(key, value);
+ }
+
+ set(key, value) {
+ checkValidKey(key);
+
+ // Weird, but because you can't assign to `this` before calling `super()`
+ // you can't get access to `$__schemaType` to cast in the initial call to
+ // `set()` from the `super()` constructor.
+
+ if (this.$__schemaType == null) {
+ this.$__deferred = this.$__deferred || [];
+ this.$__deferred.push({ key: key, value: value });
+ return;
+ }
+
+ const fullPath = this.$__path + '.' + key;
+ const populated = this.$__parent != null && this.$__parent.$__ ?
+ this.$__parent.populated(fullPath) || this.$__parent.populated(this.$__path) :
+ null;
+ const priorVal = this.get(key);
+
+ if (populated != null) {
+ if (value.$__ == null) {
+ value = new populated.options[populateModelSymbol](value);
+ }
+ value.$__.wasPopulated = true;
+ } else {
+ try {
+ value = this.$__schemaType.
+ applySetters(value, this.$__parent, false, this.get(key));
+ } catch (error) {
+ if (this.$__parent != null && this.$__parent.$__ != null) {
+ this.$__parent.invalidate(fullPath, error);
+ return;
+ }
+ throw error;
+ }
+ }
+
+ super.set(key, value);
+
+ if (value != null && value.$isSingleNested) {
+ value.$basePath = this.$__path + '.' + key;
+ }
+
+ const parent = this.$__parent;
+ if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
+ parent.markModified(this.$__path + '.' + key);
+ }
+ }
+
+ delete(key) {
+ this.set(key, undefined);
+ super.delete(key);
+ }
+
+ toBSON() {
+ return new Map(this);
+ }
+
+ toObject(options) {
+ if (get(options, 'flattenMaps')) {
+ const ret = {};
+ const keys = this.keys();
+ for (const key of keys) {
+ ret[key] = this.get(key);
+ }
+ return ret;
+ }
+
+ return new Map(this);
+ }
+
+ toJSON() {
+ const ret = {};
+ const keys = this.keys();
+ for (const key of keys) {
+ ret[key] = this.get(key);
+ }
+ return ret;
+ }
+
+ inspect() {
+ return new Map(this);
+ }
+
+ $__runDeferred() {
+ if (!this.$__deferred) {
+ return;
+ }
+ for (let i = 0; i < this.$__deferred.length; ++i) {
+ this.set(this.$__deferred[i].key, this.$__deferred[i].value);
+ }
+ this.$__deferred = null;
+ }
+}
+
+if (util.inspect.custom) {
+ Object.defineProperty(MongooseMap.prototype, util.inspect.custom, {
+ enumerable: false,
+ writable: false,
+ configurable: false,
+ value: MongooseMap.prototype.inspect
+ });
+}
+
+Object.defineProperty(MongooseMap.prototype, '$__set', {
+ enumerable: false,
+ writable: true,
+ configurable: false
+});
+
+Object.defineProperty(MongooseMap.prototype, '$__parent', {
+ enumerable: false,
+ writable: true,
+ configurable: false
+});
+
+Object.defineProperty(MongooseMap.prototype, '$__path', {
+ enumerable: false,
+ writable: true,
+ configurable: false
+});
+
+Object.defineProperty(MongooseMap.prototype, '$__schemaType', {
+ enumerable: false,
+ writable: true,
+ configurable: false
+});
+
+Object.defineProperty(MongooseMap.prototype, '$isMongooseMap', {
+ enumerable: false,
+ writable: false,
+ configurable: false,
+ value: true
+});
+
+Object.defineProperty(MongooseMap.prototype, '$__deferredCalls', {
+ enumerable: false,
+ writable: false,
+ configurable: false,
+ value: true
+});
+
+/*!
+ * Since maps are stored as objects under the hood, keys must be strings
+ * and can't contain any invalid characters
+ */
+
+function checkValidKey(key) {
+ const keyType = typeof key;
+ if (keyType !== 'string') {
+ throw new TypeError(`Mongoose maps only support string keys, got ${keyType}`);
+ }
+ if (key.startsWith('$')) {
+ throw new Error(`Mongoose maps do not support keys that start with "$", got "${key}"`);
+ }
+ if (key.includes('.')) {
+ throw new Error(`Mongoose maps do not support keys that contain ".", got "${key}"`);
+ }
+ if (specialProperties.has(key)) {
+ throw new Error(`Mongoose maps do not support reserved key name "${key}"`);
+ }
+}
+
+module.exports = MongooseMap;
diff --git a/node_modules/mongoose/lib/types/objectid.js b/node_modules/mongoose/lib/types/objectid.js
new file mode 100644
index 0000000..4c3f8b4
--- /dev/null
+++ b/node_modules/mongoose/lib/types/objectid.js
@@ -0,0 +1,30 @@
+/**
+ * ObjectId type constructor
+ *
+ * ####Example
+ *
+ * var id = new mongoose.Types.ObjectId;
+ *
+ * @constructor ObjectId
+ */
+
+'use strict';
+
+const ObjectId = require('../driver').get().ObjectId;
+const objectIdSymbol = require('../helpers/symbols').objectIdSymbol;
+
+/*!
+ * Getter for convenience with populate, see gh-6115
+ */
+
+Object.defineProperty(ObjectId.prototype, '_id', {
+ enumerable: false,
+ configurable: true,
+ get: function() {
+ return this;
+ }
+});
+
+ObjectId.prototype[objectIdSymbol] = true;
+
+module.exports = ObjectId;
diff --git a/node_modules/mongoose/lib/types/subdocument.js b/node_modules/mongoose/lib/types/subdocument.js
new file mode 100644
index 0000000..521237a
--- /dev/null
+++ b/node_modules/mongoose/lib/types/subdocument.js
@@ -0,0 +1,282 @@
+'use strict';
+
+const Document = require('../document');
+const immediate = require('../helpers/immediate');
+const internalToObjectOptions = require('../options').internalToObjectOptions;
+const promiseOrCallback = require('../helpers/promiseOrCallback');
+
+const documentArrayParent = require('../helpers/symbols').documentArrayParent;
+
+module.exports = Subdocument;
+
+/**
+ * Subdocument constructor.
+ *
+ * @inherits Document
+ * @api private
+ */
+
+function Subdocument(value, fields, parent, skipId, options) {
+ this.$isSingleNested = true;
+
+ const hasPriorDoc = options != null && options.priorDoc;
+ let initedPaths = null;
+ if (hasPriorDoc) {
+ this._doc = Object.assign({}, options.priorDoc._doc);
+ delete this._doc[this.schema.options.discriminatorKey];
+ initedPaths = Object.keys(options.priorDoc._doc || {}).
+ filter(key => key !== this.schema.options.discriminatorKey);
+ }
+ if (parent != null) {
+ // If setting a nested path, should copy isNew from parent re: gh-7048
+ options = Object.assign({}, options, { isNew: parent.isNew });
+ }
+ Document.call(this, value, fields, skipId, options);
+
+ if (hasPriorDoc) {
+ for (const key of initedPaths) {
+ if (!this.$__.activePaths.states.modify[key] &&
+ !this.$__.activePaths.states.default[key] &&
+ !this.$__.$setCalled.has(key)) {
+ const schematype = this.schema.path(key);
+ const def = schematype == null ? void 0 : schematype.getDefault(this);
+ if (def === void 0) {
+ delete this._doc[key];
+ } else {
+ this._doc[key] = def;
+ this.$__.activePaths.default(key);
+ }
+ }
+ }
+ }
+}
+
+Subdocument.prototype = Object.create(Document.prototype);
+
+Subdocument.prototype.toBSON = function() {
+ return this.toObject(internalToObjectOptions);
+};
+
+/**
+ * Used as a stub for middleware
+ *
+ * ####NOTE:
+ *
+ * _This is a no-op. Does not actually save the doc to the db._
+ *
+ * @param {Function} [fn]
+ * @return {Promise} resolved Promise
+ * @api private
+ */
+
+Subdocument.prototype.save = function(options, fn) {
+ if (typeof options === 'function') {
+ fn = options;
+ options = {};
+ }
+ options = options || {};
+
+ if (!options.suppressWarning) {
+ console.warn('mongoose: calling `save()` on a subdoc does **not** save ' +
+ 'the document to MongoDB, it only runs save middleware. ' +
+ 'Use `subdoc.save({ suppressWarning: true })` to hide this warning ' +
+ 'if you\'re sure this behavior is right for your app.');
+ }
+
+ return promiseOrCallback(fn, cb => {
+ this.$__save(cb);
+ });
+};
+
+/**
+ * Used as a stub for middleware
+ *
+ * ####NOTE:
+ *
+ * _This is a no-op. Does not actually save the doc to the db._
+ *
+ * @param {Function} [fn]
+ * @method $__save
+ * @api private
+ */
+
+Subdocument.prototype.$__save = function(fn) {
+ return immediate(() => fn(null, this));
+};
+
+Subdocument.prototype.$isValid = function(path) {
+ if (this.$parent && this.$basePath) {
+ return this.$parent.$isValid([this.$basePath, path].join('.'));
+ }
+ return Document.prototype.$isValid.call(this, path);
+};
+
+Subdocument.prototype.markModified = function(path) {
+ Document.prototype.markModified.call(this, path);
+
+ if (this.$parent && this.$basePath) {
+ if (this.$parent.isDirectModified(this.$basePath)) {
+ return;
+ }
+ this.$parent.markModified([this.$basePath, path].join('.'), this);
+ }
+};
+
+Subdocument.prototype.isModified = function(paths, modifiedPaths) {
+ if (this.$parent && this.$basePath) {
+ if (Array.isArray(paths) || typeof paths === 'string') {
+ paths = (Array.isArray(paths) ? paths : paths.split(' '));
+ paths = paths.map(p => [this.$basePath, p].join('.'));
+ }
+
+ return this.$parent.isModified(paths, modifiedPaths);
+ }
+
+ return Document.prototype.isModified.call(this, paths, modifiedPaths);
+};
+
+/**
+ * Marks a path as valid, removing existing validation errors.
+ *
+ * @param {String} path the field to mark as valid
+ * @api private
+ * @method $markValid
+ * @receiver Subdocument
+ */
+
+Subdocument.prototype.$markValid = function(path) {
+ Document.prototype.$markValid.call(this, path);
+ if (this.$parent && this.$basePath) {
+ this.$parent.$markValid([this.$basePath, path].join('.'));
+ }
+};
+
+/*!
+ * ignore
+ */
+
+Subdocument.prototype.invalidate = function(path, err, val) {
+ // Hack: array subdocuments' validationError is equal to the owner doc's,
+ // so validating an array subdoc gives the top-level doc back. Temporary
+ // workaround for #5208 so we don't have circular errors.
+ if (err !== this.ownerDocument().$__.validationError) {
+ Document.prototype.invalidate.call(this, path, err, val);
+ }
+
+ if (this.$parent && this.$basePath) {
+ this.$parent.invalidate([this.$basePath, path].join('.'), err, val);
+ } else if (err.kind === 'cast' || err.name === 'CastError') {
+ throw err;
+ }
+};
+
+/*!
+ * ignore
+ */
+
+Subdocument.prototype.$ignore = function(path) {
+ Document.prototype.$ignore.call(this, path);
+ if (this.$parent && this.$basePath) {
+ this.$parent.$ignore([this.$basePath, path].join('.'));
+ }
+};
+
+/**
+ * Returns the top level document of this sub-document.
+ *
+ * @return {Document}
+ */
+
+Subdocument.prototype.ownerDocument = function() {
+ if (this.$__.ownerDocument) {
+ return this.$__.ownerDocument;
+ }
+
+ let parent = this.$parent;
+ if (!parent) {
+ return this;
+ }
+
+ while (parent.$parent || parent[documentArrayParent]) {
+ parent = parent.$parent || parent[documentArrayParent];
+ }
+
+ this.$__.ownerDocument = parent;
+ return this.$__.ownerDocument;
+};
+
+/**
+ * Returns this sub-documents parent document.
+ *
+ * @api public
+ */
+
+Subdocument.prototype.parent = function() {
+ return this.$parent;
+};
+
+/*!
+ * no-op for hooks
+ */
+
+Subdocument.prototype.$__remove = function(cb) {
+ return cb(null, this);
+};
+
+/**
+ * Null-out this subdoc
+ *
+ * @param {Object} [options]
+ * @param {Function} [callback] optional callback for compatibility with Document.prototype.remove
+ */
+
+Subdocument.prototype.remove = function(options, callback) {
+ if (typeof options === 'function') {
+ callback = options;
+ options = null;
+ }
+
+ registerRemoveListener(this);
+
+ // If removing entire doc, no need to remove subdoc
+ if (!options || !options.noop) {
+ this.$parent.set(this.$basePath, null);
+ }
+
+ if (typeof callback === 'function') {
+ callback(null);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+Subdocument.prototype.populate = function() {
+ throw new Error('Mongoose does not support calling populate() on nested ' +
+ 'docs. Instead of `doc.nested.populate("path")`, use ' +
+ '`doc.populate("nested.path")`');
+};
+
+/*!
+ * Registers remove event listeners for triggering
+ * on subdocuments.
+ *
+ * @param {Subdocument} sub
+ * @api private
+ */
+
+function registerRemoveListener(sub) {
+ let owner = sub.ownerDocument();
+
+ function emitRemove() {
+ owner.removeListener('save', emitRemove);
+ owner.removeListener('remove', emitRemove);
+ sub.emit('remove', sub);
+ sub.constructor.emit('remove', sub);
+ owner = sub = null;
+ }
+
+ owner.on('save', emitRemove);
+ owner.on('remove', emitRemove);
+}
diff --git a/node_modules/mongoose/lib/utils.js b/node_modules/mongoose/lib/utils.js
new file mode 100644
index 0000000..b0a3749
--- /dev/null
+++ b/node_modules/mongoose/lib/utils.js
@@ -0,0 +1,901 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const ms = require('ms');
+const mpath = require('mpath');
+const sliced = require('sliced');
+const Buffer = require('safe-buffer').Buffer;
+const Decimal = require('./types/decimal128');
+const ObjectId = require('./types/objectid');
+const PopulateOptions = require('./options/PopulateOptions');
+const clone = require('./helpers/clone');
+const isObject = require('./helpers/isObject');
+const isBsonType = require('./helpers/isBsonType');
+const getFunctionName = require('./helpers/getFunctionName');
+const isMongooseObject = require('./helpers/isMongooseObject');
+const promiseOrCallback = require('./helpers/promiseOrCallback');
+const specialProperties = require('./helpers/specialProperties');
+
+let Document;
+
+exports.specialProperties = specialProperties;
+
+/*!
+ * Produces a collection name from model `name`. By default, just returns
+ * the model name
+ *
+ * @param {String} name a model name
+ * @param {Function} pluralize function that pluralizes the collection name
+ * @return {String} a collection name
+ * @api private
+ */
+
+exports.toCollectionName = function(name, pluralize) {
+ if (name === 'system.profile') {
+ return name;
+ }
+ if (name === 'system.indexes') {
+ return name;
+ }
+ if (typeof pluralize === 'function') {
+ return pluralize(name);
+ }
+ return name;
+};
+
+/*!
+ * Determines if `a` and `b` are deep equal.
+ *
+ * Modified from node/lib/assert.js
+ *
+ * @param {any} a a value to compare to `b`
+ * @param {any} b a value to compare to `a`
+ * @return {Boolean}
+ * @api private
+ */
+
+exports.deepEqual = function deepEqual(a, b) {
+ if (a === b) {
+ return true;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() === b.getTime();
+ }
+
+ if ((isBsonType(a, 'ObjectID') && isBsonType(b, 'ObjectID')) ||
+ (isBsonType(a, 'Decimal128') && isBsonType(b, 'Decimal128'))) {
+ return a.toString() === b.toString();
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return a.source === b.source &&
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline &&
+ a.global === b.global;
+ }
+
+ if (typeof a !== 'object' && typeof b !== 'object') {
+ return a == b;
+ }
+
+ if (a === null || b === null || a === undefined || b === undefined) {
+ return false;
+ }
+
+ if (a.prototype !== b.prototype) {
+ return false;
+ }
+
+ // Handle MongooseNumbers
+ if (a instanceof Number && b instanceof Number) {
+ return a.valueOf() === b.valueOf();
+ }
+
+ if (Buffer.isBuffer(a)) {
+ return exports.buffer.areEqual(a, b);
+ }
+
+ if (isMongooseObject(a)) {
+ a = a.toObject();
+ }
+ if (isMongooseObject(b)) {
+ b = b.toObject();
+ }
+
+ let ka;
+ let kb;
+ let key;
+ let i;
+ try {
+ ka = Object.keys(a);
+ kb = Object.keys(b);
+ } catch (e) {
+ // happens when one is a string literal and the other isn't
+ return false;
+ }
+
+ // having the same number of owned properties (keys incorporates
+ // hasOwnProperty)
+ if (ka.length !== kb.length) {
+ return false;
+ }
+
+ // the same set of keys (although not necessarily the same order),
+ ka.sort();
+ kb.sort();
+
+ // ~~~cheap key test
+ for (i = ka.length - 1; i >= 0; i--) {
+ if (ka[i] !== kb[i]) {
+ return false;
+ }
+ }
+
+ // equivalent values for every corresponding key, and
+ // ~~~possibly expensive deep test
+ for (i = ka.length - 1; i >= 0; i--) {
+ key = ka[i];
+ if (!deepEqual(a[key], b[key])) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+/*!
+ * Get the last element of an array
+ */
+
+exports.last = function(arr) {
+ if (arr.length > 0) {
+ return arr[arr.length - 1];
+ }
+ return void 0;
+};
+
+exports.clone = clone;
+
+/*!
+ * ignore
+ */
+
+exports.promiseOrCallback = promiseOrCallback;
+
+/*!
+ * ignore
+ */
+
+exports.omit = function omit(obj, keys) {
+ if (keys == null) {
+ return Object.assign({}, obj);
+ }
+ if (!Array.isArray(keys)) {
+ keys = [keys];
+ }
+
+ const ret = Object.assign({}, obj);
+ for (const key of keys) {
+ delete ret[key];
+ }
+ return ret;
+};
+
+
+/*!
+ * Shallow copies defaults into options.
+ *
+ * @param {Object} defaults
+ * @param {Object} options
+ * @return {Object} the merged object
+ * @api private
+ */
+
+exports.options = function(defaults, options) {
+ const keys = Object.keys(defaults);
+ let i = keys.length;
+ let k;
+
+ options = options || {};
+
+ while (i--) {
+ k = keys[i];
+ if (!(k in options)) {
+ options[k] = defaults[k];
+ }
+ }
+
+ return options;
+};
+
+/*!
+ * Generates a random string
+ *
+ * @api private
+ */
+
+exports.random = function() {
+ return Math.random().toString().substr(3);
+};
+
+/*!
+ * Merges `from` into `to` without overwriting existing properties.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ * @api private
+ */
+
+exports.merge = function merge(to, from, options, path) {
+ options = options || {};
+
+ const keys = Object.keys(from);
+ let i = 0;
+ const len = keys.length;
+ let key;
+
+ path = path || '';
+ const omitNested = options.omitNested || {};
+
+ while (i < len) {
+ key = keys[i++];
+ if (options.omit && options.omit[key]) {
+ continue;
+ }
+ if (omitNested[path]) {
+ continue;
+ }
+ if (specialProperties.has(key)) {
+ continue;
+ }
+ if (to[key] == null) {
+ to[key] = from[key];
+ } else if (exports.isObject(from[key])) {
+ if (!exports.isObject(to[key])) {
+ to[key] = {};
+ }
+ if (from[key] != null) {
+ if (from[key].instanceOfSchema) {
+ if (to[key].instanceOfSchema) {
+ to[key].add(from[key].clone());
+ } else {
+ to[key] = from[key].clone();
+ }
+ continue;
+ } else if (from[key] instanceof ObjectId) {
+ to[key] = new ObjectId(from[key]);
+ continue;
+ }
+ }
+ merge(to[key], from[key], options, path ? path + '.' + key : key);
+ } else if (options.overwrite) {
+ to[key] = from[key];
+ }
+ }
+};
+
+/*!
+ * Applies toObject recursively.
+ *
+ * @param {Document|Array|Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+exports.toObject = function toObject(obj) {
+ Document || (Document = require('./document'));
+ let ret;
+
+ if (obj == null) {
+ return obj;
+ }
+
+ if (obj instanceof Document) {
+ return obj.toObject();
+ }
+
+ if (Array.isArray(obj)) {
+ ret = [];
+
+ for (let i = 0, len = obj.length; i < len; ++i) {
+ ret.push(toObject(obj[i]));
+ }
+
+ return ret;
+ }
+
+ if (exports.isPOJO(obj)) {
+ ret = {};
+
+ for (const k in obj) {
+ if (specialProperties.has(k)) {
+ continue;
+ }
+ ret[k] = toObject(obj[k]);
+ }
+
+ return ret;
+ }
+
+ return obj;
+};
+
+exports.isObject = isObject;
+
+/*!
+ * Determines if `arg` is a plain old JavaScript object (POJO). Specifically,
+ * `arg` must be an object but not an instance of any special class, like String,
+ * ObjectId, etc.
+ *
+ * `Object.getPrototypeOf()` is part of ES5: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
+ *
+ * @param {Object|Array|String|Function|RegExp|any} arg
+ * @api private
+ * @return {Boolean}
+ */
+
+exports.isPOJO = function isPOJO(arg) {
+ if (arg == null || typeof arg !== 'object') {
+ return false;
+ }
+ const proto = Object.getPrototypeOf(arg);
+ // Prototype may be null if you used `Object.create(null)`
+ // Checking `proto`'s constructor is safe because `getPrototypeOf()`
+ // explicitly crosses the boundary from object data to object metadata
+ return !proto || proto.constructor.name === 'Object';
+};
+
+/*!
+ * Determines if `obj` is a built-in object like an array, date, boolean,
+ * etc.
+ */
+
+exports.isNativeObject = function(arg) {
+ return Array.isArray(arg) ||
+ arg instanceof Date ||
+ arg instanceof Boolean ||
+ arg instanceof Number ||
+ arg instanceof String;
+};
+
+/*!
+ * Determines if `val` is an object that has no own keys
+ */
+
+exports.isEmptyObject = function(val) {
+ return val != null &&
+ typeof val === 'object' &&
+ Object.keys(val).length === 0;
+};
+
+/*!
+ * Search if `obj` or any POJOs nested underneath `obj` has a property named
+ * `key`
+ */
+
+exports.hasKey = function hasKey(obj, key) {
+ const props = Object.keys(obj);
+ for (const prop of props) {
+ if (prop === key) {
+ return true;
+ }
+ if (exports.isPOJO(obj[prop]) && exports.hasKey(obj[prop], key)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+/*!
+ * A faster Array.prototype.slice.call(arguments) alternative
+ * @api private
+ */
+
+exports.args = sliced;
+
+/*!
+ * process.nextTick helper.
+ *
+ * Wraps `callback` in a try/catch + nextTick.
+ *
+ * node-mongodb-native has a habit of state corruption when an error is immediately thrown from within a collection callback.
+ *
+ * @param {Function} callback
+ * @api private
+ */
+
+exports.tick = function tick(callback) {
+ if (typeof callback !== 'function') {
+ return;
+ }
+ return function() {
+ try {
+ callback.apply(this, arguments);
+ } catch (err) {
+ // only nextTick on err to get out of
+ // the event loop and avoid state corruption.
+ process.nextTick(function() {
+ throw err;
+ });
+ }
+ };
+};
+
+/*!
+ * Returns true if `v` is an object that can be serialized as a primitive in
+ * MongoDB
+ */
+
+exports.isMongooseType = function(v) {
+ return v instanceof ObjectId || v instanceof Decimal || v instanceof Buffer;
+};
+
+exports.isMongooseObject = isMongooseObject;
+
+/*!
+ * Converts `expires` options of index objects to `expiresAfterSeconds` options for MongoDB.
+ *
+ * @param {Object} object
+ * @api private
+ */
+
+exports.expires = function expires(object) {
+ if (!(object && object.constructor.name === 'Object')) {
+ return;
+ }
+ if (!('expires' in object)) {
+ return;
+ }
+
+ let when;
+ if (typeof object.expires !== 'string') {
+ when = object.expires;
+ } else {
+ when = Math.round(ms(object.expires) / 1000);
+ }
+ object.expireAfterSeconds = when;
+ delete object.expires;
+};
+
+/*!
+ * populate helper
+ */
+
+exports.populate = function populate(path, select, model, match, options, subPopulate, justOne, count) {
+ // might have passed an object specifying all arguments
+ let obj = null;
+ if (arguments.length === 1) {
+ if (path instanceof PopulateOptions) {
+ return [path];
+ }
+
+ if (Array.isArray(path)) {
+ const singles = makeSingles(path);
+ return singles.map(o => exports.populate(o)[0]);
+ }
+
+ if (exports.isObject(path)) {
+ obj = Object.assign({}, path);
+ } else {
+ obj = { path: path };
+ }
+ } else if (typeof model === 'object') {
+ obj = {
+ path: path,
+ select: select,
+ match: model,
+ options: match
+ };
+ } else {
+ obj = {
+ path: path,
+ select: select,
+ model: model,
+ match: match,
+ options: options,
+ populate: subPopulate,
+ justOne: justOne,
+ count: count
+ };
+ }
+
+ if (typeof obj.path !== 'string') {
+ throw new TypeError('utils.populate: invalid path. Expected string. Got typeof `' + typeof path + '`');
+ }
+
+ return _populateObj(obj);
+
+ // The order of select/conditions args is opposite Model.find but
+ // necessary to keep backward compatibility (select could be
+ // an array, string, or object literal).
+ function makeSingles(arr) {
+ const ret = [];
+ arr.forEach(function(obj) {
+ if (/[\s]/.test(obj.path)) {
+ const paths = obj.path.split(' ');
+ paths.forEach(function(p) {
+ const copy = Object.assign({}, obj);
+ copy.path = p;
+ ret.push(copy);
+ });
+ } else {
+ ret.push(obj);
+ }
+ });
+
+ return ret;
+ }
+};
+
+function _populateObj(obj) {
+ if (Array.isArray(obj.populate)) {
+ const ret = [];
+ obj.populate.forEach(function(obj) {
+ if (/[\s]/.test(obj.path)) {
+ const copy = Object.assign({}, obj);
+ const paths = copy.path.split(' ');
+ paths.forEach(function(p) {
+ copy.path = p;
+ ret.push(exports.populate(copy)[0]);
+ });
+ } else {
+ ret.push(exports.populate(obj)[0]);
+ }
+ });
+ obj.populate = exports.populate(ret);
+ } else if (obj.populate != null && typeof obj.populate === 'object') {
+ obj.populate = exports.populate(obj.populate);
+ }
+
+ const ret = [];
+ const paths = obj.path.split(' ');
+ if (obj.options != null) {
+ obj.options = exports.clone(obj.options);
+ }
+
+ for (let i = 0; i < paths.length; ++i) {
+ ret.push(new PopulateOptions(Object.assign({}, obj, { path: paths[i] })));
+ }
+
+ return ret;
+}
+
+/*!
+ * Return the value of `obj` at the given `path`.
+ *
+ * @param {String} path
+ * @param {Object} obj
+ */
+
+exports.getValue = function(path, obj, map) {
+ return mpath.get(path, obj, '_doc', map);
+};
+
+/*!
+ * Sets the value of `obj` at the given `path`.
+ *
+ * @param {String} path
+ * @param {Anything} val
+ * @param {Object} obj
+ */
+
+exports.setValue = function(path, val, obj, map, _copying) {
+ mpath.set(path, val, obj, '_doc', map, _copying);
+};
+
+/*!
+ * Returns an array of values from object `o`.
+ *
+ * @param {Object} o
+ * @return {Array}
+ * @private
+ */
+
+exports.object = {};
+exports.object.vals = function vals(o) {
+ const keys = Object.keys(o);
+ let i = keys.length;
+ const ret = [];
+
+ while (i--) {
+ ret.push(o[keys[i]]);
+ }
+
+ return ret;
+};
+
+/*!
+ * @see exports.options
+ */
+
+exports.object.shallowCopy = exports.options;
+
+/*!
+ * Safer helper for hasOwnProperty checks
+ *
+ * @param {Object} obj
+ * @param {String} prop
+ */
+
+const hop = Object.prototype.hasOwnProperty;
+exports.object.hasOwnProperty = function(obj, prop) {
+ return hop.call(obj, prop);
+};
+
+/*!
+ * Determine if `val` is null or undefined
+ *
+ * @return {Boolean}
+ */
+
+exports.isNullOrUndefined = function(val) {
+ return val === null || val === undefined;
+};
+
+/*!
+ * ignore
+ */
+
+exports.array = {};
+
+/*!
+ * Flattens an array.
+ *
+ * [ 1, [ 2, 3, [4] ]] -> [1,2,3,4]
+ *
+ * @param {Array} arr
+ * @param {Function} [filter] If passed, will be invoked with each item in the array. If `filter` returns a falsy value, the item will not be included in the results.
+ * @return {Array}
+ * @private
+ */
+
+exports.array.flatten = function flatten(arr, filter, ret) {
+ ret || (ret = []);
+
+ arr.forEach(function(item) {
+ if (Array.isArray(item)) {
+ flatten(item, filter, ret);
+ } else {
+ if (!filter || filter(item)) {
+ ret.push(item);
+ }
+ }
+ });
+
+ return ret;
+};
+
+/*!
+ * ignore
+ */
+
+const _hasOwnProperty = Object.prototype.hasOwnProperty;
+
+exports.hasUserDefinedProperty = function(obj, key) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (Array.isArray(key)) {
+ for (const k of key) {
+ if (exports.hasUserDefinedProperty(obj, k)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (_hasOwnProperty.call(obj, key)) {
+ return true;
+ }
+ if (typeof obj === 'object' && key in obj) {
+ const v = obj[key];
+ return v !== Object.prototype[key] && v !== Array.prototype[key];
+ }
+
+ return false;
+};
+
+/*!
+ * ignore
+ */
+
+const MAX_ARRAY_INDEX = Math.pow(2, 32) - 1;
+
+exports.isArrayIndex = function(val) {
+ if (typeof val === 'number') {
+ return val >= 0 && val <= MAX_ARRAY_INDEX;
+ }
+ if (typeof val === 'string') {
+ if (!/^\d+$/.test(val)) {
+ return false;
+ }
+ val = +val;
+ return val >= 0 && val <= MAX_ARRAY_INDEX;
+ }
+
+ return false;
+};
+
+/*!
+ * Removes duplicate values from an array
+ *
+ * [1, 2, 3, 3, 5] => [1, 2, 3, 5]
+ * [ ObjectId("550988ba0c19d57f697dc45e"), ObjectId("550988ba0c19d57f697dc45e") ]
+ * => [ObjectId("550988ba0c19d57f697dc45e")]
+ *
+ * @param {Array} arr
+ * @return {Array}
+ * @private
+ */
+
+exports.array.unique = function(arr) {
+ const primitives = {};
+ const ids = {};
+ const ret = [];
+ const length = arr.length;
+ for (let i = 0; i < length; ++i) {
+ if (typeof arr[i] === 'number' || typeof arr[i] === 'string' || arr[i] == null) {
+ if (primitives[arr[i]]) {
+ continue;
+ }
+ ret.push(arr[i]);
+ primitives[arr[i]] = true;
+ } else if (arr[i] instanceof ObjectId) {
+ if (ids[arr[i].toString()]) {
+ continue;
+ }
+ ret.push(arr[i]);
+ ids[arr[i].toString()] = true;
+ } else {
+ ret.push(arr[i]);
+ }
+ }
+
+ return ret;
+};
+
+/*!
+ * Determines if two buffers are equal.
+ *
+ * @param {Buffer} a
+ * @param {Object} b
+ */
+
+exports.buffer = {};
+exports.buffer.areEqual = function(a, b) {
+ if (!Buffer.isBuffer(a)) {
+ return false;
+ }
+ if (!Buffer.isBuffer(b)) {
+ return false;
+ }
+ if (a.length !== b.length) {
+ return false;
+ }
+ for (let i = 0, len = a.length; i < len; ++i) {
+ if (a[i] !== b[i]) {
+ return false;
+ }
+ }
+ return true;
+};
+
+exports.getFunctionName = getFunctionName;
+/*!
+ * Decorate buffers
+ */
+
+exports.decorate = function(destination, source) {
+ for (const key in source) {
+ if (specialProperties.has(key)) {
+ continue;
+ }
+ destination[key] = source[key];
+ }
+};
+
+/**
+ * merges to with a copy of from
+ *
+ * @param {Object} to
+ * @param {Object} fromObj
+ * @api private
+ */
+
+exports.mergeClone = function(to, fromObj) {
+ if (isMongooseObject(fromObj)) {
+ fromObj = fromObj.toObject({
+ transform: false,
+ virtuals: false,
+ depopulate: true,
+ getters: false,
+ flattenDecimals: false
+ });
+ }
+ const keys = Object.keys(fromObj);
+ const len = keys.length;
+ let i = 0;
+ let key;
+
+ while (i < len) {
+ key = keys[i++];
+ if (specialProperties.has(key)) {
+ continue;
+ }
+ if (typeof to[key] === 'undefined') {
+ to[key] = exports.clone(fromObj[key], {
+ transform: false,
+ virtuals: false,
+ depopulate: true,
+ getters: false,
+ flattenDecimals: false
+ });
+ } else {
+ let val = fromObj[key];
+ if (val != null && val.valueOf && !(val instanceof Date)) {
+ val = val.valueOf();
+ }
+ if (exports.isObject(val)) {
+ let obj = val;
+ if (isMongooseObject(val) && !val.isMongooseBuffer) {
+ obj = obj.toObject({
+ transform: false,
+ virtuals: false,
+ depopulate: true,
+ getters: false,
+ flattenDecimals: false
+ });
+ }
+ if (val.isMongooseBuffer) {
+ obj = Buffer.from(obj);
+ }
+ exports.mergeClone(to[key], obj);
+ } else {
+ to[key] = exports.clone(val, {
+ flattenDecimals: false
+ });
+ }
+ }
+ }
+};
+
+/**
+ * Executes a function on each element of an array (like _.each)
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.each = function(arr, fn) {
+ for (let i = 0; i < arr.length; ++i) {
+ fn(arr[i]);
+ }
+};
+
+/*!
+ * ignore
+ */
+
+exports.getOption = function(name) {
+ const sources = Array.prototype.slice.call(arguments, 1);
+
+ for (const source of sources) {
+ if (source[name] != null) {
+ return source[name];
+ }
+ }
+
+ return null;
+};
+
+/*!
+ * ignore
+ */
+
+exports.noop = function() {};
diff --git a/node_modules/mongoose/lib/validoptions.js b/node_modules/mongoose/lib/validoptions.js
new file mode 100644
index 0000000..9464e4d
--- /dev/null
+++ b/node_modules/mongoose/lib/validoptions.js
@@ -0,0 +1,30 @@
+
+/*!
+ * Valid mongoose options
+ */
+
+'use strict';
+
+const VALID_OPTIONS = Object.freeze([
+ 'applyPluginsToChildSchemas',
+ 'applyPluginsToDiscriminators',
+ 'autoIndex',
+ 'bufferCommands',
+ 'cloneSchemas',
+ 'debug',
+ 'maxTimeMS',
+ 'objectIdGetter',
+ 'runValidators',
+ 'selectPopulatedPaths',
+ 'strict',
+ 'toJSON',
+ 'toObject',
+ 'useCreateIndex',
+ 'useFindAndModify',
+ 'useNewUrlParser',
+ 'usePushEach',
+ 'useUnifiedTopology',
+ 'typePojoToMixed'
+]);
+
+module.exports = VALID_OPTIONS;
diff --git a/node_modules/mongoose/lib/virtualtype.js b/node_modules/mongoose/lib/virtualtype.js
new file mode 100644
index 0000000..f91438a
--- /dev/null
+++ b/node_modules/mongoose/lib/virtualtype.js
@@ -0,0 +1,168 @@
+'use strict';
+
+/**
+ * VirtualType constructor
+ *
+ * This is what mongoose uses to define virtual attributes via `Schema.prototype.virtual`.
+ *
+ * ####Example:
+ *
+ * const fullname = schema.virtual('fullname');
+ * fullname instanceof mongoose.VirtualType // true
+ *
+ * @param {Object} options
+ * @param {string|function} [options.ref] if `ref` is not nullish, this becomes a [populated virtual](/docs/populate.html#populate-virtuals)
+ * @param {string|function} [options.localField] the local field to populate on if this is a populated virtual.
+ * @param {string|function} [options.foreignField] the foreign field to populate on if this is a populated virtual.
+ * @param {boolean} [options.justOne=false] by default, a populated virtual is an array. If you set `justOne`, the populated virtual will be a single doc or `null`.
+ * @param {boolean} [options.getters=false] if you set this to `true`, Mongoose will call any custom getters you defined on this virtual
+ * @param {boolean} [options.count=false] if you set this to `true`, `populate()` will set this virtual to the number of populated documents, as opposed to the documents themselves, using [`Query#countDocuments()`](./api.html#query_Query-countDocuments)
+ * @param {Object|Function} [options.match=null] add an extra match condition to `populate()`
+ * @param {Number} [options.limit=null] add a default `limit` to the `populate()` query
+ * @param {Number} [options.skip=null] add a default `skip` to the `populate()` query
+ * @param {Number} [options.perDocumentLimit=null] For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
+ * @param {Object} [options.options=null] Additional options like `limit` and `lean`.
+ * @api public
+ */
+
+function VirtualType(options, name) {
+ this.path = name;
+ this.getters = [];
+ this.setters = [];
+ this.options = Object.assign({}, options);
+}
+
+/**
+ * If no getters/getters, add a default
+ *
+ * @param {Function} fn
+ * @return {VirtualType} this
+ * @api private
+ */
+
+VirtualType.prototype._applyDefaultGetters = function() {
+ if (this.getters.length > 0 || this.setters.length > 0) {
+ return;
+ }
+
+ const path = this.path;
+ const internalProperty = '$' + path;
+ this.getters.push(function() {
+ return this[internalProperty];
+ });
+ this.setters.push(function(v) {
+ this[internalProperty] = v;
+ });
+};
+
+/*!
+ * ignore
+ */
+
+VirtualType.prototype.clone = function() {
+ const clone = new VirtualType(this.options, this.path);
+ clone.getters = [].concat(this.getters);
+ clone.setters = [].concat(this.setters);
+ return clone;
+};
+
+/**
+ * Adds a custom getter to this virtual.
+ *
+ * Mongoose calls the getter function with 3 parameters:
+ *
+ * - `value`: the value returned by the previous getter. If there is only one getter, `value` will be `undefined`.
+ * - `virtual`: the virtual object you called `.get()` on
+ * - `doc`: the document this virtual is attached to. Equivalent to `this`.
+ *
+ * ####Example:
+ *
+ * var virtual = schema.virtual('fullname');
+ * virtual.get(function(value, virtual, doc) {
+ * return this.name.first + ' ' + this.name.last;
+ * });
+ *
+ * @param {Function(Any, VirtualType, Document)} fn
+ * @return {VirtualType} this
+ * @api public
+ */
+
+VirtualType.prototype.get = function(fn) {
+ this.getters.push(fn);
+ return this;
+};
+
+/**
+ * Adds a custom setter to this virtual.
+ *
+ * Mongoose calls the setter function with 3 parameters:
+ *
+ * - `value`: the value being set
+ * - `virtual`: the virtual object you're calling `.set()` on
+ * - `doc`: the document this virtual is attached to. Equivalent to `this`.
+ *
+ * ####Example:
+ *
+ * const virtual = schema.virtual('fullname');
+ * virtual.set(function(value, virtual, doc) {
+ * var parts = value.split(' ');
+ * this.name.first = parts[0];
+ * this.name.last = parts[1];
+ * });
+ *
+ * const Model = mongoose.model('Test', schema);
+ * const doc = new Model();
+ * // Calls the setter with `value = 'Jean-Luc Picard'`
+ * doc.fullname = 'Jean-Luc Picard';
+ * doc.name.first; // 'Jean-Luc'
+ * doc.name.last; // 'Picard'
+ *
+ * @param {Function(Any, VirtualType, Document)} fn
+ * @return {VirtualType} this
+ * @api public
+ */
+
+VirtualType.prototype.set = function(fn) {
+ this.setters.push(fn);
+ return this;
+};
+
+/**
+ * Applies getters to `value`.
+ *
+ * @param {Object} value
+ * @param {Document} doc The document this virtual is attached to
+ * @return {any} the value after applying all getters
+ * @api public
+ */
+
+VirtualType.prototype.applyGetters = function(value, doc) {
+ let v = value;
+ for (let l = this.getters.length - 1; l >= 0; l--) {
+ v = this.getters[l].call(doc, v, this, doc);
+ }
+ return v;
+};
+
+/**
+ * Applies setters to `value`.
+ *
+ * @param {Object} value
+ * @param {Document} doc
+ * @return {any} the value after applying all setters
+ * @api public
+ */
+
+VirtualType.prototype.applySetters = function(value, doc) {
+ let v = value;
+ for (let l = this.setters.length - 1; l >= 0; l--) {
+ v = this.setters[l].call(doc, v, this, doc);
+ }
+ return v;
+};
+
+/*!
+ * exports
+ */
+
+module.exports = VirtualType;
diff --git a/node_modules/mongoose/node_modules/ms/index.js b/node_modules/mongoose/node_modules/ms/index.js
new file mode 100644
index 0000000..c4498bc
--- /dev/null
+++ b/node_modules/mongoose/node_modules/ms/index.js
@@ -0,0 +1,162 @@
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var w = d * 7;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ * - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val, options) {
+ options = options || {};
+ var type = typeof val;
+ if (type === 'string' && val.length > 0) {
+ return parse(val);
+ } else if (type === 'number' && isFinite(val)) {
+ return options.long ? fmtLong(val) : fmtShort(val);
+ }
+ throw new Error(
+ 'val is not a non-empty string or a valid number. val=' +
+ JSON.stringify(val)
+ );
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+ str = String(str);
+ if (str.length > 100) {
+ return;
+ }
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
+ str
+ );
+ if (!match) {
+ return;
+ }
+ var n = parseFloat(match[1]);
+ var type = (match[2] || 'ms').toLowerCase();
+ switch (type) {
+ case 'years':
+ case 'year':
+ case 'yrs':
+ case 'yr':
+ case 'y':
+ return n * y;
+ case 'weeks':
+ case 'week':
+ case 'w':
+ return n * w;
+ case 'days':
+ case 'day':
+ case 'd':
+ return n * d;
+ case 'hours':
+ case 'hour':
+ case 'hrs':
+ case 'hr':
+ case 'h':
+ return n * h;
+ case 'minutes':
+ case 'minute':
+ case 'mins':
+ case 'min':
+ case 'm':
+ return n * m;
+ case 'seconds':
+ case 'second':
+ case 'secs':
+ case 'sec':
+ case 's':
+ return n * s;
+ case 'milliseconds':
+ case 'millisecond':
+ case 'msecs':
+ case 'msec':
+ case 'ms':
+ return n;
+ default:
+ return undefined;
+ }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+ var msAbs = Math.abs(ms);
+ if (msAbs >= d) {
+ return Math.round(ms / d) + 'd';
+ }
+ if (msAbs >= h) {
+ return Math.round(ms / h) + 'h';
+ }
+ if (msAbs >= m) {
+ return Math.round(ms / m) + 'm';
+ }
+ if (msAbs >= s) {
+ return Math.round(ms / s) + 's';
+ }
+ return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+ var msAbs = Math.abs(ms);
+ if (msAbs >= d) {
+ return plural(ms, msAbs, d, 'day');
+ }
+ if (msAbs >= h) {
+ return plural(ms, msAbs, h, 'hour');
+ }
+ if (msAbs >= m) {
+ return plural(ms, msAbs, m, 'minute');
+ }
+ if (msAbs >= s) {
+ return plural(ms, msAbs, s, 'second');
+ }
+ return ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, msAbs, n, name) {
+ var isPlural = msAbs >= n * 1.5;
+ return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+}
diff --git a/node_modules/mongoose/node_modules/ms/license.md b/node_modules/mongoose/node_modules/ms/license.md
new file mode 100644
index 0000000..69b6125
--- /dev/null
+++ b/node_modules/mongoose/node_modules/ms/license.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Zeit, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/mongoose/node_modules/ms/package.json b/node_modules/mongoose/node_modules/ms/package.json
new file mode 100644
index 0000000..0312be8
--- /dev/null
+++ b/node_modules/mongoose/node_modules/ms/package.json
@@ -0,0 +1,291 @@
+{
+ "_args": [
+ [
+ "ms@2.1.2",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "ms@2.1.2",
+ "_hasShrinkwrap": false,
+ "_id": "ms@2.1.2",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mongoose/ms",
+ "_nodeVersion": "10.15.3",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/ms_2.1.2_1559842315767_0.4700607530567853"
+ },
+ "_npmUser": {
+ "email": "steven@ceriously.com",
+ "name": "styfle"
+ },
+ "_npmVersion": "6.4.1",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "ms",
+ "raw": "ms@2.1.2",
+ "rawSpec": "2.1.2",
+ "scope": null,
+ "spec": "2.1.2",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "_shasum": "d09d1f357b443f493382a8eb3ccd183872ae6009",
+ "_shrinkwrap": null,
+ "_spec": "ms@2.1.2",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "bugs": {
+ "url": "https://github.com/zeit/ms/issues"
+ },
+ "dependencies": {},
+ "description": "Tiny millisecond conversion utility",
+ "devDependencies": {
+ "eslint": "4.12.1",
+ "expect.js": "0.3.1",
+ "husky": "0.14.3",
+ "lint-staged": "5.0.0",
+ "mocha": "4.0.1"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 4,
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc+U4MCRA9TVsSAnZWagAA71AP/2rpu0zYdK5Z/BXrrKNW\nljsVOs4oHNJ2jeZrzpcV8eZUZ6zAi78plyxcnMCbbG+TrpjXrPcb8qFq630G\nS6+srbEF0lCGCc+ktJrNJPTeXkDxukQXVrepgZ2kxZ4m3q/QIAVoK4t9ebuH\nNYa+39wwET9oPuPsk+YY0Z7fQ1vadyuzHYOrRmtudV3ZtyT0k74Ec3IhKamW\nlLDJtCklD7IGcwirrvPssxmYu8WP+PAyFnrVaOW+iior1o07oWO2mk7sk3Fx\nwBSBFf7vZqFJP6Qg1m3TVBAiipL+Pf+b3Dy8fhmn4NhTGj/9Wl7f/LcqogOV\nV9l77qsZldCERBwmwLsHlMyCSSl/b2qaz28ZBTRwHtHdo19QT6MqX8Yvomy4\n+gyPBBAHC6bqqLZ0veRKzSNFfJYoFw8tQzyjSjpmYcdxaB5w4z4QPZAkZCku\ns+sooI5Xo33E9rcEDWmyqxdUud+Au/fTttg0dReYe8NVrUgzyk4T1W+D7I4k\nu3XV7O9bOaJiBTNsb22lGIC6E/HtjfoqW7iwl0cdZ8iZcPTBClkzsy9Hz6a4\nmNKDARFL0wjzWF/CoXyKcI6t9ruOepTQRfbAtZDAo4LEYj/bGiqm2kbX5AP6\nicCOlufTNip74l2bXv2sJNwtjGzEYF/S79Oyc49IP/ovIua4quXXtSjAh8Bg\nLrV/\r\n=GrYx\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "d09d1f357b443f493382a8eb3ccd183872ae6009",
+ "tarball": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "unpackedSize": 6842
+ },
+ "eslintConfig": {
+ "env": {
+ "es6": true,
+ "node": true
+ },
+ "extends": "eslint:recommended"
+ },
+ "gitHead": "7920885eb232fbe7a5efdab956d3e7c507c92ddf",
+ "homepage": "https://github.com/zeit/ms#readme",
+ "license": "MIT",
+ "lint-staged": {
+ "*.js": [
+ "git add",
+ "npm run lint",
+ "prettier --single-quote --write"
+ ]
+ },
+ "main": "./index",
+ "maintainers": [
+ {
+ "name": "lucleray",
+ "email": "luc.leray@gmail.com"
+ },
+ {
+ "name": "alexaltea",
+ "email": "alexandro@phi.nz"
+ },
+ {
+ "name": "andybitz",
+ "email": "artzbitz@gmail.com"
+ },
+ {
+ "name": "arunoda",
+ "email": "arunoda.susiripala@gmail.com"
+ },
+ {
+ "name": "arzafran",
+ "email": "franco@basement.studio"
+ },
+ {
+ "name": "atcastle",
+ "email": "atcastle@gmail.com"
+ },
+ {
+ "name": "b3nnyl",
+ "email": "ciao@sylin.me"
+ },
+ {
+ "name": "caarlos0",
+ "email": "caarlos0@gmail.com"
+ },
+ {
+ "name": "codetheory",
+ "email": "thecodetheory@gmail.com"
+ },
+ {
+ "name": "coetry",
+ "email": "allenhai03@gmail.com"
+ },
+ {
+ "name": "dav-is",
+ "email": "mail@connordav.is"
+ },
+ {
+ "name": "fivepointseven",
+ "email": "fivepointseven@icloud.com"
+ },
+ {
+ "name": "guybedford",
+ "email": "guybedford@gmail.com"
+ },
+ {
+ "name": "hharnisc",
+ "email": "hharnisc@gmail.com"
+ },
+ {
+ "name": "huvik",
+ "email": "lukas@huvar.cz"
+ },
+ {
+ "name": "iamevilrabbit",
+ "email": "hello@evilrabb.it"
+ },
+ {
+ "name": "igorklopov",
+ "email": "igor@klopov.com"
+ },
+ {
+ "name": "ijjk",
+ "email": "jj@jjsweb.site"
+ },
+ {
+ "name": "janicklas-ralph",
+ "email": "janicklasralph036@gmail.com"
+ },
+ {
+ "name": "javivelasco",
+ "email": "javier.velasco86@gmail.com"
+ },
+ {
+ "name": "joecohens",
+ "email": "joecohenr@gmail.com"
+ },
+ {
+ "name": "juancampa",
+ "email": "juancampa@gmail.com"
+ },
+ {
+ "name": "leo",
+ "email": "leo@zeit.co"
+ },
+ {
+ "name": "lfades",
+ "email": "luisito453@gmail.com"
+ },
+ {
+ "name": "anatrajkovska",
+ "email": "ana.trajkovska2015@gmail.com"
+ },
+ {
+ "name": "manovotny",
+ "email": "manovotny@gmail.com"
+ },
+ {
+ "name": "marcosnils",
+ "email": "marcosnils@gmail.com"
+ },
+ {
+ "name": "matheuss",
+ "email": "me@matheus.top"
+ },
+ {
+ "name": "mfix22",
+ "email": "mrfix84@gmail.com"
+ },
+ {
+ "name": "mglagola",
+ "email": "mark.glagola@gmail.com"
+ },
+ {
+ "name": "msweeneydev",
+ "email": "mail@msweeneydev.com"
+ },
+ {
+ "name": "nkzawa",
+ "email": "naoyuki.kanezawa@gmail.com"
+ },
+ {
+ "name": "olliv",
+ "email": "olli@zeit.co"
+ },
+ {
+ "name": "paco",
+ "email": "pvco.coursey@gmail.com"
+ },
+ {
+ "name": "paulogdm",
+ "email": "paulogdemitri@gmail.com"
+ },
+ {
+ "name": "quietshu",
+ "email": "ds303077135@gmail.com"
+ },
+ {
+ "name": "rabaut",
+ "email": "rabautse@gmail.com"
+ },
+ {
+ "name": "ragojose",
+ "email": "ragojosefrancisco@gmail.com"
+ },
+ {
+ "name": "rauchg",
+ "email": "rauchg@gmail.com"
+ },
+ {
+ "name": "sarupbanskota",
+ "email": "sbanskota08@gmail.com"
+ },
+ {
+ "name": "skllcrn",
+ "email": "skllcrn@zeit.co"
+ },
+ {
+ "name": "sophearak",
+ "email": "t.sophearak@gmail.com"
+ },
+ {
+ "name": "styfle",
+ "email": "steven@ceriously.com"
+ },
+ {
+ "name": "timer",
+ "email": "timer150@gmail.com"
+ },
+ {
+ "name": "timneutkens",
+ "email": "tim@timneutkens.nl"
+ },
+ {
+ "name": "tootallnate",
+ "email": "nathan@tootallnate.net"
+ },
+ {
+ "name": "umegaya",
+ "email": "iyatomi@gmail.com"
+ },
+ {
+ "name": "williamli",
+ "email": "williamli@bbi.io"
+ },
+ {
+ "name": "zeit-bot",
+ "email": "team@zeit.co"
+ }
+ ],
+ "name": "ms",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/zeit/ms.git"
+ },
+ "scripts": {
+ "lint": "eslint lib/* bin/*",
+ "precommit": "lint-staged",
+ "test": "mocha tests.js"
+ },
+ "version": "2.1.2"
+}
diff --git a/node_modules/mongoose/node_modules/ms/readme.md b/node_modules/mongoose/node_modules/ms/readme.md
new file mode 100644
index 0000000..9a1996b
--- /dev/null
+++ b/node_modules/mongoose/node_modules/ms/readme.md
@@ -0,0 +1,60 @@
+# ms
+
+[](https://travis-ci.org/zeit/ms)
+[](https://spectrum.chat/zeit)
+
+Use this package to easily convert various time formats to milliseconds.
+
+## Examples
+
+```js
+ms('2 days') // 172800000
+ms('1d') // 86400000
+ms('10h') // 36000000
+ms('2.5 hrs') // 9000000
+ms('2h') // 7200000
+ms('1m') // 60000
+ms('5s') // 5000
+ms('1y') // 31557600000
+ms('100') // 100
+ms('-3 days') // -259200000
+ms('-1h') // -3600000
+ms('-200') // -200
+```
+
+### Convert from Milliseconds
+
+```js
+ms(60000) // "1m"
+ms(2 * 60000) // "2m"
+ms(-3 * 60000) // "-3m"
+ms(ms('10 hours')) // "10h"
+```
+
+### Time Format Written-Out
+
+```js
+ms(60000, { long: true }) // "1 minute"
+ms(2 * 60000, { long: true }) // "2 minutes"
+ms(-3 * 60000, { long: true }) // "-3 minutes"
+ms(ms('10 hours'), { long: true }) // "10 hours"
+```
+
+## Features
+
+- Works both in [Node.js](https://nodejs.org) and in the browser
+- If a number is supplied to `ms`, a string with a unit is returned
+- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`)
+- If you pass a string with a number and a valid unit, the number of equivalent milliseconds is returned
+
+## Related Packages
+
+- [ms.macro](https://github.com/knpwrs/ms.macro) - Run `ms` as a macro at build-time.
+
+## Caught a Bug?
+
+1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
+2. Link the package to the global module directory: `npm link`
+3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, Node.js will now use your clone of ms!
+
+As always, you can run the tests using: `npm test`
diff --git a/node_modules/mongoose/package.json b/node_modules/mongoose/package.json
new file mode 100644
index 0000000..63697cc
--- /dev/null
+++ b/node_modules/mongoose/package.json
@@ -0,0 +1,267 @@
+{
+ "_args": [
+ [
+ "mongoose",
+ "/home/art/Documents/API-REST-Etudiants/api"
+ ]
+ ],
+ "_from": "mongoose@latest",
+ "_hasShrinkwrap": false,
+ "_id": "mongoose@5.9.6",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mongoose",
+ "_nodeVersion": "10.17.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mongoose_5.9.6_1584996157770_0.08781527253445742"
+ },
+ "_npmUser": {
+ "email": "val@karpov.io",
+ "name": "vkarpov15"
+ },
+ "_npmVersion": "6.11.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mongoose",
+ "raw": "mongoose",
+ "rawSpec": "",
+ "scope": null,
+ "spec": "latest",
+ "type": "tag"
+ },
+ "_requiredBy": [
+ "#USER"
+ ],
+ "_resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.6.tgz",
+ "_shasum": "47e2e234638eede4caa52d961e3a7459b55530ef",
+ "_shrinkwrap": null,
+ "_spec": "mongoose",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api",
+ "author": {
+ "email": "guillermo@learnboost.com",
+ "name": "Guillermo Rauch"
+ },
+ "browser": "./dist/browser.umd.js",
+ "bugs": {
+ "url": "https://github.com/Automattic/mongoose/issues/new"
+ },
+ "dependencies": {
+ "bson": "~1.1.1",
+ "kareem": "2.3.1",
+ "mongodb": "3.5.5",
+ "mongoose-legacy-pluralize": "1.0.2",
+ "mpath": "0.6.0",
+ "mquery": "3.2.2",
+ "ms": "2.1.2",
+ "regexp-clone": "1.0.0",
+ "safe-buffer": "5.1.2",
+ "sift": "7.0.1",
+ "sliced": "1.0.1"
+ },
+ "description": "Mongoose MongoDB ODM",
+ "devDependencies": {
+ "acquit": "1.x",
+ "acquit-ignore": "0.1.x",
+ "acquit-require": "0.1.x",
+ "async": "2.6.2",
+ "babel-loader": "7.1.4",
+ "babel-preset-es2015": "6.24.1",
+ "benchmark": "2.1.4",
+ "bluebird": "3.5.5",
+ "chalk": "2.4.2",
+ "cheerio": "1.0.0-rc.2",
+ "co": "4.6.0",
+ "dox": "0.3.1",
+ "eslint": "5.16.0",
+ "eslint-plugin-mocha-no-only": "1.1.0",
+ "highlight.js": "9.1.0",
+ "lodash.isequal": "4.5.0",
+ "lodash.isequalwith": "4.4.0",
+ "marked": "0.6.2",
+ "mocha": "5.x",
+ "moment": "2.x",
+ "mongodb-topology-manager": "1.0.11",
+ "mongoose-long": "0.2.1",
+ "node-static": "0.7.11",
+ "object-sizeof": "1.3.0",
+ "promise-debug": "0.1.1",
+ "pug": "2.0.3",
+ "q": "1.5.1",
+ "semver": "5.5.0",
+ "uuid": "2.0.3",
+ "uuid-parse": "1.0.0",
+ "validator": "10.8.0",
+ "webpack": "4.16.4"
+ },
+ "directories": {
+ "lib": "./lib/mongoose"
+ },
+ "dist": {
+ "fileCount": 202,
+ "integrity": "sha512-EfFGO2QUoenf/4eFeF5y2R8aBLKHtqwrMk1pVGgl3OyNWufP5XLLPIuihP006YqR1+6xM1YsBzGpgBjMZkINGA==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeeR8+CRA9TVsSAnZWagAAAHEP+wW4GZai/yHXCg0KUscz\nHCds6YktY3Iux6nf5q7COwcef/sPHcT/ubihDjsGM3jrWk8QpcU/tSD+y1Xb\nQ0iY9KqpnswLMbYxquCyedk6Am+2UFbVHOj4pi/qOIID9K8lfJWOWro6nrRi\nqbq3y35wuzEWTwJgIidG0Ssx9B5+9t3eojTh0A5Aed5/bigPisVnB0DD1BlO\nPrB6BbK+GJoOW1PN0Ub39Z5+YvORAyo2hPTFNN+oqStpLzrGeqoKY8u3JsZr\nf0YPIlx5Cb8NV+15nu+oRWfGl8B8F/EtQa8dlA2Q68w+vVeAAtxWn7e3/qMV\nuDw6cmOJcib/EcznkqX9c0ePmcgdbCtHmM1sW3Yn5bMe5iLie6T+kA2uPfLQ\nkZN1MZRxzhxCnQir+KSyp+2xiaM6+2ecJYqxX9bv373cQKvVFxoMedY9+dsW\nIMZ1CbsHxjygROUWtIROoJ97T1AJRARzKhvEuFYcxegZSGoqw5nvm85SVB3A\n9ypDjIIgm9NCwOVyfreDbE/IbEpT642hmft5eqWp61xRmZEuZ3mKdGmEFtrS\n0ggMtyuTZALZxr7WJiltDklBdswyKzE4bROVOdhCbXVqzJBDC6G7zwXyhcdS\n5c2y6Qxk696SLtA1Ugd2d+LkaySYsE1xeEtkjZhTqcFx0tU98Mfhwy9Pkt44\nzmwV\r\n=QM8n\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "47e2e234638eede4caa52d961e3a7459b55530ef",
+ "tarball": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.6.tgz",
+ "unpackedSize": 1905360
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "eslintConfig": {
+ "env": {
+ "es6": true,
+ "node": true
+ },
+ "extends": [
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "ecmaVersion": 2015
+ },
+ "plugins": [
+ "mocha-no-only"
+ ],
+ "rules": {
+ "array-bracket-spacing": 1,
+ "comma-dangle": [
+ 2,
+ "never"
+ ],
+ "comma-spacing": [
+ 2,
+ {
+ "before": false,
+ "after": true
+ }
+ ],
+ "comma-style": "error",
+ "func-call-spacing": "error",
+ "indent": [
+ 2,
+ {
+ "SwitchCase": 1,
+ "VariableDeclarator": 2
+ },
+ "error"
+ ],
+ "key-spacing": [
+ 2,
+ {
+ "beforeColon": false,
+ "afterColon": true
+ }
+ ],
+ "keyword-spacing": "error",
+ "mocha-no-only/mocha-no-only": [
+ "error"
+ ],
+ "no-buffer-constructor": "warn",
+ "no-console": "off",
+ "no-constant-condition": "off",
+ "no-multi-spaces": "error",
+ "no-restricted-globals": [
+ {
+ "name": "context",
+ "message": "Don't use Mocha's global context"
+ },
+ "error"
+ ],
+ "no-trailing-spaces": "error",
+ "no-undef": "error",
+ "no-unreachable": 2,
+ "no-var": "warn",
+ "no-whitespace-before-property": "error",
+ "object-curly-spacing": [
+ 2,
+ "always"
+ ],
+ "prefer-const": "warn",
+ "quote-props": [
+ "as-needed",
+ "error"
+ ],
+ "quotes": [
+ "error",
+ "single"
+ ],
+ "semi": "error",
+ "space-before-blocks": "error",
+ "space-before-function-paren": [
+ "error",
+ "never"
+ ],
+ "space-infix-ops": "error",
+ "space-unary-ops": "error",
+ "strict": [
+ "error",
+ "global"
+ ]
+ }
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mongoose"
+ },
+ "gitHead": "1883bc086d172a8c79252649c46a8b1ac168b13b",
+ "homepage": "https://mongoosejs.com",
+ "keywords": [
+ "data",
+ "database",
+ "datastore",
+ "db",
+ "document",
+ "model",
+ "mongodb",
+ "nosql",
+ "odm",
+ "orm",
+ "query",
+ "schema"
+ ],
+ "license": "MIT",
+ "main": "./index.js",
+ "maintainers": [
+ {
+ "name": "aaron",
+ "email": "aaron.heckmann+github@gmail.com"
+ },
+ {
+ "name": "rauchg",
+ "email": "rauchg@gmail.com"
+ },
+ {
+ "name": "tjholowaychuk",
+ "email": "tj@vision-media.ca"
+ },
+ {
+ "name": "vkarpov15",
+ "email": "val@karpov.io"
+ }
+ ],
+ "mocha": {
+ "extension": [
+ "test.js"
+ ],
+ "watch-files": [
+ "test/**/*.js"
+ ]
+ },
+ "name": "mongoose",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/Automattic/mongoose.git"
+ },
+ "scripts": {
+ "build-browser": "node build-browser.js",
+ "lint": "eslint .",
+ "prepublishOnly": "npm run build-browser",
+ "release": "git pull && git push origin master --tags && npm publish",
+ "release-legacy": "git pull origin 4.x && git push origin 4.x --tags && npm publish --tag legacy",
+ "test": "mocha --exit",
+ "test-cov": "nyc --reporter=html --reporter=text npm test"
+ },
+ "version": "5.9.6"
+}
diff --git a/node_modules/mongoose/tools/auth.js b/node_modules/mongoose/tools/auth.js
new file mode 100644
index 0000000..967f5e1
--- /dev/null
+++ b/node_modules/mongoose/tools/auth.js
@@ -0,0 +1,30 @@
+'use strict';
+
+const Server = require('mongodb-topology-manager').Server;
+const co = require('co');
+const mongodb = require('mongodb');
+
+co(function*() {
+ // Create new instance
+ var server = new Server('mongod', {
+ auth: null,
+ dbpath: '/data/db/27017'
+ });
+
+ // Purge the directory
+ yield server.purge();
+
+ // Start process
+ yield server.start();
+
+ const db = yield mongodb.MongoClient.connect('mongodb://localhost:27017/admin');
+
+ yield db.addUser('passwordIsTaco', 'taco', {
+ roles: ['dbOwner']
+ });
+
+ console.log('done');
+}).catch(error => {
+ console.error(error);
+ process.exit(-1);
+});
diff --git a/node_modules/mongoose/tools/repl.js b/node_modules/mongoose/tools/repl.js
new file mode 100644
index 0000000..ca3b6de
--- /dev/null
+++ b/node_modules/mongoose/tools/repl.js
@@ -0,0 +1,36 @@
+'use strict';
+
+const co = require('co');
+
+co(function*() {
+ var ReplSet = require('mongodb-topology-manager').ReplSet;
+
+ // Create new instance
+ var topology = new ReplSet('mongod', [{
+ // mongod process options
+ options: {
+ bind_ip: 'localhost', port: 31000, dbpath: `/data/db/31000`
+ }
+ }, {
+ // mongod process options
+ options: {
+ bind_ip: 'localhost', port: 31001, dbpath: `/data/db/31001`
+ }
+ }, {
+ // Type of node
+ arbiterOnly: true,
+ // mongod process options
+ options: {
+ bind_ip: 'localhost', port: 31002, dbpath: `/data/db/31002`
+ }
+ }], {
+ replSet: 'rs'
+ });
+
+ yield topology.start();
+
+ console.log('done');
+}).catch(error => {
+ console.error(error);
+ process.exit(-1);
+});
diff --git a/node_modules/mongoose/tools/sharded.js b/node_modules/mongoose/tools/sharded.js
new file mode 100644
index 0000000..82cad14
--- /dev/null
+++ b/node_modules/mongoose/tools/sharded.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const co = require('co');
+
+co(function*() {
+ var Sharded = require('mongodb-topology-manager').Sharded;
+
+ // Create new instance
+ var topology = new Sharded({
+ mongod: 'mongod',
+ mongos: 'mongos'
+ });
+
+ yield topology.addShard([{
+ options: {
+ bind_ip: 'localhost', port: 31000, dbpath: `/data/db/31000`, shardsvr: null
+ }
+ }], { replSet: 'rs1' });
+
+ yield topology.addConfigurationServers([{
+ options: {
+ bind_ip: 'localhost', port: 35000, dbpath: `/data/db/35000`
+ }
+ }], { replSet: 'rs0' });
+
+ yield topology.addProxies([{
+ bind_ip: 'localhost', port: 51000, configdb: 'localhost:35000'
+ }], {
+ binary: 'mongos'
+ });
+
+ console.log('Start...');
+ // Start up topology
+ yield topology.start();
+
+ console.log('Started');
+
+ // Shard db
+ yield topology.enableSharding('test');
+
+ console.log('done');
+}).catch(error => {
+ console.error(error);
+ process.exit(-1);
+});
diff --git a/node_modules/mongoose/webpack.base.config.js b/node_modules/mongoose/webpack.base.config.js
new file mode 100644
index 0000000..3332761
--- /dev/null
+++ b/node_modules/mongoose/webpack.base.config.js
@@ -0,0 +1,33 @@
+'use strict';
+
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ include: [
+ /\/mongoose\//i,
+ /\/kareem\//i
+ ],
+ loader: 'babel-loader',
+ options: {
+ presets: ['es2015']
+ }
+ }
+ ]
+ },
+ node: {
+ // Replace these Node.js native modules with empty objects, Mongoose's
+ // browser library does not use them.
+ // See https://webpack.js.org/configuration/node/
+ dns: 'empty',
+ fs: 'empty',
+ module: 'empty',
+ net: 'empty',
+ tls: 'empty'
+ },
+ target: 'web',
+ mode: 'production'
+};
+
+
diff --git a/node_modules/mongoose/webpack.config.js b/node_modules/mongoose/webpack.config.js
new file mode 100644
index 0000000..b6c6cca
--- /dev/null
+++ b/node_modules/mongoose/webpack.config.js
@@ -0,0 +1,24 @@
+'use strict';
+
+const paths = require('path');
+
+const base = require('./webpack.base.config.js');
+
+const webpackConfig = Object.assign({}, base, {
+ entry: require.resolve('./browser.js'),
+ output: {
+ filename: './dist/browser.umd.js',
+ path: paths.resolve(__dirname, ''),
+ library: 'mongoose',
+ libraryTarget: 'umd',
+ // override default 'window' globalObject so browser build will work in SSR environments
+ // may become unnecessary in webpack 5
+ globalObject: 'typeof self !== \'undefined\' ? self : this'
+ },
+ externals: [
+ /^node_modules\/.+$/
+ ]
+});
+
+module.exports = webpackConfig;
+
diff --git a/node_modules/mpath/.travis.yml b/node_modules/mpath/.travis.yml
new file mode 100644
index 0000000..9bdf212
--- /dev/null
+++ b/node_modules/mpath/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+node_js:
+ - "4"
+ - "5"
+ - "6"
+ - "7"
+ - "8"
+ - "9"
+ - "10"
diff --git a/node_modules/mpath/History.md b/node_modules/mpath/History.md
new file mode 100644
index 0000000..f1c7000
--- /dev/null
+++ b/node_modules/mpath/History.md
@@ -0,0 +1,59 @@
+0.6.0 / 2019-05-01
+==================
+ * feat: support setting dotted paths within nested arrays
+
+0.5.2 / 2019-04-25
+==================
+ * fix: avoid using subclassed array constructor when doing `map()`
+
+0.5.1 / 2018-08-30
+==================
+ * fix: prevent writing to constructor and prototype as well as __proto__
+
+0.5.0 / 2018-08-30
+==================
+ * BREAKING CHANGE: disallow setting/unsetting __proto__ properties
+ * feat: re-add support for Node < 4 for this release
+
+0.4.1 / 2018-04-08
+==================
+ * fix: allow opting out of weird `$` set behavior re: Automattic/mongoose#6273
+
+0.4.0 / 2018-03-27
+==================
+ * feat: add support for ES6 maps
+ * BREAKING CHANGE: drop support for Node < 4
+
+0.3.0 / 2017-06-05
+==================
+ * feat: add has() and unset() functions
+
+0.2.1 / 2013-03-22
+==================
+
+ * test; added for #5
+ * fix typo that breaks set #5 [Contra](https://github.com/Contra)
+
+0.2.0 / 2013-03-15
+==================
+
+ * added; adapter support for set
+ * added; adapter support for get
+ * add basic benchmarks
+ * add support for using module as a component #2 [Contra](https://github.com/Contra)
+
+0.1.1 / 2012-12-21
+==================
+
+ * added; map support
+
+0.1.0 / 2012-12-13
+==================
+
+ * added; set('array.property', val, object) support
+ * added; get('array.property', object) support
+
+0.0.1 / 2012-11-03
+==================
+
+ * initial release
diff --git a/node_modules/mpath/LICENSE b/node_modules/mpath/LICENSE
new file mode 100644
index 0000000..38c529d
--- /dev/null
+++ b/node_modules/mpath/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/mpath/Makefile b/node_modules/mpath/Makefile
new file mode 100644
index 0000000..8d6a79c
--- /dev/null
+++ b/node_modules/mpath/Makefile
@@ -0,0 +1,4 @@
+bench:
+ node bench.js
+
+.PHONY: test
diff --git a/node_modules/mpath/README.md b/node_modules/mpath/README.md
new file mode 100644
index 0000000..9831dd0
--- /dev/null
+++ b/node_modules/mpath/README.md
@@ -0,0 +1,278 @@
+#mpath
+
+{G,S}et javascript object values using MongoDB-like path notation.
+
+###Getting
+
+```js
+var mpath = require('mpath');
+
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.get('comments.1.title', obj) // 'exciting!'
+```
+
+`mpath.get` supports array property notation as well.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.get('comments.title', obj) // ['funny', 'exciting!']
+```
+
+Array property and indexing syntax, when used together, are very powerful.
+
+```js
+var obj = {
+ array: [
+ { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}
+ , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }}
+ , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+}
+
+var found = mpath.get('array.o.array.x.b.1', obj);
+
+console.log(found); // prints..
+
+ [ [6, undefined]
+ , [2, undefined, undefined]
+ , [null, 1]
+ , [null]
+ , [undefined]
+ , [undefined, undefined, undefined]
+ , undefined
+ ]
+
+```
+
+#####Field selection rules:
+
+The following rules are iteratively applied to each `segment` in the passed `path`. For example:
+
+```js
+var path = 'one.two.14'; // path
+'one' // segment 0
+'two' // segment 1
+14 // segment 2
+```
+
+- 1) when value of the segment parent is not an array, return the value of `parent.segment`
+- 2) when value of the segment parent is an array
+ - a) if the segment is an integer, replace the parent array with the value at `parent[segment]`
+ - b) if not an integer, keep the array but replace each array `item` with the value returned from calling `get(remainingSegments, item)` or undefined if falsey.
+
+#####Maps
+
+`mpath.get` also accepts an optional `map` argument which receives each individual found value. The value returned from the `map` function will be used in the original found values place.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.get('comments.title', obj, function (val) {
+ return 'funny' == val
+ ? 'amusing'
+ : val;
+});
+// ['amusing', 'exciting!']
+```
+
+###Setting
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.set('comments.1.title', 'hilarious', obj)
+console.log(obj.comments[1].title) // 'hilarious'
+```
+
+`mpath.set` supports the same array property notation as `mpath.get`.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.set('comments.title', ['hilarious', 'fruity'], obj);
+
+console.log(obj); // prints..
+
+ { comments: [
+ { title: 'hilarious' },
+ { title: 'fruity' }
+ ]}
+```
+
+Array property and indexing syntax can be used together also when setting.
+
+```js
+var obj = {
+ array: [
+ { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}
+ , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }}
+ , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ]
+}
+
+mpath.set('array.1.o', 'this was changed', obj);
+
+console.log(require('util').inspect(obj, false, 1000)); // prints..
+
+{
+ array: [
+ { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}
+ , { o: 'this was changed' }
+ , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+}
+
+mpath.set('array.o.array.x', 'this was changed too', obj);
+
+console.log(require('util').inspect(obj, false, 1000)); // prints..
+
+{
+ array: [
+ { o: { array: [{x: 'this was changed too'}, { y: 10, x: 'this was changed too'} ] }}
+ , { o: 'this was changed' }
+ , { o: { array: [{x: 'this was changed too'}, { x: 'this was changed too'}] }}
+ , { o: { array: [{x: 'this was changed too'}] }}
+ , { o: { array: [{x: 'this was changed too', y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+}
+```
+
+####Setting arrays
+
+By default, setting a property within an array to another array results in each element of the new array being set to the item in the destination array at the matching index. An example is helpful.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.set('comments.title', ['hilarious', 'fruity'], obj);
+
+console.log(obj); // prints..
+
+ { comments: [
+ { title: 'hilarious' },
+ { title: 'fruity' }
+ ]}
+```
+
+If we do not desire this destructuring-like assignment behavior we may instead specify the `$` operator in the path being set to force the array to be copied directly.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.set('comments.$.title', ['hilarious', 'fruity'], obj);
+
+console.log(obj); // prints..
+
+ { comments: [
+ { title: ['hilarious', 'fruity'] },
+ { title: ['hilarious', 'fruity'] }
+ ]}
+```
+
+####Field assignment rules
+
+The rules utilized mirror those used on `mpath.get`, meaning we can take values returned from `mpath.get`, update them, and reassign them using `mpath.set`. Note that setting nested arrays of arrays can get unweildy quickly. Check out the [tests](https://github.com/aheckmann/mpath/blob/master/test/index.js) for more extreme examples.
+
+#####Maps
+
+`mpath.set` also accepts an optional `map` argument which receives each individual value being set. The value returned from the `map` function will be used in the original values place.
+
+```js
+var obj = {
+ comments: [
+ { title: 'funny' },
+ { title: 'exciting!' }
+ ]
+}
+
+mpath.set('comments.title', ['hilarious', 'fruity'], obj, function (val) {
+ return val.length;
+});
+
+console.log(obj); // prints..
+
+ { comments: [
+ { title: 9 },
+ { title: 6 }
+ ]}
+```
+
+### Custom object types
+
+Sometimes you may want to enact the same functionality on custom object types that store all their real data internally, say for an ODM type object. No fear, `mpath` has you covered. Simply pass the name of the property being used to store the internal data and it will be traversed instead:
+
+```js
+var mpath = require('mpath');
+
+var obj = {
+ comments: [
+ { title: 'exciting!', _doc: { title: 'great!' }}
+ ]
+}
+
+mpath.get('comments.0.title', obj, '_doc') // 'great!'
+mpath.set('comments.0.title', 'nov 3rd', obj, '_doc')
+mpath.get('comments.0.title', obj, '_doc') // 'nov 3rd'
+mpath.get('comments.0.title', obj) // 'exciting'
+```
+
+When used with a `map`, the `map` argument comes last.
+
+```js
+mpath.get(path, obj, '_doc', map);
+mpath.set(path, val, obj, '_doc', map);
+```
+
+[LICENSE](https://github.com/aheckmann/mpath/blob/master/LICENSE)
+
diff --git a/node_modules/mpath/bench.js b/node_modules/mpath/bench.js
new file mode 100644
index 0000000..7ec6a87
--- /dev/null
+++ b/node_modules/mpath/bench.js
@@ -0,0 +1,109 @@
+
+var mpath = require('./')
+var Bench = require('benchmark');
+var sha = require('child_process').exec("git log --pretty=format:'%h' -n 1", function (err, sha) {
+ if (err) throw err;
+
+ var fs = require('fs')
+ var filename = __dirname + '/bench.out';
+ var out = fs.createWriteStream(filename, { flags: 'a', encoding: 'utf8' });
+
+ /**
+ * test doc creator
+ */
+
+ function doc () {
+ var o = { first: { second: { third: [3,{ name: 'aaron' }, 9] }}};
+ o.comments = [
+ { name: 'one' }
+ , { name: 'two', _doc: { name: '2' }}
+ , { name: 'three'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }}
+ ];
+ o.name = 'jiro';
+ o.array = [
+ { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}
+ , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}] }}
+ , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+ o.arr = [
+ { arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true }
+ ]
+ return o;
+ }
+
+ var o = doc();
+
+ var s = new Bench.Suite;
+ s.add('mpath.get("first", obj)', function () {
+ mpath.get('first', o);
+ })
+ s.add('mpath.get("first.second", obj)', function () {
+ mpath.get('first.second', o);
+ })
+ s.add('mpath.get("first.second.third.1.name", obj)', function () {
+ mpath.get('first.second.third.1.name', o);
+ })
+ s.add('mpath.get("comments", obj)', function () {
+ mpath.get('comments', o);
+ })
+ s.add('mpath.get("comments.1", obj)', function () {
+ mpath.get('comments.1', o);
+ })
+ s.add('mpath.get("comments.2.name", obj)', function () {
+ mpath.get('comments.2.name', o);
+ })
+ s.add('mpath.get("comments.2.comments.1.comments.0.val", obj)', function () {
+ mpath.get('comments.2.comments.1.comments.0.val', o);
+ })
+ s.add('mpath.get("comments.name", obj)', function () {
+ mpath.get('comments.name', o);
+ })
+
+ s.add('mpath.set("first", obj, val)', function () {
+ mpath.set('first', o, 1);
+ })
+ s.add('mpath.set("first.second", obj, val)', function () {
+ mpath.set('first.second', o, 1);
+ })
+ s.add('mpath.set("first.second.third.1.name", obj, val)', function () {
+ mpath.set('first.second.third.1.name', o, 1);
+ })
+ s.add('mpath.set("comments", obj, val)', function () {
+ mpath.set('comments', o, 1);
+ })
+ s.add('mpath.set("comments.1", obj, val)', function () {
+ mpath.set('comments.1', o, 1);
+ })
+ s.add('mpath.set("comments.2.name", obj, val)', function () {
+ mpath.set('comments.2.name', o, 1);
+ })
+ s.add('mpath.set("comments.2.comments.1.comments.0.val", obj, val)', function () {
+ mpath.set('comments.2.comments.1.comments.0.val', o, 1);
+ })
+ s.add('mpath.set("comments.name", obj, val)', function () {
+ mpath.set('comments.name', o, 1);
+ })
+
+ s.on('start', function () {
+ console.log('starting...');
+ out.write('*' + sha + ': ' + String(new Date()) + '\n');
+ });
+ s.on('cycle', function (e) {
+ var s = String(e.target);
+ console.log(s);
+ out.write(s + '\n');
+ })
+ s.on('complete', function () {
+ console.log('done')
+ out.end('');
+ })
+ s.run()
+})
+
diff --git a/node_modules/mpath/bench.log b/node_modules/mpath/bench.log
new file mode 100644
index 0000000..e69de29
diff --git a/node_modules/mpath/bench.out b/node_modules/mpath/bench.out
new file mode 100644
index 0000000..b9b0371
--- /dev/null
+++ b/node_modules/mpath/bench.out
@@ -0,0 +1,52 @@
+*b566c26: Fri Mar 15 2013 14:14:04 GMT-0700 (PDT)
+mpath.get("first", obj) x 3,827,405 ops/sec ±0.91% (90 runs sampled)
+mpath.get("first.second", obj) x 4,930,222 ops/sec ±1.92% (91 runs sampled)
+mpath.get("first.second.third.1.name", obj) x 3,070,837 ops/sec ±1.45% (97 runs sampled)
+mpath.get("comments", obj) x 3,649,771 ops/sec ±1.71% (93 runs sampled)
+mpath.get("comments.1", obj) x 3,846,728 ops/sec ±0.86% (94 runs sampled)
+mpath.get("comments.2.name", obj) x 3,527,680 ops/sec ±0.95% (96 runs sampled)
+mpath.get("comments.2.comments.1.comments.0.val", obj) x 2,046,982 ops/sec ±0.80% (96 runs sampled)
+mpath.get("comments.name", obj) x 625,546 ops/sec ±2.02% (82 runs sampled)
+*e42bdb1: Fri Mar 15 2013 14:19:28 GMT-0700 (PDT)
+mpath.get("first", obj) x 3,700,783 ops/sec ±1.30% (95 runs sampled)
+mpath.get("first.second", obj) x 4,621,795 ops/sec ±0.86% (95 runs sampled)
+mpath.get("first.second.third.1.name", obj) x 3,012,671 ops/sec ±1.21% (100 runs sampled)
+mpath.get("comments", obj) x 3,677,694 ops/sec ±0.80% (96 runs sampled)
+mpath.get("comments.1", obj) x 3,798,862 ops/sec ±0.81% (91 runs sampled)
+mpath.get("comments.2.name", obj) x 3,489,356 ops/sec ±0.66% (98 runs sampled)
+mpath.get("comments.2.comments.1.comments.0.val", obj) x 2,004,076 ops/sec ±0.85% (99 runs sampled)
+mpath.get("comments.name", obj) x 613,270 ops/sec ±1.33% (83 runs sampled)
+*0521aac: Fri Mar 15 2013 16:37:16 GMT-0700 (PDT)
+mpath.get("first", obj) x 3,834,755 ops/sec ±0.70% (100 runs sampled)
+mpath.get("first.second", obj) x 4,999,965 ops/sec ±1.01% (98 runs sampled)
+mpath.get("first.second.third.1.name", obj) x 3,125,953 ops/sec ±0.97% (100 runs sampled)
+mpath.get("comments", obj) x 3,759,233 ops/sec ±0.81% (97 runs sampled)
+mpath.get("comments.1", obj) x 3,894,893 ops/sec ±0.76% (96 runs sampled)
+mpath.get("comments.2.name", obj) x 3,576,929 ops/sec ±0.68% (98 runs sampled)
+mpath.get("comments.2.comments.1.comments.0.val", obj) x 2,149,610 ops/sec ±0.67% (97 runs sampled)
+mpath.get("comments.name", obj) x 629,259 ops/sec ±1.30% (87 runs sampled)
+mpath.set("first", obj, val) x 2,869,477 ops/sec ±0.63% (97 runs sampled)
+mpath.set("first.second", obj, val) x 2,418,751 ops/sec ±0.62% (98 runs sampled)
+mpath.set("first.second.third.1.name", obj, val) x 2,313,099 ops/sec ±0.69% (94 runs sampled)
+mpath.set("comments", obj, val) x 2,680,882 ops/sec ±0.76% (99 runs sampled)
+mpath.set("comments.1", obj, val) x 2,401,829 ops/sec ±0.68% (98 runs sampled)
+mpath.set("comments.2.name", obj, val) x 2,335,081 ops/sec ±1.07% (96 runs sampled)
+mpath.set("comments.2.comments.1.comments.0.val", obj, val) x 2,245,436 ops/sec ±0.76% (92 runs sampled)
+mpath.set("comments.name", obj, val) x 2,356,278 ops/sec ±1.15% (100 runs sampled)
+*97e85d3: Fri Mar 15 2013 16:39:21 GMT-0700 (PDT)
+mpath.get("first", obj) x 3,837,614 ops/sec ±0.74% (99 runs sampled)
+mpath.get("first.second", obj) x 4,991,779 ops/sec ±1.01% (94 runs sampled)
+mpath.get("first.second.third.1.name", obj) x 3,078,455 ops/sec ±1.17% (96 runs sampled)
+mpath.get("comments", obj) x 3,770,961 ops/sec ±0.45% (101 runs sampled)
+mpath.get("comments.1", obj) x 3,832,814 ops/sec ±0.67% (92 runs sampled)
+mpath.get("comments.2.name", obj) x 3,536,436 ops/sec ±0.49% (100 runs sampled)
+mpath.get("comments.2.comments.1.comments.0.val", obj) x 2,141,947 ops/sec ±0.72% (98 runs sampled)
+mpath.get("comments.name", obj) x 667,898 ops/sec ±1.62% (85 runs sampled)
+mpath.set("first", obj, val) x 2,642,517 ops/sec ±0.72% (98 runs sampled)
+mpath.set("first.second", obj, val) x 2,502,124 ops/sec ±1.28% (99 runs sampled)
+mpath.set("first.second.third.1.name", obj, val) x 2,426,804 ops/sec ±0.55% (99 runs sampled)
+mpath.set("comments", obj, val) x 2,699,478 ops/sec ±0.85% (98 runs sampled)
+mpath.set("comments.1", obj, val) x 2,494,454 ops/sec ±1.05% (96 runs sampled)
+mpath.set("comments.2.name", obj, val) x 2,463,894 ops/sec ±0.86% (98 runs sampled)
+mpath.set("comments.2.comments.1.comments.0.val", obj, val) x 2,320,398 ops/sec ±0.82% (95 runs sampled)
+mpath.set("comments.name", obj, val) x 2,512,408 ops/sec ±0.77% (95 runs sampled)
diff --git a/node_modules/mpath/component.json b/node_modules/mpath/component.json
new file mode 100644
index 0000000..53c2846
--- /dev/null
+++ b/node_modules/mpath/component.json
@@ -0,0 +1,8 @@
+{
+ "name": "mpath",
+ "version": "0.2.1",
+ "main": "lib/index.js",
+ "scripts": [
+ "lib/index.js"
+ ]
+}
diff --git a/node_modules/mpath/index.js b/node_modules/mpath/index.js
new file mode 100644
index 0000000..f7b65dd
--- /dev/null
+++ b/node_modules/mpath/index.js
@@ -0,0 +1 @@
+module.exports = exports = require('./lib');
diff --git a/node_modules/mpath/lib/index.js b/node_modules/mpath/lib/index.js
new file mode 100644
index 0000000..e5479de
--- /dev/null
+++ b/node_modules/mpath/lib/index.js
@@ -0,0 +1,308 @@
+// These properties are special and can open client libraries to security
+// issues
+var ignoreProperties = ['__proto__', 'constructor', 'prototype'];
+
+/**
+ * Returns the value of object `o` at the given `path`.
+ *
+ * ####Example:
+ *
+ * var obj = {
+ * comments: [
+ * { title: 'exciting!', _doc: { title: 'great!' }}
+ * , { title: 'number dos' }
+ * ]
+ * }
+ *
+ * mpath.get('comments.0.title', o) // 'exciting!'
+ * mpath.get('comments.0.title', o, '_doc') // 'great!'
+ * mpath.get('comments.title', o) // ['exciting!', 'number dos']
+ *
+ * // summary
+ * mpath.get(path, o)
+ * mpath.get(path, o, special)
+ * mpath.get(path, o, map)
+ * mpath.get(path, o, special, map)
+ *
+ * @param {String} path
+ * @param {Object} o
+ * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property.
+ * @param {Function} [map] Optional function which receives each individual found value. The value returned from `map` is used in the original values place.
+ */
+
+exports.get = function (path, o, special, map) {
+ var lookup;
+
+ if ('function' == typeof special) {
+ if (special.length < 2) {
+ map = special;
+ special = undefined;
+ } else {
+ lookup = special;
+ special = undefined;
+ }
+ }
+
+ map || (map = K);
+
+ var parts = 'string' == typeof path
+ ? path.split('.')
+ : path
+
+ if (!Array.isArray(parts)) {
+ throw new TypeError('Invalid `path`. Must be either string or array');
+ }
+
+ var obj = o
+ , part;
+
+ for (var i = 0; i < parts.length; ++i) {
+ part = parts[i];
+
+ if (Array.isArray(obj) && !/^\d+$/.test(part)) {
+ // reading a property from the array items
+ var paths = parts.slice(i);
+
+ // Need to `concat()` to avoid `map()` calling a constructor of an array
+ // subclass
+ return [].concat(obj).map(function (item) {
+ return item
+ ? exports.get(paths, item, special || lookup, map)
+ : map(undefined);
+ });
+ }
+
+ if (lookup) {
+ obj = lookup(obj, part);
+ } else {
+ var _from = special && obj[special] ? obj[special] : obj;
+ obj = _from instanceof Map ?
+ _from.get(part) :
+ _from[part];
+ }
+
+ if (!obj) return map(obj);
+ }
+
+ return map(obj);
+};
+
+/**
+ * Returns true if `in` returns true for every piece of the path
+ *
+ * @param {String} path
+ * @param {Object} o
+ */
+
+exports.has = function (path, o) {
+ var parts = typeof path === 'string' ?
+ path.split('.') :
+ path;
+
+ if (!Array.isArray(parts)) {
+ throw new TypeError('Invalid `path`. Must be either string or array');
+ }
+
+ var len = parts.length;
+ var cur = o;
+ for (var i = 0; i < len; ++i) {
+ if (cur == null || typeof cur !== 'object' || !(parts[i] in cur)) {
+ return false;
+ }
+ cur = cur[parts[i]];
+ }
+
+ return true;
+};
+
+/**
+ * Deletes the last piece of `path`
+ *
+ * @param {String} path
+ * @param {Object} o
+ */
+
+exports.unset = function (path, o) {
+ var parts = typeof path === 'string' ?
+ path.split('.') :
+ path;
+
+ if (!Array.isArray(parts)) {
+ throw new TypeError('Invalid `path`. Must be either string or array');
+ }
+
+ var len = parts.length;
+ var cur = o;
+ for (var i = 0; i < len; ++i) {
+ if (cur == null || typeof cur !== 'object' || !(parts[i] in cur)) {
+ return false;
+ }
+ // Disallow any updates to __proto__ or special properties.
+ if (ignoreProperties.indexOf(parts[i]) !== -1) {
+ return false;
+ }
+ if (i === len - 1) {
+ delete cur[parts[i]];
+ return true;
+ }
+ cur = cur instanceof Map ? cur.get(parts[i]) : cur[parts[i]];
+ }
+
+ return true;
+};
+
+/**
+ * Sets the `val` at the given `path` of object `o`.
+ *
+ * @param {String} path
+ * @param {Anything} val
+ * @param {Object} o
+ * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property.
+ * @param {Function} [map] Optional function which is passed each individual value before setting it. The value returned from `map` is used in the original values place.
+ */
+
+exports.set = function (path, val, o, special, map, _copying) {
+ var lookup;
+
+ if ('function' == typeof special) {
+ if (special.length < 2) {
+ map = special;
+ special = undefined;
+ } else {
+ lookup = special;
+ special = undefined;
+ }
+ }
+
+ map || (map = K);
+
+ var parts = 'string' == typeof path
+ ? path.split('.')
+ : path
+
+ if (!Array.isArray(parts)) {
+ throw new TypeError('Invalid `path`. Must be either string or array');
+ }
+
+ if (null == o) return;
+
+ for (var i = 0; i < parts.length; ++i) {
+ // Silently ignore any updates to `__proto__`, these are potentially
+ // dangerous if using mpath with unsanitized data.
+ if (ignoreProperties.indexOf(parts[i]) !== -1) {
+ return;
+ }
+ }
+
+ // the existance of $ in a path tells us if the user desires
+ // the copying of an array instead of setting each value of
+ // the array to the one by one to matching positions of the
+ // current array. Unless the user explicitly opted out by passing
+ // false, see Automattic/mongoose#6273
+ var copy = _copying || (/\$/.test(path) && _copying !== false)
+ , obj = o
+ , part
+
+ for (var i = 0, len = parts.length - 1; i < len; ++i) {
+ part = parts[i];
+
+ if ('$' == part) {
+ if (i == len - 1) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (Array.isArray(obj) && !/^\d+$/.test(part)) {
+ var paths = parts.slice(i);
+ if (!copy && Array.isArray(val)) {
+ for (var j = 0; j < obj.length && j < val.length; ++j) {
+ // assignment of single values of array
+ exports.set(paths, val[j], obj[j], special || lookup, map, copy);
+ }
+ } else {
+ for (var j = 0; j < obj.length; ++j) {
+ // assignment of entire value
+ exports.set(paths, val, obj[j], special || lookup, map, copy);
+ }
+ }
+ return;
+ }
+
+ if (lookup) {
+ obj = lookup(obj, part);
+ } else {
+ var _to = special && obj[special] ? obj[special] : obj;
+ obj = _to instanceof Map ?
+ _to.get(part) :
+ _to[part];
+ }
+
+ if (!obj) return;
+ }
+
+ // process the last property of the path
+
+ part = parts[len];
+
+ // use the special property if exists
+ if (special && obj[special]) {
+ obj = obj[special];
+ }
+
+ // set the value on the last branch
+ if (Array.isArray(obj) && !/^\d+$/.test(part)) {
+ if (!copy && Array.isArray(val)) {
+ _setArray(obj, val, part, lookup, special, map);
+ } else {
+ for (var j = 0; j < obj.length; ++j) {
+ item = obj[j];
+ if (item) {
+ if (lookup) {
+ lookup(item, part, map(val));
+ } else {
+ if (item[special]) item = item[special];
+ item[part] = map(val);
+ }
+ }
+ }
+ }
+ } else {
+ if (lookup) {
+ lookup(obj, part, map(val));
+ } else if (obj instanceof Map) {
+ obj.set(part, map(val));
+ } else {
+ obj[part] = map(val);
+ }
+ }
+}
+
+/*!
+ * Recursively set nested arrays
+ */
+
+function _setArray(obj, val, part, lookup, special, map) {
+ for (var item, j = 0; j < obj.length && j < val.length; ++j) {
+ item = obj[j];
+ if (Array.isArray(item) && Array.isArray(val[j])) {
+ _setArray(item, val[j], part, lookup, special, map);
+ } else if (item) {
+ if (lookup) {
+ lookup(item, part, map(val[j]));
+ } else {
+ if (item[special]) item = item[special];
+ item[part] = map(val[j]);
+ }
+ }
+ }
+}
+
+/*!
+ * Returns the value passed to it.
+ */
+
+function K (v) {
+ return v;
+}
diff --git a/node_modules/mpath/package.json b/node_modules/mpath/package.json
new file mode 100644
index 0000000..e2fb806
--- /dev/null
+++ b/node_modules/mpath/package.json
@@ -0,0 +1,97 @@
+{
+ "_args": [
+ [
+ "mpath@0.6.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "mpath@0.6.0",
+ "_hasShrinkwrap": false,
+ "_id": "mpath@0.6.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mpath",
+ "_nodeVersion": "8.9.4",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mpath_0.6.0_1556732532694_0.4330532228344546"
+ },
+ "_npmUser": {
+ "email": "val@karpov.io",
+ "name": "vkarpov15"
+ },
+ "_npmVersion": "5.6.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "mpath",
+ "raw": "mpath@0.6.0",
+ "rawSpec": "0.6.0",
+ "scope": null,
+ "spec": "0.6.0",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz",
+ "_shasum": "aa922029fca4f0f641f360e74c5c1b6a4c47078e",
+ "_shrinkwrap": null,
+ "_spec": "mpath@0.6.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "Aaron Heckmann"
+ },
+ "bugs": {
+ "url": "https://github.com/aheckmann/mpath/issues"
+ },
+ "dependencies": {},
+ "description": "{G,S}et object values using MongoDB-like path notation",
+ "devDependencies": {
+ "benchmark": "~1.0.0",
+ "mocha": "5.x"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 13,
+ "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcydp1CRA9TVsSAnZWagAAOCsP/1R9oX8nNwE7PVa+BSlj\nH4HrhvLGAf7O0yPSNKJb2u+hinMbRhTvmVGc8vWSkGkCjqiXxEreNaXo0+qY\nzbPlKzXGIBo55Z3X9AQXLUMTfysd/rMmmGBzIpZSDrvGcd0KUGLU2UDwvlW0\njypzTGIbbNdOkoxR43xZO8Y81DsX2M8fyPoOFDww1p4pcLiWgRQ7SZ0TtrUR\nui0ng9MrNvhsdC9yN6Uli+iJX4DH6akwriU2v4RqHxyaX2AsdG1gjtqw/rl4\nmHLJOzVr11MF3Lyy+WJunU7RaM/Lvm2aUqXOB3uBLimvAFTspfBhugmhQL+T\nZ/RTIQV2cs83/I3X7gxHgH2VShcPjahklm/3MdT+hcRCZR5UV5JtJIs9GRrv\nieZXG2BJQ6/OL9TdrfeJphmDt40++aX3ndmhv1GyYIKbG9WyU3xnMn6iSdfN\n7mxsQLx4OiS3hv85BByrV5JL5snbNb+GcwKZX3O5JiIvv2mt0PP18c5aHnjh\nTFwc7wtN4dDPy+MlG+ZGTU0gdeqlypygsGPUi960PVqnonb+Cb3tSwcMZQ/R\nRffQZX+8KPOna0plcHIaPVBfgaO1ea4OyRbXzcu4MZaP5aoFgdCoPINKG8Px\n4uRYn2BvVpSCe7poKQ9JuIUXs/heagobajucEK3BnBYa6/1GODVjILDDqVaH\nV0G5\r\n=ADYa\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "aa922029fca4f0f641f360e74c5c1b6a4c47078e",
+ "tarball": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz",
+ "unpackedSize": 88480
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "gitHead": "98b1e0fd0cdd7e83b57369bff907636566508c6b",
+ "homepage": "https://github.com/aheckmann/mpath#readme",
+ "keywords": [
+ "get",
+ "mongodb",
+ "path",
+ "set"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "aaron",
+ "email": "aaron.heckmann+github@gmail.com"
+ },
+ {
+ "name": "vkarpov15",
+ "email": "val@karpov.io"
+ }
+ ],
+ "name": "mpath",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aheckmann/mpath.git"
+ },
+ "scripts": {
+ "test": "mocha test/*"
+ },
+ "version": "0.6.0"
+}
diff --git a/node_modules/mpath/test/index.js b/node_modules/mpath/test/index.js
new file mode 100644
index 0000000..f12bdc9
--- /dev/null
+++ b/node_modules/mpath/test/index.js
@@ -0,0 +1,1879 @@
+'use strict';
+
+/**
+ * Test dependencies.
+ */
+
+var mpath = require('../')
+var assert = require('assert')
+
+/**
+ * logging helper
+ */
+
+function log (o) {
+ console.log();
+ console.log(require('util').inspect(o, false, 1000));
+}
+
+/**
+ * special path for override tests
+ */
+
+var special = '_doc';
+
+/**
+ * Tests
+ */
+
+describe('mpath', function(){
+
+ /**
+ * test doc creator
+ */
+
+ function doc () {
+ var o = { first: { second: { third: [3,{ name: 'aaron' }, 9] }}};
+ o.comments = [
+ { name: 'one' }
+ , { name: 'two', _doc: { name: '2' }}
+ , { name: 'three'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }}
+ ];
+ o.name = 'jiro';
+ o.array = [
+ { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}
+ , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}] }}
+ , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+ o.arr = [
+ { arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true }
+ ]
+ return o;
+ }
+
+ describe('get', function(){
+ var o = doc();
+
+ it('`path` must be a string or array', function(done){
+ assert.throws(function () {
+ mpath.get({}, o);
+ }, /Must be either string or array/);
+ assert.throws(function () {
+ mpath.get(4, o);
+ }, /Must be either string or array/);
+ assert.throws(function () {
+ mpath.get(function(){}, o);
+ }, /Must be either string or array/);
+ assert.throws(function () {
+ mpath.get(/asdf/, o);
+ }, /Must be either string or array/);
+ assert.throws(function () {
+ mpath.get(Math, o);
+ }, /Must be either string or array/);
+ assert.throws(function () {
+ mpath.get(Buffer, o);
+ }, /Must be either string or array/);
+ assert.doesNotThrow(function () {
+ mpath.get('string', o);
+ });
+ assert.doesNotThrow(function () {
+ mpath.get([], o);
+ });
+ done();
+ })
+
+ describe('without `special`', function(){
+ it('works', function(done){
+ assert.equal('jiro', mpath.get('name', o));
+
+ assert.deepEqual(
+ { second: { third: [3,{ name: 'aaron' }, 9] }}
+ , mpath.get('first', o)
+ );
+
+ assert.deepEqual(
+ { third: [3,{ name: 'aaron' }, 9] }
+ , mpath.get('first.second', o)
+ );
+
+ assert.deepEqual(
+ [3,{ name: 'aaron' }, 9]
+ , mpath.get('first.second.third', o)
+ );
+
+ assert.deepEqual(
+ 3
+ , mpath.get('first.second.third.0', o)
+ );
+
+ assert.deepEqual(
+ 9
+ , mpath.get('first.second.third.2', o)
+ );
+
+ assert.deepEqual(
+ { name: 'aaron' }
+ , mpath.get('first.second.third.1', o)
+ );
+
+ assert.deepEqual(
+ 'aaron'
+ , mpath.get('first.second.third.1.name', o)
+ );
+
+ assert.deepEqual([
+ { name: 'one' }
+ , { name: 'two', _doc: { name: '2' }}
+ , { name: 'three'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}]}}],
+ mpath.get('comments', o));
+
+ assert.deepEqual({ name: 'one' }, mpath.get('comments.0', o));
+ assert.deepEqual('one', mpath.get('comments.0.name', o));
+ assert.deepEqual('two', mpath.get('comments.1.name', o));
+ assert.deepEqual('three', mpath.get('comments.2.name', o));
+
+ assert.deepEqual([{},{ comments: [{val: 'twoo'}]}]
+ , mpath.get('comments.2.comments', o));
+
+ assert.deepEqual({ comments: [{val: 'twoo'}]}
+ , mpath.get('comments.2.comments.1', o));
+
+ assert.deepEqual('twoo', mpath.get('comments.2.comments.1.comments.0.val', o));
+
+ done();
+ })
+
+ it('handles array.property dot-notation', function(done){
+ assert.deepEqual(
+ ['one', 'two', 'three']
+ , mpath.get('comments.name', o)
+ );
+ done();
+ })
+
+ it('handles array.array notation', function(done){
+ assert.deepEqual(
+ [undefined, undefined, [{}, {comments:[{val:'twoo'}]}]]
+ , mpath.get('comments.comments', o)
+ );
+ done();
+ })
+
+ it('handles prop.prop.prop.arrayProperty notation', function(done){
+ assert.deepEqual(
+ [undefined, 'aaron', undefined]
+ , mpath.get('first.second.third.name', o)
+ );
+ assert.deepEqual(
+ [1, 'aaron', 1]
+ , mpath.get('first.second.third.name', o, function (v) {
+ return undefined === v ? 1 : v;
+ })
+ );
+ done();
+ })
+
+ it('handles array.prop.array', function(done){
+ assert.deepEqual(
+ [ [{x: {b: [4,6,8]}}, { y: 10} ]
+ , [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}]
+ , [{x: {b: null }}, { x: { b: [null, 1]}}]
+ , [{x: null }]
+ , [{y: 3 }]
+ , [3, 0, null]
+ , undefined
+ ]
+ , mpath.get('array.o.array', o)
+ );
+ done();
+ })
+
+ it('handles array.prop.array.index', function(done){
+ assert.deepEqual(
+ [ {x: {b: [4,6,8]}}
+ , {x: {b: [1,2,3]}}
+ , {x: {b: null }}
+ , {x: null }
+ , {y: 3 }
+ , 3
+ , undefined
+ ]
+ , mpath.get('array.o.array.0', o)
+ );
+ done();
+ })
+
+ it('handles array.prop.array.index.prop', function(done){
+ assert.deepEqual(
+ [ {b: [4,6,8]}
+ , {b: [1,2,3]}
+ , {b: null }
+ , null
+ , undefined
+ , undefined
+ , undefined
+ ]
+ , mpath.get('array.o.array.0.x', o)
+ );
+ done();
+ })
+
+ it('handles array.prop.array.prop', function(done){
+ assert.deepEqual(
+ [ [undefined, 10 ]
+ , [undefined, undefined, undefined]
+ , [undefined, undefined]
+ , [undefined]
+ , [3]
+ , [undefined, undefined, undefined]
+ , undefined
+ ]
+ , mpath.get('array.o.array.y', o)
+ );
+ assert.deepEqual(
+ [ [{b: [4,6,8]}, undefined]
+ , [{b: [1,2,3]}, {z: 10 }, {b: 'hi'}]
+ , [{b: null }, { b: [null, 1]}]
+ , [null]
+ , [undefined]
+ , [undefined, undefined, undefined]
+ , undefined
+ ]
+ , mpath.get('array.o.array.x', o)
+ );
+ done();
+ })
+
+ it('handles array.prop.array.prop.prop', function(done){
+ assert.deepEqual(
+ [ [[4,6,8], undefined]
+ , [[1,2,3], undefined, 'hi']
+ , [null, [null, 1]]
+ , [null]
+ , [undefined]
+ , [undefined, undefined, undefined]
+ , undefined
+ ]
+ , mpath.get('array.o.array.x.b', o)
+ );
+ done();
+ })
+
+ it('handles array.prop.array.prop.prop.index', function(done){
+ assert.deepEqual(
+ [ [6, undefined]
+ , [2, undefined, 'i'] // undocumented feature (string indexing)
+ , [null, 1]
+ , [null]
+ , [undefined]
+ , [undefined, undefined, undefined]
+ , undefined
+ ]
+ , mpath.get('array.o.array.x.b.1', o)
+ );
+ assert.deepEqual(
+ [ [6, 0]
+ , [2, 0, 'i'] // undocumented feature (string indexing)
+ , [null, 1]
+ , [null]
+ , [0]
+ , [0, 0, 0]
+ , 0
+ ]
+ , mpath.get('array.o.array.x.b.1', o, function (v) {
+ return undefined === v ? 0 : v;
+ })
+ );
+ done();
+ })
+
+ it('handles array.index.prop.prop', function(done){
+ assert.deepEqual(
+ [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}]
+ , mpath.get('array.1.o.array', o)
+ );
+ assert.deepEqual(
+ ['hi','hi','hi']
+ , mpath.get('array.1.o.array', o, function (v) {
+ if (Array.isArray(v)) {
+ return v.map(function (val) {
+ return 'hi';
+ })
+ }
+ return v;
+ })
+ );
+ done();
+ })
+
+ it('handles array.array.index', function(done){
+ assert.deepEqual(
+ [{ a: { c: 48 }}, undefined]
+ , mpath.get('arr.arr.1', o)
+ );
+ assert.deepEqual(
+ ['woot', undefined]
+ , mpath.get('arr.arr.1', o, function (v) {
+ if (v && v.a && v.a.c) return 'woot';
+ return v;
+ })
+ );
+ done();
+ })
+
+ it('handles array.array.index.prop', function(done){
+ assert.deepEqual(
+ [{ c: 48 }, 'woot']
+ , mpath.get('arr.arr.1.a', o, function (v) {
+ if (undefined === v) return 'woot';
+ return v;
+ })
+ );
+ assert.deepEqual(
+ [{ c: 48 }, undefined]
+ , mpath.get('arr.arr.1.a', o)
+ );
+ mpath.set('arr.arr.1.a', [{c:49},undefined], o)
+ assert.deepEqual(
+ [{ c: 49 }, undefined]
+ , mpath.get('arr.arr.1.a', o)
+ );
+ mpath.set('arr.arr.1.a', [{c:48},undefined], o)
+ done();
+ })
+
+ it('handles array.array.index.prop.prop', function(done){
+ assert.deepEqual(
+ [48, undefined]
+ , mpath.get('arr.arr.1.a.c', o)
+ );
+ assert.deepEqual(
+ [48, 'woot']
+ , mpath.get('arr.arr.1.a.c', o, function (v) {
+ if (undefined === v) return 'woot';
+ return v;
+ })
+ );
+ done();
+ })
+
+ })
+
+ describe('with `special`', function(){
+ describe('that is a string', function(){
+ it('works', function(done){
+ assert.equal('jiro', mpath.get('name', o, special));
+
+ assert.deepEqual(
+ { second: { third: [3,{ name: 'aaron' }, 9] }}
+ , mpath.get('first', o, special)
+ );
+
+ assert.deepEqual(
+ { third: [3,{ name: 'aaron' }, 9] }
+ , mpath.get('first.second', o, special)
+ );
+
+ assert.deepEqual(
+ [3,{ name: 'aaron' }, 9]
+ , mpath.get('first.second.third', o, special)
+ );
+
+ assert.deepEqual(
+ 3
+ , mpath.get('first.second.third.0', o, special)
+ );
+
+ assert.deepEqual(
+ 4
+ , mpath.get('first.second.third.0', o, special, function (v) {
+ return 3 === v ? 4 : v;
+ })
+ );
+
+ assert.deepEqual(
+ 9
+ , mpath.get('first.second.third.2', o, special)
+ );
+
+ assert.deepEqual(
+ { name: 'aaron' }
+ , mpath.get('first.second.third.1', o, special)
+ );
+
+ assert.deepEqual(
+ 'aaron'
+ , mpath.get('first.second.third.1.name', o, special)
+ );
+
+ assert.deepEqual([
+ { name: 'one' }
+ , { name: 'two', _doc: { name: '2' }}
+ , { name: 'three'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}]}}],
+ mpath.get('comments', o, special));
+
+ assert.deepEqual({ name: 'one' }, mpath.get('comments.0', o, special));
+ assert.deepEqual('one', mpath.get('comments.0.name', o, special));
+ assert.deepEqual('2', mpath.get('comments.1.name', o, special));
+ assert.deepEqual('3', mpath.get('comments.2.name', o, special));
+ assert.deepEqual('nice', mpath.get('comments.2.name', o, special, function (v) {
+ return '3' === v ? 'nice' : v;
+ }));
+
+ assert.deepEqual([{},{ _doc: { comments: [{ val: 2 }] }}]
+ , mpath.get('comments.2.comments', o, special));
+
+ assert.deepEqual({ _doc: { comments: [{val: 2}]}}
+ , mpath.get('comments.2.comments.1', o, special));
+
+ assert.deepEqual(2, mpath.get('comments.2.comments.1.comments.0.val', o, special));
+ done();
+ })
+
+ it('handles array.property dot-notation', function(done){
+ assert.deepEqual(
+ ['one', '2', '3']
+ , mpath.get('comments.name', o, special)
+ );
+ assert.deepEqual(
+ ['one', 2, '3']
+ , mpath.get('comments.name', o, special, function (v) {
+ return '2' === v ? 2 : v
+ })
+ );
+ done();
+ })
+
+ it('handles array.array notation', function(done){
+ assert.deepEqual(
+ [undefined, undefined, [{}, {_doc: { comments:[{val:2}]}}]]
+ , mpath.get('comments.comments', o, special)
+ );
+ done();
+ })
+
+ it('handles array.array.index.array', function(done){
+ assert.deepEqual(
+ [undefined, undefined, [{val:2}]]
+ , mpath.get('comments.comments.1.comments', o, special)
+ );
+ done();
+ })
+
+ it('handles array.array.index.array.prop', function(done){
+ assert.deepEqual(
+ [undefined, undefined, [2]]
+ , mpath.get('comments.comments.1.comments.val', o, special)
+ );
+ assert.deepEqual(
+ ['nil', 'nil', [2]]
+ , mpath.get('comments.comments.1.comments.val', o, special, function (v) {
+ return undefined === v ? 'nil' : v;
+ })
+ );
+ done();
+ })
+ })
+
+ describe('that is a function', function(){
+ var special = function (obj, key) {
+ return obj[key]
+ }
+
+ it('works', function(done){
+ assert.equal('jiro', mpath.get('name', o, special));
+
+ assert.deepEqual(
+ { second: { third: [3,{ name: 'aaron' }, 9] }}
+ , mpath.get('first', o, special)
+ );
+
+ assert.deepEqual(
+ { third: [3,{ name: 'aaron' }, 9] }
+ , mpath.get('first.second', o, special)
+ );
+
+ assert.deepEqual(
+ [3,{ name: 'aaron' }, 9]
+ , mpath.get('first.second.third', o, special)
+ );
+
+ assert.deepEqual(
+ 3
+ , mpath.get('first.second.third.0', o, special)
+ );
+
+ assert.deepEqual(
+ 4
+ , mpath.get('first.second.third.0', o, special, function (v) {
+ return 3 === v ? 4 : v;
+ })
+ );
+
+ assert.deepEqual(
+ 9
+ , mpath.get('first.second.third.2', o, special)
+ );
+
+ assert.deepEqual(
+ { name: 'aaron' }
+ , mpath.get('first.second.third.1', o, special)
+ );
+
+ assert.deepEqual(
+ 'aaron'
+ , mpath.get('first.second.third.1.name', o, special)
+ );
+
+ assert.deepEqual([
+ { name: 'one' }
+ , { name: 'two', _doc: { name: '2' }}
+ , { name: 'three'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}]}}],
+ mpath.get('comments', o, special));
+
+ assert.deepEqual({ name: 'one' }, mpath.get('comments.0', o, special));
+ assert.deepEqual('one', mpath.get('comments.0.name', o, special));
+ assert.deepEqual('two', mpath.get('comments.1.name', o, special));
+ assert.deepEqual('three', mpath.get('comments.2.name', o, special));
+ assert.deepEqual('nice', mpath.get('comments.2.name', o, special, function (v) {
+ return 'three' === v ? 'nice' : v;
+ }));
+
+ assert.deepEqual([{},{ comments: [{ val: 'twoo' }] }]
+ , mpath.get('comments.2.comments', o, special));
+
+ assert.deepEqual({ comments: [{val: 'twoo'}]}
+ , mpath.get('comments.2.comments.1', o, special));
+
+ assert.deepEqual('twoo', mpath.get('comments.2.comments.1.comments.0.val', o, special));
+
+ var overide = false;
+ assert.deepEqual('twoo', mpath.get('comments.8.comments.1.comments.0.val', o, function (obj, path) {
+ if (Array.isArray(obj) && 8 == path) {
+ overide = true;
+ return obj[2];
+ }
+ return obj[path];
+ }));
+ assert.ok(overide);
+
+ done();
+ })
+
+ it('in combination with map', function(done){
+ var special = function (obj, key) {
+ if (Array.isArray(obj)) return obj[key];
+ return obj.mpath;
+ }
+ var map = function (val) {
+ return 'convert' == val
+ ? 'mpath'
+ : val;
+ }
+ var o = { mpath: [{ mpath: 'converse' }, { mpath: 'convert' }] }
+
+ assert.equal('mpath', mpath.get('something.1.kewl', o, special, map));
+ done();
+ })
+ })
+ })
+ })
+
+ describe('set', function() {
+ it('prevents writing to __proto__', function() {
+ var obj = {};
+ mpath.set('__proto__.x', 'foobar', obj);
+ assert.ok(!({}.x));
+
+ mpath.set('constructor.prototype.x', 'foobar', obj);
+ assert.ok(!({}.x));
+ });
+
+ describe('without `special`', function() {
+ var o = doc();
+
+ it('works', function(done) {
+ mpath.set('name', 'a new val', o, function(v) {
+ return 'a new val' === v ? 'changed' : v;
+ });
+ assert.deepEqual('changed', o.name);
+
+ mpath.set('name', 'changed', o);
+ assert.deepEqual('changed', o.name);
+
+ mpath.set('first.second.third', [1,{name:'x'},9], o);
+ assert.deepEqual([1,{name:'x'},9], o.first.second.third);
+
+ mpath.set('first.second.third.1.name', 'y', o)
+ assert.deepEqual([1,{name:'y'},9], o.first.second.third);
+
+ mpath.set('comments.1.name', 'ttwwoo', o);
+ assert.deepEqual({ name: 'ttwwoo', _doc: { name: '2' }}, o.comments[1]);
+
+ mpath.set('comments.2.comments.1.comments.0.expand', 'added', o);
+ assert.deepEqual(
+ { val: 'twoo', expand: 'added'}
+ , o.comments[2].comments[1].comments[0]);
+
+ mpath.set('comments.2.comments.1.comments.2', 'added', o);
+ assert.equal(3, o.comments[2].comments[1].comments.length);
+ assert.deepEqual(
+ { val: 'twoo', expand: 'added'}
+ , o.comments[2].comments[1].comments[0]);
+ assert.deepEqual(
+ undefined
+ , o.comments[2].comments[1].comments[1]);
+ assert.deepEqual(
+ 'added'
+ , o.comments[2].comments[1].comments[2]);
+
+ done();
+ })
+
+ describe('array.path', function(){
+ describe('with single non-array value', function(){
+ it('works', function(done){
+ mpath.set('arr.yep', false, o, function (v) {
+ return false === v ? true: v;
+ });
+ assert.deepEqual([
+ { yep: true, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true }
+ ], o.arr);
+
+ mpath.set('arr.yep', false, o);
+
+ assert.deepEqual([
+ { yep: false, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: false }
+ ], o.arr);
+
+ done();
+ })
+ })
+ describe('with array of values', function(){
+ it('that are equal in length', function(done){
+ mpath.set('arr.yep', ['one',2], o, function (v) {
+ return 'one' === v ? 1 : v;
+ });
+ assert.deepEqual([
+ { yep: 1, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 2 }
+ ], o.arr);
+ mpath.set('arr.yep', ['one',2], o);
+
+ assert.deepEqual([
+ { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 2 }
+ ], o.arr);
+
+ done();
+ })
+
+ it('that is less than length', function(done){
+ mpath.set('arr.yep', [47], o, function (v) {
+ return 47 === v ? 4 : v;
+ });
+ assert.deepEqual([
+ { yep: 4, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 2 }
+ ], o.arr);
+
+ mpath.set('arr.yep', [47], o);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 2 }
+ ], o.arr);
+
+ done();
+ })
+
+ it('that is greater than length', function(done){
+ mpath.set('arr.yep', [5,6,7], o, function (v) {
+ return 5 === v ? 'five' : v;
+ });
+ assert.deepEqual([
+ { yep: 'five', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 6 }
+ ], o.arr);
+
+ mpath.set('arr.yep', [5,6,7], o);
+ assert.deepEqual([
+ { yep: 5, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 6 }
+ ], o.arr);
+
+ done();
+ })
+ })
+ })
+
+ describe('array.$.path', function(){
+ describe('with single non-array value', function(){
+ it('copies the value to each item in array', function(done){
+ mpath.set('arr.$.yep', {xtra: 'double good'}, o, function (v) {
+ return v && v.xtra ? 'hi' : v;
+ });
+ assert.deepEqual([
+ { yep: 'hi', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 'hi'}
+ ], o.arr);
+
+ mpath.set('arr.$.yep', {xtra: 'double good'}, o);
+ assert.deepEqual([
+ { yep: {xtra:'double good'}, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: {xtra:'double good'}}
+ ], o.arr);
+
+ done();
+ })
+ })
+ describe('with array of values', function(){
+ it('copies the value to each item in array', function(done){
+ mpath.set('arr.$.yep', [15], o, function (v) {
+ return v.length === 1 ? [] : v;
+ });
+ assert.deepEqual([
+ { yep: [], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: []}
+ ], o.arr);
+
+ mpath.set('arr.$.yep', [15], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: [15]}
+ ], o.arr);
+
+ done();
+ })
+ })
+ })
+
+ describe('array.index.path', function(){
+ it('works', function(done){
+ mpath.set('arr.1.yep', 0, o, function (v) {
+ return 0 === v ? 'zero' : v;
+ });
+ assert.deepEqual([
+ { yep: [15] , arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 'zero' }
+ ], o.arr);
+
+ mpath.set('arr.1.yep', 0, o);
+ assert.deepEqual([
+ { yep: [15] , arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.e', 35, o, function (v) {
+ return 35 === v ? 3 : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 47 }, e: 3}, { a: { c: 48 }, e: 3}, { d: 'yep', e: 3 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.e', 35, o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 47 }, e: 35}, { a: { c: 48 }, e: 35}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.e', ['a','b'], o, function (v) {
+ return 'a' === v ? 'x' : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 47 }, e: 'x'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.e', ['a','b'], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 47 }, e: 'a'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.path.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.a.b', 36, o, function (v) {
+ return 36 === v ? 3 : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 3 }, e: 'a'}, { a: { c: 48, b: 3 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.a.b', 36, o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 36 }, e: 'a'}, { a: { c: 48, b: 36 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.a.b', [1,2,3,4], o, function (v) {
+ return 2 === v ? 'two' : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 'two' }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.a.b', [1,2,3,4], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 2 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.$.path.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.$.a.b', '$', o, function (v) {
+ return '$' === v ? 'dolla billz' : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: 'dolla billz' }, e: 'a'}, { a: { c: 48, b: 'dolla billz' }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.$.a.b', '$', o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: '$' }, e: 'a'}, { a: { c: 48, b: '$' }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.$.a.b', [1], o, function (v) {
+ return Array.isArray(v) ? {} : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: {} }, e: 'a'}, { a: { c: 48, b: {} }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.0.arr.$.a.b', [1], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: { b: [1] }, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.index.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.0.a', 'single', o, function (v) {
+ return 'single' === v ? 'double' : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 'double', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.arr.0.a', 'single', o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, function (v) {
+ return 4 === v ? 3 : v;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 3, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: false }
+ ], o.arr);
+
+ mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 4, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: false }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.$.index.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.$.0.a', 'singles', o, function (v) {
+ return 0;
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 0, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('arr.arr.$.0.a', 'singles', o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 'singles', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ mpath.set('$.arr.arr.0.a', 'single', o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0 }
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, function (v) {
+ return 'nope'
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: 'nope', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0}
+ ], o.arr);
+
+ mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: [4,8,15,16,23,42], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0}
+ ], o.arr);
+
+ mpath.set('arr.$.arr.0.a', [4,8,15,16,23,42,108], o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: [4,8,15,16,23,42,108], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.path.index', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.a.7', 47, o, function (v) {
+ return 1
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,1], e: 'a'}, { a: { c: 48, b: [1], '7': 1 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0}
+ ], o.arr);
+
+ mpath.set('arr.arr.a.7', 47, o);
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,47], e: 'a'}, { a: { c: 48, b: [1], '7': 47 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ o.arr[1].arr = [{ a: [] }, { a: [] }, { a: null }];
+ mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o);
+
+ var a1 = [];
+ var a2 = [];
+ a1[7] = undefined;
+ a2[7] = 'woot';
+
+ assert.deepEqual([
+ { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] }
+ , { yep: 0, arr: [{a:a1},{a:a2},{a:null}] }
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('handles array.array.path', function(){
+ it('with single', function(done){
+ o.arr[1].arr = [{},{}];
+ assert.deepEqual([{},{}], o.arr[1].arr);
+ o.arr.push({ arr: 'something else' });
+ o.arr.push({ arr: ['something else'] });
+ o.arr.push({ arr: [[]] });
+ o.arr.push({ arr: [5] });
+
+ var weird = [];
+ weird.e = 'xmas';
+
+ // test
+ mpath.set('arr.arr.e', 47, o, function (v) {
+ return 'xmas'
+ });
+ assert.deepEqual([
+ { yep: [15], arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 'xmas'}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 'xmas'}
+ , { d: 'yep', e: 'xmas' }
+ ]
+ }
+ , { yep: 0, arr: [{e: 'xmas'}, {e:'xmas'}] }
+ , { arr: 'something else' }
+ , { arr: ['something else'] }
+ , { arr: [weird] }
+ , { arr: [5] }
+ ]
+ , o.arr);
+
+ weird.e = 47;
+
+ mpath.set('arr.arr.e', 47, o);
+ assert.deepEqual([
+ { yep: [15], arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 47}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 47}
+ , { d: 'yep', e: 47 }
+ ]
+ }
+ , { yep: 0, arr: [{e: 47}, {e:47}] }
+ , { arr: 'something else' }
+ , { arr: ['something else'] }
+ , { arr: [weird] }
+ , { arr: [5] }
+ ]
+ , o.arr);
+
+ done();
+ })
+ it('with arrays', function(done){
+ mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o, function (v) {
+ return 10;
+ });
+
+ var weird = [];
+ weird.e = 10;
+
+ assert.deepEqual([
+ { yep: [15], arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 10}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 10}
+ , { d: 'yep', e: 10 }
+ ]
+ }
+ , { yep: 0, arr: [{e: 10}, {e:10}] }
+ , { arr: 'something else' }
+ , { arr: ['something else'] }
+ , { arr: [weird] }
+ , { arr: [5] }
+ ]
+ , o.arr);
+
+ mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o);
+
+ weird.e = 6;
+
+ assert.deepEqual([
+ { yep: [15], arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 1}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 2}
+ , { d: 'yep', e: 3 }
+ ]
+ }
+ , { yep: 0, arr: [{e: 4}, {e:5}] }
+ , { arr: 'something else' }
+ , { arr: ['something else'] }
+ , { arr: [weird] }
+ , { arr: [5] }
+ ]
+ , o.arr);
+
+ done();
+ })
+ })
+ })
+
+ describe('with `special`', function(){
+ var o = doc();
+
+ it('works', function(done){
+ mpath.set('name', 'chan', o, special, function (v) {
+ return 'hi';
+ });
+ assert.deepEqual('hi', o.name);
+
+ mpath.set('name', 'changer', o, special);
+ assert.deepEqual('changer', o.name);
+
+ mpath.set('first.second.third', [1,{name:'y'},9], o, special);
+ assert.deepEqual([1,{name:'y'},9], o.first.second.third);
+
+ mpath.set('first.second.third.1.name', 'z', o, special)
+ assert.deepEqual([1,{name:'z'},9], o.first.second.third);
+
+ mpath.set('comments.1.name', 'ttwwoo', o, special);
+ assert.deepEqual({ name: 'two', _doc: { name: 'ttwwoo' }}, o.comments[1]);
+
+ mpath.set('comments.2.comments.1.comments.0.expander', 'adder', o, special, function (v) {
+ return 'super'
+ });
+ assert.deepEqual(
+ { val: 2, expander: 'super'}
+ , o.comments[2]._doc.comments[1]._doc.comments[0]);
+
+ mpath.set('comments.2.comments.1.comments.0.expander', 'adder', o, special);
+ assert.deepEqual(
+ { val: 2, expander: 'adder'}
+ , o.comments[2]._doc.comments[1]._doc.comments[0]);
+
+ mpath.set('comments.2.comments.1.comments.2', 'set', o, special);
+ assert.equal(3, o.comments[2]._doc.comments[1]._doc.comments.length);
+ assert.deepEqual(
+ { val: 2, expander: 'adder'}
+ , o.comments[2]._doc.comments[1]._doc.comments[0]);
+ assert.deepEqual(
+ undefined
+ , o.comments[2]._doc.comments[1]._doc.comments[1]);
+ assert.deepEqual(
+ 'set'
+ , o.comments[2]._doc.comments[1]._doc.comments[2]);
+ done();
+ })
+
+ describe('array.path', function(){
+ describe('with single non-array value', function(){
+ it('works', function(done){
+ o.arr[1]._doc = { special: true }
+
+ mpath.set('arr.yep', false, o, special, function (v) {
+ return 'yes';
+ });
+ assert.deepEqual([
+ { yep: 'yes', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: 'yes'}}
+ ], o.arr);
+
+ mpath.set('arr.yep', false, o, special);
+ assert.deepEqual([
+ { yep: false, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: false }}
+ ], o.arr);
+
+ done();
+ })
+ })
+ describe('with array of values', function(){
+ it('that are equal in length', function(done){
+ mpath.set('arr.yep', ['one',2], o, special, function (v) {
+ return 2 === v ? 20 : v;
+ });
+ assert.deepEqual([
+ { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: 20}}
+ ], o.arr);
+
+ mpath.set('arr.yep', ['one',2], o, special);
+ assert.deepEqual([
+ { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: 2}}
+ ], o.arr);
+
+ done();
+ })
+
+ it('that is less than length', function(done){
+ mpath.set('arr.yep', [47], o, special, function (v) {
+ return 80;
+ });
+ assert.deepEqual([
+ { yep: 80, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: 2}}
+ ], o.arr);
+
+ mpath.set('arr.yep', [47], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+ , { yep: true, _doc: { special: true, yep: 2}}
+ ], o.arr);
+
+ // add _doc to first element
+ o.arr[0]._doc = { yep: 46, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] }
+
+ mpath.set('arr.yep', [20], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 20, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 2}}
+ ], o.arr);
+
+ done();
+ })
+
+ it('that is greater than length', function(done){
+ mpath.set('arr.yep', [5,6,7], o, special, function () {
+ return 'x';
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 'x', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 'x'}}
+ ], o.arr);
+
+ mpath.set('arr.yep', [5,6,7], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 5, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 6}}
+ ], o.arr);
+
+ done();
+ })
+ })
+ })
+
+ describe('array.$.path', function(){
+ describe('with single non-array value', function(){
+ it('copies the value to each item in array', function(done){
+ mpath.set('arr.$.yep', {xtra: 'double good'}, o, special, function (v) {
+ return 9;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: 9, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 9}}
+ ], o.arr);
+
+ mpath.set('arr.$.yep', {xtra: 'double good'}, o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: {xtra:'double good'}, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: {xtra:'double good'}}}
+ ], o.arr);
+
+ done();
+ })
+ })
+ describe('with array of values', function(){
+ it('copies the value to each item in array', function(done){
+ mpath.set('arr.$.yep', [15], o, special, function (v) {
+ return 'array'
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: 'array', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 'array'}}
+ ], o.arr);
+
+ mpath.set('arr.$.yep', [15], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: [15]}}
+ ], o.arr);
+
+ done();
+ })
+ })
+ })
+
+ describe('array.index.path', function(){
+ it('works', function(done){
+ mpath.set('arr.1.yep', 0, o, special, function (v) {
+ return 1;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 1}}
+ ], o.arr);
+
+ mpath.set('arr.1.yep', 0, o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.e', 35, o, special, function (v) {
+ return 30
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 30}, { a: { c: 48 }, e: 30}, { d: 'yep', e: 30 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.e', 35, o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 35}, { a: { c: 48 }, e: 35}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.e', ['a','b'], o, special, function (v) {
+ return 'a' === v ? 'A' : v;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 'A'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.e', ['a','b'], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 'a'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.path.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.a.b', 36, o, special, function (v) {
+ return 20
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 20 }, e: 'a'}, { a: { c: 48, b: 20 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.a.b', 36, o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 36 }, e: 'a'}, { a: { c: 48, b: 36 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.a.b', [1,2,3,4], o, special, function (v) {
+ return v*2;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 2 }, e: 'a'}, { a: { c: 48, b: 4 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.a.b', [1,2,3,4], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 2 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.index.array.$.path.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.0.arr.$.a.b', '$', o, special, function (v) {
+ return 'dollaz'
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: 'dollaz' }, e: 'a'}, { a: { c: 48, b: 'dollaz' }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.$.a.b', '$', o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: '$' }, e: 'a'}, { a: { c: 48, b: '$' }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.0.arr.$.a.b', [1], o, special, function (v) {
+ return {};
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: {} }, e: 'a'}, { a: { c: 48, b: {} }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.0.arr.$.a.b', [1], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: { b: [1] }, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.index.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.0.a', 'single', o, special, function (v) {
+ return 88;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 88, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.0.a', 'single', o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, special, function (v) {
+ return v*2;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 8, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 4, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.$.index.path', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.$.0.a', 'singles', o, special, function (v) {
+ return v.toUpperCase();
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 'SINGLES', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.$.0.a', 'singles', o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 'singles', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('$.arr.arr.0.a', 'single', o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, special, function (v) {
+ return Array
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: Array, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.$.arr.0.a', [4,8,15,16,23,42,108], o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('array.array.path.index', function(){
+ it('with single value', function(done){
+ mpath.set('arr.arr.a.7', 47, o, special, function (v) {
+ return Object;
+ });
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,Object], e: 'a'}, { a: { c: 48, b: [1], '7': Object }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.a.7', 47, o, special);
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,47], e: 'a'}, { a: { c: 48, b: [1], '7': 47 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ it('with array', function(done){
+ o.arr[1]._doc.arr = [{ a: [] }, { a: [] }, { a: null }];
+ mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o, special, function (v) {
+ return undefined === v ? 'nope' : v;
+ });
+
+ var a1 = [];
+ var a2 = [];
+ a1[7] = 'nope';
+ a2[7] = 'woot';
+
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { arr: [{a:a1},{a:a2},{a:null}], special: true, yep: 0}}
+ ], o.arr);
+
+ mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o, special);
+
+ a1[7] = undefined;
+
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] } }
+ , { yep: true, _doc: { arr: [{a:a1},{a:a2},{a:null}], special: true, yep: 0}}
+ ], o.arr);
+
+ done();
+ })
+ })
+
+ describe('handles array.array.path', function(){
+ it('with single', function(done){
+ o.arr[1]._doc.arr = [{},{}];
+ assert.deepEqual([{},{}], o.arr[1]._doc.arr);
+ o.arr.push({ _doc: { arr: 'something else' }});
+ o.arr.push({ _doc: { arr: ['something else'] }});
+ o.arr.push({ _doc: { arr: [[]] }});
+ o.arr.push({ _doc: { arr: [5] }});
+
+ // test
+ mpath.set('arr.arr.e', 47, o, special);
+
+ var weird = [];
+ weird.e = 47;
+
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: {
+ yep: [15]
+ , arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 47}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 47}
+ , { d: 'yep', e: 47 }
+ ]
+ }
+ }
+ , { yep: true
+ , _doc: {
+ arr: [
+ {e:47}
+ , {e:47}
+ ]
+ , special: true
+ , yep: 0
+ }
+ }
+ , { _doc: { arr: 'something else' }}
+ , { _doc: { arr: ['something else'] }}
+ , { _doc: { arr: [weird] }}
+ , { _doc: { arr: [5] }}
+ ]
+ , o.arr);
+
+ done();
+ })
+ it('with arrays', function(done){
+ mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o, special);
+
+ var weird = [];
+ weird.e = 6;
+
+ assert.deepEqual([
+ { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }]
+ , _doc: {
+ yep: [15]
+ , arr: [
+ { a: [4,8,15,16,23,42,108,null], e: 1}
+ , { a: { c: 48, b: [1], '7': 46 }, e: 2}
+ , { d: 'yep', e: 3 }
+ ]
+ }
+ }
+ , { yep: true
+ , _doc: {
+ arr: [
+ {e:4}
+ , {e:5}
+ ]
+ , special: true
+ , yep: 0
+ }
+ }
+ , { _doc: { arr: 'something else' }}
+ , { _doc: { arr: ['something else'] }}
+ , { _doc: { arr: [weird] }}
+ , { _doc: { arr: [5] }}
+ ]
+ , o.arr);
+
+ done();
+ })
+ })
+
+ describe('that is a function', function(){
+ describe('without map', function(){
+ it('works on array value', function(done){
+ var o = { hello: { world: [{ how: 'are' }, { you: '?' }] }};
+ var special = function (obj, key, val) {
+ if (val) {
+ obj[key] = val;
+ } else {
+ return 'thing' == key
+ ? obj.world
+ : obj[key]
+ }
+ }
+ mpath.set('hello.thing.how', 'arrrr', o, special);
+ assert.deepEqual(o, { hello: { world: [{ how: 'arrrr' }, { you: '?', how: 'arrrr' }] }});
+ done();
+ })
+ it('works on non-array value', function(done){
+ var o = { hello: { world: { how: 'are you' }}};
+ var special = function (obj, key, val) {
+ if (val) {
+ obj[key] = val;
+ } else {
+ return 'thing' == key
+ ? obj.world
+ : obj[key]
+ }
+ }
+ mpath.set('hello.thing.how', 'RU', o, special);
+ assert.deepEqual(o, { hello: { world: { how: 'RU' }}});
+ done();
+ })
+ })
+ it('works with map', function(done){
+ var o = { hello: { world: [{ how: 'are' }, { you: '?' }] }};
+ var special = function (obj, key, val) {
+ if (val) {
+ obj[key] = val;
+ } else {
+ return 'thing' == key
+ ? obj.world
+ : obj[key]
+ }
+ }
+ var map = function (val) {
+ return 'convert' == val
+ ? 'ºº'
+ : val
+ }
+ mpath.set('hello.thing.how', 'convert', o, special, map);
+ assert.deepEqual(o, { hello: { world: [{ how: 'ºº' }, { you: '?', how: 'ºº' }] }});
+ done();
+ })
+ })
+
+ })
+
+ describe('get/set integration', function(){
+ var o = doc();
+
+ it('works', function(done){
+ var vals = mpath.get('array.o.array.x.b', o);
+
+ vals[0][0][2] = 10;
+ vals[1][0][1] = 0;
+ vals[1][1] = 'Rambaldi';
+ vals[1][2] = [12,14];
+ vals[2] = [{changed:true}, [null, ['changed','to','array']]];
+
+ mpath.set('array.o.array.x.b', vals, o);
+
+ var t = [
+ { o: { array: [{x: {b: [4,6,10]}}, { y: 10} ] }}
+ , { o: { array: [{x: {b: [1,0,3]}}, { x: {b:'Rambaldi',z: 10 }}, { x: {b: [12,14]}}] }}
+ , { o: { array: [{x: {b: {changed:true}}}, { x: { b: [null, ['changed','to','array']]}}]}}
+ , { o: { array: [{x: null }] }}
+ , { o: { array: [{y: 3 }] }}
+ , { o: { array: [3, 0, null] }}
+ , { o: { name: 'ha' }}
+ ];
+ assert.deepEqual(t, o.array);
+ done();
+ });
+
+ it('array.prop', function(done){
+ mpath.set('comments.name', ['this', 'was', 'changed'], o);
+
+ assert.deepEqual([
+ { name: 'this' }
+ , { name: 'was', _doc: { name: '2' }}
+ , { name: 'changed'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }}
+ ], o.comments);
+
+ mpath.set('comments.name', ['also', 'changed', 'this'], o, special);
+
+ assert.deepEqual([
+ { name: 'also' }
+ , { name: 'was', _doc: { name: 'changed' }}
+ , { name: 'changed'
+ , comments: [{},{ comments: [{val: 'twoo'}]}]
+ , _doc: { name: 'this', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }}
+ ], o.comments);
+
+ done();
+ });
+
+ it('nested array', function(done) {
+ const obj = { arr: [[{ test: 41 }]] };
+ mpath.set('arr.test', [[42]], obj);
+ assert.deepEqual(obj.arr, [[{ test: 42 }]]);
+ done();
+ });
+ });
+
+ describe('multiple $ use', function(){
+ var o = doc();
+ it('is ok', function(done){
+ assert.doesNotThrow(function () {
+ mpath.set('arr.$.arr.$.a', 35, o);
+ });
+ done();
+ });
+ });
+
+ it('has', function(done) {
+ assert.ok(mpath.has('a', { a: 1 }));
+ assert.ok(mpath.has('a', { a: undefined }));
+ assert.ok(!mpath.has('a', {}));
+ assert.ok(!mpath.has('a', null));
+
+ assert.ok(mpath.has('a.b', { a: { b: 1 } }));
+ assert.ok(mpath.has('a.b', { a: { b: undefined } }));
+ assert.ok(!mpath.has('a.b', { a: 1 }));
+ assert.ok(!mpath.has('a.b', { a: null }));
+
+ done();
+ });
+
+ it('underneath a map', function(done) {
+ if (!global.Map) {
+ done();
+ return;
+ }
+ assert.equal(mpath.get('a.b', { a: new Map([['b', 1]]) }), 1);
+
+ var m = new Map([['b', 1]]);
+ var obj = { a: m };
+ mpath.set('a.c', 2, obj);
+ assert.equal(m.get('c'), 2);
+
+ done();
+ });
+
+ it('unset', function(done) {
+ var o = { a: 1 };
+ mpath.unset('a', o);
+ assert.deepEqual(o, {});
+
+ o = { a: { b: 1 } };
+ mpath.unset('a.b', o);
+ assert.deepEqual(o, { a: {} });
+
+ o = { a: null };
+ mpath.unset('a.b', o);
+ assert.deepEqual(o, { a: null });
+
+ done();
+ });
+
+ it('unset with __proto__', function(done) {
+ // Should refuse to set __proto__
+ function Clazz() {}
+ Clazz.prototype.foobar = true;
+
+ mpath.unset('__proto__.foobar', new Clazz());
+ assert.ok(Clazz.prototype.foobar);
+
+ mpath.unset('constructor.prototype.foobar', new Clazz());
+ assert.ok(Clazz.prototype.foobar);
+
+ done();
+ });
+
+ it('get() underneath subclassed array', function(done) {
+ class MyArray extends Array {}
+
+ const obj = {
+ arr: new MyArray()
+ };
+ obj.arr.push({ test: 2 });
+
+ const arr = mpath.get('arr.test', obj);
+ assert.equal(arr.constructor.name, 'Array');
+ assert.ok(!(arr instanceof MyArray));
+
+ done();
+ });
+
+ it('ignores setting a nested path that doesnt exist', function(done){
+ var o = doc();
+ assert.doesNotThrow(function(){
+ mpath.set('thing.that.is.new', 10, o);
+ })
+ done();
+ });
+ });
+});
diff --git a/node_modules/mquery/.eslintignore b/node_modules/mquery/.eslintignore
new file mode 100644
index 0000000..4b4d863
--- /dev/null
+++ b/node_modules/mquery/.eslintignore
@@ -0,0 +1 @@
+coverage/
\ No newline at end of file
diff --git a/node_modules/mquery/.travis.yml b/node_modules/mquery/.travis.yml
new file mode 100644
index 0000000..3d207e1
--- /dev/null
+++ b/node_modules/mquery/.travis.yml
@@ -0,0 +1,17 @@
+language: node_js
+node_js:
+ - "8"
+ - "10"
+ - "12"
+matrix:
+ include:
+ - node_js: "13"
+ env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
+ allow_failures:
+ # Allow the nightly installs to fail
+ - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
+script:
+ - npm test
+ - npm run lint
+services:
+ - mongodb
diff --git a/node_modules/mquery/History.md b/node_modules/mquery/History.md
new file mode 100644
index 0000000..bc6a3c3
--- /dev/null
+++ b/node_modules/mquery/History.md
@@ -0,0 +1,342 @@
+3.2.2 / 2019-09-22
+==================
+ * fix: dont re-call setOptions() when pulling base class options Automattic/mongoose#8159
+
+3.2.1 / 2018-08-24
+==================
+ * chore: upgrade deps
+
+3.2.0 / 2018-08-24
+==================
+ * feat: add $useProjection to opt in to using `projection` instead of `fields` re: MongoDB deprecation warnings Automattic/mongoose#6880
+
+3.1.2 / 2018-08-01
+==================
+ * chore: move eslint to devDependencies #110 [jakesjews](https://github.com/jakesjews)
+
+3.1.1 / 2018-07-30
+==================
+ * chore: add eslint #107 [Fonger](https://github.com/Fonger)
+ * docs: clean up readConcern docs #106 [Fonger](https://github.com/Fonger)
+
+3.1.0 / 2018-07-29
+==================
+ * feat: add `readConcern()` helper #105 [Fonger](https://github.com/Fonger)
+ * feat: add `maxTimeMS()` as alias of `maxTime()` #105 [Fonger](https://github.com/Fonger)
+ * feat: add `collation()` helper #105 [Fonger](https://github.com/Fonger)
+
+3.0.1 / 2018-07-02
+==================
+ * fix: parse sort array options correctly #103 #102 [Fonger](https://github.com/Fonger)
+
+3.0.0 / 2018-01-20
+==================
+ * chore: upgrade deps and add nsp
+
+3.0.0-rc0 / 2017-12-06
+======================
+ * BREAKING CHANGE: remove support for node < 4
+ * BREAKING CHANGE: remove support for retainKeyOrder, will always be true by default re: Automattic/mongoose#2749
+
+2.3.3 / 2017-11-19
+==================
+ * fixed; catch sync errors in cursor.toArray() re: Automattic/mongoose#5812
+
+2.3.2 / 2017-09-27
+==================
+ * fixed; bumped debug -> 2.6.9 re: #89
+
+2.3.1 / 2017-05-22
+==================
+ * fixed; bumped debug -> 2.6.7 re: #86
+
+2.3.0 / 2017-03-05
+==================
+ * added; replaceOne function
+ * added; deleteOne and deleteMany functions
+
+2.2.3 / 2017-01-31
+==================
+ * fixed; throw correct error when passing incorrectly formatted array to sort()
+
+2.2.2 / 2017-01-31
+==================
+ * fixed; allow passing maps to sort()
+
+2.2.1 / 2017-01-29
+==================
+ * fixed; allow passing string to hint()
+
+2.2.0 / 2017-01-08
+==================
+ * added; updateOne and updateMany functions
+
+2.1.0 / 2016-12-22
+==================
+ * added; ability to pass an array to select() #81 [dciccale](https://github.com/dciccale)
+
+2.0.0 / 2016-09-25
+==================
+ * added; support for mongodb driver 2.0 streams
+
+1.12.0 / 2016-09-25
+===================
+ * added; `retainKeyOrder` option re: Automattic/mongoose#4542
+
+1.11.0 / 2016-06-04
+===================
+ * added; `.minDistance()` helper and minDistance for `.near()` Automattic/mongoose#4179
+
+1.10.1 / 2016-04-26
+===================
+ * fixed; ensure conditions is an object before assigning #75
+
+1.10.0 / 2016-03-16
+==================
+
+ * updated; bluebird to latest 2.10.2 version #74 [matskiv](https://github.com/matskiv)
+
+1.9.0 / 2016-03-15
+==================
+ * added; `.eq` as a shortcut for `.equals` #72 [Fonger](https://github.com/Fonger)
+ * added; ability to use array syntax for sort re: https://jira.mongodb.org/browse/NODE-578 #67
+
+1.8.0 / 2016-03-01
+==================
+ * fixed; dont throw an error if count used with sort or select Automattic/mongoose#3914
+
+1.7.0 / 2016-02-23
+==================
+ * fixed; don't treat objects with a length property as argument objects #70
+ * added; `.findCursor()` method #69 [nswbmw](https://github.com/nswbmw)
+ * added; `_compiledUpdate` property #68 [nswbmw](https://github.com/nswbmw)
+
+1.6.2 / 2015-07-12
+==================
+
+ * fixed; support exec cb being called synchronously #66
+
+1.6.1 / 2015-06-16
+==================
+
+ * fixed; do not treat $meta projection as inclusive [vkarpov15](https://github.com/vkarpov15)
+
+1.6.0 / 2015-05-27
+==================
+
+ * update dependencies #65 [bachp](https://github.com/bachp)
+
+1.5.0 / 2015-03-31
+==================
+
+ * fixed; debug output
+ * fixed; allow hint usage with count #61 [trueinsider](https://github.com/trueinsider)
+
+1.4.0 / 2015-03-29
+==================
+
+ * added; object support to slice() #60 [vkarpov15](https://github.com/vkarpov15)
+ * debug; improved output #57 [flyvictor](https://github.com/flyvictor)
+
+1.3.0 / 2014-11-06
+==================
+
+ * added; setTraceFunction() #53 from [jlai](https://github.com/jlai)
+
+1.2.1 / 2014-09-26
+==================
+
+ * fixed; distinct assignment in toConstructor() #51 from [esco](https://github.com/esco)
+
+1.2.0 / 2014-09-18
+==================
+
+ * added; stream() support for find()
+
+1.1.0 / 2014-09-15
+==================
+
+ * add #then for co / koa support
+ * start checking code coverage
+
+1.0.0 / 2014-07-07
+==================
+
+ * Remove broken require() calls until they're actually implemented #48 [vkarpov15](https://github.com/vkarpov15)
+
+0.9.0 / 2014-05-22
+==================
+
+ * added; thunk() support
+ * release 0.8.0
+
+0.8.0 / 2014-05-15
+==================
+
+ * added; support for maxTimeMS #44 [yoitsro](https://github.com/yoitsro)
+ * updated; devDependency (driver to 1.4.4)
+
+0.7.0 / 2014-05-02
+==================
+
+ * fixed; pass $maxDistance in $near object as described in docs #43 [vkarpov15](https://github.com/vkarpov15)
+ * fixed; cloning buffers #42 [gjohnson](https://github.com/gjohnson)
+ * tests; a little bit more `mongodb` agnostic #34 [refack](https://github.com/refack)
+
+0.6.0 / 2014-04-01
+==================
+
+ * fixed; Allow $meta args in sort() so text search sorting works #37 [vkarpov15](https://github.com/vkarpov15)
+
+0.5.3 / 2014-02-22
+==================
+
+ * fixed; cloning mongodb.Binary
+
+0.5.2 / 2014-01-30
+==================
+
+ * fixed; cloning ObjectId constructors
+ * fixed; cloning of ReadPreferences #30 [ashtuchkin](https://github.com/ashtuchkin)
+ * tests; use specific mongodb version #29 [AvianFlu](https://github.com/AvianFlu)
+ * tests; remove dependency on ObjectId #28 [refack](https://github.com/refack)
+ * tests; add failing ReadPref test
+
+0.5.1 / 2014-01-17
+==================
+
+ * added; deprecation notice to tags parameter #27 [ashtuchkin](https://github.com/ashtuchkin)
+ * readme; add links
+
+0.5.0 / 2014-01-16
+==================
+
+ * removed; mongodb driver dependency #26 [ashtuchkin](https://github.com/ashtuchkin)
+ * removed; first class support of read preference tags #26 (still supported though) [ashtuchkin](https://github.com/ashtuchkin)
+ * added; better ObjectId clone support
+ * fixed; cloning objects that have no constructor #21
+ * docs; cleaned up [ashtuchkin](https://github.com/ashtuchkin)
+
+0.4.2 / 2014-01-08
+==================
+
+ * updated; debug module 0.7.4 [refack](https://github.com/refack)
+
+0.4.1 / 2014-01-07
+==================
+
+ * fixed; inclusive/exclusive logic
+
+0.4.0 / 2014-01-06
+==================
+
+ * added; selected()
+ * added; selectedInclusively()
+ * added; selectedExclusively()
+
+0.3.3 / 2013-11-14
+==================
+
+ * Fix Mongo DB Dependency #20 [rschmukler](https://github.com/rschmukler)
+
+0.3.2 / 2013-09-06
+==================
+
+ * added; geometry support for near()
+
+0.3.1 / 2013-08-22
+==================
+
+ * fixed; update retains key order #19
+
+0.3.0 / 2013-08-22
+==================
+
+ * less hardcoded isNode env detection #18 [vshulyak](https://github.com/vshulyak)
+ * added; validation of findAndModify varients
+ * clone update doc before execution
+ * stricter env checks
+
+0.2.7 / 2013-08-2
+==================
+
+ * Now support GeoJSON point values for Query#near
+
+0.2.6 / 2013-07-30
+==================
+
+ * internally, 'asc' and 'desc' for sorts are now converted into 1 and -1, respectively
+
+0.2.5 / 2013-07-30
+==================
+
+ * updated docs
+ * changed internal representation of `sort` to use objects instead of arrays
+
+0.2.4 / 2013-07-25
+==================
+
+ * updated; sliced to 0.0.5
+
+0.2.3 / 2013-07-09
+==================
+
+ * now using a callback in collection.find instead of directly calling toArray() on the cursor [ebensing](https://github.com/ebensing)
+
+0.2.2 / 2013-07-09
+==================
+
+ * now exposing mongodb export to allow for better testing [ebensing](https://github.com/ebensing)
+
+0.2.1 / 2013-07-08
+==================
+
+ * select no longer accepts arrays as parameters [ebensing](https://github.com/ebensing)
+
+0.2.0 / 2013-07-05
+==================
+
+ * use $geoWithin by default
+
+0.1.2 / 2013-07-02
+==================
+
+ * added use$geoWithin flag [ebensing](https://github.com/ebensing)
+ * fix read preferences typo [ebensing](https://github.com/ebensing)
+ * fix reference to old param name in exists() [ebensing](https://github.com/ebensing)
+
+0.1.1 / 2013-06-24
+==================
+
+ * fixed; $intersects -> $geoIntersects #14 [ebensing](https://github.com/ebensing)
+ * fixed; Retain key order when copying objects #15 [ebensing](https://github.com/ebensing)
+ * bump mongodb dev dep
+
+0.1.0 / 2013-05-06
+==================
+
+ * findAndModify; return the query
+ * move mquery.proto.canMerge to mquery.canMerge
+ * overwrite option now works with non-empty objects
+ * use strict mode
+ * validate count options
+ * validate distinct options
+ * add aggregate to base collection methods
+ * clone merge arguments
+ * clone merged update arguments
+ * move subclass to mquery.prototype.toConstructor
+ * fixed; maxScan casing
+ * use regexp-clone
+ * added; geometry/intersects support
+ * support $and
+ * near: do not use "radius"
+ * callbacks always fire on next turn of loop
+ * defined collection interface
+ * remove time from tests
+ * clarify goals
+ * updated docs;
+
+0.0.1 / 2012-12-15
+==================
+
+ * initial release
diff --git a/node_modules/mquery/LICENSE b/node_modules/mquery/LICENSE
new file mode 100644
index 0000000..38c529d
--- /dev/null
+++ b/node_modules/mquery/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/mquery/Makefile b/node_modules/mquery/Makefile
new file mode 100644
index 0000000..587655d
--- /dev/null
+++ b/node_modules/mquery/Makefile
@@ -0,0 +1,26 @@
+
+test:
+ @NODE_ENV=test ./node_modules/.bin/mocha $(T) $(TESTS)
+
+test-cov:
+ @NODE_ENV=test node \
+ node_modules/.bin/istanbul cover \
+ ./node_modules/.bin/_mocha \
+ -- -u exports \
+
+open-cov:
+ open coverage/lcov-report/index.html
+
+lint:
+ @NODE_ENV=test node ./node_modules/eslint/bin/eslint.js .
+
+test-travis:
+ @NODE_ENV=test node \
+ node_modules/.bin/istanbul cover \
+ ./node_modules/.bin/_mocha \
+ --report lcovonly \
+ --bail
+ @NODE_ENV=test node \
+ ./node_modules/eslint/bin/eslint.js .
+
+.PHONY: test test-cov open-cov lint test-travis
diff --git a/node_modules/mquery/README.md b/node_modules/mquery/README.md
new file mode 100644
index 0000000..58d6322
--- /dev/null
+++ b/node_modules/mquery/README.md
@@ -0,0 +1,1375 @@
+# mquery
+
+`mquery` is a fluent mongodb query builder designed to run in multiple environments.
+
+[](https://travis-ci.org/aheckmann/mquery)
+[](http://badge.fury.io/js/mquery)
+
+[](https://www.npmjs.com/package/mquery)
+
+## Features
+
+ - fluent query builder api
+ - custom base query support
+ - MongoDB 2.4 geoJSON support
+ - method + option combinations validation
+ - node.js driver compatibility
+ - environment detection
+ - [debug](https://github.com/visionmedia/debug) support
+ - separated collection implementations for maximum flexibility
+
+## Use
+
+```js
+require('mongodb').connect(uri, function (err, db) {
+ if (err) return handleError(err);
+
+ // get a collection
+ var collection = db.collection('artists');
+
+ // pass it to the constructor
+ mquery(collection).find({..}, callback);
+
+ // or pass it to the collection method
+ mquery().find({..}).collection(collection).exec(callback)
+
+ // or better yet, create a custom query constructor that has it always set
+ var Artist = mquery(collection).toConstructor();
+ Artist().find(..).where(..).exec(callback)
+})
+```
+
+`mquery` requires a collection object to work with. In the example above we just pass the collection object created using the official [MongoDB driver](https://github.com/mongodb/node-mongodb-native).
+
+
+## Fluent API
+
+- [find](#find)
+- [findOne](#findOne)
+- [count](#count)
+- [remove](#remove)
+- [update](#update)
+- [findOneAndUpdate](#findoneandupdate)
+- [findOneAndDelete, findOneAndRemove](#findoneandremove)
+- [distinct](#distinct)
+- [exec](#exec)
+- [stream](#stream)
+- [all](#all)
+- [and](#and)
+- [box](#box)
+- [circle](#circle)
+- [elemMatch](#elemmatch)
+- [equals](#equals)
+- [exists](#exists)
+- [geometry](#geometry)
+- [gt](#gt)
+- [gte](#gte)
+- [in](#in)
+- [intersects](#intersects)
+- [lt](#lt)
+- [lte](#lte)
+- [maxDistance](#maxdistance)
+- [mod](#mod)
+- [ne](#ne)
+- [nin](#nin)
+- [nor](#nor)
+- [near](#near)
+- [or](#or)
+- [polygon](#polygon)
+- [regex](#regex)
+- [select](#select)
+- [selected](#selected)
+- [selectedInclusively](#selectedinclusively)
+- [selectedExclusively](#selectedexclusively)
+- [size](#size)
+- [slice](#slice)
+- [within](#within)
+- [where](#where)
+- [$where](#where-1)
+- [batchSize](#batchsize)
+- [collation](#collation)
+- [comment](#comment)
+- [hint](#hint)
+- [j](#j)
+- [limit](#limit)
+- [maxScan](#maxscan)
+- [maxTime, maxTimeMS](#maxtime)
+- [skip](#skip)
+- [sort](#sort)
+- [read, setReadPreference](#read)
+- [readConcern, r](#readconcern)
+- [slaveOk](#slaveok)
+- [snapshot](#snapshot)
+- [tailable](#tailable)
+- [writeConcern, w](#writeconcern)
+- [wtimeout, wTimeout](#wtimeout)
+
+## Helpers
+
+- [collection](#collection)
+- [then](#then)
+- [thunk](#thunk)
+- [merge](#mergeobject)
+- [setOptions](#setoptionsoptions)
+- [setTraceFunction](#settracefunctionfunc)
+- [mquery.setGlobalTraceFunction](#mquerysetglobaltracefunctionfunc)
+- [mquery.canMerge](#mquerycanmerge)
+- [mquery.use$geoWithin](#mqueryusegeowithin)
+
+### find()
+
+Declares this query a _find_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
+
+```js
+mquery().find()
+mquery().find(match)
+mquery().find(callback)
+mquery().find(match, function (err, docs) {
+ assert(Array.isArray(docs));
+})
+```
+
+### findOne()
+
+Declares this query a _findOne_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
+
+```js
+mquery().findOne()
+mquery().findOne(match)
+mquery().findOne(callback)
+mquery().findOne(match, function (err, doc) {
+ if (doc) {
+ // the document may not be found
+ console.log(doc);
+ }
+})
+```
+
+### count()
+
+Declares this query a _count_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
+
+```js
+mquery().count()
+mquery().count(match)
+mquery().count(callback)
+mquery().count(match, function (err, number){
+ console.log('we found %d matching documents', number);
+})
+```
+
+### remove()
+
+Declares this query a _remove_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
+
+```js
+mquery().remove()
+mquery().remove(match)
+mquery().remove(callback)
+mquery().remove(match, function (err){})
+```
+
+### update()
+
+Declares this query an _update_ query. Optionally pass an update document, match clause, options or callback. If a callback is passed, the query is executed. To force execution without passing a callback, run `update(true)`.
+
+```js
+mquery().update()
+mquery().update(match, updateDocument)
+mquery().update(match, updateDocument, options)
+
+// the following all execute the command
+mquery().update(callback)
+mquery().update({$set: updateDocument, callback)
+mquery().update(match, updateDocument, callback)
+mquery().update(match, updateDocument, options, function (err, result){})
+mquery().update(true) // executes (unsafe write)
+```
+
+##### the update document
+
+All paths passed that are not `$atomic` operations will become `$set` ops. For example:
+
+```js
+mquery(collection).where({ _id: id }).update({ title: 'words' }, callback)
+```
+
+becomes
+
+```js
+collection.update({ _id: id }, { $set: { title: 'words' }}, callback)
+```
+
+This behavior can be overridden using the `overwrite` option (see below).
+
+##### options
+
+Options are passed to the `setOptions()` method.
+
+- overwrite
+
+Passing an empty object `{ }` as the update document will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option, the update operation will be ignored and the callback executed without sending the command to MongoDB to prevent accidently overwritting documents in the collection.
+
+```js
+var q = mquery(collection).where({ _id: id }).setOptions({ overwrite: true });
+q.update({ }, callback); // overwrite with an empty doc
+```
+
+The `overwrite` option isn't just for empty objects, it also provides a means to override the default `$set` conversion and send the update document as is.
+
+```js
+// create a base query
+var base = mquery({ _id: 108 }).collection(collection).toConstructor();
+
+base().findOne(function (err, doc) {
+ console.log(doc); // { _id: 108, name: 'cajon' })
+
+ base().setOptions({ overwrite: true }).update({ changed: true }, function (err) {
+ base.findOne(function (err, doc) {
+ console.log(doc); // { _id: 108, changed: true }) - the doc was overwritten
+ });
+ });
+})
+```
+
+- multi
+
+Updates only modify a single document by default. To update multiple documents, set the `multi` option to `true`.
+
+```js
+mquery()
+ .collection(coll)
+ .update({ name: /^match/ }, { $addToSet: { arr: 4 }}, { multi: true }, callback)
+
+// another way of doing it
+mquery({ name: /^match/ })
+ .collection(coll)
+ .setOptions({ multi: true })
+ .update({ $addToSet: { arr: 4 }}, callback)
+
+// update multiple documents with an empty doc
+var q = mquery(collection).where({ name: /^match/ });
+q.setOptions({ multi: true, overwrite: true })
+q.update({ });
+q.update(function (err, result) {
+ console.log(arguments);
+});
+```
+
+### findOneAndUpdate()
+
+Declares this query a _findAndModify_ with update query. Optionally pass a match clause, update document, options, or callback. If a callback is passed, the query is executed.
+
+When executed, the first matching document (if found) is modified according to the update document and passed back to the callback.
+
+##### options
+
+Options are passed to the `setOptions()` method.
+
+- `new`: boolean - true to return the modified document rather than the original. defaults to true
+- `upsert`: boolean - creates the object if it doesn't exist. defaults to false
+- `sort`: if multiple docs are found by the match condition, sets the sort order to choose which doc to update
+
+```js
+query.findOneAndUpdate()
+query.findOneAndUpdate(updateDocument)
+query.findOneAndUpdate(match, updateDocument)
+query.findOneAndUpdate(match, updateDocument, options)
+
+// the following all execute the command
+query.findOneAndUpdate(callback)
+query.findOneAndUpdate(updateDocument, callback)
+query.findOneAndUpdate(match, updateDocument, callback)
+query.findOneAndUpdate(match, updateDocument, options, function (err, doc) {
+ if (doc) {
+ // the document may not be found
+ console.log(doc);
+ }
+})
+ ```
+
+### findOneAndRemove()
+
+Declares this query a _findAndModify_ with remove query. Alias of findOneAndDelete.
+Optionally pass a match clause, options, or callback. If a callback is passed, the query is executed.
+
+When executed, the first matching document (if found) is modified according to the update document, removed from the collection and passed to the callback.
+
+##### options
+
+Options are passed to the `setOptions()` method.
+
+- `sort`: if multiple docs are found by the condition, sets the sort order to choose which doc to modify and remove
+
+```js
+A.where().findOneAndDelete()
+A.where().findOneAndRemove()
+A.where().findOneAndRemove(match)
+A.where().findOneAndRemove(match, options)
+
+// the following all execute the command
+A.where().findOneAndRemove(callback)
+A.where().findOneAndRemove(match, callback)
+A.where().findOneAndRemove(match, options, function (err, doc) {
+ if (doc) {
+ // the document may not be found
+ console.log(doc);
+ }
+})
+ ```
+
+### distinct()
+
+Declares this query a _distinct_ query. Optionally pass the distinct field, a match clause or callback. If a callback is passed the query is executed.
+
+```js
+mquery().distinct()
+mquery().distinct(match)
+mquery().distinct(match, field)
+mquery().distinct(field)
+
+// the following all execute the command
+mquery().distinct(callback)
+mquery().distinct(field, callback)
+mquery().distinct(match, callback)
+mquery().distinct(match, field, function (err, result) {
+ console.log(result);
+})
+```
+
+### exec()
+
+Executes the query.
+
+```js
+mquery().findOne().where('route').intersects(polygon).exec(function (err, docs){})
+```
+
+### stream()
+
+Executes the query and returns a stream.
+
+```js
+var stream = mquery().find().stream(options);
+stream.on('data', cb);
+stream.on('close', fn);
+```
+
+Note: this only works with `find()` operations.
+
+Note: returns the stream object directly from the node-mongodb-native driver. (currently streams1 type stream). Any options will be passed along to the [driver method](http://mongodb.github.io/node-mongodb-native/api-generated/cursor.html#stream).
+
+-------------
+
+### all()
+
+Specifies an `$all` query condition
+
+```js
+mquery().where('permission').all(['read', 'write'])
+```
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/all/)
+
+### and()
+
+Specifies arguments for an `$and` condition
+
+```js
+mquery().and([{ color: 'green' }, { status: 'ok' }])
+```
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/and/)
+
+### box()
+
+Specifies a `$box` condition
+
+```js
+var lowerLeft = [40.73083, -73.99756]
+var upperRight= [40.741404, -73.988135]
+
+mquery().where('location').within().box(lowerLeft, upperRight)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/box/)
+
+### circle()
+
+Specifies a `$center` or `$centerSphere` condition.
+
+```js
+var area = { center: [50, 50], radius: 10, unique: true }
+query.where('loc').within().circle(area)
+query.circle('loc', area);
+
+// for spherical calculations
+var area = { center: [50, 50], radius: 10, unique: true, spherical: true }
+query.where('loc').within().circle(area)
+query.circle('loc', area);
+```
+
+- [MongoDB Documentation - center](http://docs.mongodb.org/manual/reference/operator/center/)
+- [MongoDB Documentation - centerSphere](http://docs.mongodb.org/manual/reference/operator/centerSphere/)
+
+### elemMatch()
+
+Specifies an `$elemMatch` condition
+
+```js
+query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})
+
+query.elemMatch('comment', function (elem) {
+ elem.where('author').equals('autobot');
+ elem.where('votes').gte(5);
+})
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/elemMatch/)
+
+### equals()
+
+Specifies the complementary comparison value for the path specified with `where()`.
+
+```js
+mquery().where('age').equals(49);
+
+// is the same as
+
+mquery().where({ 'age': 49 });
+```
+
+### exists()
+
+Specifies an `$exists` condition
+
+```js
+// { name: { $exists: true }}
+mquery().where('name').exists()
+mquery().where('name').exists(true)
+mquery().exists('name')
+
+// { name: { $exists: false }}
+mquery().where('name').exists(false);
+mquery().exists('name', false);
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/exists/)
+
+### geometry()
+
+Specifies a `$geometry` condition
+
+```js
+var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
+query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
+
+// or
+var polyB = [[ 0, 0 ], [ 1, 1 ]]
+query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
+
+// or
+var polyC = [ 0, 0 ]
+query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
+
+// or
+query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
+
+// or
+query.where('loc').near().geometry({ type: 'Point', coordinates: [3,5] })
+```
+
+`geometry()` **must** come after `intersects()`, `within()`, or `near()`.
+
+The `object` argument must contain `type` and `coordinates` properties.
+
+- type `String`
+- coordinates `Array`
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geometry/)
+
+### gt()
+
+Specifies a `$gt` query condition.
+
+```js
+mquery().where('clicks').gt(999)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gt/)
+
+### gte()
+
+Specifies a `$gte` query condition.
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gte/)
+
+```js
+mquery().where('clicks').gte(1000)
+```
+
+### in()
+
+Specifies an `$in` query condition.
+
+```js
+mquery().where('author_id').in([3, 48901, 761])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/in/)
+
+### intersects()
+
+Declares an `$geoIntersects` query for `geometry()`.
+
+```js
+query.where('path').intersects().geometry({
+ type: 'LineString'
+ , coordinates: [[180.0, 11.0], [180, 9.0]]
+})
+
+// geometry arguments are supported
+query.where('path').intersects({
+ type: 'LineString'
+ , coordinates: [[180.0, 11.0], [180, 9.0]]
+})
+```
+
+**Must** be used after `where()`.
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoIntersects/)
+
+### lt()
+
+Specifies a `$lt` query condition.
+
+```js
+mquery().where('clicks').lt(50)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lt/)
+
+### lte()
+
+Specifies a `$lte` query condition.
+
+```js
+mquery().where('clicks').lte(49)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lte/)
+
+### maxDistance()
+
+Specifies a `$maxDistance` query condition.
+
+```js
+mquery().where('location').near({ center: [139, 74.3] }).maxDistance(5)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/maxDistance/)
+
+### mod()
+
+Specifies a `$mod` condition
+
+```js
+mquery().where('count').mod(2, 0)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/mod/)
+
+### ne()
+
+Specifies a `$ne` query condition.
+
+```js
+mquery().where('status').ne('ok')
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/ne/)
+
+### nin()
+
+Specifies an `$nin` query condition.
+
+```js
+mquery().where('author_id').nin([3, 48901, 761])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nin/)
+
+### nor()
+
+Specifies arguments for an `$nor` condition.
+
+```js
+mquery().nor([{ color: 'green' }, { status: 'ok' }])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nor/)
+
+### near()
+
+Specifies arguments for a `$near` or `$nearSphere` condition.
+
+These operators return documents sorted by distance.
+
+#### Example
+
+```js
+query.where('loc').near({ center: [10, 10] });
+query.where('loc').near({ center: [10, 10], maxDistance: 5 });
+query.near('loc', { center: [10, 10], maxDistance: 5 });
+
+// GeoJSON
+query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }});
+query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }, maxDistance: 5, spherical: true });
+query.where('loc').near().geometry({ type: 'Point', coordinates: [10, 10] });
+
+// For a $nearSphere condition, pass the `spherical` option.
+query.near({ center: [10, 10], maxDistance: 5, spherical: true });
+```
+
+[MongoDB Documentation](http://www.mongodb.org/display/DOCS/Geospatial+Indexing)
+
+### or()
+
+Specifies arguments for an `$or` condition.
+
+```js
+mquery().or([{ color: 'red' }, { status: 'emergency' }])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/or/)
+
+### polygon()
+
+Specifies a `$polygon` condition
+
+```js
+mquery().where('loc').within().polygon([10,20], [13, 25], [7,15])
+mquery().polygon('loc', [10,20], [13, 25], [7,15])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/polygon/)
+
+### regex()
+
+Specifies a `$regex` query condition.
+
+```js
+mquery().where('name').regex(/^sixstepsrecords/)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/regex/)
+
+### select()
+
+Specifies which document fields to include or exclude
+
+```js
+// 1 means include, 0 means exclude
+mquery().select({ name: 1, address: 1, _id: 0 })
+
+// or
+
+mquery().select('name address -_id')
+```
+
+##### String syntax
+
+When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included.
+
+```js
+// include a and b, exclude c
+query.select('a b -c');
+
+// or you may use object notation, useful when
+// you have keys already prefixed with a "-"
+query.select({a: 1, b: 1, c: 0});
+```
+
+_Cannot be used with `distinct()`._
+
+### selected()
+
+Determines if the query has selected any fields.
+
+```js
+var query = mquery();
+query.selected() // false
+query.select('-name');
+query.selected() // true
+```
+
+### selectedInclusively()
+
+Determines if the query has selected any fields inclusively.
+
+```js
+var query = mquery().select('name');
+query.selectedInclusively() // true
+
+var query = mquery();
+query.selected() // false
+query.select('-name');
+query.selectedInclusively() // false
+query.selectedExclusively() // true
+```
+
+### selectedExclusively()
+
+Determines if the query has selected any fields exclusively.
+
+```js
+var query = mquery().select('-name');
+query.selectedExclusively() // true
+
+var query = mquery();
+query.selected() // false
+query.select('name');
+query.selectedExclusively() // false
+query.selectedInclusively() // true
+```
+
+### size()
+
+Specifies a `$size` query condition.
+
+```js
+mquery().where('someArray').size(6)
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/size/)
+
+### slice()
+
+Specifies a `$slice` projection for a `path`
+
+```js
+mquery().where('comments').slice(5)
+mquery().where('comments').slice(-5)
+mquery().where('comments').slice([-10, 5])
+```
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/projection/slice/)
+
+### within()
+
+Sets a `$geoWithin` or `$within` argument for geo-spatial queries.
+
+```js
+mquery().within().box()
+mquery().within().circle()
+mquery().within().geometry()
+
+mquery().where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
+mquery().where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
+mquery().where('loc').within({ polygon: [[],[],[],[]] });
+
+mquery().where('loc').within([], [], []) // polygon
+mquery().where('loc').within([], []) // box
+mquery().where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
+```
+
+As of mquery 2.0, `$geoWithin` is used by default. This impacts you if running MongoDB < 2.4. To alter this behavior, see [mquery.use$geoWithin](#mqueryusegeowithin).
+
+**Must** be used after `where()`.
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoWithin/)
+
+### where()
+
+Specifies a `path` for use with chaining
+
+```js
+// instead of writing:
+mquery().find({age: {$gte: 21, $lte: 65}});
+
+// we can instead write:
+mquery().where('age').gte(21).lte(65);
+
+// passing query conditions is permitted too
+mquery().find().where({ name: 'vonderful' })
+
+// chaining
+mquery()
+.where('age').gte(21).lte(65)
+.where({ 'name': /^vonderful/i })
+.where('friends').slice(10)
+.exec(callback)
+```
+
+### $where()
+
+Specifies a `$where` condition.
+
+Use `$where` when you need to select documents using a JavaScript expression.
+
+```js
+query.$where('this.comments.length > 10 || this.name.length > 5').exec(callback)
+
+query.$where(function () {
+ return this.comments.length > 10 || this.name.length > 5;
+})
+```
+
+Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.
+
+-----------
+
+### batchSize()
+
+Specifies the batchSize option.
+
+```js
+query.batchSize(100)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/)
+
+### collation()
+
+Specifies the collation option.
+
+```js
+query.collation({ locale: "en_US", strength: 1 })
+```
+
+[MongoDB documentation](https://docs.mongodb.com/manual/reference/method/cursor.collation/#cursor.collation)
+
+### comment()
+
+Specifies the comment option.
+
+```js
+query.comment('login query');
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/)
+
+### hint()
+
+Sets query hints.
+
+```js
+mquery().hint({ indexA: 1, indexB: -1 })
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/hint/)
+
+### j()
+
+Requests acknowledgement that this operation has been persisted to MongoDB's on-disk journal.
+
+This option is only valid for operations that write to the database:
+
+- `deleteOne()`
+- `deleteMany()`
+- `findOneAndDelete()`
+- `findOneAndUpdate()`
+- `remove()`
+- `update()`
+- `updateOne()`
+- `updateMany()`
+
+Defaults to the `j` value if it is specified in [writeConcern](#writeconcern)
+
+```js
+mquery().j(true);
+```
+
+### limit()
+
+Specifies the limit option.
+
+```js
+query.limit(20)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.limit/)
+
+### maxScan()
+
+Specifies the maxScan option.
+
+```js
+query.maxScan(100)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/maxScan/)
+
+### maxTime()
+
+Specifies the maxTimeMS option.
+
+```js
+query.maxTime(100)
+query.maxTimeMS(100)
+```
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.maxTimeMS/)
+
+
+### skip()
+
+Specifies the skip option.
+
+```js
+query.skip(100).limit(20)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.skip/)
+
+### sort()
+
+Sets the query sort order.
+
+If an object is passed, key values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
+
+If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
+
+```js
+// these are equivalent
+query.sort({ field: 'asc', test: -1 });
+query.sort('field -test');
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.sort/)
+
+### read()
+
+Sets the readPreference option for the query.
+
+```js
+mquery().read('primary')
+mquery().read('p') // same as primary
+
+mquery().read('primaryPreferred')
+mquery().read('pp') // same as primaryPreferred
+
+mquery().read('secondary')
+mquery().read('s') // same as secondary
+
+mquery().read('secondaryPreferred')
+mquery().read('sp') // same as secondaryPreferred
+
+mquery().read('nearest')
+mquery().read('n') // same as nearest
+
+mquery().setReadPreference('primary') // alias of .read()
+```
+
+##### Preferences:
+
+- `primary` - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
+- `secondary` - Read from secondary if available, otherwise error.
+- `primaryPreferred` - Read from primary if available, otherwise a secondary.
+- `secondaryPreferred` - Read from a secondary if available, otherwise read from the primary.
+- `nearest` - All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.
+
+Aliases
+
+- `p` primary
+- `pp` primaryPreferred
+- `s` secondary
+- `sp` secondaryPreferred
+- `n` nearest
+
+##### Preference Tags:
+
+To keep the separation of concerns between `mquery` and your driver
+clean, `mquery#read()` no longer handles specifying a second `tags` argument as of version 0.5.
+If you need to specify tags, pass any non-string argument as the first argument.
+`mquery` will pass this argument untouched to your collections methods later.
+For example:
+
+```js
+// example of specifying tags using the Node.js driver
+var ReadPref = require('mongodb').ReadPreference;
+var preference = new ReadPref('secondary', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]);
+mquery(..).read(preference).exec();
+```
+
+Read more about how to use read preferences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).
+
+
+### readConcern()
+
+Sets the readConcern option for the query.
+
+```js
+// local
+mquery().readConcern('local')
+mquery().readConcern('l')
+mquery().r('l')
+
+// available
+mquery().readConcern('available')
+mquery().readConcern('a')
+mquery().r('a')
+
+// majority
+mquery().readConcern('majority')
+mquery().readConcern('m')
+mquery().r('m')
+
+// linearizable
+mquery().readConcern('linearizable')
+mquery().readConcern('lz')
+mquery().r('lz')
+
+// snapshot
+mquery().readConcern('snapshot')
+mquery().readConcern('s')
+mquery().r('s')
+```
+
+##### Read Concern Level:
+
+- `local` - The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). (MongoDB 3.2+)
+- `available` - The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). (MongoDB 3.6+)
+- `majority` - The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure. (MongoDB 3.2+)
+- `linearizable` - The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results. (MongoDB 3.4+)
+- `snapshot` - Only available for operations within multi-document transactions. Upon transaction commit with write concern "majority", the transaction operations are guaranteed to have read from a snapshot of majority-committed data. (MongoDB 4.0+)
+
+Aliases
+
+- `l` local
+- `a` available
+- `m` majority
+- `lz` linearizable
+- `s` snapshot
+
+Read more about how to use read concern [here](https://docs.mongodb.com/manual/reference/read-concern/).
+
+### writeConcern()
+
+Sets the writeConcern option for the query.
+
+This option is only valid for operations that write to the database:
+
+- `deleteOne()`
+- `deleteMany()`
+- `findOneAndDelete()`
+- `findOneAndUpdate()`
+- `remove()`
+- `update()`
+- `updateOne()`
+- `updateMany()`
+
+```js
+mquery().writeConcern(0)
+mquery().writeConcern(1)
+mquery().writeConcern({ w: 1, j: true, wtimeout: 2000 })
+mquery().writeConcern('majority')
+mquery().writeConcern('m') // same as majority
+mquery().writeConcern('tagSetName') // if the tag set is 'm', use .writeConcern({ w: 'm' }) instead
+mquery().w(1) // w is alias of writeConcern
+```
+
+##### Write Concern:
+
+writeConcern({ w: ``, j: ``, wtimeout: `` }`)
+
+- the w option to request acknowledgement that the write operation has propagated to a specified number of mongod instances or to mongod instances with specified tags
+- the j option to request acknowledgement that the write operation has been written to the journal
+- the wtimeout option to specify a time limit to prevent write operations from blocking indefinitely
+
+Can be break down to use the following syntax:
+
+mquery().w(``).j(``).wtimeout(``)
+
+Read more about how to use write concern [here](https://docs.mongodb.com/manual/reference/write-concern/)
+
+### slaveOk()
+
+Sets the slaveOk option. `true` allows reading from secondaries.
+
+**deprecated** use [read()](#read) preferences instead if on mongodb >= 2.2
+
+```js
+query.slaveOk() // true
+query.slaveOk(true)
+query.slaveOk(false)
+```
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/rs.slaveOk/)
+
+### snapshot()
+
+Specifies this query as a snapshot query.
+
+```js
+mquery().snapshot() // true
+mquery().snapshot(true)
+mquery().snapshot(false)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/snapshot/)
+
+### tailable()
+
+Sets tailable option.
+
+```js
+mquery().tailable() <== true
+mquery().tailable(true)
+mquery().tailable(false)
+```
+
+_Cannot be used with `distinct()`._
+
+[MongoDB Documentation](http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/)
+
+### wtimeout()
+
+Specifies a time limit, in milliseconds, for the write concern. If `w > 1`, it is maximum amount of time to
+wait for this write to propagate through the replica set before this operation fails. The default is `0`, which means no timeout.
+
+This option is only valid for operations that write to the database:
+
+- `deleteOne()`
+- `deleteMany()`
+- `findOneAndDelete()`
+- `findOneAndUpdate()`
+- `remove()`
+- `update()`
+- `updateOne()`
+- `updateMany()`
+
+Defaults to `wtimeout` value if it is specified in [writeConcern](#writeconcern)
+
+```js
+mquery().wtimeout(2000)
+mquery().wTimeout(2000)
+```
+
+## Helpers
+
+### collection()
+
+Sets the querys collection.
+
+```js
+mquery().collection(aCollection)
+```
+
+### then()
+
+Executes the query and returns a promise which will be resolved with the query results or rejected if the query responds with an error.
+
+```js
+mquery().find(..).then(success, error);
+```
+
+This is very useful when combined with [co](https://github.com/visionmedia/co) or [koa](https://github.com/koajs/koa), which automatically resolve promise-like objects for you.
+
+```js
+co(function*(){
+ var doc = yield mquery().findOne({ _id: 499 });
+ console.log(doc); // { _id: 499, name: 'amazing', .. }
+})();
+```
+
+_NOTE_:
+The returned promise is a [bluebird](https://github.com/petkaantonov/bluebird/) promise but this is customizable. If you want to
+use your favorite promise library, simply set `mquery.Promise = YourPromiseConstructor`.
+Your `Promise` must be [promises A+](http://promisesaplus.com/) compliant.
+
+### thunk()
+
+Returns a thunk which when called runs the query's `exec` method passing the results to the callback.
+
+```js
+var thunk = mquery(collection).find({..}).thunk();
+
+thunk(function(err, results) {
+
+})
+```
+
+### merge(object)
+
+Merges other mquery or match condition objects into this one. When an mquery instance is passed, its match conditions, field selection and options are merged.
+
+```js
+var drum = mquery({ type: 'drum' }).collection(instruments);
+var redDrum = mquery({ color: 'red' }).merge(drum);
+redDrum.count(function (err, n) {
+ console.log('there are %d red drums', n);
+})
+```
+
+Internally uses `mquery.canMerge` to determine validity.
+
+### setOptions(options)
+
+Sets query options.
+
+```js
+mquery().setOptions({ collection: coll, limit: 20 })
+```
+
+##### options
+
+- [tailable](#tailable) *
+- [sort](#sort) *
+- [limit](#limit) *
+- [skip](#skip) *
+- [maxScan](#maxscan) *
+- [maxTime](#maxtime) *
+- [batchSize](#batchSize) *
+- [comment](#comment) *
+- [snapshot](#snapshot) *
+- [hint](#hint) *
+- [slaveOk](#slaveOk) *
+- [safe](http://docs.mongodb.org/manual/reference/write-concern/): Boolean - passed through to the collection. Setting to `true` is equivalent to `{ w: 1 }`
+- [collection](#collection): the collection to query against
+
+_* denotes a query helper method is also available_
+
+### setTraceFunction(func)
+
+Set a function to trace this query. Useful for profiling or logging.
+
+```js
+function traceFunction (method, queryInfo, query) {
+ console.log('starting ' + method + ' query');
+
+ return function (err, result, millis) {
+ console.log('finished ' + method + ' query in ' + millis + 'ms');
+ };
+}
+
+mquery().setTraceFunction(traceFunction).findOne({name: 'Joe'}, cb);
+```
+
+The trace function is passed (method, queryInfo, query)
+
+- method is the name of the method being called (e.g. findOne)
+- queryInfo contains information about the query:
+ - conditions: query conditions/criteria
+ - options: options such as sort, fields, etc
+ - doc: document being updated
+- query is the query object
+
+The trace function should return a callback function which accepts:
+- err: error, if any
+- result: result, if any
+- millis: time spent waiting for query result
+
+NOTE: stream requests are not traced.
+
+### mquery.setGlobalTraceFunction(func)
+
+Similar to `setTraceFunction()` but automatically applied to all queries.
+
+```js
+mquery.setTraceFunction(traceFunction);
+```
+
+### mquery.canMerge(conditions)
+
+Determines if `conditions` can be merged using `mquery().merge()`.
+
+```js
+var query = mquery({ type: 'drum' });
+var okToMerge = mquery.canMerge(anObject)
+if (okToMerge) {
+ query.merge(anObject);
+}
+```
+
+## mquery.use$geoWithin
+
+MongoDB 2.4 introduced the `$geoWithin` operator which replaces and is 100% backward compatible with `$within`. As of mquery 0.2, we default to using `$geoWithin` for all `within()` calls.
+
+If you are running MongoDB < 2.4 this will be problematic. To force `mquery` to be backward compatible and always use `$within`, set the `mquery.use$geoWithin` flag to `false`.
+
+```js
+mquery.use$geoWithin = false;
+```
+
+## Custom Base Queries
+
+Often times we want custom base queries that encapsulate predefined criteria. With `mquery` this is easy. First create the query you want to reuse and call its `toConstructor()` method which returns a new subclass of `mquery` that retains all options and criteria of the original.
+
+```js
+var greatMovies = mquery(movieCollection).where('rating').gte(4.5).toConstructor();
+
+// use it!
+greatMovies().count(function (err, n) {
+ console.log('There are %d great movies', n);
+});
+
+greatMovies().where({ name: /^Life/ }).select('name').find(function (err, docs) {
+ console.log(docs);
+});
+```
+
+## Validation
+
+Method and options combinations are checked for validity at runtime to prevent creation of invalid query constructs. For example, a `distinct` query does not support specifying options like `hint` or field selection. In this case an error will be thrown so you can catch these mistakes in development.
+
+## Debug support
+
+Debug mode is provided through the use of the [debug](https://github.com/visionmedia/debug) module. To enable:
+
+ DEBUG=mquery node yourprogram.js
+
+Read the debug module documentation for more details.
+
+## General compatibility
+
+#### ObjectIds
+
+`mquery` clones query arguments before passing them to a `collection` method for execution.
+This prevents accidental side-affects to the objects you pass.
+To clone `ObjectIds` we need to make some assumptions.
+
+First, to check if an object is an `ObjectId`, we check its constructors name. If it matches either
+`ObjectId` or `ObjectID` we clone it.
+
+To clone `ObjectIds`, we call its optional `clone` method. If a `clone` method does not exist, we fall
+back to calling `new obj.constructor(obj.id)`. We assume, for compatibility with the
+Node.js driver, that the `ObjectId` instance has a public `id` property and that
+when creating an `ObjectId` instance we can pass that `id` as an argument.
+
+#### Read Preferences
+
+`mquery` supports specifying [Read Preferences]() to control from which MongoDB node your query will read.
+The Read Preferences spec also support specifying tags. To pass tags, some
+drivers (Node.js driver) require passing a special constructor that handles both the read preference and its tags.
+If you need to specify tags, pass an instance of your drivers ReadPreference constructor or roll your own. `mquery` will store whatever you provide and pass later to your collection during execution.
+
+## Future goals
+
+ - mongo shell compatibility
+ - browser compatibility
+
+## Installation
+
+ $ npm install mquery
+
+## License
+
+[MIT](https://github.com/aheckmann/mquery/blob/master/LICENSE)
+
diff --git a/node_modules/mquery/lib/collection/collection.js b/node_modules/mquery/lib/collection/collection.js
new file mode 100644
index 0000000..0f39c76
--- /dev/null
+++ b/node_modules/mquery/lib/collection/collection.js
@@ -0,0 +1,46 @@
+'use strict';
+
+/**
+ * methods a collection must implement
+ */
+
+var methods = [
+ 'find',
+ 'findOne',
+ 'update',
+ 'updateMany',
+ 'updateOne',
+ 'replaceOne',
+ 'remove',
+ 'count',
+ 'distinct',
+ 'findAndModify',
+ 'aggregate',
+ 'findStream',
+ 'deleteOne',
+ 'deleteMany'
+];
+
+/**
+ * Collection base class from which implementations inherit
+ */
+
+function Collection() {}
+
+for (var i = 0, len = methods.length; i < len; ++i) {
+ var method = methods[i];
+ Collection.prototype[method] = notImplemented(method);
+}
+
+module.exports = exports = Collection;
+Collection.methods = methods;
+
+/**
+ * creates a function which throws an implementation error
+ */
+
+function notImplemented(method) {
+ return function() {
+ throw new Error('collection.' + method + ' not implemented');
+ };
+}
diff --git a/node_modules/mquery/lib/collection/index.js b/node_modules/mquery/lib/collection/index.js
new file mode 100644
index 0000000..1992e20
--- /dev/null
+++ b/node_modules/mquery/lib/collection/index.js
@@ -0,0 +1,13 @@
+'use strict';
+
+var env = require('../env');
+
+if ('unknown' == env.type) {
+ throw new Error('Unknown environment');
+}
+
+module.exports =
+ env.isNode ? require('./node') :
+ env.isMongo ? require('./collection') :
+ require('./collection');
+
diff --git a/node_modules/mquery/lib/collection/node.js b/node_modules/mquery/lib/collection/node.js
new file mode 100644
index 0000000..cc07d60
--- /dev/null
+++ b/node_modules/mquery/lib/collection/node.js
@@ -0,0 +1,151 @@
+'use strict';
+
+/**
+ * Module dependencies
+ */
+
+var Collection = require('./collection');
+var utils = require('../utils');
+
+function NodeCollection(col) {
+ this.collection = col;
+ this.collectionName = col.collectionName;
+}
+
+/**
+ * inherit from collection base class
+ */
+
+utils.inherits(NodeCollection, Collection);
+
+/**
+ * find(match, options, function(err, docs))
+ */
+
+NodeCollection.prototype.find = function(match, options, cb) {
+ this.collection.find(match, options, function(err, cursor) {
+ if (err) return cb(err);
+
+ try {
+ cursor.toArray(cb);
+ } catch (error) {
+ cb(error);
+ }
+ });
+};
+
+/**
+ * findOne(match, options, function(err, doc))
+ */
+
+NodeCollection.prototype.findOne = function(match, options, cb) {
+ this.collection.findOne(match, options, cb);
+};
+
+/**
+ * count(match, options, function(err, count))
+ */
+
+NodeCollection.prototype.count = function(match, options, cb) {
+ this.collection.count(match, options, cb);
+};
+
+/**
+ * distinct(prop, match, options, function(err, count))
+ */
+
+NodeCollection.prototype.distinct = function(prop, match, options, cb) {
+ this.collection.distinct(prop, match, options, cb);
+};
+
+/**
+ * update(match, update, options, function(err[, result]))
+ */
+
+NodeCollection.prototype.update = function(match, update, options, cb) {
+ this.collection.update(match, update, options, cb);
+};
+
+/**
+ * update(match, update, options, function(err[, result]))
+ */
+
+NodeCollection.prototype.updateMany = function(match, update, options, cb) {
+ this.collection.updateMany(match, update, options, cb);
+};
+
+/**
+ * update(match, update, options, function(err[, result]))
+ */
+
+NodeCollection.prototype.updateOne = function(match, update, options, cb) {
+ this.collection.updateOne(match, update, options, cb);
+};
+
+/**
+ * replaceOne(match, update, options, function(err[, result]))
+ */
+
+NodeCollection.prototype.replaceOne = function(match, update, options, cb) {
+ this.collection.replaceOne(match, update, options, cb);
+};
+
+/**
+ * deleteOne(match, options, function(err[, result])
+ */
+
+NodeCollection.prototype.deleteOne = function(match, options, cb) {
+ this.collection.deleteOne(match, options, cb);
+};
+
+/**
+ * deleteMany(match, options, function(err[, result])
+ */
+
+NodeCollection.prototype.deleteMany = function(match, options, cb) {
+ this.collection.deleteMany(match, options, cb);
+};
+
+/**
+ * remove(match, options, function(err[, result])
+ */
+
+NodeCollection.prototype.remove = function(match, options, cb) {
+ this.collection.remove(match, options, cb);
+};
+
+/**
+ * findAndModify(match, update, options, function(err, doc))
+ */
+
+NodeCollection.prototype.findAndModify = function(match, update, options, cb) {
+ var sort = Array.isArray(options.sort) ? options.sort : [];
+ this.collection.findAndModify(match, sort, update, options, cb);
+};
+
+/**
+ * var stream = findStream(match, findOptions, streamOptions)
+ */
+
+NodeCollection.prototype.findStream = function(match, findOptions, streamOptions) {
+ return this.collection.find(match, findOptions).stream(streamOptions);
+};
+
+/**
+ * var cursor = findCursor(match, findOptions)
+ */
+
+NodeCollection.prototype.findCursor = function(match, findOptions) {
+ return this.collection.find(match, findOptions);
+};
+
+/**
+ * aggregation(operators..., function(err, doc))
+ * TODO
+ */
+
+/**
+ * Expose
+ */
+
+module.exports = exports = NodeCollection;
diff --git a/node_modules/mquery/lib/env.js b/node_modules/mquery/lib/env.js
new file mode 100644
index 0000000..d3d225b
--- /dev/null
+++ b/node_modules/mquery/lib/env.js
@@ -0,0 +1,22 @@
+'use strict';
+
+exports.isNode = 'undefined' != typeof process
+ && 'object' == typeof module
+ && 'object' == typeof global
+ && 'function' == typeof Buffer
+ && process.argv;
+
+exports.isMongo = !exports.isNode
+ && 'function' == typeof printjson
+ && 'function' == typeof ObjectId
+ && 'function' == typeof rs
+ && 'function' == typeof sh;
+
+exports.isBrowser = !exports.isNode
+ && !exports.isMongo
+ && 'undefined' != typeof window;
+
+exports.type = exports.isNode ? 'node'
+ : exports.isMongo ? 'mongo'
+ : exports.isBrowser ? 'browser'
+ : 'unknown';
diff --git a/node_modules/mquery/lib/mquery.js b/node_modules/mquery/lib/mquery.js
new file mode 100644
index 0000000..8fdd9e1
--- /dev/null
+++ b/node_modules/mquery/lib/mquery.js
@@ -0,0 +1,3252 @@
+'use strict';
+
+/**
+ * Dependencies
+ */
+
+var slice = require('sliced');
+var assert = require('assert');
+var util = require('util');
+var utils = require('./utils');
+var debug = require('debug')('mquery');
+
+/* global Map */
+
+/**
+ * Query constructor used for building queries.
+ *
+ * ####Example:
+ *
+ * var query = new Query({ name: 'mquery' });
+ * query.setOptions({ collection: moduleCollection })
+ * query.where('age').gte(21).exec(callback);
+ *
+ * @param {Object} [criteria]
+ * @param {Object} [options]
+ * @api public
+ */
+
+function Query(criteria, options) {
+ if (!(this instanceof Query))
+ return new Query(criteria, options);
+
+ var proto = this.constructor.prototype;
+
+ this.op = proto.op || undefined;
+
+ this.options = Object.assign({}, proto.options);
+
+ this._conditions = proto._conditions
+ ? utils.clone(proto._conditions)
+ : {};
+
+ this._fields = proto._fields
+ ? utils.clone(proto._fields)
+ : undefined;
+
+ this._update = proto._update
+ ? utils.clone(proto._update)
+ : undefined;
+
+ this._path = proto._path || undefined;
+ this._distinct = proto._distinct || undefined;
+ this._collection = proto._collection || undefined;
+ this._traceFunction = proto._traceFunction || undefined;
+
+ if (options) {
+ this.setOptions(options);
+ }
+
+ if (criteria) {
+ if (criteria.find && criteria.remove && criteria.update) {
+ // quack quack!
+ this.collection(criteria);
+ } else {
+ this.find(criteria);
+ }
+ }
+}
+
+/**
+ * This is a parameter that the user can set which determines if mquery
+ * uses $within or $geoWithin for queries. It defaults to true which
+ * means $geoWithin will be used. If using MongoDB < 2.4 you should
+ * set this to false.
+ *
+ * @api public
+ * @property use$geoWithin
+ */
+
+var $withinCmd = '$geoWithin';
+Object.defineProperty(Query, 'use$geoWithin', {
+ get: function( ) { return $withinCmd == '$geoWithin'; },
+ set: function(v) {
+ if (true === v) {
+ // mongodb >= 2.4
+ $withinCmd = '$geoWithin';
+ } else {
+ $withinCmd = '$within';
+ }
+ }
+});
+
+/**
+ * Converts this query to a constructor function with all arguments and options retained.
+ *
+ * ####Example
+ *
+ * // Create a query that will read documents with a "video" category from
+ * // `aCollection` on the primary node in the replica-set unless it is down,
+ * // in which case we'll read from a secondary node.
+ * var query = mquery({ category: 'video' })
+ * query.setOptions({ collection: aCollection, read: 'primaryPreferred' });
+ *
+ * // create a constructor based off these settings
+ * var Video = query.toConstructor();
+ *
+ * // Video is now a subclass of mquery() and works the same way but with the
+ * // default query parameters and options set.
+ *
+ * // run a query with the previous settings but filter for movies with names
+ * // that start with "Life".
+ * Video().where({ name: /^Life/ }).exec(cb);
+ *
+ * @return {Query} new Query
+ * @api public
+ */
+
+Query.prototype.toConstructor = function toConstructor() {
+ function CustomQuery(criteria, options) {
+ if (!(this instanceof CustomQuery))
+ return new CustomQuery(criteria, options);
+ Query.call(this, criteria, options);
+ }
+
+ utils.inherits(CustomQuery, Query);
+
+ // set inherited defaults
+ var p = CustomQuery.prototype;
+
+ p.options = {};
+ p.setOptions(this.options);
+
+ p.op = this.op;
+ p._conditions = utils.clone(this._conditions);
+ p._fields = utils.clone(this._fields);
+ p._update = utils.clone(this._update);
+ p._path = this._path;
+ p._distinct = this._distinct;
+ p._collection = this._collection;
+ p._traceFunction = this._traceFunction;
+
+ return CustomQuery;
+};
+
+/**
+ * Sets query options.
+ *
+ * ####Options:
+ *
+ * - [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors) *
+ * - [sort](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsort(\)%7D%7D) *
+ * - [limit](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D) *
+ * - [skip](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D) *
+ * - [maxScan](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan) *
+ * - [maxTime](http://docs.mongodb.org/manual/reference/operator/meta/maxTimeMS/#op._S_maxTimeMS) *
+ * - [batchSize](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D) *
+ * - [comment](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment) *
+ * - [snapshot](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D) *
+ * - [hint](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint) *
+ * - [slaveOk](http://docs.mongodb.org/manual/applications/replication/#read-preference) *
+ * - [safe](http://www.mongodb.org/display/DOCS/getLastError+Command)
+ * - collection the collection to query against
+ *
+ * _* denotes a query helper method is also available_
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+Query.prototype.setOptions = function(options) {
+ if (!(options && utils.isObject(options)))
+ return this;
+
+ // set arbitrary options
+ var methods = utils.keys(options),
+ method;
+
+ for (var i = 0; i < methods.length; ++i) {
+ method = methods[i];
+
+ // use methods if exist (safer option manipulation)
+ if ('function' == typeof this[method]) {
+ var args = utils.isArray(options[method])
+ ? options[method]
+ : [options[method]];
+ this[method].apply(this, args);
+ } else {
+ this.options[method] = options[method];
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Sets this Querys collection.
+ *
+ * @param {Collection} coll
+ * @return {Query} this
+ */
+
+Query.prototype.collection = function collection(coll) {
+ this._collection = new Query.Collection(coll);
+
+ return this;
+};
+
+/**
+ * Adds a collation to this op (MongoDB 3.4 and up)
+ *
+ * ####Example
+ *
+ * query.find().collation({ locale: "en_US", strength: 1 })
+ *
+ * @param {Object} value
+ * @return {Query} this
+ * @see MongoDB docs https://docs.mongodb.com/manual/reference/method/cursor.collation/#cursor.collation
+ * @api public
+ */
+
+Query.prototype.collation = function(value) {
+ this.options.collation = value;
+ return this;
+};
+
+/**
+ * Specifies a `$where` condition
+ *
+ * Use `$where` when you need to select documents using a JavaScript expression.
+ *
+ * ####Example
+ *
+ * query.$where('this.comments.length > 10 || this.name.length > 5')
+ *
+ * query.$where(function () {
+ * return this.comments.length > 10 || this.name.length > 5;
+ * })
+ *
+ * @param {String|Function} js javascript string or function
+ * @return {Query} this
+ * @memberOf Query
+ * @method $where
+ * @api public
+ */
+
+Query.prototype.$where = function(js) {
+ this._conditions.$where = js;
+ return this;
+};
+
+/**
+ * Specifies a `path` for use with chaining.
+ *
+ * ####Example
+ *
+ * // instead of writing:
+ * User.find({age: {$gte: 21, $lte: 65}}, callback);
+ *
+ * // we can instead write:
+ * User.where('age').gte(21).lte(65);
+ *
+ * // passing query conditions is permitted
+ * User.find().where({ name: 'vonderful' })
+ *
+ * // chaining
+ * User
+ * .where('age').gte(21).lte(65)
+ * .where('name', /^vonderful/i)
+ * .where('friends').slice(10)
+ * .exec(callback)
+ *
+ * @param {String} [path]
+ * @param {Object} [val]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.where = function() {
+ if (!arguments.length) return this;
+ if (!this.op) this.op = 'find';
+
+ var type = typeof arguments[0];
+
+ if ('string' == type) {
+ this._path = arguments[0];
+
+ if (2 === arguments.length) {
+ this._conditions[this._path] = arguments[1];
+ }
+
+ return this;
+ }
+
+ if ('object' == type && !Array.isArray(arguments[0])) {
+ return this.merge(arguments[0]);
+ }
+
+ throw new TypeError('path must be a string or object');
+};
+
+/**
+ * Specifies the complementary comparison value for paths specified with `where()`
+ *
+ * ####Example
+ *
+ * User.where('age').equals(49);
+ *
+ * // is the same as
+ *
+ * User.where('age', 49);
+ *
+ * @param {Object} val
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.equals = function equals(val) {
+ this._ensurePath('equals');
+ var path = this._path;
+ this._conditions[path] = val;
+ return this;
+};
+
+/**
+ * Specifies the complementary comparison value for paths specified with `where()`
+ * This is alias of `equals`
+ *
+ * ####Example
+ *
+ * User.where('age').eq(49);
+ *
+ * // is the same as
+ *
+ * User.shere('age').equals(49);
+ *
+ * // is the same as
+ *
+ * User.where('age', 49);
+ *
+ * @param {Object} val
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.eq = function eq(val) {
+ this._ensurePath('eq');
+ var path = this._path;
+ this._conditions[path] = val;
+ return this;
+};
+
+/**
+ * Specifies arguments for an `$or` condition.
+ *
+ * ####Example
+ *
+ * query.or([{ color: 'red' }, { status: 'emergency' }])
+ *
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.or = function or(array) {
+ var or = this._conditions.$or || (this._conditions.$or = []);
+ if (!utils.isArray(array)) array = [array];
+ or.push.apply(or, array);
+ return this;
+};
+
+/**
+ * Specifies arguments for a `$nor` condition.
+ *
+ * ####Example
+ *
+ * query.nor([{ color: 'green' }, { status: 'ok' }])
+ *
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.nor = function nor(array) {
+ var nor = this._conditions.$nor || (this._conditions.$nor = []);
+ if (!utils.isArray(array)) array = [array];
+ nor.push.apply(nor, array);
+ return this;
+};
+
+/**
+ * Specifies arguments for a `$and` condition.
+ *
+ * ####Example
+ *
+ * query.and([{ color: 'green' }, { status: 'ok' }])
+ *
+ * @see $and http://docs.mongodb.org/manual/reference/operator/and/
+ * @param {Array} array array of conditions
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.and = function and(array) {
+ var and = this._conditions.$and || (this._conditions.$and = []);
+ if (!Array.isArray(array)) array = [array];
+ and.push.apply(and, array);
+ return this;
+};
+
+/**
+ * Specifies a $gt query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * ####Example
+ *
+ * Thing.find().where('age').gt(21)
+ *
+ * // or
+ * Thing.find().gt('age', 21)
+ *
+ * @method gt
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $gte query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method gte
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $lt query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method lt
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $lte query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method lte
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $ne query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method ne
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an $in query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method in
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an $nin query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method nin
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies an $all query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method all
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $size query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method size
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/**
+ * Specifies a $regex query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method regex
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {String|RegExp} val
+ * @api public
+ */
+
+/**
+ * Specifies a $maxDistance query condition.
+ *
+ * When called with one argument, the most recent path passed to `where()` is used.
+ *
+ * @method maxDistance
+ * @memberOf Query
+ * @param {String} [path]
+ * @param {Number} val
+ * @api public
+ */
+
+/*!
+ * gt, gte, lt, lte, ne, in, nin, all, regex, size, maxDistance
+ *
+ * Thing.where('type').nin(array)
+ */
+
+'gt gte lt lte ne in nin all regex size maxDistance minDistance'.split(' ').forEach(function($conditional) {
+ Query.prototype[$conditional] = function() {
+ var path, val;
+
+ if (1 === arguments.length) {
+ this._ensurePath($conditional);
+ val = arguments[0];
+ path = this._path;
+ } else {
+ val = arguments[1];
+ path = arguments[0];
+ }
+
+ var conds = this._conditions[path] === null || typeof this._conditions[path] === 'object' ?
+ this._conditions[path] :
+ (this._conditions[path] = {});
+ conds['$' + $conditional] = val;
+ return this;
+ };
+});
+
+/**
+ * Specifies a `$mod` condition
+ *
+ * @param {String} [path]
+ * @param {Number} val
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.mod = function() {
+ var val, path;
+
+ if (1 === arguments.length) {
+ this._ensurePath('mod');
+ val = arguments[0];
+ path = this._path;
+ } else if (2 === arguments.length && !utils.isArray(arguments[1])) {
+ this._ensurePath('mod');
+ val = slice(arguments);
+ path = this._path;
+ } else if (3 === arguments.length) {
+ val = slice(arguments, 1);
+ path = arguments[0];
+ } else {
+ val = arguments[1];
+ path = arguments[0];
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds.$mod = val;
+ return this;
+};
+
+/**
+ * Specifies an `$exists` condition
+ *
+ * ####Example
+ *
+ * // { name: { $exists: true }}
+ * Thing.where('name').exists()
+ * Thing.where('name').exists(true)
+ * Thing.find().exists('name')
+ *
+ * // { name: { $exists: false }}
+ * Thing.where('name').exists(false);
+ * Thing.find().exists('name', false);
+ *
+ * @param {String} [path]
+ * @param {Number} val
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.exists = function() {
+ var path, val;
+
+ if (0 === arguments.length) {
+ this._ensurePath('exists');
+ path = this._path;
+ val = true;
+ } else if (1 === arguments.length) {
+ if ('boolean' === typeof arguments[0]) {
+ this._ensurePath('exists');
+ path = this._path;
+ val = arguments[0];
+ } else {
+ path = arguments[0];
+ val = true;
+ }
+ } else if (2 === arguments.length) {
+ path = arguments[0];
+ val = arguments[1];
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds.$exists = val;
+ return this;
+};
+
+/**
+ * Specifies an `$elemMatch` condition
+ *
+ * ####Example
+ *
+ * query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}})
+ *
+ * query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})
+ *
+ * query.elemMatch('comment', function (elem) {
+ * elem.where('author').equals('autobot');
+ * elem.where('votes').gte(5);
+ * })
+ *
+ * query.where('comment').elemMatch(function (elem) {
+ * elem.where({ author: 'autobot' });
+ * elem.where('votes').gte(5);
+ * })
+ *
+ * @param {String|Object|Function} path
+ * @param {Object|Function} criteria
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.elemMatch = function() {
+ if (null == arguments[0])
+ throw new TypeError('Invalid argument');
+
+ var fn, path, criteria;
+
+ if ('function' === typeof arguments[0]) {
+ this._ensurePath('elemMatch');
+ path = this._path;
+ fn = arguments[0];
+ } else if (utils.isObject(arguments[0])) {
+ this._ensurePath('elemMatch');
+ path = this._path;
+ criteria = arguments[0];
+ } else if ('function' === typeof arguments[1]) {
+ path = arguments[0];
+ fn = arguments[1];
+ } else if (arguments[1] && utils.isObject(arguments[1])) {
+ path = arguments[0];
+ criteria = arguments[1];
+ } else {
+ throw new TypeError('Invalid argument');
+ }
+
+ if (fn) {
+ criteria = new Query;
+ fn(criteria);
+ criteria = criteria._conditions;
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds.$elemMatch = criteria;
+ return this;
+};
+
+// Spatial queries
+
+/**
+ * Sugar for geo-spatial queries.
+ *
+ * ####Example
+ *
+ * query.within().box()
+ * query.within().circle()
+ * query.within().geometry()
+ *
+ * query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
+ * query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
+ * query.where('loc').within({ polygon: [[],[],[],[]] });
+ *
+ * query.where('loc').within([], [], []) // polygon
+ * query.where('loc').within([], []) // box
+ * query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
+ *
+ * ####NOTE:
+ *
+ * Must be used after `where()`.
+ *
+ * @memberOf Query
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.within = function within() {
+ // opinionated, must be used after where
+ this._ensurePath('within');
+ this._geoComparison = $withinCmd;
+
+ if (0 === arguments.length) {
+ return this;
+ }
+
+ if (2 === arguments.length) {
+ return this.box.apply(this, arguments);
+ } else if (2 < arguments.length) {
+ return this.polygon.apply(this, arguments);
+ }
+
+ var area = arguments[0];
+
+ if (!area)
+ throw new TypeError('Invalid argument');
+
+ if (area.center)
+ return this.circle(area);
+
+ if (area.box)
+ return this.box.apply(this, area.box);
+
+ if (area.polygon)
+ return this.polygon.apply(this, area.polygon);
+
+ if (area.type && area.coordinates)
+ return this.geometry(area);
+
+ throw new TypeError('Invalid argument');
+};
+
+/**
+ * Specifies a $box condition
+ *
+ * ####Example
+ *
+ * var lowerLeft = [40.73083, -73.99756]
+ * var upperRight= [40.741404, -73.988135]
+ *
+ * query.where('loc').within().box(lowerLeft, upperRight)
+ * query.box('loc', lowerLeft, upperRight )
+ *
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @see Query#within #query_Query-within
+ * @param {String} path
+ * @param {Object} val
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.box = function() {
+ var path, box;
+
+ if (3 === arguments.length) {
+ // box('loc', [], [])
+ path = arguments[0];
+ box = [arguments[1], arguments[2]];
+ } else if (2 === arguments.length) {
+ // box([], [])
+ this._ensurePath('box');
+ path = this._path;
+ box = [arguments[0], arguments[1]];
+ } else {
+ throw new TypeError('Invalid argument');
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds[this._geoComparison || $withinCmd] = { '$box': box };
+ return this;
+};
+
+/**
+ * Specifies a $polygon condition
+ *
+ * ####Example
+ *
+ * query.where('loc').within().polygon([10,20], [13, 25], [7,15])
+ * query.polygon('loc', [10,20], [13, 25], [7,15])
+ *
+ * @param {String|Array} [path]
+ * @param {Array|Object} [val]
+ * @return {Query} this
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+Query.prototype.polygon = function() {
+ var val, path;
+
+ if ('string' == typeof arguments[0]) {
+ // polygon('loc', [],[],[])
+ path = arguments[0];
+ val = slice(arguments, 1);
+ } else {
+ // polygon([],[],[])
+ this._ensurePath('polygon');
+ path = this._path;
+ val = slice(arguments);
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds[this._geoComparison || $withinCmd] = { '$polygon': val };
+ return this;
+};
+
+/**
+ * Specifies a $center or $centerSphere condition.
+ *
+ * ####Example
+ *
+ * var area = { center: [50, 50], radius: 10, unique: true }
+ * query.where('loc').within().circle(area)
+ * query.center('loc', area);
+ *
+ * // for spherical calculations
+ * var area = { center: [50, 50], radius: 10, unique: true, spherical: true }
+ * query.where('loc').within().circle(area)
+ * query.center('loc', area);
+ *
+ * @param {String} [path]
+ * @param {Object} area
+ * @return {Query} this
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+Query.prototype.circle = function() {
+ var path, val;
+
+ if (1 === arguments.length) {
+ this._ensurePath('circle');
+ path = this._path;
+ val = arguments[0];
+ } else if (2 === arguments.length) {
+ path = arguments[0];
+ val = arguments[1];
+ } else {
+ throw new TypeError('Invalid argument');
+ }
+
+ if (!('radius' in val && val.center))
+ throw new Error('center and radius are required');
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+
+ var type = val.spherical
+ ? '$centerSphere'
+ : '$center';
+
+ var wKey = this._geoComparison || $withinCmd;
+ conds[wKey] = {};
+ conds[wKey][type] = [val.center, val.radius];
+
+ if ('unique' in val)
+ conds[wKey].$uniqueDocs = !!val.unique;
+
+ return this;
+};
+
+/**
+ * Specifies a `$near` or `$nearSphere` condition
+ *
+ * These operators return documents sorted by distance.
+ *
+ * ####Example
+ *
+ * query.where('loc').near({ center: [10, 10] });
+ * query.where('loc').near({ center: [10, 10], maxDistance: 5 });
+ * query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true });
+ * query.near('loc', { center: [10, 10], maxDistance: 5 });
+ * query.near({ center: { type: 'Point', coordinates: [..] }})
+ * query.near().geometry({ type: 'Point', coordinates: [..] })
+ *
+ * @param {String} [path]
+ * @param {Object} val
+ * @return {Query} this
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @api public
+ */
+
+Query.prototype.near = function near() {
+ var path, val;
+
+ this._geoComparison = '$near';
+
+ if (0 === arguments.length) {
+ return this;
+ } else if (1 === arguments.length) {
+ this._ensurePath('near');
+ path = this._path;
+ val = arguments[0];
+ } else if (2 === arguments.length) {
+ path = arguments[0];
+ val = arguments[1];
+ } else {
+ throw new TypeError('Invalid argument');
+ }
+
+ if (!val.center) {
+ throw new Error('center is required');
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+
+ var type = val.spherical
+ ? '$nearSphere'
+ : '$near';
+
+ // center could be a GeoJSON object or an Array
+ if (Array.isArray(val.center)) {
+ conds[type] = val.center;
+
+ var radius = 'maxDistance' in val
+ ? val.maxDistance
+ : null;
+
+ if (null != radius) {
+ conds.$maxDistance = radius;
+ }
+ if (null != val.minDistance) {
+ conds.$minDistance = val.minDistance;
+ }
+ } else {
+ // GeoJSON?
+ if (val.center.type != 'Point' || !Array.isArray(val.center.coordinates)) {
+ throw new Error(util.format('Invalid GeoJSON specified for %s', type));
+ }
+ conds[type] = { $geometry : val.center };
+
+ // MongoDB 2.6 insists on maxDistance being in $near / $nearSphere
+ if ('maxDistance' in val) {
+ conds[type]['$maxDistance'] = val.maxDistance;
+ }
+ if ('minDistance' in val) {
+ conds[type]['$minDistance'] = val.minDistance;
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Declares an intersects query for `geometry()`.
+ *
+ * ####Example
+ *
+ * query.where('path').intersects().geometry({
+ * type: 'LineString'
+ * , coordinates: [[180.0, 11.0], [180, 9.0]]
+ * })
+ *
+ * query.where('path').intersects({
+ * type: 'LineString'
+ * , coordinates: [[180.0, 11.0], [180, 9.0]]
+ * })
+ *
+ * @param {Object} [arg]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.intersects = function intersects() {
+ // opinionated, must be used after where
+ this._ensurePath('intersects');
+
+ this._geoComparison = '$geoIntersects';
+
+ if (0 === arguments.length) {
+ return this;
+ }
+
+ var area = arguments[0];
+
+ if (null != area && area.type && area.coordinates)
+ return this.geometry(area);
+
+ throw new TypeError('Invalid argument');
+};
+
+/**
+ * Specifies a `$geometry` condition
+ *
+ * ####Example
+ *
+ * var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
+ * query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
+ *
+ * // or
+ * var polyB = [[ 0, 0 ], [ 1, 1 ]]
+ * query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
+ *
+ * // or
+ * var polyC = [ 0, 0 ]
+ * query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
+ *
+ * // or
+ * query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
+ *
+ * ####NOTE:
+ *
+ * `geometry()` **must** come after either `intersects()` or `within()`.
+ *
+ * The `object` argument must contain `type` and `coordinates` properties.
+ * - type {String}
+ * - coordinates {Array}
+ *
+ * The most recent path passed to `where()` is used.
+ *
+ * @param {Object} object Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples.
+ * @return {Query} this
+ * @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry
+ * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
+ * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/
+ * @api public
+ */
+
+Query.prototype.geometry = function geometry() {
+ if (!('$within' == this._geoComparison ||
+ '$geoWithin' == this._geoComparison ||
+ '$near' == this._geoComparison ||
+ '$geoIntersects' == this._geoComparison)) {
+ throw new Error('geometry() must come after `within()`, `intersects()`, or `near()');
+ }
+
+ var val, path;
+
+ if (1 === arguments.length) {
+ this._ensurePath('geometry');
+ path = this._path;
+ val = arguments[0];
+ } else {
+ throw new TypeError('Invalid argument');
+ }
+
+ if (!(val.type && Array.isArray(val.coordinates))) {
+ throw new TypeError('Invalid argument');
+ }
+
+ var conds = this._conditions[path] || (this._conditions[path] = {});
+ conds[this._geoComparison] = { $geometry: val };
+
+ return this;
+};
+
+// end spatial
+
+/**
+ * Specifies which document fields to include or exclude
+ *
+ * ####String syntax
+ *
+ * When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included.
+ *
+ * ####Example
+ *
+ * // include a and b, exclude c
+ * query.select('a b -c');
+ *
+ * // or you may use object notation, useful when
+ * // you have keys already prefixed with a "-"
+ * query.select({a: 1, b: 1, c: 0});
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @param {Object|String} arg
+ * @return {Query} this
+ * @see SchemaType
+ * @api public
+ */
+
+Query.prototype.select = function select() {
+ var arg = arguments[0];
+ if (!arg) return this;
+
+ if (arguments.length !== 1) {
+ throw new Error('Invalid select: select only takes 1 argument');
+ }
+
+ this._validate('select');
+
+ var fields = this._fields || (this._fields = {});
+ var type = typeof arg;
+ var i, len;
+
+ if (('string' == type || utils.isArgumentsObject(arg)) &&
+ 'number' == typeof arg.length || Array.isArray(arg)) {
+ if ('string' == type)
+ arg = arg.split(/\s+/);
+
+ for (i = 0, len = arg.length; i < len; ++i) {
+ var field = arg[i];
+ if (!field) continue;
+ var include = '-' == field[0] ? 0 : 1;
+ if (include === 0) field = field.substring(1);
+ fields[field] = include;
+ }
+
+ return this;
+ }
+
+ if (utils.isObject(arg)) {
+ var keys = utils.keys(arg);
+ for (i = 0; i < keys.length; ++i) {
+ fields[keys[i]] = arg[keys[i]];
+ }
+ return this;
+ }
+
+ throw new TypeError('Invalid select() argument. Must be string or object.');
+};
+
+/**
+ * Specifies a $slice condition for a `path`
+ *
+ * ####Example
+ *
+ * query.slice('comments', 5)
+ * query.slice('comments', -5)
+ * query.slice('comments', [10, 5])
+ * query.where('comments').slice(5)
+ * query.where('comments').slice([-10, 5])
+ *
+ * @param {String} [path]
+ * @param {Number} val number/range of elements to slice
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements
+ * @api public
+ */
+
+Query.prototype.slice = function() {
+ if (0 === arguments.length)
+ return this;
+
+ this._validate('slice');
+
+ var path, val;
+
+ if (1 === arguments.length) {
+ var arg = arguments[0];
+ if (typeof arg === 'object' && !Array.isArray(arg)) {
+ var keys = Object.keys(arg);
+ var numKeys = keys.length;
+ for (var i = 0; i < numKeys; ++i) {
+ this.slice(keys[i], arg[keys[i]]);
+ }
+ return this;
+ }
+ this._ensurePath('slice');
+ path = this._path;
+ val = arguments[0];
+ } else if (2 === arguments.length) {
+ if ('number' === typeof arguments[0]) {
+ this._ensurePath('slice');
+ path = this._path;
+ val = slice(arguments);
+ } else {
+ path = arguments[0];
+ val = arguments[1];
+ }
+ } else if (3 === arguments.length) {
+ path = arguments[0];
+ val = slice(arguments, 1);
+ }
+
+ var myFields = this._fields || (this._fields = {});
+ myFields[path] = { '$slice': val };
+ return this;
+};
+
+/**
+ * Sets the sort order
+ *
+ * If an object is passed, values allowed are 'asc', 'desc', 'ascending', 'descending', 1, and -1.
+ *
+ * If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
+ *
+ * ####Example
+ *
+ * // these are equivalent
+ * query.sort({ field: 'asc', test: -1 });
+ * query.sort('field -test');
+ * query.sort([['field', 1], ['test', -1]]);
+ *
+ * ####Note
+ *
+ * - The array syntax `.sort([['field', 1], ['test', -1]])` can only be used with [mongodb driver >= 2.0.46](https://github.com/mongodb/node-mongodb-native/blob/2.1/HISTORY.md#2046-2015-10-15).
+ * - Cannot be used with `distinct()`
+ *
+ * @param {Object|String|Array} arg
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.sort = function(arg) {
+ if (!arg) return this;
+ var i, len, field;
+
+ this._validate('sort');
+
+ var type = typeof arg;
+
+ // .sort([['field', 1], ['test', -1]])
+ if (Array.isArray(arg)) {
+ len = arg.length;
+ for (i = 0; i < arg.length; ++i) {
+ if (!Array.isArray(arg[i])) {
+ throw new Error('Invalid sort() argument, must be array of arrays');
+ }
+ _pushArr(this.options, arg[i][0], arg[i][1]);
+ }
+ return this;
+ }
+
+ // .sort('field -test')
+ if (1 === arguments.length && 'string' == type) {
+ arg = arg.split(/\s+/);
+ len = arg.length;
+ for (i = 0; i < len; ++i) {
+ field = arg[i];
+ if (!field) continue;
+ var ascend = '-' == field[0] ? -1 : 1;
+ if (ascend === -1) field = field.substring(1);
+ push(this.options, field, ascend);
+ }
+
+ return this;
+ }
+
+ // .sort({ field: 1, test: -1 })
+ if (utils.isObject(arg)) {
+ var keys = utils.keys(arg);
+ for (i = 0; i < keys.length; ++i) {
+ field = keys[i];
+ push(this.options, field, arg[field]);
+ }
+
+ return this;
+ }
+
+ if (typeof Map !== 'undefined' && arg instanceof Map) {
+ _pushMap(this.options, arg);
+ return this;
+ }
+ throw new TypeError('Invalid sort() argument. Must be a string, object, or array.');
+};
+
+/*!
+ * @ignore
+ */
+
+var _validSortValue = {
+ '1': 1,
+ '-1': -1,
+ 'asc': 1,
+ 'ascending': 1,
+ 'desc': -1,
+ 'descending': -1
+};
+
+function push(opts, field, value) {
+ if (Array.isArray(opts.sort)) {
+ throw new TypeError('Can\'t mix sort syntaxes. Use either array or object:' +
+ '\n- `.sort([[\'field\', 1], [\'test\', -1]])`' +
+ '\n- `.sort({ field: 1, test: -1 })`');
+ }
+
+ var s;
+ if (value && value.$meta) {
+ s = opts.sort || (opts.sort = {});
+ s[field] = { $meta : value.$meta };
+ return;
+ }
+
+ s = opts.sort || (opts.sort = {});
+ var val = String(value || 1).toLowerCase();
+ val = _validSortValue[val];
+ if (!val) throw new TypeError('Invalid sort value: { ' + field + ': ' + value + ' }');
+
+ s[field] = val;
+}
+
+function _pushArr(opts, field, value) {
+ opts.sort = opts.sort || [];
+ if (!Array.isArray(opts.sort)) {
+ throw new TypeError('Can\'t mix sort syntaxes. Use either array or object:' +
+ '\n- `.sort([[\'field\', 1], [\'test\', -1]])`' +
+ '\n- `.sort({ field: 1, test: -1 })`');
+ }
+
+ var val = String(value || 1).toLowerCase();
+ val = _validSortValue[val];
+ if (!val) throw new TypeError('Invalid sort value: [ ' + field + ', ' + value + ' ]');
+
+ opts.sort.push([field, val]);
+}
+
+function _pushMap(opts, map) {
+ opts.sort = opts.sort || new Map();
+ if (!(opts.sort instanceof Map)) {
+ throw new TypeError('Can\'t mix sort syntaxes. Use either array or ' +
+ 'object or map consistently');
+ }
+ map.forEach(function(value, key) {
+ var val = String(value || 1).toLowerCase();
+ val = _validSortValue[val];
+ if (!val) throw new TypeError('Invalid sort value: < ' + key + ': ' + value + ' >');
+
+ opts.sort.set(key, val);
+ });
+}
+
+
+
+/**
+ * Specifies the limit option.
+ *
+ * ####Example
+ *
+ * query.limit(20)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method limit
+ * @memberOf Query
+ * @param {Number} val
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D
+ * @api public
+ */
+/**
+ * Specifies the skip option.
+ *
+ * ####Example
+ *
+ * query.skip(100).limit(20)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method skip
+ * @memberOf Query
+ * @param {Number} val
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D
+ * @api public
+ */
+/**
+ * Specifies the maxScan option.
+ *
+ * ####Example
+ *
+ * query.maxScan(100)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method maxScan
+ * @memberOf Query
+ * @param {Number} val
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan
+ * @api public
+ */
+/**
+ * Specifies the batchSize option.
+ *
+ * ####Example
+ *
+ * query.batchSize(100)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method batchSize
+ * @memberOf Query
+ * @param {Number} val
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D
+ * @api public
+ */
+/**
+ * Specifies the `comment` option.
+ *
+ * ####Example
+ *
+ * query.comment('login query')
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @method comment
+ * @memberOf Query
+ * @param {Number} val
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment
+ * @api public
+ */
+
+/*!
+ * limit, skip, maxScan, batchSize, comment
+ *
+ * Sets these associated options.
+ *
+ * query.comment('feed query');
+ */
+
+['limit', 'skip', 'maxScan', 'batchSize', 'comment'].forEach(function(method) {
+ Query.prototype[method] = function(v) {
+ this._validate(method);
+ this.options[method] = v;
+ return this;
+ };
+});
+
+/**
+ * Specifies the maxTimeMS option.
+ *
+ * ####Example
+ *
+ * query.maxTime(100)
+ * query.maxTimeMS(100)
+ *
+ * @method maxTime
+ * @memberOf Query
+ * @param {Number} ms
+ * @see mongodb http://docs.mongodb.org/manual/reference/operator/meta/maxTimeMS/#op._S_maxTimeMS
+ * @api public
+ */
+
+Query.prototype.maxTime = Query.prototype.maxTimeMS = function(ms) {
+ this._validate('maxTime');
+ this.options.maxTimeMS = ms;
+ return this;
+};
+
+/**
+ * Specifies this query as a `snapshot` query.
+ *
+ * ####Example
+ *
+ * mquery().snapshot() // true
+ * mquery().snapshot(true)
+ * mquery().snapshot(false)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.snapshot = function() {
+ this._validate('snapshot');
+
+ this.options.snapshot = arguments.length
+ ? !!arguments[0]
+ : true;
+
+ return this;
+};
+
+/**
+ * Sets query hints.
+ *
+ * ####Example
+ *
+ * query.hint({ indexA: 1, indexB: -1});
+ * query.hint('indexA_1_indexB_1');
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @param {Object|string} val a hint object or the index name
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint
+ * @api public
+ */
+
+Query.prototype.hint = function() {
+ if (0 === arguments.length) return this;
+
+ this._validate('hint');
+
+ var arg = arguments[0];
+ if (utils.isObject(arg)) {
+ var hint = this.options.hint || (this.options.hint = {});
+
+ // must keep object keys in order so don't use Object.keys()
+ for (var k in arg) {
+ hint[k] = arg[k];
+ }
+
+ return this;
+ }
+ if (typeof arg === 'string') {
+ this.options.hint = arg;
+ return this;
+ }
+
+ throw new TypeError('Invalid hint. ' + arg);
+};
+
+/**
+ * Requests acknowledgement that this operation has been persisted to MongoDB's
+ * on-disk journal.
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to the `j` value if it is specified in writeConcern options
+ *
+ * ####Example:
+ *
+ * mquery().w(2).j(true).wtimeout(2000);
+ *
+ * @method j
+ * @memberOf Query
+ * @instance
+ * @param {boolean} val
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#j-option
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.j = function j(val) {
+ this.options.j = val;
+ return this;
+};
+
+/**
+ * Sets the slaveOk option. _Deprecated_ in MongoDB 2.2 in favor of read preferences.
+ *
+ * ####Example:
+ *
+ * query.slaveOk() // true
+ * query.slaveOk(true)
+ * query.slaveOk(false)
+ *
+ * @deprecated use read() preferences instead if on mongodb >= 2.2
+ * @param {Boolean} v defaults to true
+ * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
+ * @see read()
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.slaveOk = function(v) {
+ this.options.slaveOk = arguments.length ? !!v : true;
+ return this;
+};
+
+/**
+ * Sets the readPreference option for the query.
+ *
+ * ####Example:
+ *
+ * new Query().read('primary')
+ * new Query().read('p') // same as primary
+ *
+ * new Query().read('primaryPreferred')
+ * new Query().read('pp') // same as primaryPreferred
+ *
+ * new Query().read('secondary')
+ * new Query().read('s') // same as secondary
+ *
+ * new Query().read('secondaryPreferred')
+ * new Query().read('sp') // same as secondaryPreferred
+ *
+ * new Query().read('nearest')
+ * new Query().read('n') // same as nearest
+ *
+ * // you can also use mongodb.ReadPreference class to also specify tags
+ * new Query().read(mongodb.ReadPreference('secondary', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]))
+ *
+ * new Query().setReadPreference('primary') // alias of .read()
+ *
+ * ####Preferences:
+ *
+ * primary - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
+ * secondary Read from secondary if available, otherwise error.
+ * primaryPreferred Read from primary if available, otherwise a secondary.
+ * secondaryPreferred Read from a secondary if available, otherwise read from the primary.
+ * nearest All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.
+ *
+ * Aliases
+ *
+ * p primary
+ * pp primaryPreferred
+ * s secondary
+ * sp secondaryPreferred
+ * n nearest
+ *
+ * Read more about how to use read preferences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).
+ *
+ * @param {String|ReadPreference} pref one of the listed preference options or their aliases
+ * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
+ * @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.read = Query.prototype.setReadPreference = function(pref) {
+ if (arguments.length > 1 && !Query.prototype.read.deprecationWarningIssued) {
+ console.error('Deprecation warning: \'tags\' argument is not supported anymore in Query.read() method. Please use mongodb.ReadPreference object instead.');
+ Query.prototype.read.deprecationWarningIssued = true;
+ }
+ this.options.readPreference = utils.readPref(pref);
+ return this;
+};
+
+/**
+ * Sets the readConcern option for the query.
+ *
+ * ####Example:
+ *
+ * new Query().readConcern('local')
+ * new Query().readConcern('l') // same as local
+ *
+ * new Query().readConcern('available')
+ * new Query().readConcern('a') // same as available
+ *
+ * new Query().readConcern('majority')
+ * new Query().readConcern('m') // same as majority
+ *
+ * new Query().readConcern('linearizable')
+ * new Query().readConcern('lz') // same as linearizable
+ *
+ * new Query().readConcern('snapshot')
+ * new Query().readConcern('s') // same as snapshot
+ *
+ * new Query().r('s') // r is alias of readConcern
+ *
+ *
+ * ####Read Concern Level:
+ *
+ * local MongoDB 3.2+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
+ * available MongoDB 3.6+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back).
+ * majority MongoDB 3.2+ The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure.
+ * linearizable MongoDB 3.4+ The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results.
+ * snapshot MongoDB 4.0+ Only available for operations within multi-document transactions. Upon transaction commit with write concern "majority", the transaction operations are guaranteed to have read from a snapshot of majority-committed data.
+
+
+ *
+ *
+ * Aliases
+ *
+ * l local
+ * a available
+ * m majority
+ * lz linearizable
+ * s snapshot
+ *
+ * Read more about how to use read concern [here](https://docs.mongodb.com/manual/reference/read-concern/).
+ *
+ * @param {String} level one of the listed read concern level or their aliases
+ * @see mongodb https://docs.mongodb.com/manual/reference/read-concern/
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.readConcern = Query.prototype.r = function(level) {
+ this.options.readConcern = utils.readConcern(level);
+ return this;
+};
+
+/**
+ * Sets tailable option.
+ *
+ * ####Example
+ *
+ * query.tailable() <== true
+ * query.tailable(true)
+ * query.tailable(false)
+ *
+ * ####Note
+ *
+ * Cannot be used with `distinct()`
+ *
+ * @param {Boolean} v defaults to true
+ * @see mongodb http://www.mongodb.org/display/DOCS/Tailable+Cursors
+ * @api public
+ */
+
+Query.prototype.tailable = function() {
+ this._validate('tailable');
+
+ this.options.tailable = arguments.length
+ ? !!arguments[0]
+ : true;
+
+ return this;
+};
+
+/**
+ * Sets the specified number of `mongod` servers, or tag set of `mongod` servers,
+ * that must acknowledge this write before this write is considered successful.
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to the `w` value if it is specified in writeConcern options
+ *
+ * ####Example:
+ *
+ * mquery().writeConcern(0)
+ * mquery().writeConcern(1)
+ * mquery().writeConcern({ w: 1, j: true, wtimeout: 2000 })
+ * mquery().writeConcern('majority')
+ * mquery().writeConcern('m') // same as majority
+ * mquery().writeConcern('tagSetName') // if the tag set is 'm', use .writeConcern({ w: 'm' }) instead
+ * mquery().w(1) // w is alias of writeConcern
+ *
+ * @method writeConcern
+ * @memberOf Query
+ * @instance
+ * @param {String|number|object} concern 0 for fire-and-forget, 1 for acknowledged by one server, 'majority' for majority of the replica set, or [any of the more advanced options](https://docs.mongodb.com/manual/reference/write-concern/#w-option).
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#w-option
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.writeConcern = Query.prototype.w = function writeConcern(concern) {
+ if ('object' === typeof concern) {
+ if ('undefined' !== typeof concern.j) this.options.j = concern.j;
+ if ('undefined' !== typeof concern.w) this.options.w = concern.w;
+ if ('undefined' !== typeof concern.wtimeout) this.options.wtimeout = concern.wtimeout;
+ } else {
+ this.options.w = 'm' === concern ? 'majority' : concern;
+ }
+ return this;
+};
+
+/**
+ * Specifies a time limit, in milliseconds, for the write concern.
+ * If `ms > 1`, it is maximum amount of time to wait for this write
+ * to propagate through the replica set before this operation fails.
+ * The default is `0`, which means no timeout.
+ *
+ * This option is only valid for operations that write to the database:
+ *
+ * - `deleteOne()`
+ * - `deleteMany()`
+ * - `findOneAndDelete()`
+ * - `findOneAndUpdate()`
+ * - `remove()`
+ * - `update()`
+ * - `updateOne()`
+ * - `updateMany()`
+ *
+ * Defaults to `wtimeout` value if it is specified in writeConcern
+ *
+ * ####Example:
+ *
+ * mquery().w(2).j(true).wtimeout(2000)
+ *
+ * @method wtimeout
+ * @memberOf Query
+ * @instance
+ * @param {number} ms number of milliseconds to wait
+ * @see mongodb https://docs.mongodb.com/manual/reference/write-concern/#wtimeout
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.wtimeout = Query.prototype.wTimeout = function wtimeout(ms) {
+ this.options.wtimeout = ms;
+ return this;
+};
+
+/**
+ * Merges another Query or conditions object into this one.
+ *
+ * When a Query is passed, conditions, field selection and options are merged.
+ *
+ * @param {Query|Object} source
+ * @return {Query} this
+ */
+
+Query.prototype.merge = function(source) {
+ if (!source)
+ return this;
+
+ if (!Query.canMerge(source))
+ throw new TypeError('Invalid argument. Expected instanceof mquery or plain object');
+
+ if (source instanceof Query) {
+ // if source has a feature, apply it to ourselves
+
+ if (source._conditions) {
+ utils.merge(this._conditions, source._conditions);
+ }
+
+ if (source._fields) {
+ this._fields || (this._fields = {});
+ utils.merge(this._fields, source._fields);
+ }
+
+ if (source.options) {
+ this.options || (this.options = {});
+ utils.merge(this.options, source.options);
+ }
+
+ if (source._update) {
+ this._update || (this._update = {});
+ utils.mergeClone(this._update, source._update);
+ }
+
+ if (source._distinct) {
+ this._distinct = source._distinct;
+ }
+
+ return this;
+ }
+
+ // plain object
+ utils.merge(this._conditions, source);
+
+ return this;
+};
+
+/**
+ * Finds documents.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * ####Example
+ *
+ * query.find()
+ * query.find(callback)
+ * query.find({ name: 'Burning Lights' }, callback)
+ *
+ * @param {Object} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.find = function(criteria, callback) {
+ this.op = 'find';
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ if (!callback) return this;
+
+ var conds = this._conditions;
+ var options = this._optionsForExec();
+
+ if (this.$useProjection) {
+ options.projection = this._fieldsForExec();
+ } else {
+ options.fields = this._fieldsForExec();
+ }
+
+ debug('find', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('find', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.find(conds, options, utils.tick(callback));
+ return this;
+};
+
+/**
+ * Returns the query cursor
+ *
+ * ####Examples
+ *
+ * query.find().cursor();
+ * query.cursor({ name: 'Burning Lights' });
+ *
+ * @param {Object} [criteria] mongodb selector
+ * @return {Object} cursor
+ * @api public
+ */
+
+Query.prototype.cursor = function cursor(criteria) {
+ if (this.op) {
+ if (this.op !== 'find') {
+ throw new TypeError('.cursor only support .find method');
+ }
+ } else {
+ this.find(criteria);
+ }
+
+ var conds = this._conditions;
+ var options = this._optionsForExec();
+
+ if (this.$useProjection) {
+ options.projection = this._fieldsForExec();
+ } else {
+ options.fields = this._fieldsForExec();
+ }
+
+ debug('findCursor', this._collection.collectionName, conds, options);
+ return this._collection.findCursor(conds, options);
+};
+
+/**
+ * Executes the query as a findOne() operation.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * ####Example
+ *
+ * query.findOne().where('name', /^Burning/);
+ *
+ * query.findOne({ name: /^Burning/ })
+ *
+ * query.findOne({ name: /^Burning/ }, callback); // executes
+ *
+ * query.findOne(function (err, doc) {
+ * if (err) return handleError(err);
+ * if (doc) {
+ * // doc may be null if no document matched
+ *
+ * }
+ * });
+ *
+ * @param {Object|Query} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.findOne = function(criteria, callback) {
+ this.op = 'findOne';
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ if (!callback) return this;
+
+ var conds = this._conditions;
+ var options = this._optionsForExec();
+
+ if (this.$useProjection) {
+ options.projection = this._fieldsForExec();
+ } else {
+ options.fields = this._fieldsForExec();
+ }
+
+ debug('findOne', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('findOne', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.findOne(conds, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Exectues the query as a count() operation.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * ####Example
+ *
+ * query.count().where('color', 'black').exec(callback);
+ *
+ * query.count({ color: 'black' }).count(callback)
+ *
+ * query.count({ color: 'black' }, callback)
+ *
+ * query.where('color', 'black').count(function (err, count) {
+ * if (err) return handleError(err);
+ * console.log('there are %d kittens', count);
+ * })
+ *
+ * @param {Object} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Count
+ * @api public
+ */
+
+Query.prototype.count = function(criteria, callback) {
+ this.op = 'count';
+ this._validate();
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ if (!callback) return this;
+
+ var conds = this._conditions,
+ options = this._optionsForExec();
+
+ debug('count', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('count', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.count(conds, options, utils.tick(callback));
+ return this;
+};
+
+/**
+ * Declares or executes a distinct() operation.
+ *
+ * Passing a `callback` executes the query.
+ *
+ * ####Example
+ *
+ * distinct(criteria, field, fn)
+ * distinct(criteria, field)
+ * distinct(field, fn)
+ * distinct(field)
+ * distinct(fn)
+ * distinct()
+ *
+ * @param {Object|Query} [criteria]
+ * @param {String} [field]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Distinct
+ * @api public
+ */
+
+Query.prototype.distinct = function(criteria, field, callback) {
+ this.op = 'distinct';
+ this._validate();
+
+ if (!callback) {
+ switch (typeof field) {
+ case 'function':
+ callback = field;
+ if ('string' == typeof criteria) {
+ field = criteria;
+ criteria = undefined;
+ }
+ break;
+ case 'undefined':
+ case 'string':
+ break;
+ default:
+ throw new TypeError('Invalid `field` argument. Must be string or function');
+ }
+
+ switch (typeof criteria) {
+ case 'function':
+ callback = criteria;
+ criteria = field = undefined;
+ break;
+ case 'string':
+ field = criteria;
+ criteria = undefined;
+ break;
+ }
+ }
+
+ if ('string' == typeof field) {
+ this._distinct = field;
+ }
+
+ if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ if (!callback) {
+ return this;
+ }
+
+ if (!this._distinct) {
+ throw new Error('No value for `distinct` has been declared');
+ }
+
+ var conds = this._conditions,
+ options = this._optionsForExec();
+
+ debug('distinct', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('distinct', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.distinct(this._distinct, conds, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Declare and/or execute this query as an update() operation. By default,
+ * `update()` only modifies the _first_ document that matches `criteria`.
+ *
+ * _All paths passed that are not $atomic operations will become $set ops._
+ *
+ * ####Example
+ *
+ * mquery({ _id: id }).update({ title: 'words' }, ...)
+ *
+ * becomes
+ *
+ * collection.update({ _id: id }, { $set: { title: 'words' }}, ...)
+ *
+ * ####Note
+ *
+ * Passing an empty object `{}` as the doc will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option set, the update operation will be ignored and the callback executed without sending the command to MongoDB so as to prevent accidently overwritting documents in the collection.
+ *
+ * ####Note
+ *
+ * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call update() and then execute it by using the `exec()` method.
+ *
+ * var q = mquery(collection).where({ _id: id });
+ * q.update({ $set: { name: 'bob' }}).update(); // not executed
+ *
+ * var q = mquery(collection).where({ _id: id });
+ * q.update({ $set: { name: 'bob' }}).exec(); // executed as unsafe
+ *
+ * // keys that are not $atomic ops become $set.
+ * // this executes the same command as the previous example.
+ * q.update({ name: 'bob' }).where({ _id: id }).exec();
+ *
+ * var q = mquery(collection).update(); // not executed
+ *
+ * // overwriting with empty docs
+ * var q.where({ _id: id }).setOptions({ overwrite: true })
+ * q.update({ }, callback); // executes
+ *
+ * // multi update with overwrite to empty doc
+ * var q = mquery(collection).where({ _id: id });
+ * q.setOptions({ multi: true, overwrite: true })
+ * q.update({ });
+ * q.update(callback); // executed
+ *
+ * // multi updates
+ * mquery()
+ * .collection(coll)
+ * .update({ name: /^match/ }, { $set: { arr: [] }}, { multi: true }, callback)
+ * // more multi updates
+ * mquery({ })
+ * .collection(coll)
+ * .setOptions({ multi: true })
+ * .update({ $set: { arr: [] }}, callback)
+ *
+ * // single update by default
+ * mquery({ email: 'address@example.com' })
+ * .collection(coll)
+ * .update({ $inc: { counter: 1 }}, callback)
+ *
+ * // summary
+ * update(criteria, doc, opts, cb) // executes
+ * update(criteria, doc, opts)
+ * update(criteria, doc, cb) // executes
+ * update(criteria, doc)
+ * update(doc, cb) // executes
+ * update(doc)
+ * update(cb) // executes
+ * update(true) // executes (unsafe write)
+ * update()
+ *
+ * @param {Object} [criteria]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.update = function update(criteria, doc, options, callback) {
+ var force;
+
+ switch (arguments.length) {
+ case 3:
+ if ('function' == typeof options) {
+ callback = options;
+ options = undefined;
+ }
+ break;
+ case 2:
+ if ('function' == typeof doc) {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ break;
+ case 1:
+ switch (typeof criteria) {
+ case 'function':
+ callback = criteria;
+ criteria = options = doc = undefined;
+ break;
+ case 'boolean':
+ // execution with no callback (unsafe write)
+ force = criteria;
+ criteria = undefined;
+ break;
+ default:
+ doc = criteria;
+ criteria = options = undefined;
+ break;
+ }
+ }
+
+ return _update(this, 'update', criteria, doc, options, force, callback);
+};
+
+/**
+ * Declare and/or execute this query as an `updateMany()` operation. Identical
+ * to `update()` except `updateMany()` will update _all_ documents that match
+ * `criteria`, rather than just the first one.
+ *
+ * _All paths passed that are not $atomic operations will become $set ops._
+ *
+ * ####Example
+ *
+ * // Update every document whose `title` contains 'test'
+ * mquery().updateMany({ title: /test/ }, { year: 2017 })
+ *
+ * @param {Object} [criteria]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.updateMany = function updateMany(criteria, doc, options, callback) {
+ var force;
+
+ switch (arguments.length) {
+ case 3:
+ if ('function' == typeof options) {
+ callback = options;
+ options = undefined;
+ }
+ break;
+ case 2:
+ if ('function' == typeof doc) {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ break;
+ case 1:
+ switch (typeof criteria) {
+ case 'function':
+ callback = criteria;
+ criteria = options = doc = undefined;
+ break;
+ case 'boolean':
+ // execution with no callback (unsafe write)
+ force = criteria;
+ criteria = undefined;
+ break;
+ default:
+ doc = criteria;
+ criteria = options = undefined;
+ break;
+ }
+ }
+
+ return _update(this, 'updateMany', criteria, doc, options, force, callback);
+};
+
+/**
+ * Declare and/or execute this query as an `updateOne()` operation. Identical
+ * to `update()` except `updateOne()` will _always_ update just one document,
+ * regardless of the `multi` option.
+ *
+ * _All paths passed that are not $atomic operations will become $set ops._
+ *
+ * ####Example
+ *
+ * // Update the first document whose `title` contains 'test'
+ * mquery().updateMany({ title: /test/ }, { year: 2017 })
+ *
+ * @param {Object} [criteria]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.updateOne = function updateOne(criteria, doc, options, callback) {
+ var force;
+
+ switch (arguments.length) {
+ case 3:
+ if ('function' == typeof options) {
+ callback = options;
+ options = undefined;
+ }
+ break;
+ case 2:
+ if ('function' == typeof doc) {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ break;
+ case 1:
+ switch (typeof criteria) {
+ case 'function':
+ callback = criteria;
+ criteria = options = doc = undefined;
+ break;
+ case 'boolean':
+ // execution with no callback (unsafe write)
+ force = criteria;
+ criteria = undefined;
+ break;
+ default:
+ doc = criteria;
+ criteria = options = undefined;
+ break;
+ }
+ }
+
+ return _update(this, 'updateOne', criteria, doc, options, force, callback);
+};
+
+/**
+ * Declare and/or execute this query as an `replaceOne()` operation. Similar
+ * to `updateOne()`, except `replaceOne()` is not allowed to use atomic
+ * modifiers (`$set`, `$push`, etc.). Calling `replaceOne()` will always
+ * replace the existing doc.
+ *
+ * ####Example
+ *
+ * // Replace the document with `_id` 1 with `{ _id: 1, year: 2017 }`
+ * mquery().replaceOne({ _id: 1 }, { year: 2017 })
+ *
+ * @param {Object} [criteria]
+ * @param {Object} [doc] the update command
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.replaceOne = function replaceOne(criteria, doc, options, callback) {
+ var force;
+
+ switch (arguments.length) {
+ case 3:
+ if ('function' == typeof options) {
+ callback = options;
+ options = undefined;
+ }
+ break;
+ case 2:
+ if ('function' == typeof doc) {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ break;
+ case 1:
+ switch (typeof criteria) {
+ case 'function':
+ callback = criteria;
+ criteria = options = doc = undefined;
+ break;
+ case 'boolean':
+ // execution with no callback (unsafe write)
+ force = criteria;
+ criteria = undefined;
+ break;
+ default:
+ doc = criteria;
+ criteria = options = undefined;
+ break;
+ }
+ }
+
+ this.setOptions({ overwrite: true });
+ return _update(this, 'replaceOne', criteria, doc, options, force, callback);
+};
+
+
+/*!
+ * Internal helper for update, updateMany, updateOne
+ */
+
+function _update(query, op, criteria, doc, options, force, callback) {
+ query.op = op;
+
+ if (Query.canMerge(criteria)) {
+ query.merge(criteria);
+ }
+
+ if (doc) {
+ query._mergeUpdate(doc);
+ }
+
+ if (utils.isObject(options)) {
+ // { overwrite: true }
+ query.setOptions(options);
+ }
+
+ // we are done if we don't have callback and they are
+ // not forcing an unsafe write.
+ if (!(force || callback)) {
+ return query;
+ }
+
+ if (!query._update ||
+ !query.options.overwrite && 0 === utils.keys(query._update).length) {
+ callback && utils.soon(callback.bind(null, null, 0));
+ return query;
+ }
+
+ options = query._optionsForExec();
+ if (!callback) options.safe = false;
+
+ criteria = query._conditions;
+ doc = query._updateForExec();
+
+ debug('update', query._collection.collectionName, criteria, doc, options);
+ callback = query._wrapCallback(op, callback, {
+ conditions: criteria,
+ doc: doc,
+ options: options
+ });
+
+ query._collection[op](criteria, doc, options, utils.tick(callback));
+
+ return query;
+}
+
+/**
+ * Declare and/or execute this query as a remove() operation.
+ *
+ * ####Example
+ *
+ * mquery(collection).remove({ artist: 'Anne Murray' }, callback)
+ *
+ * ####Note
+ *
+ * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call remove() and then execute it by using the `exec()` method.
+ *
+ * // not executed
+ * var query = mquery(collection).remove({ name: 'Anne Murray' })
+ *
+ * // executed
+ * mquery(collection).remove({ name: 'Anne Murray' }, callback)
+ * mquery(collection).remove({ name: 'Anne Murray' }).remove(callback)
+ *
+ * // executed without a callback (unsafe write)
+ * query.exec()
+ *
+ * // summary
+ * query.remove(conds, fn); // executes
+ * query.remove(conds)
+ * query.remove(fn) // executes
+ * query.remove()
+ *
+ * @param {Object|Query} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.remove = function(criteria, callback) {
+ this.op = 'remove';
+ var force;
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ } else if (true === criteria) {
+ force = criteria;
+ criteria = undefined;
+ }
+
+ if (!(force || callback))
+ return this;
+
+ var options = this._optionsForExec();
+ if (!callback) options.safe = false;
+
+ var conds = this._conditions;
+
+ debug('remove', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('remove', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.remove(conds, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Declare and/or execute this query as a `deleteOne()` operation. Behaves like
+ * `remove()`, except for ignores the `justOne` option and always deletes at
+ * most one document.
+ *
+ * ####Example
+ *
+ * mquery(collection).deleteOne({ artist: 'Anne Murray' }, callback)
+ *
+ * @param {Object|Query} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.deleteOne = function(criteria, callback) {
+ this.op = 'deleteOne';
+ var force;
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ } else if (true === criteria) {
+ force = criteria;
+ criteria = undefined;
+ }
+
+ if (!(force || callback))
+ return this;
+
+ var options = this._optionsForExec();
+ if (!callback) options.safe = false;
+ delete options.justOne;
+
+ var conds = this._conditions;
+
+ debug('deleteOne', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('deleteOne', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.deleteOne(conds, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Declare and/or execute this query as a `deleteMany()` operation. Behaves like
+ * `remove()`, except for ignores the `justOne` option and always deletes
+ * _every_ document that matches `criteria`.
+ *
+ * ####Example
+ *
+ * mquery(collection).deleteMany({ artist: 'Anne Murray' }, callback)
+ *
+ * @param {Object|Query} [criteria] mongodb selector
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.deleteMany = function(criteria, callback) {
+ this.op = 'deleteMany';
+ var force;
+
+ if ('function' === typeof criteria) {
+ callback = criteria;
+ criteria = undefined;
+ } else if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ } else if (true === criteria) {
+ force = criteria;
+ criteria = undefined;
+ }
+
+ if (!(force || callback))
+ return this;
+
+ var options = this._optionsForExec();
+ if (!callback) options.safe = false;
+ delete options.justOne;
+
+ var conds = this._conditions;
+
+ debug('deleteOne', this._collection.collectionName, conds, options);
+ callback = this._wrapCallback('deleteOne', callback, {
+ conditions: conds,
+ options: options
+ });
+
+ this._collection.deleteMany(conds, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) update command.
+ *
+ * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed.
+ *
+ * ####Available options
+ *
+ * - `new`: bool - true to return the modified document rather than the original. defaults to true
+ * - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ *
+ * ####Examples
+ *
+ * query.findOneAndUpdate(conditions, update, options, callback) // executes
+ * query.findOneAndUpdate(conditions, update, options) // returns Query
+ * query.findOneAndUpdate(conditions, update, callback) // executes
+ * query.findOneAndUpdate(conditions, update) // returns Query
+ * query.findOneAndUpdate(update, callback) // returns Query
+ * query.findOneAndUpdate(update) // returns Query
+ * query.findOneAndUpdate(callback) // executes
+ * query.findOneAndUpdate() // returns Query
+ *
+ * @param {Object|Query} [query]
+ * @param {Object} [doc]
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @return {Query} this
+ * @api public
+ */
+
+Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
+ this.op = 'findOneAndUpdate';
+ this._validate();
+
+ switch (arguments.length) {
+ case 3:
+ if ('function' == typeof options) {
+ callback = options;
+ options = {};
+ }
+ break;
+ case 2:
+ if ('function' == typeof doc) {
+ callback = doc;
+ doc = criteria;
+ criteria = undefined;
+ }
+ options = undefined;
+ break;
+ case 1:
+ if ('function' == typeof criteria) {
+ callback = criteria;
+ criteria = options = doc = undefined;
+ } else {
+ doc = criteria;
+ criteria = options = undefined;
+ }
+ }
+
+ if (Query.canMerge(criteria)) {
+ this.merge(criteria);
+ }
+
+ // apply doc
+ if (doc) {
+ this._mergeUpdate(doc);
+ }
+
+ options && this.setOptions(options);
+
+ if (!callback) return this;
+ return this._findAndModify('update', callback);
+};
+
+/**
+ * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command.
+ *
+ * Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed.
+ *
+ * ####Available options
+ *
+ * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
+ *
+ * ####Examples
+ *
+ * A.where().findOneAndRemove(conditions, options, callback) // executes
+ * A.where().findOneAndRemove(conditions, options) // return Query
+ * A.where().findOneAndRemove(conditions, callback) // executes
+ * A.where().findOneAndRemove(conditions) // returns Query
+ * A.where().findOneAndRemove(callback) // executes
+ * A.where().findOneAndRemove() // returns Query
+ * A.where().findOneAndDelete() // alias of .findOneAndRemove()
+ *
+ * @param {Object} [conditions]
+ * @param {Object} [options]
+ * @param {Function} [callback]
+ * @return {Query} this
+ * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
+ * @api public
+ */
+
+Query.prototype.findOneAndRemove = Query.prototype.findOneAndDelete = function(conditions, options, callback) {
+ this.op = 'findOneAndRemove';
+ this._validate();
+
+ if ('function' == typeof options) {
+ callback = options;
+ options = undefined;
+ } else if ('function' == typeof conditions) {
+ callback = conditions;
+ conditions = undefined;
+ }
+
+ // apply conditions
+ if (Query.canMerge(conditions)) {
+ this.merge(conditions);
+ }
+
+ // apply options
+ options && this.setOptions(options);
+
+ if (!callback) return this;
+
+ return this._findAndModify('remove', callback);
+};
+
+/**
+ * _findAndModify
+ *
+ * @param {String} type - either "remove" or "update"
+ * @param {Function} callback
+ * @api private
+ */
+
+Query.prototype._findAndModify = function(type, callback) {
+ assert.equal('function', typeof callback);
+
+ var options = this._optionsForExec();
+ var fields;
+ var doc;
+
+ if ('remove' == type) {
+ options.remove = true;
+ } else {
+ if (!('new' in options)) options.new = true;
+ if (!('upsert' in options)) options.upsert = false;
+
+ doc = this._updateForExec();
+ if (!doc) {
+ if (options.upsert) {
+ // still need to do the upsert to empty doc
+ doc = { $set: {} };
+ } else {
+ return this.findOne(callback);
+ }
+ }
+ }
+
+ fields = this._fieldsForExec();
+ if (fields != null) {
+ if (this.$useProjection) {
+ options.projection = this._fieldsForExec();
+ } else {
+ options.fields = this._fieldsForExec();
+ }
+ }
+
+ var conds = this._conditions;
+
+ debug('findAndModify', this._collection.collectionName, conds, doc, options);
+ callback = this._wrapCallback('findAndModify', callback, {
+ conditions: conds,
+ doc: doc,
+ options: options
+ });
+
+ this._collection.findAndModify(conds, doc, options, utils.tick(callback));
+
+ return this;
+};
+
+/**
+ * Wrap callback to add tracing
+ *
+ * @param {Function} callback
+ * @param {Object} [queryInfo]
+ * @api private
+ */
+Query.prototype._wrapCallback = function(method, callback, queryInfo) {
+ var traceFunction = this._traceFunction || Query.traceFunction;
+
+ if (traceFunction) {
+ queryInfo.collectionName = this._collection.collectionName;
+
+ var traceCallback = traceFunction &&
+ traceFunction.call(null, method, queryInfo, this);
+
+ var startTime = new Date().getTime();
+
+ return function wrapperCallback(err, result) {
+ if (traceCallback) {
+ var millis = new Date().getTime() - startTime;
+ traceCallback.call(null, err, result, millis);
+ }
+
+ if (callback) {
+ callback.apply(null, arguments);
+ }
+ };
+ }
+
+ return callback;
+};
+
+/**
+ * Add trace function that gets called when the query is executed.
+ * The function will be called with (method, queryInfo, query) and
+ * should return a callback function which will be called
+ * with (err, result, millis) when the query is complete.
+ *
+ * queryInfo is an object containing: {
+ * collectionName: ,
+ * conditions: ,
+ * options: ,
+ * doc: [document to update, if applicable]
+ * }
+ *
+ * NOTE: Does not trace stream queries.
+ *
+ * @param {Function} traceFunction
+ * @return {Query} this
+ * @api public
+ */
+Query.prototype.setTraceFunction = function(traceFunction) {
+ this._traceFunction = traceFunction;
+ return this;
+};
+
+/**
+ * Executes the query
+ *
+ * ####Examples
+ *
+ * query.exec();
+ * query.exec(callback);
+ * query.exec('update');
+ * query.exec('find', callback);
+ *
+ * @param {String|Function} [operation]
+ * @param {Function} [callback]
+ * @api public
+ */
+
+Query.prototype.exec = function exec(op, callback) {
+ switch (typeof op) {
+ case 'function':
+ callback = op;
+ op = null;
+ break;
+ case 'string':
+ this.op = op;
+ break;
+ }
+
+ assert.ok(this.op, 'Missing query type: (find, update, etc)');
+
+ if ('update' == this.op || 'remove' == this.op) {
+ callback || (callback = true);
+ }
+
+ var _this = this;
+
+ if ('function' == typeof callback) {
+ this[this.op](callback);
+ } else {
+ return new Query.Promise(function(success, error) {
+ _this[_this.op](function(err, val) {
+ if (err) error(err);
+ else success(val);
+ success = error = null;
+ });
+ });
+ }
+};
+
+/**
+ * Returns a thunk which when called runs this.exec()
+ *
+ * The thunk receives a callback function which will be
+ * passed to `this.exec()`
+ *
+ * @return {Function}
+ * @api public
+ */
+
+Query.prototype.thunk = function() {
+ var _this = this;
+ return function(cb) {
+ _this.exec(cb);
+ };
+};
+
+/**
+ * Executes the query returning a `Promise` which will be
+ * resolved with either the doc(s) or rejected with the error.
+ *
+ * @param {Function} [resolve]
+ * @param {Function} [reject]
+ * @return {Promise}
+ * @api public
+ */
+
+Query.prototype.then = function(resolve, reject) {
+ var _this = this;
+ var promise = new Query.Promise(function(success, error) {
+ _this.exec(function(err, val) {
+ if (err) error(err);
+ else success(val);
+ success = error = null;
+ });
+ });
+ return promise.then(resolve, reject);
+};
+
+/**
+ * Returns a stream for the given find query.
+ *
+ * @throws Error if operation is not a find
+ * @returns {Stream} Node 0.8 style
+ */
+
+Query.prototype.stream = function(streamOptions) {
+ if ('find' != this.op)
+ throw new Error('stream() is only available for find');
+
+ var conds = this._conditions;
+
+ var options = this._optionsForExec();
+ if (this.$useProjection) {
+ options.projection = this._fieldsForExec();
+ } else {
+ options.fields = this._fieldsForExec();
+ }
+
+ debug('stream', this._collection.collectionName, conds, options, streamOptions);
+
+ return this._collection.findStream(conds, options, streamOptions);
+};
+
+/**
+ * Determines if field selection has been made.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+Query.prototype.selected = function selected() {
+ return !!(this._fields && Object.keys(this._fields).length > 0);
+};
+
+/**
+ * Determines if inclusive field selection has been made.
+ *
+ * query.selectedInclusively() // false
+ * query.select('name')
+ * query.selectedInclusively() // true
+ * query.selectedExlusively() // false
+ *
+ * @returns {Boolean}
+ */
+
+Query.prototype.selectedInclusively = function selectedInclusively() {
+ if (!this._fields) return false;
+
+ var keys = Object.keys(this._fields);
+ if (0 === keys.length) return false;
+
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ if (0 === this._fields[key]) return false;
+ if (this._fields[key] &&
+ typeof this._fields[key] === 'object' &&
+ this._fields[key].$meta) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+/**
+ * Determines if exclusive field selection has been made.
+ *
+ * query.selectedExlusively() // false
+ * query.select('-name')
+ * query.selectedExlusively() // true
+ * query.selectedInclusively() // false
+ *
+ * @returns {Boolean}
+ */
+
+Query.prototype.selectedExclusively = function selectedExclusively() {
+ if (!this._fields) return false;
+
+ var keys = Object.keys(this._fields);
+ if (0 === keys.length) return false;
+
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ if (0 === this._fields[key]) return true;
+ }
+
+ return false;
+};
+
+/**
+ * Merges `doc` with the current update object.
+ *
+ * @param {Object} doc
+ */
+
+Query.prototype._mergeUpdate = function(doc) {
+ if (!this._update) this._update = {};
+ if (doc instanceof Query) {
+ if (doc._update) {
+ utils.mergeClone(this._update, doc._update);
+ }
+ } else {
+ utils.mergeClone(this._update, doc);
+ }
+};
+
+/**
+ * Returns default options.
+ *
+ * @return {Object}
+ * @api private
+ */
+
+Query.prototype._optionsForExec = function() {
+ var options = utils.clone(this.options);
+ return options;
+};
+
+/**
+ * Returns fields selection for this query.
+ *
+ * @return {Object}
+ * @api private
+ */
+
+Query.prototype._fieldsForExec = function() {
+ return utils.clone(this._fields);
+};
+
+/**
+ * Return an update document with corrected $set operations.
+ *
+ * @api private
+ */
+
+Query.prototype._updateForExec = function() {
+ var update = utils.clone(this._update),
+ ops = utils.keys(update),
+ i = ops.length,
+ ret = {};
+
+ while (i--) {
+ var op = ops[i];
+
+ if (this.options.overwrite) {
+ ret[op] = update[op];
+ continue;
+ }
+
+ if ('$' !== op[0]) {
+ // fix up $set sugar
+ if (!ret.$set) {
+ if (update.$set) {
+ ret.$set = update.$set;
+ } else {
+ ret.$set = {};
+ }
+ }
+ ret.$set[op] = update[op];
+ ops.splice(i, 1);
+ if (!~ops.indexOf('$set')) ops.push('$set');
+ } else if ('$set' === op) {
+ if (!ret.$set) {
+ ret[op] = update[op];
+ }
+ } else {
+ ret[op] = update[op];
+ }
+ }
+
+ this._compiledUpdate = ret;
+ return ret;
+};
+
+/**
+ * Make sure _path is set.
+ *
+ * @parmam {String} method
+ */
+
+Query.prototype._ensurePath = function(method) {
+ if (!this._path) {
+ var msg = method + '() must be used after where() '
+ + 'when called with these arguments';
+ throw new Error(msg);
+ }
+};
+
+/*!
+ * Permissions
+ */
+
+Query.permissions = require('./permissions');
+
+Query._isPermitted = function(a, b) {
+ var denied = Query.permissions[b];
+ if (!denied) return true;
+ return true !== denied[a];
+};
+
+Query.prototype._validate = function(action) {
+ var fail;
+ var validator;
+
+ if (undefined === action) {
+
+ validator = Query.permissions[this.op];
+ if ('function' != typeof validator) return true;
+
+ fail = validator(this);
+
+ } else if (!Query._isPermitted(action, this.op)) {
+ fail = action;
+ }
+
+ if (fail) {
+ throw new Error(fail + ' cannot be used with ' + this.op);
+ }
+};
+
+/**
+ * Determines if `conds` can be merged using `mquery().merge()`
+ *
+ * @param {Object} conds
+ * @return {Boolean}
+ */
+
+Query.canMerge = function(conds) {
+ return conds instanceof Query || utils.isObject(conds);
+};
+
+/**
+ * Set a trace function that will get called whenever a
+ * query is executed.
+ *
+ * See `setTraceFunction()` for details.
+ *
+ * @param {Object} conds
+ * @return {Boolean}
+ */
+Query.setGlobalTraceFunction = function(traceFunction) {
+ Query.traceFunction = traceFunction;
+};
+
+/*!
+ * Exports.
+ */
+
+Query.utils = utils;
+Query.env = require('./env');
+Query.Collection = require('./collection');
+Query.BaseCollection = require('./collection/collection');
+Query.Promise = require('bluebird');
+module.exports = exports = Query;
+
+// TODO
+// test utils
diff --git a/node_modules/mquery/lib/permissions.js b/node_modules/mquery/lib/permissions.js
new file mode 100644
index 0000000..c306f3a
--- /dev/null
+++ b/node_modules/mquery/lib/permissions.js
@@ -0,0 +1,88 @@
+'use strict';
+
+var denied = exports;
+
+denied.distinct = function(self) {
+ if (self._fields && Object.keys(self._fields).length > 0) {
+ return 'field selection and slice';
+ }
+
+ var keys = Object.keys(denied.distinct);
+ var err;
+
+ keys.every(function(option) {
+ if (self.options[option]) {
+ err = option;
+ return false;
+ }
+ return true;
+ });
+
+ return err;
+};
+denied.distinct.select =
+denied.distinct.slice =
+denied.distinct.sort =
+denied.distinct.limit =
+denied.distinct.skip =
+denied.distinct.batchSize =
+denied.distinct.comment =
+denied.distinct.maxScan =
+denied.distinct.snapshot =
+denied.distinct.hint =
+denied.distinct.tailable = true;
+
+
+// aggregation integration
+
+
+denied.findOneAndUpdate =
+denied.findOneAndRemove = function(self) {
+ var keys = Object.keys(denied.findOneAndUpdate);
+ var err;
+
+ keys.every(function(option) {
+ if (self.options[option]) {
+ err = option;
+ return false;
+ }
+ return true;
+ });
+
+ return err;
+};
+denied.findOneAndUpdate.limit =
+denied.findOneAndUpdate.skip =
+denied.findOneAndUpdate.batchSize =
+denied.findOneAndUpdate.maxScan =
+denied.findOneAndUpdate.snapshot =
+denied.findOneAndUpdate.hint =
+denied.findOneAndUpdate.tailable =
+denied.findOneAndUpdate.comment = true;
+
+
+denied.count = function(self) {
+ if (self._fields && Object.keys(self._fields).length > 0) {
+ return 'field selection and slice';
+ }
+
+ var keys = Object.keys(denied.count);
+ var err;
+
+ keys.every(function(option) {
+ if (self.options[option]) {
+ err = option;
+ return false;
+ }
+ return true;
+ });
+
+ return err;
+};
+
+denied.count.slice =
+denied.count.batchSize =
+denied.count.comment =
+denied.count.maxScan =
+denied.count.snapshot =
+denied.count.tailable = true;
diff --git a/node_modules/mquery/lib/utils.js b/node_modules/mquery/lib/utils.js
new file mode 100644
index 0000000..ef51712
--- /dev/null
+++ b/node_modules/mquery/lib/utils.js
@@ -0,0 +1,356 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+var Buffer = require('safe-buffer').Buffer;
+var RegExpClone = require('regexp-clone');
+
+/**
+ * Clones objects
+ *
+ * @param {Object} obj the object to clone
+ * @param {Object} options
+ * @return {Object} the cloned object
+ * @api private
+ */
+
+var clone = exports.clone = function clone(obj, options) {
+ if (obj === undefined || obj === null)
+ return obj;
+
+ if (Array.isArray(obj))
+ return exports.cloneArray(obj, options);
+
+ if (obj.constructor) {
+ if (/ObjectI[dD]$/.test(obj.constructor.name)) {
+ return 'function' == typeof obj.clone
+ ? obj.clone()
+ : new obj.constructor(obj.id);
+ }
+
+ if (obj.constructor.name === 'ReadPreference') {
+ return new obj.constructor(obj.mode, clone(obj.tags, options));
+ }
+
+ if ('Binary' == obj._bsontype && obj.buffer && obj.value) {
+ return 'function' == typeof obj.clone
+ ? obj.clone()
+ : new obj.constructor(obj.value(true), obj.sub_type);
+ }
+
+ if ('Date' === obj.constructor.name || 'Function' === obj.constructor.name)
+ return new obj.constructor(+obj);
+
+ if ('RegExp' === obj.constructor.name)
+ return RegExpClone(obj);
+
+ if ('Buffer' === obj.constructor.name)
+ return exports.cloneBuffer(obj);
+ }
+
+ if (isObject(obj))
+ return exports.cloneObject(obj, options);
+
+ if (obj.valueOf)
+ return obj.valueOf();
+};
+
+/*!
+ * ignore
+ */
+
+exports.cloneObject = function cloneObject(obj, options) {
+ var minimize = options && options.minimize;
+ var ret = {};
+ var hasKeys;
+ var val;
+ var k;
+
+ for (k in obj) {
+ val = clone(obj[k], options);
+
+ if (!minimize || ('undefined' !== typeof val)) {
+ hasKeys || (hasKeys = true);
+ ret[k] = val;
+ }
+ }
+
+ return minimize
+ ? hasKeys && ret
+ : ret;
+};
+
+exports.cloneArray = function cloneArray(arr, options) {
+ var ret = [];
+ for (var i = 0, l = arr.length; i < l; i++)
+ ret.push(clone(arr[i], options));
+ return ret;
+};
+
+/**
+ * process.nextTick helper.
+ *
+ * Wraps the given `callback` in a try/catch. If an error is
+ * caught it will be thrown on nextTick.
+ *
+ * node-mongodb-native had a habit of state corruption when
+ * an error was immediately thrown from within a collection
+ * method (find, update, etc) callback.
+ *
+ * @param {Function} [callback]
+ * @api private
+ */
+
+exports.tick = function tick(callback) {
+ if ('function' !== typeof callback) return;
+ return function() {
+ // callbacks should always be fired on the next
+ // turn of the event loop. A side benefit is
+ // errors thrown from executing the callback
+ // will not cause drivers state to be corrupted
+ // which has historically been a problem.
+ var args = arguments;
+ soon(function() {
+ callback.apply(this, args);
+ });
+ };
+};
+
+/**
+ * Merges `from` into `to` without overwriting existing properties.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ * @api private
+ */
+
+exports.merge = function merge(to, from) {
+ var keys = Object.keys(from),
+ i = keys.length,
+ key;
+
+ while (i--) {
+ key = keys[i];
+ if ('undefined' === typeof to[key]) {
+ to[key] = from[key];
+ } else {
+ if (exports.isObject(from[key])) {
+ merge(to[key], from[key]);
+ } else {
+ to[key] = from[key];
+ }
+ }
+ }
+};
+
+/**
+ * Same as merge but clones the assigned values.
+ *
+ * @param {Object} to
+ * @param {Object} from
+ * @api private
+ */
+
+exports.mergeClone = function mergeClone(to, from) {
+ var keys = Object.keys(from),
+ i = keys.length,
+ key;
+
+ while (i--) {
+ key = keys[i];
+ if ('undefined' === typeof to[key]) {
+ to[key] = clone(from[key]);
+ } else {
+ if (exports.isObject(from[key])) {
+ mergeClone(to[key], from[key]);
+ } else {
+ to[key] = clone(from[key]);
+ }
+ }
+ }
+};
+
+/**
+ * Read pref helper (mongo 2.2 drivers support this)
+ *
+ * Allows using aliases instead of full preference names:
+ *
+ * p primary
+ * pp primaryPreferred
+ * s secondary
+ * sp secondaryPreferred
+ * n nearest
+ *
+ * @param {String} pref
+ */
+
+exports.readPref = function readPref(pref) {
+ switch (pref) {
+ case 'p':
+ pref = 'primary';
+ break;
+ case 'pp':
+ pref = 'primaryPreferred';
+ break;
+ case 's':
+ pref = 'secondary';
+ break;
+ case 'sp':
+ pref = 'secondaryPreferred';
+ break;
+ case 'n':
+ pref = 'nearest';
+ break;
+ }
+
+ return pref;
+};
+
+
+/**
+ * Read Concern helper (mongo 3.2 drivers support this)
+ *
+ * Allows using string to specify read concern level:
+ *
+ * local 3.2+
+ * available 3.6+
+ * majority 3.2+
+ * linearizable 3.4+
+ * snapshot 4.0+
+ *
+ * @param {String|Object} concern
+ */
+
+exports.readConcern = function readConcern(concern) {
+ if ('string' === typeof concern) {
+ switch (concern) {
+ case 'l':
+ concern = 'local';
+ break;
+ case 'a':
+ concern = 'available';
+ break;
+ case 'm':
+ concern = 'majority';
+ break;
+ case 'lz':
+ concern = 'linearizable';
+ break;
+ case 's':
+ concern = 'snapshot';
+ break;
+ }
+ concern = { level: concern };
+ }
+ return concern;
+};
+
+/**
+ * Object.prototype.toString.call helper
+ */
+
+var _toString = Object.prototype.toString;
+exports.toString = function(arg) {
+ return _toString.call(arg);
+};
+
+/**
+ * Determines if `arg` is an object.
+ *
+ * @param {Object|Array|String|Function|RegExp|any} arg
+ * @return {Boolean}
+ */
+
+var isObject = exports.isObject = function(arg) {
+ return '[object Object]' == exports.toString(arg);
+};
+
+/**
+ * Determines if `arg` is an array.
+ *
+ * @param {Object}
+ * @return {Boolean}
+ * @see nodejs utils
+ */
+
+exports.isArray = function(arg) {
+ return Array.isArray(arg) ||
+ 'object' == typeof arg && '[object Array]' == exports.toString(arg);
+};
+
+/**
+ * Object.keys helper
+ */
+
+exports.keys = Object.keys || function(obj) {
+ var keys = [];
+ for (var k in obj) if (obj.hasOwnProperty(k)) {
+ keys.push(k);
+ }
+ return keys;
+};
+
+/**
+ * Basic Object.create polyfill.
+ * Only one argument is supported.
+ *
+ * Based on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
+ */
+
+exports.create = 'function' == typeof Object.create
+ ? Object.create
+ : create;
+
+function create(proto) {
+ if (arguments.length > 1) {
+ throw new Error('Adding properties is not supported');
+ }
+
+ function F() {}
+ F.prototype = proto;
+ return new F;
+}
+
+/**
+ * inheritance
+ */
+
+exports.inherits = function(ctor, superCtor) {
+ ctor.prototype = exports.create(superCtor.prototype);
+ ctor.prototype.constructor = ctor;
+};
+
+/**
+ * nextTick helper
+ * compat with node 0.10 which behaves differently than previous versions
+ */
+
+var soon = exports.soon = 'function' == typeof setImmediate
+ ? setImmediate
+ : process.nextTick;
+
+/**
+ * Clones the contents of a buffer.
+ *
+ * @param {Buffer} buff
+ * @return {Buffer}
+ */
+
+exports.cloneBuffer = function(buff) {
+ var dupe = Buffer.alloc(buff.length);
+ buff.copy(dupe, 0, 0, buff.length);
+ return dupe;
+};
+
+/**
+ * Check if this object is an arguments object
+ *
+ * @param {Any} v
+ * @return {Boolean}
+ */
+
+exports.isArgumentsObject = function(v) {
+ return Object.prototype.toString.call(v) === '[object Arguments]';
+};
diff --git a/node_modules/mquery/node_modules/debug/.coveralls.yml b/node_modules/mquery/node_modules/debug/.coveralls.yml
new file mode 100644
index 0000000..20a7068
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/.coveralls.yml
@@ -0,0 +1 @@
+repo_token: SIAeZjKYlHK74rbcFvNHMUzjRiMpflxve
diff --git a/node_modules/mquery/node_modules/debug/.eslintrc b/node_modules/mquery/node_modules/debug/.eslintrc
new file mode 100644
index 0000000..146371e
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/.eslintrc
@@ -0,0 +1,14 @@
+{
+ "env": {
+ "browser": true,
+ "node": true
+ },
+ "globals": {
+ "chrome": true
+ },
+ "rules": {
+ "no-console": 0,
+ "no-empty": [1, { "allowEmptyCatch": true }]
+ },
+ "extends": "eslint:recommended"
+}
diff --git a/node_modules/mquery/node_modules/debug/.npmignore b/node_modules/mquery/node_modules/debug/.npmignore
new file mode 100644
index 0000000..5f60eec
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/.npmignore
@@ -0,0 +1,9 @@
+support
+test
+examples
+example
+*.sock
+dist
+yarn.lock
+coverage
+bower.json
diff --git a/node_modules/mquery/node_modules/debug/.travis.yml b/node_modules/mquery/node_modules/debug/.travis.yml
new file mode 100644
index 0000000..a764300
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/.travis.yml
@@ -0,0 +1,20 @@
+sudo: false
+
+language: node_js
+
+node_js:
+ - "4"
+ - "6"
+ - "8"
+
+install:
+ - make install
+
+script:
+ - make lint
+ - make test
+
+matrix:
+ include:
+ - node_js: '8'
+ env: BROWSER=1
diff --git a/node_modules/mquery/node_modules/debug/CHANGELOG.md b/node_modules/mquery/node_modules/debug/CHANGELOG.md
new file mode 100644
index 0000000..820d21e
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/CHANGELOG.md
@@ -0,0 +1,395 @@
+
+3.1.0 / 2017-09-26
+==================
+
+ * Add `DEBUG_HIDE_DATE` env var (#486)
+ * Remove ReDoS regexp in %o formatter (#504)
+ * Remove "component" from package.json
+ * Remove `component.json`
+ * Ignore package-lock.json
+ * Examples: fix colors printout
+ * Fix: browser detection
+ * Fix: spelling mistake (#496, @EdwardBetts)
+
+3.0.1 / 2017-08-24
+==================
+
+ * Fix: Disable colors in Edge and Internet Explorer (#489)
+
+3.0.0 / 2017-08-08
+==================
+
+ * Breaking: Remove DEBUG_FD (#406)
+ * Breaking: Use `Date#toISOString()` instead to `Date#toUTCString()` when output is not a TTY (#418)
+ * Breaking: Make millisecond timer namespace specific and allow 'always enabled' output (#408)
+ * Addition: document `enabled` flag (#465)
+ * Addition: add 256 colors mode (#481)
+ * Addition: `enabled()` updates existing debug instances, add `destroy()` function (#440)
+ * Update: component: update "ms" to v2.0.0
+ * Update: separate the Node and Browser tests in Travis-CI
+ * Update: refactor Readme, fixed documentation, added "Namespace Colors" section, redid screenshots
+ * Update: separate Node.js and web browser examples for organization
+ * Update: update "browserify" to v14.4.0
+ * Fix: fix Readme typo (#473)
+
+2.6.9 / 2017-09-22
+==================
+
+ * remove ReDoS regexp in %o formatter (#504)
+
+2.6.8 / 2017-05-18
+==================
+
+ * Fix: Check for undefined on browser globals (#462, @marbemac)
+
+2.6.7 / 2017-05-16
+==================
+
+ * Fix: Update ms to 2.0.0 to fix regular expression denial of service vulnerability (#458, @hubdotcom)
+ * Fix: Inline extend function in node implementation (#452, @dougwilson)
+ * Docs: Fix typo (#455, @msasad)
+
+2.6.5 / 2017-04-27
+==================
+
+ * Fix: null reference check on window.documentElement.style.WebkitAppearance (#447, @thebigredgeek)
+ * Misc: clean up browser reference checks (#447, @thebigredgeek)
+ * Misc: add npm-debug.log to .gitignore (@thebigredgeek)
+
+
+2.6.4 / 2017-04-20
+==================
+
+ * Fix: bug that would occur if process.env.DEBUG is a non-string value. (#444, @LucianBuzzo)
+ * Chore: ignore bower.json in npm installations. (#437, @joaovieira)
+ * Misc: update "ms" to v0.7.3 (@tootallnate)
+
+2.6.3 / 2017-03-13
+==================
+
+ * Fix: Electron reference to `process.env.DEBUG` (#431, @paulcbetts)
+ * Docs: Changelog fix (@thebigredgeek)
+
+2.6.2 / 2017-03-10
+==================
+
+ * Fix: DEBUG_MAX_ARRAY_LENGTH (#420, @slavaGanzin)
+ * Docs: Add backers and sponsors from Open Collective (#422, @piamancini)
+ * Docs: Add Slackin invite badge (@tootallnate)
+
+2.6.1 / 2017-02-10
+==================
+
+ * Fix: Module's `export default` syntax fix for IE8 `Expected identifier` error
+ * Fix: Whitelist DEBUG_FD for values 1 and 2 only (#415, @pi0)
+ * Fix: IE8 "Expected identifier" error (#414, @vgoma)
+ * Fix: Namespaces would not disable once enabled (#409, @musikov)
+
+2.6.0 / 2016-12-28
+==================
+
+ * Fix: added better null pointer checks for browser useColors (@thebigredgeek)
+ * Improvement: removed explicit `window.debug` export (#404, @tootallnate)
+ * Improvement: deprecated `DEBUG_FD` environment variable (#405, @tootallnate)
+
+2.5.2 / 2016-12-25
+==================
+
+ * Fix: reference error on window within webworkers (#393, @KlausTrainer)
+ * Docs: fixed README typo (#391, @lurch)
+ * Docs: added notice about v3 api discussion (@thebigredgeek)
+
+2.5.1 / 2016-12-20
+==================
+
+ * Fix: babel-core compatibility
+
+2.5.0 / 2016-12-20
+==================
+
+ * Fix: wrong reference in bower file (@thebigredgeek)
+ * Fix: webworker compatibility (@thebigredgeek)
+ * Fix: output formatting issue (#388, @kribblo)
+ * Fix: babel-loader compatibility (#383, @escwald)
+ * Misc: removed built asset from repo and publications (@thebigredgeek)
+ * Misc: moved source files to /src (#378, @yamikuronue)
+ * Test: added karma integration and replaced babel with browserify for browser tests (#378, @yamikuronue)
+ * Test: coveralls integration (#378, @yamikuronue)
+ * Docs: simplified language in the opening paragraph (#373, @yamikuronue)
+
+2.4.5 / 2016-12-17
+==================
+
+ * Fix: `navigator` undefined in Rhino (#376, @jochenberger)
+ * Fix: custom log function (#379, @hsiliev)
+ * Improvement: bit of cleanup + linting fixes (@thebigredgeek)
+ * Improvement: rm non-maintainted `dist/` dir (#375, @freewil)
+ * Docs: simplified language in the opening paragraph. (#373, @yamikuronue)
+
+2.4.4 / 2016-12-14
+==================
+
+ * Fix: work around debug being loaded in preload scripts for electron (#368, @paulcbetts)
+
+2.4.3 / 2016-12-14
+==================
+
+ * Fix: navigation.userAgent error for react native (#364, @escwald)
+
+2.4.2 / 2016-12-14
+==================
+
+ * Fix: browser colors (#367, @tootallnate)
+ * Misc: travis ci integration (@thebigredgeek)
+ * Misc: added linting and testing boilerplate with sanity check (@thebigredgeek)
+
+2.4.1 / 2016-12-13
+==================
+
+ * Fix: typo that broke the package (#356)
+
+2.4.0 / 2016-12-13
+==================
+
+ * Fix: bower.json references unbuilt src entry point (#342, @justmatt)
+ * Fix: revert "handle regex special characters" (@tootallnate)
+ * Feature: configurable util.inspect()`options for NodeJS (#327, @tootallnate)
+ * Feature: %O`(big O) pretty-prints objects (#322, @tootallnate)
+ * Improvement: allow colors in workers (#335, @botverse)
+ * Improvement: use same color for same namespace. (#338, @lchenay)
+
+2.3.3 / 2016-11-09
+==================
+
+ * Fix: Catch `JSON.stringify()` errors (#195, Jovan Alleyne)
+ * Fix: Returning `localStorage` saved values (#331, Levi Thomason)
+ * Improvement: Don't create an empty object when no `process` (Nathan Rajlich)
+
+2.3.2 / 2016-11-09
+==================
+
+ * Fix: be super-safe in index.js as well (@TooTallNate)
+ * Fix: should check whether process exists (Tom Newby)
+
+2.3.1 / 2016-11-09
+==================
+
+ * Fix: Added electron compatibility (#324, @paulcbetts)
+ * Improvement: Added performance optimizations (@tootallnate)
+ * Readme: Corrected PowerShell environment variable example (#252, @gimre)
+ * Misc: Removed yarn lock file from source control (#321, @fengmk2)
+
+2.3.0 / 2016-11-07
+==================
+
+ * Fix: Consistent placement of ms diff at end of output (#215, @gorangajic)
+ * Fix: Escaping of regex special characters in namespace strings (#250, @zacronos)
+ * Fix: Fixed bug causing crash on react-native (#282, @vkarpov15)
+ * Feature: Enabled ES6+ compatible import via default export (#212 @bucaran)
+ * Feature: Added %O formatter to reflect Chrome's console.log capability (#279, @oncletom)
+ * Package: Update "ms" to 0.7.2 (#315, @DevSide)
+ * Package: removed superfluous version property from bower.json (#207 @kkirsche)
+ * Readme: fix USE_COLORS to DEBUG_COLORS
+ * Readme: Doc fixes for format string sugar (#269, @mlucool)
+ * Readme: Updated docs for DEBUG_FD and DEBUG_COLORS environment variables (#232, @mattlyons0)
+ * Readme: doc fixes for PowerShell (#271 #243, @exoticknight @unreadable)
+ * Readme: better docs for browser support (#224, @matthewmueller)
+ * Tooling: Added yarn integration for development (#317, @thebigredgeek)
+ * Misc: Renamed History.md to CHANGELOG.md (@thebigredgeek)
+ * Misc: Added license file (#226 #274, @CantemoInternal @sdaitzman)
+ * Misc: Updated contributors (@thebigredgeek)
+
+2.2.0 / 2015-05-09
+==================
+
+ * package: update "ms" to v0.7.1 (#202, @dougwilson)
+ * README: add logging to file example (#193, @DanielOchoa)
+ * README: fixed a typo (#191, @amir-s)
+ * browser: expose `storage` (#190, @stephenmathieson)
+ * Makefile: add a `distclean` target (#189, @stephenmathieson)
+
+2.1.3 / 2015-03-13
+==================
+
+ * Updated stdout/stderr example (#186)
+ * Updated example/stdout.js to match debug current behaviour
+ * Renamed example/stderr.js to stdout.js
+ * Update Readme.md (#184)
+ * replace high intensity foreground color for bold (#182, #183)
+
+2.1.2 / 2015-03-01
+==================
+
+ * dist: recompile
+ * update "ms" to v0.7.0
+ * package: update "browserify" to v9.0.3
+ * component: fix "ms.js" repo location
+ * changed bower package name
+ * updated documentation about using debug in a browser
+ * fix: security error on safari (#167, #168, @yields)
+
+2.1.1 / 2014-12-29
+==================
+
+ * browser: use `typeof` to check for `console` existence
+ * browser: check for `console.log` truthiness (fix IE 8/9)
+ * browser: add support for Chrome apps
+ * Readme: added Windows usage remarks
+ * Add `bower.json` to properly support bower install
+
+2.1.0 / 2014-10-15
+==================
+
+ * node: implement `DEBUG_FD` env variable support
+ * package: update "browserify" to v6.1.0
+ * package: add "license" field to package.json (#135, @panuhorsmalahti)
+
+2.0.0 / 2014-09-01
+==================
+
+ * package: update "browserify" to v5.11.0
+ * node: use stderr rather than stdout for logging (#29, @stephenmathieson)
+
+1.0.4 / 2014-07-15
+==================
+
+ * dist: recompile
+ * example: remove `console.info()` log usage
+ * example: add "Content-Type" UTF-8 header to browser example
+ * browser: place %c marker after the space character
+ * browser: reset the "content" color via `color: inherit`
+ * browser: add colors support for Firefox >= v31
+ * debug: prefer an instance `log()` function over the global one (#119)
+ * Readme: update documentation about styled console logs for FF v31 (#116, @wryk)
+
+1.0.3 / 2014-07-09
+==================
+
+ * Add support for multiple wildcards in namespaces (#122, @seegno)
+ * browser: fix lint
+
+1.0.2 / 2014-06-10
+==================
+
+ * browser: update color palette (#113, @gscottolson)
+ * common: make console logging function configurable (#108, @timoxley)
+ * node: fix %o colors on old node <= 0.8.x
+ * Makefile: find node path using shell/which (#109, @timoxley)
+
+1.0.1 / 2014-06-06
+==================
+
+ * browser: use `removeItem()` to clear localStorage
+ * browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777)
+ * package: add "contributors" section
+ * node: fix comment typo
+ * README: list authors
+
+1.0.0 / 2014-06-04
+==================
+
+ * make ms diff be global, not be scope
+ * debug: ignore empty strings in enable()
+ * node: make DEBUG_COLORS able to disable coloring
+ * *: export the `colors` array
+ * npmignore: don't publish the `dist` dir
+ * Makefile: refactor to use browserify
+ * package: add "browserify" as a dev dependency
+ * Readme: add Web Inspector Colors section
+ * node: reset terminal color for the debug content
+ * node: map "%o" to `util.inspect()`
+ * browser: map "%j" to `JSON.stringify()`
+ * debug: add custom "formatters"
+ * debug: use "ms" module for humanizing the diff
+ * Readme: add "bash" syntax highlighting
+ * browser: add Firebug color support
+ * browser: add colors for WebKit browsers
+ * node: apply log to `console`
+ * rewrite: abstract common logic for Node & browsers
+ * add .jshintrc file
+
+0.8.1 / 2014-04-14
+==================
+
+ * package: re-add the "component" section
+
+0.8.0 / 2014-03-30
+==================
+
+ * add `enable()` method for nodejs. Closes #27
+ * change from stderr to stdout
+ * remove unnecessary index.js file
+
+0.7.4 / 2013-11-13
+==================
+
+ * remove "browserify" key from package.json (fixes something in browserify)
+
+0.7.3 / 2013-10-30
+==================
+
+ * fix: catch localStorage security error when cookies are blocked (Chrome)
+ * add debug(err) support. Closes #46
+ * add .browser prop to package.json. Closes #42
+
+0.7.2 / 2013-02-06
+==================
+
+ * fix package.json
+ * fix: Mobile Safari (private mode) is broken with debug
+ * fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript
+
+0.7.1 / 2013-02-05
+==================
+
+ * add repository URL to package.json
+ * add DEBUG_COLORED to force colored output
+ * add browserify support
+ * fix component. Closes #24
+
+0.7.0 / 2012-05-04
+==================
+
+ * Added .component to package.json
+ * Added debug.component.js build
+
+0.6.0 / 2012-03-16
+==================
+
+ * Added support for "-" prefix in DEBUG [Vinay Pulim]
+ * Added `.enabled` flag to the node version [TooTallNate]
+
+0.5.0 / 2012-02-02
+==================
+
+ * Added: humanize diffs. Closes #8
+ * Added `debug.disable()` to the CS variant
+ * Removed padding. Closes #10
+ * Fixed: persist client-side variant again. Closes #9
+
+0.4.0 / 2012-02-01
+==================
+
+ * Added browser variant support for older browsers [TooTallNate]
+ * Added `debug.enable('project:*')` to browser variant [TooTallNate]
+ * Added padding to diff (moved it to the right)
+
+0.3.0 / 2012-01-26
+==================
+
+ * Added millisecond diff when isatty, otherwise UTC string
+
+0.2.0 / 2012-01-22
+==================
+
+ * Added wildcard support
+
+0.1.0 / 2011-12-02
+==================
+
+ * Added: remove colors unless stderr isatty [TooTallNate]
+
+0.0.1 / 2010-01-03
+==================
+
+ * Initial release
diff --git a/node_modules/mquery/node_modules/debug/LICENSE b/node_modules/mquery/node_modules/debug/LICENSE
new file mode 100644
index 0000000..658c933
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/LICENSE
@@ -0,0 +1,19 @@
+(The MIT License)
+
+Copyright (c) 2014 TJ Holowaychuk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+and associated documentation files (the 'Software'), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/node_modules/mquery/node_modules/debug/Makefile b/node_modules/mquery/node_modules/debug/Makefile
new file mode 100644
index 0000000..3ddd136
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/Makefile
@@ -0,0 +1,58 @@
+# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
+THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
+
+# BIN directory
+BIN := $(THIS_DIR)/node_modules/.bin
+
+# Path
+PATH := node_modules/.bin:$(PATH)
+SHELL := /bin/bash
+
+# applications
+NODE ?= $(shell which node)
+YARN ?= $(shell which yarn)
+PKG ?= $(if $(YARN),$(YARN),$(NODE) $(shell which npm))
+BROWSERIFY ?= $(NODE) $(BIN)/browserify
+
+install: node_modules
+
+browser: dist/debug.js
+
+node_modules: package.json
+ @NODE_ENV= $(PKG) install
+ @touch node_modules
+
+dist/debug.js: src/*.js node_modules
+ @mkdir -p dist
+ @$(BROWSERIFY) \
+ --standalone debug \
+ . > dist/debug.js
+
+lint:
+ @eslint *.js src/*.js
+
+test-node:
+ @istanbul cover node_modules/mocha/bin/_mocha -- test/**.js
+ @cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
+
+test-browser:
+ @$(MAKE) browser
+ @karma start --single-run
+
+test-all:
+ @concurrently \
+ "make test-node" \
+ "make test-browser"
+
+test:
+ @if [ "x$(BROWSER)" = "x" ]; then \
+ $(MAKE) test-node; \
+ else \
+ $(MAKE) test-browser; \
+ fi
+
+clean:
+ rimraf dist coverage
+
+.PHONY: browser install clean lint test test-all test-node test-browser
diff --git a/node_modules/mquery/node_modules/debug/README.md b/node_modules/mquery/node_modules/debug/README.md
new file mode 100644
index 0000000..8e754d1
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/README.md
@@ -0,0 +1,368 @@
+# debug
+[](https://travis-ci.org/visionmedia/debug) [](https://coveralls.io/github/visionmedia/debug?branch=master) [](https://visionmedia-community-slackin.now.sh/) [](#backers)
+[](#sponsors)
+
+
+
+A tiny JavaScript debugging utility modelled after Node.js core's debugging
+technique. Works in Node.js and web browsers.
+
+## Installation
+
+```bash
+$ npm install debug
+```
+
+## Usage
+
+`debug` exposes a function; simply pass this function the name of your module, and it will return a decorated version of `console.error` for you to pass debug statements to. This will allow you to toggle the debug output for different parts of your module as well as the module as a whole.
+
+Example [_app.js_](./examples/node/app.js):
+
+```js
+var debug = require('debug')('http')
+ , http = require('http')
+ , name = 'My App';
+
+// fake app
+
+debug('booting %o', name);
+
+http.createServer(function(req, res){
+ debug(req.method + ' ' + req.url);
+ res.end('hello\n');
+}).listen(3000, function(){
+ debug('listening');
+});
+
+// fake worker of some kind
+
+require('./worker');
+```
+
+Example [_worker.js_](./examples/node/worker.js):
+
+```js
+var a = require('debug')('worker:a')
+ , b = require('debug')('worker:b');
+
+function work() {
+ a('doing lots of uninteresting work');
+ setTimeout(work, Math.random() * 1000);
+}
+
+work();
+
+function workb() {
+ b('doing some work');
+ setTimeout(workb, Math.random() * 2000);
+}
+
+workb();
+```
+
+The `DEBUG` environment variable is then used to enable these based on space or
+comma-delimited names.
+
+Here are some examples:
+
+
+
+
+
+#### Windows note
+
+On Windows the environment variable is set using the `set` command.
+
+```cmd
+set DEBUG=*,-not_this
+```
+
+Note that PowerShell uses different syntax to set environment variables.
+
+```cmd
+$env:DEBUG = "*,-not_this"
+```
+
+Then, run the program to be debugged as usual.
+
+
+## Namespace Colors
+
+Every debug instance has a color generated for it based on its namespace name.
+This helps when visually parsing the debug output to identify which debug instance
+a debug line belongs to.
+
+#### Node.js
+
+In Node.js, colors are enabled when stderr is a TTY. You also _should_ install
+the [`supports-color`](https://npmjs.org/supports-color) module alongside debug,
+otherwise debug will only use a small handful of basic colors.
+
+
+
+#### Web Browser
+
+Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
+option. These are WebKit web inspectors, Firefox ([since version
+31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
+and the Firebug plugin for Firefox (any version).
+
+
+
+
+## Millisecond diff
+
+When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
+
+
+
+When stdout is not a TTY, `Date#toISOString()` is used, making it more useful for logging the debug information as shown below:
+
+
+
+
+## Conventions
+
+If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". If you append a "*" to the end of your name, it will always be enabled regardless of the setting of the DEBUG environment variable. You can then use it for normal output as well as debug output.
+
+## Wildcards
+
+The `*` character may be used as a wildcard. Suppose for example your library has
+debuggers named "connect:bodyParser", "connect:compress", "connect:session",
+instead of listing all three with
+`DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do
+`DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
+
+You can also exclude specific debuggers by prefixing them with a "-" character.
+For example, `DEBUG=*,-connect:*` would include all debuggers except those
+starting with "connect:".
+
+## Environment Variables
+
+When running through Node.js, you can set a few environment variables that will
+change the behavior of the debug logging:
+
+| Name | Purpose |
+|-----------|-------------------------------------------------|
+| `DEBUG` | Enables/disables specific debugging namespaces. |
+| `DEBUG_HIDE_DATE` | Hide date from debug output (non-TTY). |
+| `DEBUG_COLORS`| Whether or not to use colors in the debug output. |
+| `DEBUG_DEPTH` | Object inspection depth. |
+| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. |
+
+
+__Note:__ The environment variables beginning with `DEBUG_` end up being
+converted into an Options object that gets used with `%o`/`%O` formatters.
+See the Node.js documentation for
+[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
+for the complete list.
+
+## Formatters
+
+Debug uses [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting.
+Below are the officially supported formatters:
+
+| Formatter | Representation |
+|-----------|----------------|
+| `%O` | Pretty-print an Object on multiple lines. |
+| `%o` | Pretty-print an Object all on a single line. |
+| `%s` | String. |
+| `%d` | Number (both integer and float). |
+| `%j` | JSON. Replaced with the string '[Circular]' if the argument contains circular references. |
+| `%%` | Single percent sign ('%'). This does not consume an argument. |
+
+
+### Custom formatters
+
+You can add custom formatters by extending the `debug.formatters` object.
+For example, if you wanted to add support for rendering a Buffer as hex with
+`%h`, you could do something like:
+
+```js
+const createDebug = require('debug')
+createDebug.formatters.h = (v) => {
+ return v.toString('hex')
+}
+
+// …elsewhere
+const debug = createDebug('foo')
+debug('this is hex: %h', new Buffer('hello world'))
+// foo this is hex: 68656c6c6f20776f726c6421 +0ms
+```
+
+
+## Browser Support
+
+You can build a browser-ready script using [browserify](https://github.com/substack/node-browserify),
+or just use the [browserify-as-a-service](https://wzrd.in/) [build](https://wzrd.in/standalone/debug@latest),
+if you don't want to build it yourself.
+
+Debug's enable state is currently persisted by `localStorage`.
+Consider the situation shown below where you have `worker:a` and `worker:b`,
+and wish to debug both. You can enable this using `localStorage.debug`:
+
+```js
+localStorage.debug = 'worker:*'
+```
+
+And then refresh the page.
+
+```js
+a = debug('worker:a');
+b = debug('worker:b');
+
+setInterval(function(){
+ a('doing some work');
+}, 1000);
+
+setInterval(function(){
+ b('doing some work');
+}, 1200);
+```
+
+
+## Output streams
+
+ By default `debug` will log to stderr, however this can be configured per-namespace by overriding the `log` method:
+
+Example [_stdout.js_](./examples/node/stdout.js):
+
+```js
+var debug = require('debug');
+var error = debug('app:error');
+
+// by default stderr is used
+error('goes to stderr!');
+
+var log = debug('app:log');
+// set this namespace to log via console.log
+log.log = console.log.bind(console); // don't forget to bind to console!
+log('goes to stdout');
+error('still goes to stderr!');
+
+// set all output to go via console.info
+// overrides all per-namespace log settings
+debug.log = console.info.bind(console);
+error('now goes to stdout via console.info');
+log('still goes to stdout, but via console.info now');
+```
+
+## Checking whether a debug target is enabled
+
+After you've created a debug instance, you can determine whether or not it is
+enabled by checking the `enabled` property:
+
+```javascript
+const debug = require('debug')('http');
+
+if (debug.enabled) {
+ // do stuff...
+}
+```
+
+You can also manually toggle this property to force the debug instance to be
+enabled or disabled.
+
+
+## Authors
+
+ - TJ Holowaychuk
+ - Nathan Rajlich
+ - Andrew Rhyne
+
+## Backers
+
+Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/debug#backer)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Sponsors
+
+Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/debug#sponsor)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/mquery/node_modules/debug/karma.conf.js b/node_modules/mquery/node_modules/debug/karma.conf.js
new file mode 100644
index 0000000..103a82d
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/karma.conf.js
@@ -0,0 +1,70 @@
+// Karma configuration
+// Generated on Fri Dec 16 2016 13:09:51 GMT+0000 (UTC)
+
+module.exports = function(config) {
+ config.set({
+
+ // base path that will be used to resolve all patterns (eg. files, exclude)
+ basePath: '',
+
+
+ // frameworks to use
+ // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+ frameworks: ['mocha', 'chai', 'sinon'],
+
+
+ // list of files / patterns to load in the browser
+ files: [
+ 'dist/debug.js',
+ 'test/*spec.js'
+ ],
+
+
+ // list of files to exclude
+ exclude: [
+ 'src/node.js'
+ ],
+
+
+ // preprocess matching files before serving them to the browser
+ // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+ preprocessors: {
+ },
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress'
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+ reporters: ['progress'],
+
+
+ // web server port
+ port: 9876,
+
+
+ // enable / disable colors in the output (reporters and logs)
+ colors: true,
+
+
+ // level of logging
+ // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+ logLevel: config.LOG_INFO,
+
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch: true,
+
+
+ // start these browsers
+ // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+ browsers: ['PhantomJS'],
+
+
+ // Continuous Integration mode
+ // if true, Karma captures browsers, runs the tests and exits
+ singleRun: false,
+
+ // Concurrency level
+ // how many browser should be started simultaneous
+ concurrency: Infinity
+ })
+}
diff --git a/node_modules/mquery/node_modules/debug/node.js b/node_modules/mquery/node_modules/debug/node.js
new file mode 100644
index 0000000..7fc36fe
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/node.js
@@ -0,0 +1 @@
+module.exports = require('./src/node');
diff --git a/node_modules/mquery/node_modules/debug/package.json b/node_modules/mquery/node_modules/debug/package.json
new file mode 100644
index 0000000..efcf652
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/package.json
@@ -0,0 +1,122 @@
+{
+ "_args": [
+ [
+ "debug@3.1.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mquery"
+ ]
+ ],
+ "_from": "debug@3.1.0",
+ "_id": "debug@3.1.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mquery/debug",
+ "_nodeVersion": "8.4.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/debug-3.1.0.tgz_1506453230282_0.13498495938256383"
+ },
+ "_npmUser": {
+ "email": "nathan@tootallnate.net",
+ "name": "tootallnate"
+ },
+ "_npmVersion": "5.3.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "debug",
+ "raw": "debug@3.1.0",
+ "rawSpec": "3.1.0",
+ "scope": null,
+ "spec": "3.1.0",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mquery"
+ ],
+ "_resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "_shasum": "5bb5a0672628b64149566ba16819e61518c67261",
+ "_shrinkwrap": null,
+ "_spec": "debug@3.1.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mquery",
+ "author": {
+ "email": "tj@vision-media.ca",
+ "name": "TJ Holowaychuk"
+ },
+ "browser": "./src/browser.js",
+ "bugs": {
+ "url": "https://github.com/visionmedia/debug/issues"
+ },
+ "contributors": [
+ {
+ "name": "Nathan Rajlich",
+ "email": "nathan@tootallnate.net",
+ "url": "http://n8.io"
+ },
+ {
+ "name": "Andrew Rhyne",
+ "email": "rhyneandrew@gmail.com"
+ }
+ ],
+ "dependencies": {
+ "ms": "2.0.0"
+ },
+ "description": "small debugging utility",
+ "devDependencies": {
+ "browserify": "14.4.0",
+ "chai": "^3.5.0",
+ "concurrently": "^3.1.0",
+ "coveralls": "^2.11.15",
+ "eslint": "^3.12.1",
+ "istanbul": "^0.4.5",
+ "karma": "^1.3.0",
+ "karma-chai": "^0.1.0",
+ "karma-mocha": "^1.3.0",
+ "karma-phantomjs-launcher": "^1.0.2",
+ "karma-sinon": "^1.0.5",
+ "mocha": "^3.2.0",
+ "mocha-lcov-reporter": "^1.2.0",
+ "rimraf": "^2.5.4",
+ "sinon": "^1.17.6",
+ "sinon-chai": "^2.8.0"
+ },
+ "directories": {},
+ "dist": {
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "shasum": "5bb5a0672628b64149566ba16819e61518c67261",
+ "tarball": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz"
+ },
+ "gitHead": "f073e056f33efdd5b311381eb6bca2bc850745bf",
+ "homepage": "https://github.com/visionmedia/debug#readme",
+ "keywords": [
+ "debug",
+ "debugger",
+ "log"
+ ],
+ "license": "MIT",
+ "main": "./src/index.js",
+ "maintainers": [
+ {
+ "name": "thebigredgeek",
+ "email": "rhyneandrew@gmail.com"
+ },
+ {
+ "name": "kolban",
+ "email": "kolban1@kolban.com"
+ },
+ {
+ "name": "tootallnate",
+ "email": "nathan@tootallnate.net"
+ },
+ {
+ "name": "tjholowaychuk",
+ "email": "tj@vision-media.ca"
+ }
+ ],
+ "name": "debug",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/visionmedia/debug.git"
+ },
+ "version": "3.1.0"
+}
diff --git a/node_modules/mquery/node_modules/debug/src/browser.js b/node_modules/mquery/node_modules/debug/src/browser.js
new file mode 100644
index 0000000..f5149ff
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/src/browser.js
@@ -0,0 +1,195 @@
+/**
+ * This is the web browser implementation of `debug()`.
+ *
+ * Expose `debug()` as the module.
+ */
+
+exports = module.exports = require('./debug');
+exports.log = log;
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+exports.storage = 'undefined' != typeof chrome
+ && 'undefined' != typeof chrome.storage
+ ? chrome.storage.local
+ : localstorage();
+
+/**
+ * Colors.
+ */
+
+exports.colors = [
+ '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC',
+ '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF',
+ '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC',
+ '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF',
+ '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC',
+ '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033',
+ '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366',
+ '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933',
+ '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC',
+ '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF',
+ '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'
+];
+
+/**
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+ * and the Firebug extension (any Firefox version) are known
+ * to support "%c" CSS customizations.
+ *
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
+ */
+
+function useColors() {
+ // NB: In an Electron preload script, document will be defined but not fully
+ // initialized. Since we know we're in Chrome, we'll just detect this case
+ // explicitly
+ if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
+ return true;
+ }
+
+ // Internet Explorer and Edge do not support colors.
+ if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+ return false;
+ }
+
+ // is webkit? http://stackoverflow.com/a/16459606/376773
+ // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+ return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
+ // is firebug? http://stackoverflow.com/a/398120/376773
+ (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
+ // is firefox >= v31?
+ // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
+ // double check webkit in userAgent just in case we are in a worker
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
+}
+
+/**
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+ */
+
+exports.formatters.j = function(v) {
+ try {
+ return JSON.stringify(v);
+ } catch (err) {
+ return '[UnexpectedJSONParseError]: ' + err.message;
+ }
+};
+
+
+/**
+ * Colorize log arguments if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+ var useColors = this.useColors;
+
+ args[0] = (useColors ? '%c' : '')
+ + this.namespace
+ + (useColors ? ' %c' : ' ')
+ + args[0]
+ + (useColors ? '%c ' : ' ')
+ + '+' + exports.humanize(this.diff);
+
+ if (!useColors) return;
+
+ var c = 'color: ' + this.color;
+ args.splice(1, 0, c, 'color: inherit')
+
+ // the final "%c" is somewhat tricky, because there could be other
+ // arguments passed either before or after the %c, so we need to
+ // figure out the correct index to insert the CSS into
+ var index = 0;
+ var lastC = 0;
+ args[0].replace(/%[a-zA-Z%]/g, function(match) {
+ if ('%%' === match) return;
+ index++;
+ if ('%c' === match) {
+ // we only are interested in the *last* %c
+ // (the user may have provided their own)
+ lastC = index;
+ }
+ });
+
+ args.splice(lastC, 0, c);
+}
+
+/**
+ * Invokes `console.log()` when available.
+ * No-op when `console.log` is not a "function".
+ *
+ * @api public
+ */
+
+function log() {
+ // this hackery is required for IE8/9, where
+ // the `console.log` function doesn't have 'apply'
+ return 'object' === typeof console
+ && console.log
+ && Function.prototype.apply.call(console.log, console, arguments);
+}
+
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+
+function save(namespaces) {
+ try {
+ if (null == namespaces) {
+ exports.storage.removeItem('debug');
+ } else {
+ exports.storage.debug = namespaces;
+ }
+ } catch(e) {}
+}
+
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+
+function load() {
+ var r;
+ try {
+ r = exports.storage.debug;
+ } catch(e) {}
+
+ // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+ if (!r && typeof process !== 'undefined' && 'env' in process) {
+ r = process.env.DEBUG;
+ }
+
+ return r;
+}
+
+/**
+ * Enable namespaces listed in `localStorage.debug` initially.
+ */
+
+exports.enable(load());
+
+/**
+ * Localstorage attempts to return the localstorage.
+ *
+ * This is necessary because safari throws
+ * when a user disables cookies/localstorage
+ * and you attempt to access it.
+ *
+ * @return {LocalStorage}
+ * @api private
+ */
+
+function localstorage() {
+ try {
+ return window.localStorage;
+ } catch (e) {}
+}
diff --git a/node_modules/mquery/node_modules/debug/src/debug.js b/node_modules/mquery/node_modules/debug/src/debug.js
new file mode 100644
index 0000000..77e6384
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/src/debug.js
@@ -0,0 +1,225 @@
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ *
+ * Expose `debug()` as the module.
+ */
+
+exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
+exports.coerce = coerce;
+exports.disable = disable;
+exports.enable = enable;
+exports.enabled = enabled;
+exports.humanize = require('ms');
+
+/**
+ * Active `debug` instances.
+ */
+exports.instances = [];
+
+/**
+ * The currently active debug mode names, and names to skip.
+ */
+
+exports.names = [];
+exports.skips = [];
+
+/**
+ * Map of special "%n" handling functions, for the debug "format" argument.
+ *
+ * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+ */
+
+exports.formatters = {};
+
+/**
+ * Select a color.
+ * @param {String} namespace
+ * @return {Number}
+ * @api private
+ */
+
+function selectColor(namespace) {
+ var hash = 0, i;
+
+ for (i in namespace) {
+ hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
+ hash |= 0; // Convert to 32bit integer
+ }
+
+ return exports.colors[Math.abs(hash) % exports.colors.length];
+}
+
+/**
+ * Create a debugger with the given `namespace`.
+ *
+ * @param {String} namespace
+ * @return {Function}
+ * @api public
+ */
+
+function createDebug(namespace) {
+
+ var prevTime;
+
+ function debug() {
+ // disabled?
+ if (!debug.enabled) return;
+
+ var self = debug;
+
+ // set `diff` timestamp
+ var curr = +new Date();
+ var ms = curr - (prevTime || curr);
+ self.diff = ms;
+ self.prev = prevTime;
+ self.curr = curr;
+ prevTime = curr;
+
+ // turn the `arguments` into a proper Array
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; i++) {
+ args[i] = arguments[i];
+ }
+
+ args[0] = exports.coerce(args[0]);
+
+ if ('string' !== typeof args[0]) {
+ // anything else let's inspect with %O
+ args.unshift('%O');
+ }
+
+ // apply any `formatters` transformations
+ var index = 0;
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
+ // if we encounter an escaped % then don't increase the array index
+ if (match === '%%') return match;
+ index++;
+ var formatter = exports.formatters[format];
+ if ('function' === typeof formatter) {
+ var val = args[index];
+ match = formatter.call(self, val);
+
+ // now we need to remove `args[index]` since it's inlined in the `format`
+ args.splice(index, 1);
+ index--;
+ }
+ return match;
+ });
+
+ // apply env-specific formatting (colors, etc.)
+ exports.formatArgs.call(self, args);
+
+ var logFn = debug.log || exports.log || console.log.bind(console);
+ logFn.apply(self, args);
+ }
+
+ debug.namespace = namespace;
+ debug.enabled = exports.enabled(namespace);
+ debug.useColors = exports.useColors();
+ debug.color = selectColor(namespace);
+ debug.destroy = destroy;
+
+ // env-specific initialization logic for debug instances
+ if ('function' === typeof exports.init) {
+ exports.init(debug);
+ }
+
+ exports.instances.push(debug);
+
+ return debug;
+}
+
+function destroy () {
+ var index = exports.instances.indexOf(this);
+ if (index !== -1) {
+ exports.instances.splice(index, 1);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Enables a debug mode by namespaces. This can include modes
+ * separated by a colon and wildcards.
+ *
+ * @param {String} namespaces
+ * @api public
+ */
+
+function enable(namespaces) {
+ exports.save(namespaces);
+
+ exports.names = [];
+ exports.skips = [];
+
+ var i;
+ var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+ var len = split.length;
+
+ for (i = 0; i < len; i++) {
+ if (!split[i]) continue; // ignore empty strings
+ namespaces = split[i].replace(/\*/g, '.*?');
+ if (namespaces[0] === '-') {
+ exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+ } else {
+ exports.names.push(new RegExp('^' + namespaces + '$'));
+ }
+ }
+
+ for (i = 0; i < exports.instances.length; i++) {
+ var instance = exports.instances[i];
+ instance.enabled = exports.enabled(instance.namespace);
+ }
+}
+
+/**
+ * Disable debug output.
+ *
+ * @api public
+ */
+
+function disable() {
+ exports.enable('');
+}
+
+/**
+ * Returns true if the given mode name is enabled, false otherwise.
+ *
+ * @param {String} name
+ * @return {Boolean}
+ * @api public
+ */
+
+function enabled(name) {
+ if (name[name.length - 1] === '*') {
+ return true;
+ }
+ var i, len;
+ for (i = 0, len = exports.skips.length; i < len; i++) {
+ if (exports.skips[i].test(name)) {
+ return false;
+ }
+ }
+ for (i = 0, len = exports.names.length; i < len; i++) {
+ if (exports.names[i].test(name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Coerce `val`.
+ *
+ * @param {Mixed} val
+ * @return {Mixed}
+ * @api private
+ */
+
+function coerce(val) {
+ if (val instanceof Error) return val.stack || val.message;
+ return val;
+}
diff --git a/node_modules/mquery/node_modules/debug/src/index.js b/node_modules/mquery/node_modules/debug/src/index.js
new file mode 100644
index 0000000..cabcbcd
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/src/index.js
@@ -0,0 +1,10 @@
+/**
+ * Detect Electron renderer process, which is node, but we should
+ * treat as a browser.
+ */
+
+if (typeof process === 'undefined' || process.type === 'renderer') {
+ module.exports = require('./browser.js');
+} else {
+ module.exports = require('./node.js');
+}
diff --git a/node_modules/mquery/node_modules/debug/src/node.js b/node_modules/mquery/node_modules/debug/src/node.js
new file mode 100644
index 0000000..d666fb9
--- /dev/null
+++ b/node_modules/mquery/node_modules/debug/src/node.js
@@ -0,0 +1,186 @@
+/**
+ * Module dependencies.
+ */
+
+var tty = require('tty');
+var util = require('util');
+
+/**
+ * This is the Node.js implementation of `debug()`.
+ *
+ * Expose `debug()` as the module.
+ */
+
+exports = module.exports = require('./debug');
+exports.init = init;
+exports.log = log;
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+
+/**
+ * Colors.
+ */
+
+exports.colors = [ 6, 2, 3, 4, 5, 1 ];
+
+try {
+ var supportsColor = require('supports-color');
+ if (supportsColor && supportsColor.level >= 2) {
+ exports.colors = [
+ 20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62, 63, 68,
+ 69, 74, 75, 76, 77, 78, 79, 80, 81, 92, 93, 98, 99, 112, 113, 128, 129, 134,
+ 135, 148, 149, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 178, 179, 184, 185, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 214, 215, 220, 221
+ ];
+ }
+} catch (err) {
+ // swallow - we only care if `supports-color` is available; it doesn't have to be.
+}
+
+/**
+ * Build up the default `inspectOpts` object from the environment variables.
+ *
+ * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
+ */
+
+exports.inspectOpts = Object.keys(process.env).filter(function (key) {
+ return /^debug_/i.test(key);
+}).reduce(function (obj, key) {
+ // camel-case
+ var prop = key
+ .substring(6)
+ .toLowerCase()
+ .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() });
+
+ // coerce string value into JS value
+ var val = process.env[key];
+ if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
+ else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
+ else if (val === 'null') val = null;
+ else val = Number(val);
+
+ obj[prop] = val;
+ return obj;
+}, {});
+
+/**
+ * Is stdout a TTY? Colored output is enabled when `true`.
+ */
+
+function useColors() {
+ return 'colors' in exports.inspectOpts
+ ? Boolean(exports.inspectOpts.colors)
+ : tty.isatty(process.stderr.fd);
+}
+
+/**
+ * Map %o to `util.inspect()`, all on a single line.
+ */
+
+exports.formatters.o = function(v) {
+ this.inspectOpts.colors = this.useColors;
+ return util.inspect(v, this.inspectOpts)
+ .split('\n').map(function(str) {
+ return str.trim()
+ }).join(' ');
+};
+
+/**
+ * Map %o to `util.inspect()`, allowing multiple lines if needed.
+ */
+
+exports.formatters.O = function(v) {
+ this.inspectOpts.colors = this.useColors;
+ return util.inspect(v, this.inspectOpts);
+};
+
+/**
+ * Adds ANSI color escape codes if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+ var name = this.namespace;
+ var useColors = this.useColors;
+
+ if (useColors) {
+ var c = this.color;
+ var colorCode = '\u001b[3' + (c < 8 ? c : '8;5;' + c);
+ var prefix = ' ' + colorCode + ';1m' + name + ' ' + '\u001b[0m';
+
+ args[0] = prefix + args[0].split('\n').join('\n' + prefix);
+ args.push(colorCode + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
+ } else {
+ args[0] = getDate() + name + ' ' + args[0];
+ }
+}
+
+function getDate() {
+ if (exports.inspectOpts.hideDate) {
+ return '';
+ } else {
+ return new Date().toISOString() + ' ';
+ }
+}
+
+/**
+ * Invokes `util.format()` with the specified arguments and writes to stderr.
+ */
+
+function log() {
+ return process.stderr.write(util.format.apply(util, arguments) + '\n');
+}
+
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+
+function save(namespaces) {
+ if (null == namespaces) {
+ // If you set a process.env field to null or undefined, it gets cast to the
+ // string 'null' or 'undefined'. Just delete instead.
+ delete process.env.DEBUG;
+ } else {
+ process.env.DEBUG = namespaces;
+ }
+}
+
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+
+function load() {
+ return process.env.DEBUG;
+}
+
+/**
+ * Init logic for `debug` instances.
+ *
+ * Create a new `inspectOpts` object in case `useColors` is set
+ * differently for a particular `debug` instance.
+ */
+
+function init (debug) {
+ debug.inspectOpts = {};
+
+ var keys = Object.keys(exports.inspectOpts);
+ for (var i = 0; i < keys.length; i++) {
+ debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
+ }
+}
+
+/**
+ * Enable namespaces listed in `process.env.DEBUG` initially.
+ */
+
+exports.enable(load());
diff --git a/node_modules/mquery/package.json b/node_modules/mquery/package.json
new file mode 100644
index 0000000..9c21774
--- /dev/null
+++ b/node_modules/mquery/package.json
@@ -0,0 +1,150 @@
+{
+ "_args": [
+ [
+ "mquery@3.2.2",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "mquery@3.2.2",
+ "_hasShrinkwrap": false,
+ "_id": "mquery@3.2.2",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/mquery",
+ "_nodeVersion": "8.9.4",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mquery_3.2.2_1569174208916_0.691751805301654"
+ },
+ "_npmUser": {
+ "email": "val@karpov.io",
+ "name": "vkarpov15"
+ },
+ "_npmVersion": "5.6.0",
+ "_phantomChildren": {
+ "ms": "2.0.0"
+ },
+ "_requested": {
+ "name": "mquery",
+ "raw": "mquery@3.2.2",
+ "rawSpec": "3.2.2",
+ "scope": null,
+ "spec": "3.2.2",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
+ "_shasum": "e1383a3951852ce23e37f619a9b350f1fb3664e7",
+ "_shrinkwrap": null,
+ "_spec": "mquery@3.2.2",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "Aaron Heckmann"
+ },
+ "bugs": {
+ "url": "https://github.com/aheckmann/mquery/issues/new"
+ },
+ "dependencies": {
+ "bluebird": "3.5.1",
+ "debug": "3.1.0",
+ "regexp-clone": "^1.0.0",
+ "safe-buffer": "5.1.2",
+ "sliced": "1.0.1"
+ },
+ "description": "Expressive query building for MongoDB",
+ "devDependencies": {
+ "eslint": "5.x",
+ "mocha": "4.1.0",
+ "mongodb": "3.1.1"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 20,
+ "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdh7LBCRA9TVsSAnZWagAAaqwQAKAvwKlvGfwhp52gfQGx\n6J07o1XiSxD9SMeKFH/ynRzq+QfIG8pTgE2KwHDdCJ3VPg9VuOmmGG1agfQ3\ncHnP30kJAiJ1kQVWDuS5e5Ep+SSqBBVma15BCjadulKF6XsT/ckFh1KjAr0W\n43CbmW+4fhfmgKWdWGpKpqMRUUcD/KR7RdzNKddRk3Jw+24LCi6HxvWvaSZ2\nuQ04RnE+hjwpQXtKQ3VfHeYYsQ+1TYB3EW8QUhiOv/eKimVJR3RbyOlj+FLT\n3sNu5/iXbSfQnJwdSmJBMNqNWAWFt3raMAtXzHwEkePMQikWJAC2VloBcaw8\nvX2G1Tt0DanBp12VaipzF2EmEAHRcnoy8PWKV1OVrvT0OZeMLOzgKubw6mK6\nlW/XfNO9Cyybg8QbKwvjo0LI9huEW2MrYdw3UFfEAgLfDYTDH4bGKndmO/gX\nNAR2JGSQP68PAfXYNUmoLrcK7Pq9O08J3jYXvXKNb1q6h5IzOQ/5Mu8wEr6N\nqq88UtNa+61kSU4YRUC0cNVV8d8K23hVNMmIt8YGp4Hv90MVUzY3SqOExGec\ntFsyADf3YcloB5xquyJucCmYibHv2ZN0u78NN4tnpMPwL8Y946W2nDYv/N93\n7DPXEvT9XOX5MZcC1JS1MI3zSW8jIBneO10TPms3l2IMLTxQoEqbxNjUK0T9\nH5Nb\r\n=cwY4\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "e1383a3951852ce23e37f619a9b350f1fb3664e7",
+ "tarball": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
+ "unpackedSize": 246135
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "eslintConfig": {
+ "env": {
+ "es6": false,
+ "mocha": true,
+ "node": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 5
+ },
+ "rules": {
+ "comma-style": "error",
+ "consistent-this": [
+ "_this",
+ "error"
+ ],
+ "func-call-spacing": "error",
+ "indent": [
+ 2,
+ {
+ "SwitchCase": 1,
+ "VariableDeclarator": 2
+ },
+ "error"
+ ],
+ "keyword-spacing": "error",
+ "no-console": "off",
+ "no-multi-spaces": "error",
+ "no-trailing-spaces": "error",
+ "quotes": [
+ "error",
+ "single"
+ ],
+ "semi": "error",
+ "space-before-blocks": "error",
+ "space-before-function-paren": [
+ "error",
+ "never"
+ ],
+ "space-infix-ops": "error",
+ "space-unary-ops": "error"
+ }
+ },
+ "gitHead": "6d3e0c758917206e56448b572cc1cdbd7394acff",
+ "homepage": "https://github.com/aheckmann/mquery/",
+ "keywords": [
+ "builder",
+ "mongodb",
+ "query"
+ ],
+ "license": "MIT",
+ "main": "lib/mquery.js",
+ "maintainers": [
+ {
+ "name": "aaron",
+ "email": "aaron.heckmann+github@gmail.com"
+ },
+ {
+ "name": "vkarpov15",
+ "email": "val@karpov.io"
+ }
+ ],
+ "name": "mquery",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aheckmann/mquery.git"
+ },
+ "scripts": {
+ "fix-lint": "eslint . --fix",
+ "lint": "eslint .",
+ "test": "mocha test/index.js test/*.test.js"
+ },
+ "version": "3.2.2"
+}
diff --git a/node_modules/mquery/test/collection/browser.js b/node_modules/mquery/test/collection/browser.js
new file mode 100644
index 0000000..e69de29
diff --git a/node_modules/mquery/test/collection/mongo.js b/node_modules/mquery/test/collection/mongo.js
new file mode 100644
index 0000000..e69de29
diff --git a/node_modules/mquery/test/collection/node.js b/node_modules/mquery/test/collection/node.js
new file mode 100644
index 0000000..8ac380b
--- /dev/null
+++ b/node_modules/mquery/test/collection/node.js
@@ -0,0 +1,28 @@
+
+var assert = require('assert');
+var mongo = require('mongodb');
+
+var uri = process.env.MQUERY_URI || 'mongodb://localhost/mquery';
+var client;
+var db;
+
+exports.getCollection = function(cb) {
+ mongo.MongoClient.connect(uri, function(err, _client) {
+ assert.ifError(err);
+ client = _client;
+ db = client.db();
+
+ var collection = db.collection('stuff');
+
+ // clean test db before starting
+ db.dropDatabase(function() {
+ cb(null, collection);
+ });
+ });
+};
+
+exports.dropCollection = function(cb) {
+ db.dropDatabase(function() {
+ client.close(cb);
+ });
+};
diff --git a/node_modules/mquery/test/env.js b/node_modules/mquery/test/env.js
new file mode 100644
index 0000000..38385b0
--- /dev/null
+++ b/node_modules/mquery/test/env.js
@@ -0,0 +1,21 @@
+
+var env = require('../').env;
+
+console.log('environment: %s', env.type);
+
+var col;
+switch (env.type) {
+ case 'node':
+ col = require('./collection/node');
+ break;
+ case 'mongo':
+ col = require('./collection/mongo');
+ break;
+ case 'browser':
+ col = require('./collection/browser');
+ break;
+ default:
+ throw new Error('missing collection implementation for environment: ' + env.type);
+}
+
+module.exports = exports = col;
diff --git a/node_modules/mquery/test/index.js b/node_modules/mquery/test/index.js
new file mode 100644
index 0000000..44adb17
--- /dev/null
+++ b/node_modules/mquery/test/index.js
@@ -0,0 +1,3076 @@
+var mquery = require('../');
+var assert = require('assert');
+
+/* global Map */
+
+describe('mquery', function() {
+ var col;
+
+ before(function(done) {
+ // get the env specific collection interface
+ require('./env').getCollection(function(err, collection) {
+ assert.ifError(err);
+ col = collection;
+ done();
+ });
+ });
+
+ after(function(done) {
+ require('./env').dropCollection(done);
+ });
+
+ describe('mquery', function() {
+ it('is a function', function() {
+ assert.equal('function', typeof mquery);
+ });
+ it('creates instances with the `new` keyword', function() {
+ assert.ok(mquery() instanceof mquery);
+ });
+ describe('defaults', function() {
+ it('are set', function() {
+ var m = mquery();
+ assert.strictEqual(undefined, m.op);
+ assert.deepEqual({}, m.options);
+ });
+ });
+ describe('criteria', function() {
+ it('if collection-like is used as collection', function() {
+ var m = mquery(col);
+ assert.equal(col, m._collection.collection);
+ });
+ it('non-collection-like is used as criteria', function() {
+ var m = mquery({ works: true });
+ assert.ok(!m._collection);
+ assert.deepEqual({ works: true }, m._conditions);
+ });
+ });
+ describe('options', function() {
+ it('are merged when passed', function() {
+ var m;
+ m = mquery(col, { safe: true });
+ assert.deepEqual({ safe: true }, m.options);
+ m = mquery({ name: 'mquery' }, { safe: true });
+ assert.deepEqual({ safe: true }, m.options);
+ });
+ });
+ });
+
+ describe('toConstructor', function() {
+ it('creates subclasses of mquery', function() {
+ var opts = { safe: { w: 'majority' }, readPreference: 'p' };
+ var match = { name: 'test', count: { $gt: 101 }};
+ var select = { name: 1, count: 0 };
+ var update = { $set: { x: true }};
+ var path = 'street';
+
+ var q = mquery().setOptions(opts);
+ q.where(match);
+ q.select(select);
+ q.update(update);
+ q.where(path);
+ q.find();
+
+ var M = q.toConstructor();
+ var m = M();
+
+ assert.ok(m instanceof mquery);
+ assert.deepEqual(opts, m.options);
+ assert.deepEqual(match, m._conditions);
+ assert.deepEqual(select, m._fields);
+ assert.deepEqual(update, m._update);
+ assert.equal(path, m._path);
+ assert.equal('find', m.op);
+ });
+ });
+
+ describe('setOptions', function() {
+ it('calls associated methods', function() {
+ var m = mquery();
+ assert.equal(m._collection, null);
+ m.setOptions({ collection: col });
+ assert.equal(m._collection.collection, col);
+ });
+ it('directly sets option when no method exists', function() {
+ var m = mquery();
+ assert.equal(m.options.woot, null);
+ m.setOptions({ woot: 'yay' });
+ assert.equal(m.options.woot, 'yay');
+ });
+ it('is chainable', function() {
+ var m = mquery(),
+ n;
+
+ n = m.setOptions();
+ assert.equal(m, n);
+ n = m.setOptions({ x: 1 });
+ assert.equal(m, n);
+ });
+ });
+
+ describe('collection', function() {
+ it('sets the _collection', function() {
+ var m = mquery();
+ m.collection(col);
+ assert.equal(m._collection.collection, col);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ var n = m.collection(col);
+ assert.equal(m, n);
+ });
+ });
+
+ describe('$where', function() {
+ it('sets the $where condition', function() {
+ var m = mquery();
+ function go() {}
+ m.$where(go);
+ assert.ok(go === m._conditions.$where);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ var n = m.$where('x');
+ assert.equal(m, n);
+ });
+ });
+
+ describe('where', function() {
+ it('without arguments', function() {
+ var m = mquery();
+ m.where();
+ assert.deepEqual({}, m._conditions);
+ });
+ it('with non-string/object argument', function() {
+ var m = mquery();
+
+ assert.throws(function() {
+ m.where([]);
+ }, /path must be a string or object/);
+ });
+ describe('with one argument', function() {
+ it('that is an object', function() {
+ var m = mquery();
+ m.where({ name: 'flawed' });
+ assert.strictEqual(m._conditions.name, 'flawed');
+ });
+ it('that is a query', function() {
+ var m = mquery({ name: 'first' });
+ var n = mquery({ name: 'changed' });
+ m.where(n);
+ assert.strictEqual(m._conditions.name, 'changed');
+ });
+ it('that is a string', function() {
+ var m = mquery();
+ m.where('name');
+ assert.equal('name', m._path);
+ assert.strictEqual(m._conditions.name, undefined);
+ });
+ });
+ it('with two arguments', function() {
+ var m = mquery();
+ m.where('name', 'The Great Pumpkin');
+ assert.equal('name', m._path);
+ assert.strictEqual(m._conditions.name, 'The Great Pumpkin');
+ });
+ it('is chainable', function() {
+ var m = mquery(),
+ n;
+
+ n = m.where('x', 'y');
+ assert.equal(m, n);
+ n = m.where();
+ assert.equal(m, n);
+ });
+ });
+ describe('equals', function() {
+ it('must be called after where()', function() {
+ var m = mquery();
+ assert.throws(function() {
+ m.equals();
+ }, /must be used after where/);
+ });
+ it('sets value of path set with where()', function() {
+ var m = mquery();
+ m.where('age').equals(1000);
+ assert.deepEqual({ age: 1000 }, m._conditions);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ var n = m.where('x').equals(3);
+ assert.equal(m, n);
+ });
+ });
+ describe('eq', function() {
+ it('is alias of equals', function() {
+ var m = mquery();
+ m.where('age').eq(1000);
+ assert.deepEqual({ age: 1000 }, m._conditions);
+ });
+ });
+ describe('or', function() {
+ it('pushes onto the internal $or condition', function() {
+ var m = mquery();
+ m.or({ 'Nightmare Before Christmas': true });
+ assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$or);
+ });
+ it('allows passing arrays', function() {
+ var m = mquery();
+ var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }];
+ m.or(arg);
+ assert.deepEqual(arg, m._conditions.$or);
+ });
+ it('allows calling multiple times', function() {
+ var m = mquery();
+ var arg = [{ looper: true }, { x: 1 }];
+ m.or(arg);
+ m.or({ y: 1 });
+ m.or([{ w: 'oo' }, { z: 'oo'} ]);
+ assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$or);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ m.or({ o: 'k'}).where('name', 'table');
+ assert.deepEqual({ name: 'table', $or: [{ o: 'k' }] }, m._conditions);
+ });
+ });
+
+ describe('nor', function() {
+ it('pushes onto the internal $nor condition', function() {
+ var m = mquery();
+ m.nor({ 'Nightmare Before Christmas': true });
+ assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$nor);
+ });
+ it('allows passing arrays', function() {
+ var m = mquery();
+ var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }];
+ m.nor(arg);
+ assert.deepEqual(arg, m._conditions.$nor);
+ });
+ it('allows calling multiple times', function() {
+ var m = mquery();
+ var arg = [{ looper: true }, { x: 1 }];
+ m.nor(arg);
+ m.nor({ y: 1 });
+ m.nor([{ w: 'oo' }, { z: 'oo'} ]);
+ assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$nor);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ m.nor({ o: 'k'}).where('name', 'table');
+ assert.deepEqual({ name: 'table', $nor: [{ o: 'k' }] }, m._conditions);
+ });
+ });
+
+ describe('and', function() {
+ it('pushes onto the internal $and condition', function() {
+ var m = mquery();
+ m.and({ 'Nightmare Before Christmas': true });
+ assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$and);
+ });
+ it('allows passing arrays', function() {
+ var m = mquery();
+ var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }];
+ m.and(arg);
+ assert.deepEqual(arg, m._conditions.$and);
+ });
+ it('allows calling multiple times', function() {
+ var m = mquery();
+ var arg = [{ looper: true }, { x: 1 }];
+ m.and(arg);
+ m.and({ y: 1 });
+ m.and([{ w: 'oo' }, { z: 'oo'} ]);
+ assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$and);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ m.and({ o: 'k'}).where('name', 'table');
+ assert.deepEqual({ name: 'table', $and: [{ o: 'k' }] }, m._conditions);
+ });
+ });
+
+ function generalCondition(type) {
+ return function() {
+ it('accepts 2 args', function() {
+ var m = mquery()[type]('count', 3);
+ var check = {};
+ check['$' + type] = 3;
+ assert.deepEqual(m._conditions.count, check);
+ });
+ it('uses previously set `where` path if 1 arg passed', function() {
+ var m = mquery().where('count')[type](3);
+ var check = {};
+ check['$' + type] = 3;
+ assert.deepEqual(m._conditions.count, check);
+ });
+ it('throws if 1 arg was passed but no previous `where` was used', function() {
+ assert.throws(function() {
+ mquery()[type](3);
+ }, /must be used after where/);
+ });
+ it('is chainable', function() {
+ var m = mquery().where('count')[type](3).where('x', 8);
+ var check = {x: 8, count: {}};
+ check.count['$' + type] = 3;
+ assert.deepEqual(m._conditions, check);
+ });
+ it('overwrites previous value', function() {
+ var m = mquery().where('count')[type](3)[type](8);
+ var check = {};
+ check['$' + type] = 8;
+ assert.deepEqual(m._conditions.count, check);
+ });
+ };
+ }
+
+ 'gt gte lt lte ne in nin regex size maxDistance minDistance'.split(' ').forEach(function(type) {
+ describe(type, generalCondition(type));
+ });
+
+ describe('mod', function() {
+ describe('with 1 argument', function() {
+ it('requires a previous where()', function() {
+ assert.throws(function() {
+ mquery().mod([30, 10]);
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('madmen').mod([10,20]);
+ assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }});
+ });
+ });
+
+ describe('with 2 arguments and second is non-Array', function() {
+ it('requires a previous where()', function() {
+ assert.throws(function() {
+ mquery().mod('x', 10);
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('madmen').mod(10, 20);
+ assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }});
+ });
+ });
+
+ it('with 2 arguments and second is an array', function() {
+ var m = mquery().mod('madmen', [10,20]);
+ assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }});
+ });
+
+ it('with 3 arguments', function() {
+ var m = mquery().mod('madmen', 10, 20);
+ assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }});
+ });
+
+ it('is chainable', function() {
+ var m = mquery().mod('madmen', 10, 20).where('x', 8);
+ var check = { madmen: { $mod: [10,20] }, x: 8};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+
+ describe('exists', function() {
+ it('with 0 args', function() {
+ it('throws if not used after where()', function() {
+ assert.throws(function() {
+ mquery().exists();
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('name').exists();
+ var check = { name: { $exists: true }};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+
+ describe('with 1 arg', function() {
+ describe('that is boolean', function() {
+ it('throws if not used after where()', function() {
+ assert.throws(function() {
+ mquery().exists();
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().exists('name', false);
+ var check = { name: { $exists: false }};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+ describe('that is not boolean', function() {
+ it('sets the value to `true`', function() {
+ var m = mquery().where('name').exists('yummy');
+ var check = { yummy: { $exists: true }};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+ });
+
+ describe('with 2 args', function() {
+ it('works', function() {
+ var m = mquery().exists('yummy', false);
+ var check = { yummy: { $exists: false }};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery().where('name').exists().find({ x: 1 });
+ var check = { name: { $exists: true }, x: 1};
+ assert.deepEqual(m._conditions, check);
+ });
+ });
+
+ describe('elemMatch', function() {
+ describe('with null/undefined first argument', function() {
+ assert.throws(function() {
+ mquery().elemMatch();
+ }, /Invalid argument/);
+ assert.throws(function() {
+ mquery().elemMatch(null);
+ }, /Invalid argument/);
+ assert.doesNotThrow(function() {
+ mquery().elemMatch('', {});
+ });
+ });
+
+ describe('with 1 argument', function() {
+ it('throws if not a function or object', function() {
+ assert.throws(function() {
+ mquery().elemMatch([]);
+ }, /Invalid argument/);
+ });
+
+ describe('that is an object', function() {
+ it('throws if no previous `where` was used', function() {
+ assert.throws(function() {
+ mquery().elemMatch({});
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('comment').elemMatch({ author: 'joe', votes: {$gte: 3 }});
+ assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions);
+ });
+ });
+ describe('that is a function', function() {
+ it('throws if no previous `where` was used', function() {
+ assert.throws(function() {
+ mquery().elemMatch(function() {});
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('comment').elemMatch(function(query) {
+ query.where({ author: 'joe', votes: {$gte: 3 }});
+ });
+ assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions);
+ });
+ });
+ });
+
+ describe('with 2 arguments', function() {
+ describe('and the 2nd is an object', function() {
+ it('works', function() {
+ var m = mquery().elemMatch('comment', { author: 'joe', votes: {$gte: 3 }});
+ assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions);
+ });
+ });
+ describe('and the 2nd is a function', function() {
+ it('works', function() {
+ var m = mquery().elemMatch('comment', function(query) {
+ query.where({ author: 'joe', votes: {$gte: 3 }});
+ });
+ assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions);
+ });
+ });
+ it('and the 2nd is not a function or object', function() {
+ assert.throws(function() {
+ mquery().elemMatch('comment', []);
+ }, /Invalid argument/);
+ });
+ });
+ });
+
+ describe('within', function() {
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m.where('a').within(), m);
+ });
+ describe('when called with arguments', function() {
+ it('must follow where()', function() {
+ assert.throws(function() {
+ mquery().within([]);
+ }, /must be used after where/);
+ });
+
+ describe('of length 1', function() {
+ it('throws if not a recognized shape', function() {
+ assert.throws(function() {
+ mquery().where('loc').within({});
+ }, /Invalid argument/);
+ assert.throws(function() {
+ mquery().where('loc').within(null);
+ }, /Invalid argument/);
+ });
+ it('delegates to circle when center exists', function() {
+ var m = mquery().where('loc').within({ center: [10,10], radius: 3 });
+ assert.deepEqual({ $geoWithin: {$center:[[10,10], 3]}}, m._conditions.loc);
+ });
+ it('delegates to box when exists', function() {
+ var m = mquery().where('loc').within({ box: [[10,10], [11,14]] });
+ assert.deepEqual({ $geoWithin: {$box:[[10,10], [11,14]]}}, m._conditions.loc);
+ });
+ it('delegates to polygon when exists', function() {
+ var m = mquery().where('loc').within({ polygon: [[10,10], [11,14],[10,9]] });
+ assert.deepEqual({ $geoWithin: {$polygon:[[10,10], [11,14],[10,9]]}}, m._conditions.loc);
+ });
+ it('delegates to geometry when exists', function() {
+ var m = mquery().where('loc').within({ type: 'Polygon', coordinates: [[10,10], [11,14],[10,9]] });
+ assert.deepEqual({ $geoWithin: {$geometry: {type:'Polygon', coordinates: [[10,10], [11,14],[10,9]]}}}, m._conditions.loc);
+ });
+ });
+
+ describe('of length 2', function() {
+ it('delegates to box()', function() {
+ var m = mquery().where('loc').within([1,2],[2,5]);
+ assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[2,5]]}});
+ });
+ });
+
+ describe('of length > 2', function() {
+ it('delegates to polygon()', function() {
+ var m = mquery().where('loc').within([1,2],[2,5],[2,4],[1,3]);
+ assert.deepEqual(m._conditions.loc, { $geoWithin: { $polygon: [[1,2],[2,5],[2,4],[1,3]]}});
+ });
+ });
+ });
+ });
+
+ describe('geoWithin', function() {
+ before(function() {
+ mquery.use$geoWithin = false;
+ });
+ after(function() {
+ mquery.use$geoWithin = true;
+ });
+ describe('when called with arguments', function() {
+ describe('of length 1', function() {
+ it('delegates to circle when center exists', function() {
+ var m = mquery().where('loc').within({ center: [10,10], radius: 3 });
+ assert.deepEqual({ $within: {$center:[[10,10], 3]}}, m._conditions.loc);
+ });
+ it('delegates to box when exists', function() {
+ var m = mquery().where('loc').within({ box: [[10,10], [11,14]] });
+ assert.deepEqual({ $within: {$box:[[10,10], [11,14]]}}, m._conditions.loc);
+ });
+ it('delegates to polygon when exists', function() {
+ var m = mquery().where('loc').within({ polygon: [[10,10], [11,14],[10,9]] });
+ assert.deepEqual({ $within: {$polygon:[[10,10], [11,14],[10,9]]}}, m._conditions.loc);
+ });
+ it('delegates to geometry when exists', function() {
+ var m = mquery().where('loc').within({ type: 'Polygon', coordinates: [[10,10], [11,14],[10,9]] });
+ assert.deepEqual({ $within: {$geometry: {type:'Polygon', coordinates: [[10,10], [11,14],[10,9]]}}}, m._conditions.loc);
+ });
+ });
+
+ describe('of length 2', function() {
+ it('delegates to box()', function() {
+ var m = mquery().where('loc').within([1,2],[2,5]);
+ assert.deepEqual(m._conditions.loc, { $within: { $box: [[1,2],[2,5]]}});
+ });
+ });
+
+ describe('of length > 2', function() {
+ it('delegates to polygon()', function() {
+ var m = mquery().where('loc').within([1,2],[2,5],[2,4],[1,3]);
+ assert.deepEqual(m._conditions.loc, { $within: { $polygon: [[1,2],[2,5],[2,4],[1,3]]}});
+ });
+ });
+ });
+ });
+
+ describe('box', function() {
+ describe('with 1 argument', function() {
+ it('throws', function() {
+ assert.throws(function() {
+ mquery().box('sometihng');
+ }, /Invalid argument/);
+ });
+ });
+ describe('with > 3 arguments', function() {
+ it('throws', function() {
+ assert.throws(function() {
+ mquery().box(1,2,3,4);
+ }, /Invalid argument/);
+ });
+ });
+
+ describe('with 2 arguments', function() {
+ it('throws if not used after where()', function() {
+ assert.throws(function() {
+ mquery().box([],[]);
+ }, /must be used after where/);
+ });
+ it('works', function() {
+ var m = mquery().where('loc').box([1,2],[3,4]);
+ assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[3,4]] }});
+ });
+ });
+
+ describe('with 3 arguments', function() {
+ it('works', function() {
+ var m = mquery().box('loc', [1,2],[3,4]);
+ assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[3,4]] }});
+ });
+ });
+ });
+
+ describe('polygon', function() {
+ describe('when first argument is not a string', function() {
+ it('throws if not used after where()', function() {
+ assert.throws(function() {
+ mquery().polygon({});
+ }, /must be used after where/);
+
+ assert.doesNotThrow(function() {
+ mquery().where('loc').polygon([1,2], [2,3], [3,6]);
+ });
+ });
+
+ it('assigns arguments to within polygon condition', function() {
+ var m = mquery().where('loc').polygon([1,2], [2,3], [3,6]);
+ assert.deepEqual(m._conditions, { loc: {$geoWithin: {$polygon: [[1,2],[2,3],[3,6]]}} });
+ });
+ });
+
+ describe('when first arg is a string', function() {
+ it('assigns remaining arguments to within polygon condition', function() {
+ var m = mquery().polygon('loc', [1,2], [2,3], [3,6]);
+ assert.deepEqual(m._conditions, { loc: {$geoWithin: {$polygon: [[1,2],[2,3],[3,6]]}} });
+ });
+ });
+ });
+
+ describe('circle', function() {
+ describe('with one arg', function() {
+ it('must follow where()', function() {
+ assert.throws(function() {
+ mquery().circle('x');
+ }, /must be used after where/);
+ assert.doesNotThrow(function() {
+ mquery().where('loc').circle({center:[0,0], radius: 3 });
+ });
+ });
+ it('works', function() {
+ var m = mquery().where('loc').circle({center:[0,0], radius: 3 });
+ assert.deepEqual(m._conditions, { loc: { $geoWithin: {$center: [[0,0],3] }}});
+ });
+ });
+ describe('with 3 args', function() {
+ it('throws', function() {
+ assert.throws(function() {
+ mquery().where('loc').circle(1,2,3);
+ }, /Invalid argument/);
+ });
+ });
+ describe('requires radius and center', function() {
+ assert.throws(function() {
+ mquery().circle('loc', { center: 1 });
+ }, /center and radius are required/);
+ assert.throws(function() {
+ mquery().circle('loc', { radius: 1 });
+ }, /center and radius are required/);
+ assert.doesNotThrow(function() {
+ mquery().circle('loc', { center: [1,2], radius: 1 });
+ });
+ });
+ });
+
+ describe('geometry', function() {
+ // within + intersects
+ var point = { type: 'Point', coordinates: [[0,0],[1,1]] };
+
+ it('must be called after within or intersects', function(done) {
+ assert.throws(function() {
+ mquery().where('a').geometry(point);
+ }, /must come after/);
+
+ assert.doesNotThrow(function() {
+ mquery().where('a').within().geometry(point);
+ });
+
+ assert.doesNotThrow(function() {
+ mquery().where('a').intersects().geometry(point);
+ });
+
+ done();
+ });
+
+ describe('when called with one argument', function() {
+ describe('after within()', function() {
+ it('and arg quacks like geoJSON', function(done) {
+ var m = mquery().where('a').within().geometry(point);
+ assert.deepEqual({ a: { $geoWithin: { $geometry: point }}}, m._conditions);
+ done();
+ });
+ });
+
+ describe('after intersects()', function() {
+ it('and arg quacks like geoJSON', function(done) {
+ var m = mquery().where('a').intersects().geometry(point);
+ assert.deepEqual({ a: { $geoIntersects: { $geometry: point }}}, m._conditions);
+ done();
+ });
+ });
+
+ it('and arg does not quack like geoJSON', function(done) {
+ assert.throws(function() {
+ mquery().where('b').within().geometry({type:1, coordinates:2});
+ }, /Invalid argument/);
+ done();
+ });
+ });
+
+ describe('when called with zero arguments', function() {
+ it('throws', function(done) {
+ assert.throws(function() {
+ mquery().where('a').within().geometry();
+ }, /Invalid argument/);
+
+ done();
+ });
+ });
+
+ describe('when called with more than one arguments', function() {
+ it('throws', function(done) {
+ assert.throws(function() {
+ mquery().where('a').within().geometry({type:'a',coordinates:[]}, 2);
+ }, /Invalid argument/);
+ done();
+ });
+ });
+ });
+
+ describe('intersects', function() {
+ it('must be used after where()', function(done) {
+ var m = mquery();
+ assert.throws(function() {
+ m.intersects();
+ }, /must be used after where/);
+ done();
+ });
+
+ it('sets geo comparison to "$intersects"', function(done) {
+ var n = mquery().where('a').intersects();
+ assert.equal('$geoIntersects', n._geoComparison);
+ done();
+ });
+
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m.where('a').intersects(), m);
+ });
+
+ it('calls geometry if argument quacks like geojson', function(done) {
+ var m = mquery();
+ var o = { type: 'LineString', coordinates: [[0,1],[3,40]] };
+ var ran = false;
+
+ m.geometry = function(arg) {
+ ran = true;
+ assert.deepEqual(o, arg);
+ };
+
+ m.where('a').intersects(o);
+ assert.ok(ran);
+
+ done();
+ });
+
+ it('throws if argument is not geometry-like', function(done) {
+ var m = mquery().where('a');
+
+ assert.throws(function() {
+ m.intersects(null);
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects(undefined);
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects(false);
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects({});
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects([]);
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects(function() {});
+ }, /Invalid argument/);
+
+ assert.throws(function() {
+ m.intersects(NaN);
+ }, /Invalid argument/);
+
+ done();
+ });
+ });
+
+ describe('near', function() {
+ // near nearSphere
+ describe('with 0 args', function() {
+ it('is compatible with geometry()', function(done) {
+ var q = mquery().where('x').near().geometry({ type: 'Point', coordinates: [180, 11] });
+ assert.deepEqual({ $near: {$geometry: {type:'Point', coordinates: [180,11]}}}, q._conditions.x);
+ done();
+ });
+ });
+
+ describe('with 1 arg', function() {
+ it('throws if not used after where()', function() {
+ assert.throws(function() {
+ mquery().near(1);
+ }, /must be used after where/);
+ });
+ it('does not throw if used after where()', function() {
+ assert.doesNotThrow(function() {
+ mquery().where('loc').near({center:[1,1]});
+ });
+ });
+ });
+ describe('with > 2 args', function() {
+ it('throws', function() {
+ assert.throws(function() {
+ mquery().near(1,2,3);
+ }, /Invalid argument/);
+ });
+ });
+
+ it('creates $geometry args for GeoJSON', function() {
+ var m = mquery().where('loc').near({ center: { type: 'Point', coordinates: [10,10] }});
+ assert.deepEqual({ $near: {$geometry: {type:'Point', coordinates: [10,10]}}}, m._conditions.loc);
+ });
+
+ it('expects `center`', function() {
+ assert.throws(function() {
+ mquery().near('loc', { maxDistance: 3 });
+ }, /center is required/);
+ assert.doesNotThrow(function() {
+ mquery().near('loc', { center: [3,4] });
+ });
+ });
+
+ it('accepts spherical conditions', function() {
+ var m = mquery().where('loc').near({ center: [1,2], spherical: true });
+ assert.deepEqual(m._conditions, { loc: { $nearSphere: [1,2]}});
+ });
+
+ it('is non-spherical by default', function() {
+ var m = mquery().where('loc').near({ center: [1,2] });
+ assert.deepEqual(m._conditions, { loc: { $near: [1,2]}});
+ });
+
+ it('supports maxDistance', function() {
+ var m = mquery().where('loc').near({ center: [1,2], maxDistance:4 });
+ assert.deepEqual(m._conditions, { loc: { $near: [1,2], $maxDistance: 4}});
+ });
+
+ it('supports minDistance', function() {
+ var m = mquery().where('loc').near({ center: [1,2], minDistance:4 });
+ assert.deepEqual(m._conditions, { loc: { $near: [1,2], $minDistance: 4}});
+ });
+
+ it('is chainable', function() {
+ var m = mquery().where('loc').near({ center: [1,2], maxDistance:4 }).find({ x: 1 });
+ assert.deepEqual(m._conditions, { loc: { $near: [1,2], $maxDistance: 4}, x: 1});
+ });
+
+ describe('supports passing GeoJSON, gh-13', function() {
+ it('with center', function() {
+ var m = mquery().where('loc').near({
+ center: { type: 'Point', coordinates: [1,1] },
+ maxDistance: 2
+ });
+
+ var expect = {
+ loc: {
+ $near: {
+ $geometry: {
+ type: 'Point',
+ coordinates : [1,1]
+ },
+ $maxDistance : 2
+ }
+ }
+ };
+
+ assert.deepEqual(m._conditions, expect);
+ });
+ });
+ });
+
+ // fields
+
+ describe('select', function() {
+ describe('with 0 args', function() {
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.select());
+ });
+ });
+
+ it('accepts an object', function() {
+ var o = { x: 1, y: 1 };
+ var m = mquery().select(o);
+ assert.deepEqual(m._fields, o);
+ });
+
+ it('accepts a string', function() {
+ var o = 'x -y';
+ var m = mquery().select(o);
+ assert.deepEqual(m._fields, { x: 1, y: 0 });
+ });
+
+ it('does accept an array', function() {
+ var o = ['x', '-y'];
+ var m = mquery().select(o);
+ assert.deepEqual(m._fields, { x: 1, y: 0 });
+ });
+
+ it('merges previous arguments', function() {
+ var o = { x: 1, y: 0, a: 1 };
+ var m = mquery().select(o);
+ m.select('z -u w').select({ x: 0 });
+ assert.deepEqual(m._fields, {
+ x: 0,
+ y: 0,
+ z: 1,
+ u: 0,
+ w: 1,
+ a: 1
+ });
+ });
+
+ it('rejects non-string, object, arrays', function() {
+ assert.throws(function() {
+ mquery().select(function() {});
+ }, /Invalid select\(\) argument/);
+ });
+
+ it('accepts arguments objects', function() {
+ var m = mquery();
+ function t() {
+ m.select(arguments);
+ assert.deepEqual(m._fields, { x: 1, y: 0 });
+ }
+ t('x', '-y');
+ });
+
+ noDistinct('select');
+ });
+
+ describe('selected', function() {
+ it('returns true when fields have been selected', function(done) {
+ var m;
+
+ m = mquery().select({ name: 1 });
+ assert.ok(m.selected());
+
+ m = mquery().select('name');
+ assert.ok(m.selected());
+
+ done();
+ });
+
+ it('returns false when no fields have been selected', function(done) {
+ var m = mquery();
+ assert.strictEqual(false, m.selected());
+ done();
+ });
+ });
+
+ describe('selectedInclusively', function() {
+ describe('returns false', function() {
+ it('when no fields have been selected', function(done) {
+ assert.strictEqual(false, mquery().selectedInclusively());
+ assert.equal(false, mquery().select({}).selectedInclusively());
+ done();
+ });
+ it('when any fields have been excluded', function(done) {
+ assert.strictEqual(false, mquery().select('-name').selectedInclusively());
+ assert.strictEqual(false, mquery().select({ name: 0 }).selectedInclusively());
+ assert.strictEqual(false, mquery().select('name bio -_id').selectedInclusively());
+ assert.strictEqual(false, mquery().select({ name: 1, _id: 0 }).selectedInclusively());
+ done();
+ });
+ it('when using $meta', function(done) {
+ assert.strictEqual(false, mquery().select({ name: { $meta: 'textScore' } }).selectedInclusively());
+ done();
+ });
+ });
+
+ describe('returns true', function() {
+ it('when fields have been included', function(done) {
+ assert.equal(true, mquery().select('name').selectedInclusively());
+ assert.equal(true, mquery().select({ name:1 }).selectedInclusively());
+ done();
+ });
+ });
+ });
+
+ describe('selectedExclusively', function() {
+ describe('returns false', function() {
+ it('when no fields have been selected', function(done) {
+ assert.equal(false, mquery().selectedExclusively());
+ assert.equal(false, mquery().select({}).selectedExclusively());
+ done();
+ });
+ it('when fields have only been included', function(done) {
+ assert.equal(false, mquery().select('name').selectedExclusively());
+ assert.equal(false, mquery().select({ name: 1 }).selectedExclusively());
+ done();
+ });
+ });
+
+ describe('returns true', function() {
+ it('when any field has been excluded', function(done) {
+ assert.equal(true, mquery().select('-name').selectedExclusively());
+ assert.equal(true, mquery().select({ name:0 }).selectedExclusively());
+ assert.equal(true, mquery().select('-_id').selectedExclusively());
+ assert.strictEqual(true, mquery().select('name bio -_id').selectedExclusively());
+ assert.strictEqual(true, mquery().select({ name: 1, _id: 0 }).selectedExclusively());
+ done();
+ });
+ });
+ });
+
+ describe('slice', function() {
+ describe('with 0 args', function() {
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.slice());
+ });
+ it('is a noop', function() {
+ var m = mquery().slice();
+ assert.deepEqual(m._fields, undefined);
+ });
+ });
+
+ describe('with 1 arg', function() {
+ it('throws if not called after where()', function() {
+ assert.throws(function() {
+ mquery().slice(1);
+ }, /must be used after where/);
+ assert.doesNotThrow(function() {
+ mquery().where('a').slice(1);
+ });
+ });
+ it('that is a number', function() {
+ var query = mquery();
+ query.where('collection').slice(5);
+ assert.deepEqual(query._fields, {collection: {$slice: 5}});
+ });
+ it('that is an array', function() {
+ var query = mquery();
+ query.where('collection').slice([5,10]);
+ assert.deepEqual(query._fields, {collection: {$slice: [5,10]}});
+ });
+ it('that is an object', function() {
+ var query = mquery();
+ query.slice({ collection: [5, 10] });
+ assert.deepEqual(query._fields, {collection: {$slice: [5,10]}});
+ });
+ });
+
+ describe('with 2 args', function() {
+ describe('and first is a number', function() {
+ it('throws if not called after where', function() {
+ assert.throws(function() {
+ mquery().slice(2,3);
+ }, /must be used after where/);
+ });
+ it('does not throw if used after where', function() {
+ var query = mquery();
+ query.where('collection').slice(2,3);
+ assert.deepEqual(query._fields, {collection: {$slice: [2,3]}});
+ });
+ });
+ it('and first is not a number', function() {
+ var query = mquery().slice('collection', [-5, 2]);
+ assert.deepEqual(query._fields, {collection: {$slice: [-5,2]}});
+ });
+ });
+
+ describe('with 3 args', function() {
+ it('works', function() {
+ var query = mquery();
+ query.slice('collection', 14, 10);
+ assert.deepEqual(query._fields, {collection: {$slice: [14, 10]}});
+ });
+ });
+
+ noDistinct('slice');
+ no('count', 'slice');
+ });
+
+ // options
+
+ describe('sort', function() {
+ describe('with 0 args', function() {
+ it('chains', function() {
+ var m = mquery();
+ assert.equal(m, m.sort());
+ });
+ it('has no affect', function() {
+ var m = mquery();
+ assert.equal(m.options.sort, undefined);
+ });
+ });
+
+ it('works', function() {
+ var query = mquery();
+ query.sort('a -c b');
+ assert.deepEqual(query.options.sort, { a : 1, b: 1, c : -1});
+
+ query = mquery();
+ query.sort({'a': 1, 'c': -1, 'b': 'asc', e: 'descending', f: 'ascending'});
+ assert.deepEqual(query.options.sort, {'a': 1, 'c': -1, 'b': 1, 'e': -1, 'f': 1});
+
+ query = mquery();
+ query.sort([['a', -1], ['c', 1], ['b', 'desc'], ['e', 'ascending'], ['f', 'descending']]);
+ assert.deepEqual(query.options.sort, [['a', -1], ['c', 1], ['b', -1], ['e', 1], ['f', -1]]);
+
+ query = mquery();
+ var e = undefined;
+ try {
+ query.sort([['a', 1], { 'b': 5 }]);
+ } catch (err) {
+ e = err;
+ }
+ assert.ok(e, 'uh oh. no error was thrown');
+ assert.equal(e.message, 'Invalid sort() argument, must be array of arrays');
+
+ query = mquery();
+ e = undefined;
+
+ try {
+ query.sort('a', 1, 'c', -1, 'b', 1);
+ } catch (err) {
+ e = err;
+ }
+ assert.ok(e, 'uh oh. no error was thrown');
+ assert.equal(e.message, 'Invalid sort() argument. Must be a string, object, or array.');
+ });
+
+ it('handles $meta sort options', function() {
+ var query = mquery();
+ query.sort({ score: { $meta : 'textScore' } });
+ assert.deepEqual(query.options.sort, { score : { $meta : 'textScore' } });
+ });
+
+ it('array syntax', function() {
+ var query = mquery();
+ query.sort([['field', 1], ['test', -1]]);
+ assert.deepEqual(query.options.sort, [['field', 1], ['test', -1]]);
+ });
+
+ it('throws with mixed array/object syntax', function() {
+ var query = mquery();
+ assert.throws(function() {
+ query.sort({ field: 1 }).sort([['test', -1]]);
+ }, /Can't mix sort syntaxes/);
+ assert.throws(function() {
+ query.sort([['field', 1]]).sort({ test: 1 });
+ }, /Can't mix sort syntaxes/);
+ });
+
+ it('works with maps', function() {
+ if (typeof Map === 'undefined') {
+ return this.skip();
+ }
+ var query = mquery();
+ query.sort(new Map().set('field', 1).set('test', -1));
+ assert.deepEqual(query.options.sort, new Map().set('field', 1).set('test', -1));
+ });
+ });
+
+ function simpleOption(type, options) {
+ describe(type, function() {
+ it('sets the ' + type + ' option', function() {
+ var m = mquery()[type](2);
+ var optionName = options.name || type;
+ assert.equal(2, m.options[optionName]);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m[type](3), m);
+ });
+
+ if (!options.distinct) noDistinct(type);
+ if (!options.count) no('count', type);
+ });
+ }
+
+ var negated = {
+ limit: {distinct: false, count: true},
+ skip: {distinct: false, count: true},
+ maxScan: {distinct: false, count: false},
+ batchSize: {distinct: false, count: false},
+ maxTime: {distinct: true, count: true, name: 'maxTimeMS' },
+ comment: {distinct: false, count: false}
+ };
+ Object.keys(negated).forEach(function(key) {
+ simpleOption(key, negated[key]);
+ });
+
+ describe('snapshot', function() {
+ it('works', function() {
+ var query;
+
+ query = mquery();
+ query.snapshot();
+ assert.equal(true, query.options.snapshot);
+
+ query = mquery();
+ query.snapshot(true);
+ assert.equal(true, query.options.snapshot);
+
+ query = mquery();
+ query.snapshot(false);
+ assert.equal(false, query.options.snapshot);
+ });
+ noDistinct('snapshot');
+ no('count', 'snapshot');
+ });
+
+ describe('hint', function() {
+ it('accepts an object', function() {
+ var query2 = mquery();
+ query2.hint({'a': 1, 'b': -1});
+ assert.deepEqual(query2.options.hint, {'a': 1, 'b': -1});
+ });
+
+ it('accepts a string', function() {
+ var query2 = mquery();
+ query2.hint('a');
+ assert.deepEqual(query2.options.hint, 'a');
+ });
+
+ it('rejects everything else', function() {
+ assert.throws(function() {
+ mquery().hint(['c']);
+ }, /Invalid hint./);
+ assert.throws(function() {
+ mquery().hint(1);
+ }, /Invalid hint./);
+ });
+
+ describe('does not have side affects', function() {
+ it('on invalid arg', function() {
+ var m = mquery();
+ try {
+ m.hint(1);
+ } catch (err) {
+ // ignore
+ }
+ assert.equal(undefined, m.options.hint);
+ });
+ it('on missing arg', function() {
+ var m = mquery().hint();
+ assert.equal(undefined, m.options.hint);
+ });
+ });
+
+ noDistinct('hint');
+ });
+
+ describe('j', function() {
+ it('works', function() {
+ var m = mquery().j(true);
+ assert.equal(true, m.options.j);
+ });
+ });
+
+ describe('slaveOk', function() {
+ it('works', function() {
+ var query;
+
+ query = mquery();
+ query.slaveOk();
+ assert.equal(true, query.options.slaveOk);
+
+ query = mquery();
+ query.slaveOk(true);
+ assert.equal(true, query.options.slaveOk);
+
+ query = mquery();
+ query.slaveOk(false);
+ assert.equal(false, query.options.slaveOk);
+ });
+ });
+
+ describe('read', function() {
+ it('sets associated readPreference option', function() {
+ var m = mquery();
+ m.read('p');
+ assert.equal('primary', m.options.readPreference);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.read('sp'));
+ });
+ });
+
+ describe('readConcern', function() {
+ it('sets associated readConcern option', function() {
+ var m;
+
+ m = mquery();
+ m.readConcern('s');
+ assert.deepEqual({ level: 'snapshot' }, m.options.readConcern);
+
+ m = mquery();
+ m.r('local');
+ assert.deepEqual({ level: 'local' }, m.options.readConcern);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.readConcern('lz'));
+ });
+ });
+
+ describe('tailable', function() {
+ it('works', function() {
+ var query;
+
+ query = mquery();
+ query.tailable();
+ assert.equal(true, query.options.tailable);
+
+ query = mquery();
+ query.tailable(true);
+ assert.equal(true, query.options.tailable);
+
+ query = mquery();
+ query.tailable(false);
+ assert.equal(false, query.options.tailable);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.tailable());
+ });
+ noDistinct('tailable');
+ no('count', 'tailable');
+ });
+
+ describe('writeConcern', function() {
+ it('sets associated writeConcern option', function() {
+ var m;
+ m = mquery();
+ m.writeConcern('majority');
+ assert.equal('majority', m.options.w);
+
+ m = mquery();
+ m.writeConcern('m'); // m is alias of majority
+ assert.equal('majority', m.options.w);
+
+ m = mquery();
+ m.writeConcern(1);
+ assert.equal(1, m.options.w);
+ });
+ it('accepts object', function() {
+ var m;
+
+ m = mquery().writeConcern({ w: 'm', j: true, wtimeout: 1000 });
+ assert.equal('m', m.options.w); // check it does not convert m to majority
+ assert.equal(true, m.options.j);
+ assert.equal(1000, m.options.wtimeout);
+
+ m = mquery().w('m').w({j: false, wtimeout: 0 });
+ assert.equal('majority', m.options.w);
+ assert.strictEqual(false, m.options.j);
+ assert.strictEqual(0, m.options.wtimeout);
+ });
+ it('is chainable', function() {
+ var m = mquery();
+ assert.equal(m, m.writeConcern('majority'));
+ });
+ });
+
+ // query utilities
+
+ describe('merge', function() {
+ describe('with falsy arg', function() {
+ it('returns itself', function() {
+ var m = mquery();
+ assert.equal(m, m.merge());
+ assert.equal(m, m.merge(null));
+ assert.equal(m, m.merge(0));
+ });
+ });
+ describe('with an argument', function() {
+ describe('that is not a query or plain object', function() {
+ it('throws', function() {
+ assert.throws(function() {
+ mquery().merge([]);
+ }, /Invalid argument/);
+ assert.throws(function() {
+ mquery().merge('merge');
+ }, /Invalid argument/);
+ assert.doesNotThrow(function() {
+ mquery().merge({});
+ }, /Invalid argument/);
+ });
+ });
+
+ describe('that is a query', function() {
+ it('merges conditions, field selection, and options', function() {
+ var m = mquery({ x: 'hi' }, { select: 'x y', another: true });
+ var n = mquery().merge(m);
+ assert.deepEqual(n._conditions, m._conditions);
+ assert.deepEqual(n._fields, m._fields);
+ assert.deepEqual(n.options, m.options);
+ });
+ it('clones update arguments', function(done) {
+ var original = { $set: { iTerm: true }};
+ var m = mquery().update(original);
+ var n = mquery().merge(m);
+ m.update({ $set: { x: 2 }});
+ assert.notDeepEqual(m._update, n._update);
+ done();
+ });
+ it('is chainable', function() {
+ var m = mquery({ x: 'hi' });
+ var n = mquery();
+ assert.equal(n, n.merge(m));
+ });
+ });
+
+ describe('that is an object', function() {
+ it('merges', function() {
+ var m = { x: 'hi' };
+ var n = mquery().merge(m);
+ assert.deepEqual(n._conditions, { x: 'hi' });
+ });
+ it('clones update arguments', function(done) {
+ var original = { $set: { iTerm: true }};
+ var m = mquery().update(original);
+ var n = mquery().merge(original);
+ m.update({ $set: { x: 2 }});
+ assert.notDeepEqual(m._update, n._update);
+ done();
+ });
+ it('is chainable', function() {
+ var m = { x: 'hi' };
+ var n = mquery();
+ assert.equal(n, n.merge(m));
+ });
+ });
+ });
+ });
+
+ // queries
+
+ describe('find', function() {
+ describe('with no callback', function() {
+ it('does not execute', function() {
+ var m = mquery();
+ assert.doesNotThrow(function() {
+ m.find();
+ });
+ assert.doesNotThrow(function() {
+ m.find({ x: 1 });
+ });
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery().find({ x: 1 }).find().find({ y: 2 });
+ assert.deepEqual(m._conditions, {x:1,y:2});
+ });
+
+ it('merges other queries', function() {
+ var m = mquery({ name: 'mquery' });
+ m.tailable();
+ m.select('_id');
+ var a = mquery().find(m);
+ assert.deepEqual(a._conditions, m._conditions);
+ assert.deepEqual(a.options, m.options);
+ assert.deepEqual(a._fields, m._fields);
+ });
+
+ describe('executes', function() {
+ before(function(done) {
+ col.insert({ name: 'mquery' }, { safe: true }, done);
+ });
+
+ after(function(done) {
+ col.remove({ name: 'mquery' }, done);
+ });
+
+ it('when criteria is passed with a callback', function(done) {
+ mquery(col).find({ name: 'mquery' }, function(err, docs) {
+ assert.ifError(err);
+ assert.equal(1, docs.length);
+ done();
+ });
+ });
+ it('when Query is passed with a callback', function(done) {
+ var m = mquery({ name: 'mquery' });
+ mquery(col).find(m, function(err, docs) {
+ assert.ifError(err);
+ assert.equal(1, docs.length);
+ done();
+ });
+ });
+ it('when just a callback is passed', function(done) {
+ mquery({ name: 'mquery' }).collection(col).find(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(1, docs.length);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('findOne', function() {
+ describe('with no callback', function() {
+ it('does not execute', function() {
+ var m = mquery();
+ assert.doesNotThrow(function() {
+ m.findOne();
+ });
+ assert.doesNotThrow(function() {
+ m.findOne({ x: 1 });
+ });
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery();
+ var n = m.findOne({ x: 1 }).findOne().findOne({ y: 2 });
+ assert.equal(m, n);
+ assert.deepEqual(m._conditions, {x:1,y:2});
+ assert.equal('findOne', m.op);
+ });
+
+ it('merges other queries', function() {
+ var m = mquery({ name: 'mquery' });
+ m.read('nearest');
+ m.select('_id');
+ var a = mquery().findOne(m);
+ assert.deepEqual(a._conditions, m._conditions);
+ assert.deepEqual(a.options, m.options);
+ assert.deepEqual(a._fields, m._fields);
+ });
+
+ describe('executes', function() {
+ before(function(done) {
+ col.insert({ name: 'mquery findone' }, { safe: true }, done);
+ });
+
+ after(function(done) {
+ col.remove({ name: 'mquery findone' }, done);
+ });
+
+ it('when criteria is passed with a callback', function(done) {
+ mquery(col).findOne({ name: 'mquery findone' }, function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ assert.equal('mquery findone', doc.name);
+ done();
+ });
+ });
+ it('when Query is passed with a callback', function(done) {
+ var m = mquery(col).where({ name: 'mquery findone' });
+ mquery(col).findOne(m, function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ assert.equal('mquery findone', doc.name);
+ done();
+ });
+ });
+ it('when just a callback is passed', function(done) {
+ mquery({ name: 'mquery findone' }).collection(col).findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ assert.equal('mquery findone', doc.name);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('count', function() {
+ describe('with no callback', function() {
+ it('does not execute', function() {
+ var m = mquery();
+ assert.doesNotThrow(function() {
+ m.count();
+ });
+ assert.doesNotThrow(function() {
+ m.count({ x: 1 });
+ });
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery();
+ var n = m.count({ x: 1 }).count().count({ y: 2 });
+ assert.equal(m, n);
+ assert.deepEqual(m._conditions, {x:1,y:2});
+ assert.equal('count', m.op);
+ });
+
+ it('merges other queries', function() {
+ var m = mquery({ name: 'mquery' });
+ m.read('nearest');
+ m.select('_id');
+ var a = mquery().count(m);
+ assert.deepEqual(a._conditions, m._conditions);
+ assert.deepEqual(a.options, m.options);
+ assert.deepEqual(a._fields, m._fields);
+ });
+
+ describe('executes', function() {
+ before(function(done) {
+ col.insert({ name: 'mquery count' }, { safe: true }, done);
+ });
+
+ after(function(done) {
+ col.remove({ name: 'mquery count' }, done);
+ });
+
+ it('when criteria is passed with a callback', function(done) {
+ mquery(col).count({ name: 'mquery count' }, function(err, count) {
+ assert.ifError(err);
+ assert.ok(count);
+ assert.ok(1 === count);
+ done();
+ });
+ });
+ it('when Query is passed with a callback', function(done) {
+ var m = mquery({ name: 'mquery count' });
+ mquery(col).count(m, function(err, count) {
+ assert.ifError(err);
+ assert.ok(count);
+ assert.ok(1 === count);
+ done();
+ });
+ });
+ it('when just a callback is passed', function(done) {
+ mquery({ name: 'mquery count' }).collection(col).count(function(err, count) {
+ assert.ifError(err);
+ assert.ok(1 === count);
+ done();
+ });
+ });
+ });
+
+ describe('validates its option', function() {
+ it('sort', function(done) {
+ assert.doesNotThrow(function() {
+ mquery().sort('x').count();
+ });
+ done();
+ });
+
+ it('select', function(done) {
+ assert.throws(function() {
+ mquery().select('x').count();
+ }, /field selection and slice cannot be used with count/);
+ done();
+ });
+
+ it('slice', function(done) {
+ assert.throws(function() {
+ mquery().where('x').slice(-3).count();
+ }, /field selection and slice cannot be used with count/);
+ done();
+ });
+
+ it('limit', function(done) {
+ assert.doesNotThrow(function() {
+ mquery().limit(3).count();
+ });
+ done();
+ });
+
+ it('skip', function(done) {
+ assert.doesNotThrow(function() {
+ mquery().skip(3).count();
+ });
+ done();
+ });
+
+ it('batchSize', function(done) {
+ assert.throws(function() {
+ mquery({}, { batchSize: 3 }).count();
+ }, /batchSize cannot be used with count/);
+ done();
+ });
+
+ it('comment', function(done) {
+ assert.throws(function() {
+ mquery().comment('mquery').count();
+ }, /comment cannot be used with count/);
+ done();
+ });
+
+ it('maxScan', function(done) {
+ assert.throws(function() {
+ mquery().maxScan(300).count();
+ }, /maxScan cannot be used with count/);
+ done();
+ });
+
+ it('snapshot', function(done) {
+ assert.throws(function() {
+ mquery().snapshot().count();
+ }, /snapshot cannot be used with count/);
+ done();
+ });
+
+ it('tailable', function(done) {
+ assert.throws(function() {
+ mquery().tailable().count();
+ }, /tailable cannot be used with count/);
+ done();
+ });
+ });
+ });
+
+ describe('distinct', function() {
+ describe('with no callback', function() {
+ it('does not execute', function() {
+ var m = mquery();
+ assert.doesNotThrow(function() {
+ m.distinct();
+ });
+ assert.doesNotThrow(function() {
+ m.distinct('name');
+ });
+ assert.doesNotThrow(function() {
+ m.distinct({ name: 'mquery distinct' });
+ });
+ assert.doesNotThrow(function() {
+ m.distinct({ name: 'mquery distinct' }, 'name');
+ });
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery({x:1}).distinct('name');
+ var n = m.distinct({y:2});
+ assert.equal(m, n);
+ assert.deepEqual(n._conditions, {x:1, y:2});
+ assert.equal('name', n._distinct);
+ assert.equal('distinct', n.op);
+ });
+
+ it('overwrites field', function() {
+ var m = mquery({ name: 'mquery' }).distinct('name');
+ m.distinct('rename');
+ assert.equal(m._distinct, 'rename');
+ m.distinct({x:1}, 'renamed');
+ assert.equal(m._distinct, 'renamed');
+ });
+
+ it('merges other queries', function() {
+ var m = mquery().distinct({ name: 'mquery' }, 'age');
+ m.read('nearest');
+ var a = mquery().distinct(m);
+ assert.deepEqual(a._conditions, m._conditions);
+ assert.deepEqual(a.options, m.options);
+ assert.deepEqual(a._fields, m._fields);
+ assert.deepEqual(a._distinct, m._distinct);
+ });
+
+ describe('executes', function() {
+ before(function(done) {
+ col.insert({ name: 'mquery distinct', age: 1 }, { safe: true }, done);
+ });
+
+ after(function(done) {
+ col.remove({ name: 'mquery distinct' }, done);
+ });
+
+ it('when distinct arg is passed with a callback', function(done) {
+ mquery(col).distinct('distinct', function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ done();
+ });
+ });
+ describe('when criteria is passed with a callback', function() {
+ it('if distinct arg was declared', function(done) {
+ mquery(col).distinct('age').distinct({ name: 'mquery distinct' }, function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ done();
+ });
+ });
+ it('but not if distinct arg was not declared', function() {
+ assert.throws(function() {
+ mquery(col).distinct({ name: 'mquery distinct' }, function() {});
+ }, /No value for `distinct`/);
+ });
+ });
+ describe('when Query is passed with a callback', function() {
+ var m = mquery({ name: 'mquery distinct' });
+ it('if distinct arg was declared', function(done) {
+ mquery(col).distinct('age').distinct(m, function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ done();
+ });
+ });
+ it('but not if distinct arg was not declared', function() {
+ assert.throws(function() {
+ mquery(col).distinct(m, function() {});
+ }, /No value for `distinct`/);
+ });
+ });
+ describe('when just a callback is passed', function() {
+ it('if distinct arg was declared', function(done) {
+ var m = mquery({ name: 'mquery distinct' });
+ m.collection(col);
+ m.distinct('age');
+ m.distinct(function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ done();
+ });
+ });
+ it('but not if no distinct arg was declared', function() {
+ var m = mquery();
+ m.collection(col);
+ assert.throws(function() {
+ m.distinct(function() {});
+ }, /No value for `distinct`/);
+ });
+ });
+ });
+
+ describe('validates its option', function() {
+ it('sort', function(done) {
+ assert.throws(function() {
+ mquery().sort('x').distinct();
+ }, /sort cannot be used with distinct/);
+ done();
+ });
+
+ it('select', function(done) {
+ assert.throws(function() {
+ mquery().select('x').distinct();
+ }, /field selection and slice cannot be used with distinct/);
+ done();
+ });
+
+ it('slice', function(done) {
+ assert.throws(function() {
+ mquery().where('x').slice(-3).distinct();
+ }, /field selection and slice cannot be used with distinct/);
+ done();
+ });
+
+ it('limit', function(done) {
+ assert.throws(function() {
+ mquery().limit(3).distinct();
+ }, /limit cannot be used with distinct/);
+ done();
+ });
+
+ it('skip', function(done) {
+ assert.throws(function() {
+ mquery().skip(3).distinct();
+ }, /skip cannot be used with distinct/);
+ done();
+ });
+
+ it('batchSize', function(done) {
+ assert.throws(function() {
+ mquery({}, { batchSize: 3 }).distinct();
+ }, /batchSize cannot be used with distinct/);
+ done();
+ });
+
+ it('comment', function(done) {
+ assert.throws(function() {
+ mquery().comment('mquery').distinct();
+ }, /comment cannot be used with distinct/);
+ done();
+ });
+
+ it('maxScan', function(done) {
+ assert.throws(function() {
+ mquery().maxScan(300).distinct();
+ }, /maxScan cannot be used with distinct/);
+ done();
+ });
+
+ it('snapshot', function(done) {
+ assert.throws(function() {
+ mquery().snapshot().distinct();
+ }, /snapshot cannot be used with distinct/);
+ done();
+ });
+
+ it('hint', function(done) {
+ assert.throws(function() {
+ mquery().hint({ x: 1 }).distinct();
+ }, /hint cannot be used with distinct/);
+ done();
+ });
+
+ it('tailable', function(done) {
+ assert.throws(function() {
+ mquery().tailable().distinct();
+ }, /tailable cannot be used with distinct/);
+ done();
+ });
+ });
+ });
+
+ describe('update', function() {
+ describe('with no callback', function() {
+ it('does not execute', function() {
+ var m = mquery();
+ assert.doesNotThrow(function() {
+ m.update({ name: 'old' }, { name: 'updated' }, { multi: true });
+ });
+ assert.doesNotThrow(function() {
+ m.update({ name: 'old' }, { name: 'updated' });
+ });
+ assert.doesNotThrow(function() {
+ m.update({ name: 'updated' });
+ });
+ assert.doesNotThrow(function() {
+ m.update();
+ });
+ });
+ });
+
+ it('is chainable', function() {
+ var m = mquery({x:1}).update({ y: 2 });
+ var n = m.where({y:2});
+ assert.equal(m, n);
+ assert.deepEqual(n._conditions, {x:1, y:2});
+ assert.deepEqual({ y: 2 }, n._update);
+ assert.equal('update', n.op);
+ });
+
+ it('merges update doc arg', function() {
+ var a = [1,2];
+ var m = mquery().where({ name: 'mquery' }).update({ x: 'stuff', a: a });
+ m.update({ z: 'stuff' });
+ assert.deepEqual(m._update, { z: 'stuff', x: 'stuff', a: a });
+ assert.deepEqual(m._conditions, { name: 'mquery' });
+ assert.ok(!m.options.overwrite);
+ m.update({}, { z: 'renamed' }, { overwrite: true });
+ assert.ok(m.options.overwrite === true);
+ assert.deepEqual(m._conditions, { name: 'mquery' });
+ assert.deepEqual(m._update, { z: 'renamed', x: 'stuff', a: a });
+ a.push(3);
+ assert.notDeepEqual(m._update, { z: 'renamed', x: 'stuff', a: a });
+ });
+
+ it('merges other options', function() {
+ var m = mquery();
+ m.setOptions({ overwrite: true });
+ m.update({ age: 77 }, { name: 'pagemill' }, { multi: true });
+ assert.deepEqual({ age: 77 }, m._conditions);
+ assert.deepEqual({ name: 'pagemill' }, m._update);
+ assert.deepEqual({ overwrite: true, multi: true }, m.options);
+ });
+
+ describe('executes', function() {
+ var id;
+ before(function(done) {
+ col.insert({ name: 'mquery update', age: 1 }, { safe: true }, function(err, res) {
+ id = res.insertedIds[0];
+ done();
+ });
+ });
+
+ after(function(done) {
+ col.remove({ _id: id }, done);
+ });
+
+ describe('when conds + doc + opts + callback passed', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.update({}, { name: 'Sparky' }, { safe: true }, function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(doc.name, 'Sparky');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('when conds + doc + callback passed', function() {
+ it('works', function(done) {
+ var m = mquery(col).update({ _id: id }, { name: 'fairgrounds' }, function(err, num) {
+ assert.ifError(err);
+ assert.ok(1, num);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(doc.name, 'fairgrounds');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('when doc + callback passed', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id }).update({ name: 'changed' }, function(err, num) {
+ assert.ifError(err);
+ assert.ok(1, num);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(doc.name, 'changed');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('when just callback passed', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.setOptions({ safe: true });
+ m.update({ name: 'Frankenweenie' });
+ m.update(function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(doc.name, 'Frankenweenie');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('without a callback', function() {
+ it('when forced by exec()', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.setOptions({ safe: true, multi: true });
+ m.update({ name: 'forced' });
+
+ var update = m._collection.update;
+ m._collection.update = function(conds, doc, opts) {
+ m._collection.update = update;
+
+ assert.ok(opts.safe);
+ assert.ok(true === opts.multi);
+ assert.equal('forced', doc.$set.name);
+ done();
+ };
+
+ m.exec();
+ });
+ });
+
+ describe('except when update doc is empty and missing overwrite flag', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.setOptions({ safe: true });
+ m.update({ }, function(err, num) {
+ assert.ifError(err);
+ assert.ok(0 === num);
+ setTimeout(function() {
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(3, mquery.utils.keys(doc).length);
+ assert.equal(id, doc._id.toString());
+ assert.equal('Frankenweenie', doc.name);
+ done();
+ });
+ }, 300);
+ });
+ });
+ });
+
+ describe('when update doc is set with overwrite flag', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.setOptions({ safe: true, overwrite: true });
+ m.update({ all: 'yep', two: 2 }, function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(3, mquery.utils.keys(doc).length);
+ assert.equal('yep', doc.all);
+ assert.equal(2, doc.two);
+ assert.equal(id, doc._id.toString());
+ done();
+ });
+ });
+ });
+ });
+
+ describe('when update doc is empty with overwrite flag', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.setOptions({ safe: true, overwrite: true });
+ m.update({ }, function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(1, mquery.utils.keys(doc).length);
+ assert.equal(id, doc._id.toString());
+ done();
+ });
+ });
+ });
+ });
+
+ describe('when boolean (true) - exec()', function() {
+ it('works', function(done) {
+ var m = mquery(col).where({ _id: id });
+ m.update({ name: 'bool' }).update(true);
+ setTimeout(function() {
+ m.findOne(function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ assert.equal('bool', doc.name);
+ done();
+ });
+ }, 300);
+ });
+ });
+ });
+ });
+
+ describe('remove', function() {
+ describe('with 0 args', function() {
+ var name = 'remove: no args test';
+ before(function(done) {
+ col.insert({ name: name }, { safe: true }, done);
+ });
+ after(function(done) {
+ col.remove({ name: name }, { safe: true }, done);
+ });
+
+ it('does not execute', function(done) {
+ var remove = col.remove;
+ col.remove = function() {
+ col.remove = remove;
+ done(new Error('remove executed!'));
+ };
+
+ mquery(col).where({ name: name }).remove();
+ setTimeout(function() {
+ col.remove = remove;
+ done();
+ }, 10);
+ });
+
+ it('chains', function() {
+ var m = mquery();
+ assert.equal(m, m.remove());
+ });
+ });
+
+ describe('with 1 argument', function() {
+ var name = 'remove: 1 arg test';
+ before(function(done) {
+ col.insert({ name: name }, { safe: true }, done);
+ });
+ after(function(done) {
+ col.remove({ name: name }, { safe: true }, done);
+ });
+
+ describe('that is a', function() {
+ it('plain object', function() {
+ var m = mquery(col).remove({ name: 'Whiskers' });
+ m.remove({ color: '#fff' });
+ assert.deepEqual({ name: 'Whiskers', color: '#fff' }, m._conditions);
+ });
+
+ it('query', function() {
+ var q = mquery({ color: '#fff' });
+ var m = mquery(col).remove({ name: 'Whiskers' });
+ m.remove(q);
+ assert.deepEqual({ name: 'Whiskers', color: '#fff' }, m._conditions);
+ });
+
+ it('function', function(done) {
+ mquery(col, { safe: true }).where({name: name}).remove(function(err) {
+ assert.ifError(err);
+ mquery(col).findOne({ name: name }, function(err, doc) {
+ assert.ifError(err);
+ assert.equal(null, doc);
+ done();
+ });
+ });
+ });
+
+ it('boolean (true) - execute', function(done) {
+ col.insert({ name: name }, { safe: true }, function(err) {
+ assert.ifError(err);
+ mquery(col).findOne({ name: name }, function(err, doc) {
+ assert.ifError(err);
+ assert.ok(doc);
+ mquery(col).remove(true);
+ setTimeout(function() {
+ mquery(col).find(function(err, docs) {
+ assert.ifError(err);
+ assert.ok(docs);
+ assert.equal(0, docs.length);
+ done();
+ });
+ }, 300);
+ });
+ });
+ });
+ });
+ });
+
+ describe('with 2 arguments', function() {
+ var name = 'remove: 2 arg test';
+ beforeEach(function(done) {
+ col.remove({}, { safe: true }, function(err) {
+ assert.ifError(err);
+ col.insert([{ name: 'shelly' }, { name: name }], { safe: true }, function(err) {
+ assert.ifError(err);
+ mquery(col).find(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('plain object + callback', function() {
+ it('works', function(done) {
+ mquery(col).remove({ name: name }, function(err) {
+ assert.ifError(err);
+ mquery(col).find(function(err, docs) {
+ assert.ifError(err);
+ assert.ok(docs);
+ assert.equal(1, docs.length);
+ assert.equal('shelly', docs[0].name);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('mquery + callback', function() {
+ it('works', function(done) {
+ var m = mquery({ name: name });
+ mquery(col).remove(m, function(err) {
+ assert.ifError(err);
+ mquery(col).find(function(err, docs) {
+ assert.ifError(err);
+ assert.ok(docs);
+ assert.equal(1, docs.length);
+ assert.equal('shelly', docs[0].name);
+ done();
+ });
+ });
+ });
+ });
+ });
+ });
+
+ function validateFindAndModifyOptions(method) {
+ describe('validates its option', function() {
+ it('sort', function(done) {
+ assert.doesNotThrow(function() {
+ mquery().sort('x')[method]();
+ });
+ done();
+ });
+
+ it('select', function(done) {
+ assert.doesNotThrow(function() {
+ mquery().select('x')[method]();
+ });
+ done();
+ });
+
+ it('limit', function(done) {
+ assert.throws(function() {
+ mquery().limit(3)[method]();
+ }, new RegExp('limit cannot be used with ' + method));
+ done();
+ });
+
+ it('skip', function(done) {
+ assert.throws(function() {
+ mquery().skip(3)[method]();
+ }, new RegExp('skip cannot be used with ' + method));
+ done();
+ });
+
+ it('batchSize', function(done) {
+ assert.throws(function() {
+ mquery({}, { batchSize: 3 })[method]();
+ }, new RegExp('batchSize cannot be used with ' + method));
+ done();
+ });
+
+ it('maxScan', function(done) {
+ assert.throws(function() {
+ mquery().maxScan(300)[method]();
+ }, new RegExp('maxScan cannot be used with ' + method));
+ done();
+ });
+
+ it('snapshot', function(done) {
+ assert.throws(function() {
+ mquery().snapshot()[method]();
+ }, new RegExp('snapshot cannot be used with ' + method));
+ done();
+ });
+
+ it('hint', function(done) {
+ assert.throws(function() {
+ mquery().hint({ x: 1 })[method]();
+ }, new RegExp('hint cannot be used with ' + method));
+ done();
+ });
+
+ it('tailable', function(done) {
+ assert.throws(function() {
+ mquery().tailable()[method]();
+ }, new RegExp('tailable cannot be used with ' + method));
+ done();
+ });
+
+ it('comment', function(done) {
+ assert.throws(function() {
+ mquery().comment('mquery')[method]();
+ }, new RegExp('comment cannot be used with ' + method));
+ done();
+ });
+ });
+ }
+
+ describe('findOneAndUpdate', function() {
+ var name = 'findOneAndUpdate + fn';
+
+ validateFindAndModifyOptions('findOneAndUpdate');
+
+ describe('with 0 args', function() {
+ it('makes no changes', function() {
+ var m = mquery();
+ var n = m.findOneAndUpdate();
+ assert.deepEqual(m, n);
+ });
+ });
+ describe('with 1 arg', function() {
+ describe('that is an object', function() {
+ it('updates the doc', function() {
+ var m = mquery();
+ var n = m.findOneAndUpdate({ $set: { name: '1 arg' }});
+ assert.deepEqual(n._update, { $set: { name: '1 arg' }});
+ });
+ });
+ describe('that is a query', function() {
+ it('updates the doc', function() {
+ var m = mquery({ name: name }).update({ x: 1 });
+ var n = mquery().findOneAndUpdate(m);
+ assert.deepEqual(n._update, { x: 1 });
+ });
+ });
+ it('that is a function', function(done) {
+ col.insert({ name: name }, { safe: true }, function(err) {
+ assert.ifError(err);
+ var m = mquery({ name: name }).collection(col);
+ name = '1 arg';
+ var n = m.update({ $set: { name: name }});
+ n.findOneAndUpdate(function(err, res) {
+ assert.ifError(err);
+ assert.ok(res.value);
+ assert.equal(name, res.value.name);
+ done();
+ });
+ });
+ });
+ });
+ describe('with 2 args', function() {
+ it('conditions + update', function() {
+ var m = mquery(col);
+ m.findOneAndUpdate({ name: name }, { age: 100 });
+ assert.deepEqual({ name: name }, m._conditions);
+ assert.deepEqual({ age: 100 }, m._update);
+ });
+ it('query + update', function() {
+ var n = mquery({ name: name });
+ var m = mquery(col);
+ m.findOneAndUpdate(n, { age: 100 });
+ assert.deepEqual({ name: name }, m._conditions);
+ assert.deepEqual({ age: 100 }, m._update);
+ });
+ it('update + callback', function(done) {
+ var m = mquery(col).where({ name: name });
+ m.findOneAndUpdate({}, { $inc: { age: 10 }}, { new: true }, function(err, res) {
+ assert.ifError(err);
+ assert.equal(10, res.value.age);
+ done();
+ });
+ });
+ });
+ describe('with 3 args', function() {
+ it('conditions + update + options', function() {
+ var m = mquery();
+ var n = m.findOneAndUpdate({ name: name }, { works: true }, { new: false });
+ assert.deepEqual({ name: name}, n._conditions);
+ assert.deepEqual({ works: true }, n._update);
+ assert.deepEqual({ new: false }, n.options);
+ });
+ it('conditions + update + callback', function(done) {
+ var m = mquery(col);
+ m.findOneAndUpdate({ name: name }, { works: true }, { new: true }, function(err, res) {
+ assert.ifError(err);
+ assert.ok(res.value);
+ assert.equal(name, res.value.name);
+ assert.ok(true === res.value.works);
+ done();
+ });
+ });
+ });
+ describe('with 4 args', function() {
+ it('conditions + update + options + callback', function(done) {
+ var m = mquery(col);
+ m.findOneAndUpdate({ name: name }, { works: false }, { new: false }, function(err, res) {
+ assert.ifError(err);
+ assert.ok(res.value);
+ assert.equal(name, res.value.name);
+ assert.ok(true === res.value.works);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('findOneAndRemove', function() {
+ var name = 'findOneAndRemove';
+
+ validateFindAndModifyOptions('findOneAndRemove');
+
+ describe('with 0 args', function() {
+ it('makes no changes', function() {
+ var m = mquery();
+ var n = m.findOneAndRemove();
+ assert.deepEqual(m, n);
+ });
+ });
+ describe('with 1 arg', function() {
+ describe('that is an object', function() {
+ it('updates the doc', function() {
+ var m = mquery();
+ var n = m.findOneAndRemove({ name: '1 arg' });
+ assert.deepEqual(n._conditions, { name: '1 arg' });
+ });
+ });
+ describe('that is a query', function() {
+ it('updates the doc', function() {
+ var m = mquery({ name: name });
+ var n = m.findOneAndRemove(m);
+ assert.deepEqual(n._conditions, { name: name });
+ });
+ });
+ it('that is a function', function(done) {
+ col.insert({ name: name }, { safe: true }, function(err) {
+ assert.ifError(err);
+ var m = mquery({ name: name }).collection(col);
+ m.findOneAndRemove(function(err, res) {
+ assert.ifError(err);
+ assert.ok(res.value);
+ assert.equal(name, res.value.name);
+ done();
+ });
+ });
+ });
+ });
+ describe('with 2 args', function() {
+ it('conditions + options', function() {
+ var m = mquery(col);
+ m.findOneAndRemove({ name: name }, { new: false });
+ assert.deepEqual({ name: name }, m._conditions);
+ assert.deepEqual({ new: false }, m.options);
+ });
+ it('query + options', function() {
+ var n = mquery({ name: name });
+ var m = mquery(col);
+ m.findOneAndRemove(n, { sort: { x: 1 }});
+ assert.deepEqual({ name: name }, m._conditions);
+ assert.deepEqual({ sort: { 'x': 1 }}, m.options);
+ });
+ it('conditions + callback', function(done) {
+ col.insert({ name: name }, { safe: true }, function(err) {
+ assert.ifError(err);
+ var m = mquery(col);
+ m.findOneAndRemove({ name: name }, function(err, res) {
+ assert.ifError(err);
+ assert.equal(name, res.value.name);
+ done();
+ });
+ });
+ });
+ it('query + callback', function(done) {
+ col.insert({ name: name }, { safe: true }, function(err) {
+ assert.ifError(err);
+ var n = mquery({ name: name });
+ var m = mquery(col);
+ m.findOneAndRemove(n, function(err, res) {
+ assert.ifError(err);
+ assert.equal(name, res.value.name);
+ done();
+ });
+ });
+ });
+ });
+ describe('with 3 args', function() {
+ it('conditions + options + callback', function(done) {
+ name = 'findOneAndRemove + conds + options + cb';
+ col.insert([{ name: name }, { name: 'a' }], { safe: true }, function(err) {
+ assert.ifError(err);
+ var m = mquery(col);
+ m.findOneAndRemove({ name: name }, { sort: { name: 1 }}, function(err, res) {
+ assert.ifError(err);
+ assert.ok(res.value);
+ assert.equal(name, res.value.name);
+ done();
+ });
+ });
+ });
+ });
+ });
+
+ describe('exec', function() {
+ beforeEach(function(done) {
+ col.insert([{ name: 'exec', age: 1 }, { name: 'exec', age: 2 }], done);
+ });
+
+ afterEach(function(done) {
+ mquery(col).remove(done);
+ });
+
+ it('requires an op', function() {
+ assert.throws(function() {
+ mquery().exec();
+ }, /Missing query type/);
+ });
+
+ describe('find', function() {
+ it('works', function(done) {
+ var m = mquery(col).find({ name: 'exec' });
+ m.exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ });
+
+ it('works with readPreferences', function(done) {
+ var m = mquery(col).find({ name: 'exec' });
+ try {
+ var rp = new require('mongodb').ReadPreference('primary');
+ m.read(rp);
+ } catch (e) {
+ done(e.code === 'MODULE_NOT_FOUND' ? null : e);
+ return;
+ }
+ m.exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ });
+
+ it('works with hint', function(done) {
+ mquery(col).hint({ _id: 1 }).find({ name: 'exec' }).exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+
+ mquery(col).hint('_id_').find({ age: 1 }).exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(1, docs.length);
+ done();
+ });
+ });
+ });
+
+ it('works with readConcern', function(done) {
+ var m = mquery(col).find({ name: 'exec' });
+ m.readConcern('l');
+ m.exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ });
+
+ it('works with collation', function(done) {
+ var m = mquery(col).find({ name: 'EXEC' });
+ m.collation({ locale: 'en_US', strength: 1 });
+ m.exec(function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ });
+ });
+
+ it('findOne', function(done) {
+ var m = mquery(col).findOne({ age: 2 });
+ m.exec(function(err, doc) {
+ assert.ifError(err);
+ assert.equal(2, doc.age);
+ done();
+ });
+ });
+
+ it('count', function(done) {
+ var m = mquery(col).count({ name: 'exec' });
+ m.exec(function(err, count) {
+ assert.ifError(err);
+ assert.equal(2, count);
+ done();
+ });
+ });
+
+ it('distinct', function(done) {
+ var m = mquery({ name: 'exec' });
+ m.collection(col);
+ m.distinct('age');
+ m.exec(function(err, array) {
+ assert.ifError(err);
+ assert.ok(Array.isArray(array));
+ assert.equal(2, array.length);
+ assert(~array.indexOf(1));
+ assert(~array.indexOf(2));
+ done();
+ });
+ });
+
+ describe('update', function() {
+ var num;
+
+ it('with a callback', function(done) {
+ var m = mquery(col);
+ m.where({ name: 'exec' });
+
+ m.count(function(err, _num) {
+ assert.ifError(err);
+ num = _num;
+ m.setOptions({ multi: true });
+ m.update({ name: 'exec + update' });
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal(num, res.result.n);
+ mquery(col).find({ name: 'exec + update' }, function(err, docs) {
+ assert.ifError(err);
+ assert.equal(num, docs.length);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('updateMany', function() {
+ it('works', function(done) {
+ mquery(col).updateMany({ name: 'exec' }, { name: 'test' }).
+ exec(function(error) {
+ assert.ifError(error);
+ mquery(col).count({ name: 'test' }).exec(function(error, res) {
+ assert.ifError(error);
+ assert.equal(res, 2);
+ done();
+ });
+ });
+ });
+ it('works with write concern', function(done) {
+ mquery(col).updateMany({ name: 'exec' }, { name: 'test' })
+ .w(1).j(true).wtimeout(1000)
+ .exec(function(error) {
+ assert.ifError(error);
+ mquery(col).count({ name: 'test' }).exec(function(error, res) {
+ assert.ifError(error);
+ assert.equal(res, 2);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('updateOne', function() {
+ it('works', function(done) {
+ mquery(col).updateOne({ name: 'exec' }, { name: 'test' }).
+ exec(function(error) {
+ assert.ifError(error);
+ mquery(col).count({ name: 'test' }).exec(function(error, res) {
+ assert.ifError(error);
+ assert.equal(res, 1);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('replaceOne', function() {
+ it('works', function(done) {
+ mquery(col).replaceOne({ name: 'exec' }, { name: 'test' }).
+ exec(function(error) {
+ assert.ifError(error);
+ mquery(col).findOne({ name: 'test' }).exec(function(error, res) {
+ assert.ifError(error);
+ assert.equal(res.name, 'test');
+ assert.ok(res.age == null);
+ done();
+ });
+ });
+ });
+ });
+
+ it('without a callback', function(done) {
+ var m = mquery(col);
+ m.where({ name: 'exec + update' }).setOptions({ multi: true });
+ m.update({ name: 'exec' });
+
+ // unsafe write
+ m.exec();
+
+ setTimeout(function() {
+ mquery(col).find({ name: 'exec' }, function(err, docs) {
+ assert.ifError(err);
+ assert.equal(2, docs.length);
+ done();
+ });
+ }, 200);
+ });
+ it('preserves key ordering', function(done) {
+ var m = mquery(col);
+
+ var m2 = m.update({ _id : 'something' }, { '1' : 1, '2' : 2, '3' : 3});
+ var doc = m2._updateForExec().$set;
+ var count = 0;
+ for (var i in doc) {
+ if (count == 0) {
+ assert.equal('1', i);
+ } else if (count == 1) {
+ assert.equal('2', i);
+ } else if (count == 2) {
+ assert.equal('3', i);
+ }
+ count++;
+ }
+ done();
+ });
+ });
+
+ describe('remove', function() {
+ it('with a callback', function(done) {
+ var m = mquery(col).where({ age: 2 }).remove();
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal(1, res.result.n);
+ done();
+ });
+ });
+
+ it('without a callback', function(done) {
+ var m = mquery(col).where({ age: 1 }).remove();
+ m.exec();
+
+ setTimeout(function() {
+ mquery(col).where('name', 'exec').count(function(err, num) {
+ assert.equal(1, num);
+ done();
+ });
+ }, 200);
+ });
+ });
+
+ describe('deleteOne', function() {
+ it('with a callback', function(done) {
+ var m = mquery(col).where({ age: { $gte: 0 } }).deleteOne();
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ done();
+ });
+ });
+
+ it('with justOne set', function(done) {
+ var m = mquery(col).where({ age: { $gte: 0 } }).
+ // Should ignore `justOne`
+ setOptions({ justOne: false }).
+ deleteOne();
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 1);
+ done();
+ });
+ });
+ });
+
+ describe('deleteMany', function() {
+ it('with a callback', function(done) {
+ var m = mquery(col).where({ age: { $gte: 0 } }).deleteMany();
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal(res.result.n, 2);
+ done();
+ });
+ });
+ });
+
+ describe('findOneAndUpdate', function() {
+ it('with a callback', function(done) {
+ var m = mquery(col);
+ m.findOneAndUpdate({ name: 'exec', age: 1 }, { $set: { name: 'findOneAndUpdate' }});
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal('findOneAndUpdate', res.value.name);
+ done();
+ });
+ });
+ });
+
+ describe('findOneAndRemove', function() {
+ it('with a callback', function(done) {
+ var m = mquery(col);
+ m.findOneAndRemove({ name: 'exec', age: 2 });
+ m.exec(function(err, res) {
+ assert.ifError(err);
+ assert.equal('exec', res.value.name);
+ assert.equal(2, res.value.age);
+ mquery(col).count({ name: 'exec' }, function(err, num) {
+ assert.ifError(err);
+ assert.equal(1, num);
+ done();
+ });
+ });
+ });
+ });
+ });
+
+ describe('setTraceFunction', function() {
+ beforeEach(function(done) {
+ col.insert([{ name: 'trace', age: 93 }], done);
+ });
+
+ it('calls trace function when executing query', function(done) {
+ var m = mquery(col);
+
+ var resultTraceCalled;
+
+ m.setTraceFunction(function(method, queryInfo) {
+ try {
+ assert.equal('findOne', method);
+ assert.equal('trace', queryInfo.conditions.name);
+ } catch (e) {
+ done(e);
+ }
+
+ return function(err, result, millis) {
+ try {
+ assert.equal(93, result.age);
+ assert.ok(typeof millis === 'number');
+ } catch (e) {
+ done(e);
+ }
+ resultTraceCalled = true;
+ };
+ });
+
+ m.findOne({name: 'trace'}, function(err, doc) {
+ assert.ifError(err);
+ assert.equal(resultTraceCalled, true);
+ assert.equal(93, doc.age);
+ done();
+ });
+ });
+
+ it('inherits trace function when calling toConstructor', function(done) {
+ function traceFunction() { return function() {}; }
+
+ var tracedQuery = mquery().setTraceFunction(traceFunction).toConstructor();
+
+ var query = tracedQuery();
+ assert.equal(traceFunction, query._traceFunction);
+
+ done();
+ });
+ });
+
+ describe('thunk', function() {
+ it('returns a function', function(done) {
+ assert.equal('function', typeof mquery().thunk());
+ done();
+ });
+
+ it('passes the fn arg to `exec`', function(done) {
+ function cb() {}
+ var m = mquery();
+
+ m.exec = function testing(fn) {
+ assert.equal(this, m);
+ assert.equal(cb, fn);
+ done();
+ };
+
+ m.thunk()(cb);
+ });
+ });
+
+ describe('then', function() {
+ before(function(done) {
+ col.insert([{ name: 'then', age: 1 }, { name: 'then', age: 2 }], done);
+ });
+
+ after(function(done) {
+ mquery(col).remove({ name: 'then' }).exec(done);
+ });
+
+ it('returns a promise A+ compat object', function(done) {
+ var m = mquery(col).find();
+ assert.equal('function', typeof m.then);
+ done();
+ });
+
+ it('creates a promise that is resolved on success', function(done) {
+ var promise = mquery(col).count({ name: 'then' }).then();
+ promise.then(function(count) {
+ assert.equal(2, count);
+ done();
+ }, done);
+ });
+
+ it('supports exec() cb being called synchronously #66', function(done) {
+ var query = mquery(col).count({ name: 'then' });
+ query.exec = function(cb) {
+ cb(null, 66);
+ };
+
+ query.then(success, done);
+ function success(count) {
+ assert.equal(66, count);
+ done();
+ }
+ });
+
+ it('supports other Promise libs', function(done) {
+ var bluebird = mquery.Promise;
+
+ // hack for testing
+ mquery.Promise = function P() {
+ mquery.Promise = bluebird;
+ this.then = function(x, y) {
+ return x + y;
+ };
+ };
+
+ var val = mquery(col).count({ name: 'exec' }).then(1, 2);
+ assert.equal(val, 3);
+ done();
+ });
+ });
+
+ describe('stream', function() {
+ before(function(done) {
+ col.insert([{ name: 'stream', age: 1 }, { name: 'stream', age: 2 }], done);
+ });
+
+ after(function(done) {
+ mquery(col).remove({ name: 'stream' }).exec(done);
+ });
+
+ describe('throws', function() {
+ describe('if used with non-find operations', function() {
+ var ops = ['update', 'findOneAndUpdate', 'remove', 'count', 'distinct'];
+
+ ops.forEach(function(op) {
+ assert.throws(function() {
+ mquery(col)[op]().stream();
+ });
+ });
+ });
+ });
+
+ it('returns a stream', function(done) {
+ var stream = mquery(col).find({ name: 'stream' }).stream();
+ var count = 0;
+ var err;
+
+ stream.on('data', function(doc) {
+ assert.equal('stream', doc.name);
+ ++count;
+ });
+
+ stream.on('error', function(er) {
+ err = er;
+ });
+
+ stream.on('end', function() {
+ if (err) return done(err);
+ assert.equal(2, count);
+ done();
+ });
+ });
+ });
+
+ function noDistinct(type) {
+ it('cannot be used with distinct()', function(done) {
+ assert.throws(function() {
+ mquery().distinct('name')[type](4);
+ }, new RegExp(type + ' cannot be used with distinct'));
+ done();
+ });
+ }
+
+ function no(method, type) {
+ it('cannot be used with ' + method + '()', function(done) {
+ assert.throws(function() {
+ mquery()[method]()[type](4);
+ }, new RegExp(type + ' cannot be used with ' + method));
+ done();
+ });
+ }
+
+ // query internal
+
+ describe('_updateForExec', function() {
+ it('returns a clone of the update object with same key order #19', function(done) {
+ var update = {};
+ update.$push = { n: { $each: [{x:10}], $slice: -1, $sort: {x:1}}};
+
+ var q = mquery().update({ x: 1 }, update);
+
+ // capture original key order
+ var order = [];
+ var key;
+ for (key in q._update.$push.n) {
+ order.push(key);
+ }
+
+ // compare output
+ var doc = q._updateForExec();
+ var i = 0;
+ for (key in doc.$push.n) {
+ assert.equal(key, order[i]);
+ i++;
+ }
+
+ done();
+ });
+ });
+});
diff --git a/node_modules/mquery/test/utils.test.js b/node_modules/mquery/test/utils.test.js
new file mode 100644
index 0000000..ff95f33
--- /dev/null
+++ b/node_modules/mquery/test/utils.test.js
@@ -0,0 +1,144 @@
+'use strict';
+
+var Buffer = require('safe-buffer').Buffer;
+var utils = require('../lib/utils');
+var assert = require('assert');
+var debug = require('debug');
+
+var mongo;
+try {
+ mongo = new require('mongodb');
+} catch (e) {
+ debug('mongo', 'cannot construct mongodb instance');
+}
+
+describe('lib/utils', function() {
+ describe('clone', function() {
+ it('clones constructors named ObjectId', function(done) {
+ function ObjectId(id) {
+ this.id = id;
+ }
+
+ var o1 = new ObjectId('1234');
+ var o2 = utils.clone(o1);
+ assert.ok(o2 instanceof ObjectId);
+
+ done();
+ });
+
+ it('clones constructors named ObjectID', function(done) {
+ function ObjectID(id) {
+ this.id = id;
+ }
+
+ var o1 = new ObjectID('1234');
+ var o2 = utils.clone(o1);
+
+ assert.ok(o2 instanceof ObjectID);
+ done();
+ });
+
+ it('does not clone constructors named ObjectIdd', function(done) {
+ function ObjectIdd(id) {
+ this.id = id;
+ }
+
+ var o1 = new ObjectIdd('1234');
+ var o2 = utils.clone(o1);
+ assert.ok(!(o2 instanceof ObjectIdd));
+
+ done();
+ });
+
+ it('optionally clones ObjectId constructors using its clone method', function(done) {
+ function ObjectID(id) {
+ this.id = id;
+ this.cloned = false;
+ }
+
+ ObjectID.prototype.clone = function() {
+ var ret = new ObjectID(this.id);
+ ret.cloned = true;
+ return ret;
+ };
+
+ var id = 1234;
+ var o1 = new ObjectID(id);
+ assert.equal(id, o1.id);
+ assert.equal(false, o1.cloned);
+
+ var o2 = utils.clone(o1);
+ assert.ok(o2 instanceof ObjectID);
+ assert.equal(id, o2.id);
+ assert.ok(o2.cloned);
+ done();
+ });
+
+ it('clones mongodb.ReadPreferences', function(done) {
+ if (!mongo) return done();
+
+ var tags = [
+ {dc: 'tag1'}
+ ];
+ var prefs = [
+ new mongo.ReadPreference('primary'),
+ new mongo.ReadPreference(mongo.ReadPreference.PRIMARY_PREFERRED),
+ new mongo.ReadPreference('secondary', tags)
+ ];
+
+ var prefsCloned = utils.clone(prefs);
+
+ for (var i = 0; i < prefsCloned.length; i++) {
+ assert.notEqual(prefs[i], prefsCloned[i]);
+ if (prefs[i].tags) {
+ assert.ok(prefsCloned[i].tags);
+ assert.notEqual(prefs[i].tags, prefsCloned[i].tags);
+ assert.notEqual(prefs[i].tags[0], prefsCloned[i].tags[0]);
+ } else {
+ assert.equal(prefsCloned[i].tags, null);
+ }
+ }
+
+ done();
+ });
+
+ it('clones mongodb.Binary', function(done) {
+ if (!mongo) return done();
+ var buf = Buffer.from('hi');
+ var binary = new mongo.Binary(buf, 2);
+ var clone = utils.clone(binary);
+ assert.equal(binary.sub_type, clone.sub_type);
+ assert.equal(String(binary.buffer), String(buf));
+ assert.ok(binary !== clone);
+ done();
+ });
+
+ it('handles objects with no constructor', function(done) {
+ var name = '335';
+
+ var o = Object.create(null);
+ o.name = name;
+
+ var clone;
+ assert.doesNotThrow(function() {
+ clone = utils.clone(o);
+ });
+
+ assert.equal(name, clone.name);
+ assert.ok(o != clone);
+ done();
+ });
+
+ it('handles buffers', function(done) {
+ var buff = Buffer.alloc(10);
+ buff.fill(1);
+ var clone = utils.clone(buff);
+
+ for (var i = 0; i < buff.length; i++) {
+ assert.equal(buff[i], clone[i]);
+ }
+
+ done();
+ });
+ });
+});
diff --git a/node_modules/process-nextick-args/index.js b/node_modules/process-nextick-args/index.js
new file mode 100644
index 0000000..3eecf11
--- /dev/null
+++ b/node_modules/process-nextick-args/index.js
@@ -0,0 +1,45 @@
+'use strict';
+
+if (typeof process === 'undefined' ||
+ !process.version ||
+ process.version.indexOf('v0.') === 0 ||
+ process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {
+ module.exports = { nextTick: nextTick };
+} else {
+ module.exports = process
+}
+
+function nextTick(fn, arg1, arg2, arg3) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('"callback" argument must be a function');
+ }
+ var len = arguments.length;
+ var args, i;
+ switch (len) {
+ case 0:
+ case 1:
+ return process.nextTick(fn);
+ case 2:
+ return process.nextTick(function afterTickOne() {
+ fn.call(null, arg1);
+ });
+ case 3:
+ return process.nextTick(function afterTickTwo() {
+ fn.call(null, arg1, arg2);
+ });
+ case 4:
+ return process.nextTick(function afterTickThree() {
+ fn.call(null, arg1, arg2, arg3);
+ });
+ default:
+ args = new Array(len - 1);
+ i = 0;
+ while (i < args.length) {
+ args[i++] = arguments[i];
+ }
+ return process.nextTick(function afterTick() {
+ fn.apply(null, args);
+ });
+ }
+}
+
diff --git a/node_modules/process-nextick-args/license.md b/node_modules/process-nextick-args/license.md
new file mode 100644
index 0000000..c67e353
--- /dev/null
+++ b/node_modules/process-nextick-args/license.md
@@ -0,0 +1,19 @@
+# Copyright (c) 2015 Calvin Metcalf
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.**
diff --git a/node_modules/process-nextick-args/package.json b/node_modules/process-nextick-args/package.json
new file mode 100644
index 0000000..0bf6973
--- /dev/null
+++ b/node_modules/process-nextick-args/package.json
@@ -0,0 +1,80 @@
+{
+ "_args": [
+ [
+ "process-nextick-args@~2.0.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream"
+ ]
+ ],
+ "_from": "process-nextick-args@>=2.0.0 <2.1.0",
+ "_hasShrinkwrap": false,
+ "_id": "process-nextick-args@2.0.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/process-nextick-args",
+ "_nodeVersion": "10.15.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/process-nextick-args_2.0.1_1560976479045_0.30434079670500513"
+ },
+ "_npmUser": {
+ "email": "calvin.metcalf@gmail.com",
+ "name": "cwmma"
+ },
+ "_npmVersion": "6.9.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "process-nextick-args",
+ "raw": "process-nextick-args@~2.0.0",
+ "rawSpec": "~2.0.0",
+ "scope": null,
+ "spec": ">=2.0.0 <2.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/readable-stream"
+ ],
+ "_resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "_shasum": "7820d9b16120cc55ca9ae7792680ae7dba6d7fe2",
+ "_shrinkwrap": null,
+ "_spec": "process-nextick-args@~2.0.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream",
+ "author": "",
+ "bugs": {
+ "url": "https://github.com/calvinmetcalf/process-nextick-args/issues"
+ },
+ "dependencies": {},
+ "description": "process.nextTick but always with args",
+ "devDependencies": {
+ "tap": "~0.2.6"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 4,
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdCpxfCRA9TVsSAnZWagAA2wUQAJE/zQojeYBtJTNHDGq7\ntlqxR0qbiugyY02+BV/s6cTIRG7uCAwpyWelDotgFeE5IfxoLNOLuRtc5y5w\nZr/xlgT5KxchI87af3FpNTB2Y/0+lKDjbSdj0k+Mz8IjxwUtBdt/8yqH89EF\nxOE+H9WCjL94tqDrnaPAXfIo84m0FLUA5hneNrJqmhXGfC/a7ncO5x1AmBDj\nPGV0pyS4XxuUEsV2KSx2Fy2pXxsI01mxq7nAeOwNPb20XbPbGhzTU9eLOzAJ\nMggd+bKbuDdxCFdf/CQ76d9Gz2T6fxjHNsKrw7AYcfrTi6bLQQKBpeN5KE7i\nagIYpzq2HWsjhrClsm1TQNbV8SWQR2OhbgDdMKn8OkIsvQGKJpJbW6I+m1va\nTd4Gc9i1dIweSjvS2g/iaVdm2E0EWhU9tSH7SnKKmEOBCsWsGW5XJQP7W+sO\nKuxicRik6vCGyaMrZz83blayXuXGWPSP9uDt0/2MINRefJTTusWaSikZxyQn\nZ0uqV9Li6WEEWALHQf3NtlAq49U0w/NN9jRPI2iViPdf4Q/cyf/Fwp5PmVKt\nFYx9V7me9XNCxu1kBlx7ZkbZW0M0eEuLYW8J2hNMiJjuksUr0mOlXjSKwMGf\nru2wMy7dCU+zVeA65QtGPSSfMOrATVzjbRWuXkR3xAmv3bJmbMIn1IG/rtSr\nnc/W\r\n=K8U9\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "7820d9b16120cc55ca9ae7792680ae7dba6d7fe2",
+ "tarball": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "unpackedSize": 3175
+ },
+ "gitHead": "b96d59913025441b00c4fd40e6894ddfa8e1c398",
+ "homepage": "https://github.com/calvinmetcalf/process-nextick-args",
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "cwmma",
+ "email": "calvin.metcalf@gmail.com"
+ }
+ ],
+ "name": "process-nextick-args",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/calvinmetcalf/process-nextick-args.git"
+ },
+ "scripts": {
+ "test": "node test.js"
+ },
+ "version": "2.0.1"
+}
diff --git a/node_modules/process-nextick-args/readme.md b/node_modules/process-nextick-args/readme.md
new file mode 100644
index 0000000..ecb432c
--- /dev/null
+++ b/node_modules/process-nextick-args/readme.md
@@ -0,0 +1,18 @@
+process-nextick-args
+=====
+
+[](https://travis-ci.org/calvinmetcalf/process-nextick-args)
+
+```bash
+npm install --save process-nextick-args
+```
+
+Always be able to pass arguments to process.nextTick, no matter the platform
+
+```js
+var pna = require('process-nextick-args');
+
+pna.nextTick(function (a, b, c) {
+ console.log(a, b, c);
+}, 'step', 3, 'profit');
+```
diff --git a/node_modules/readable-stream/.travis.yml b/node_modules/readable-stream/.travis.yml
new file mode 100644
index 0000000..f62cdac
--- /dev/null
+++ b/node_modules/readable-stream/.travis.yml
@@ -0,0 +1,34 @@
+sudo: false
+language: node_js
+before_install:
+ - (test $NPM_LEGACY && npm install -g npm@2 && npm install -g npm@3) || true
+notifications:
+ email: false
+matrix:
+ fast_finish: true
+ include:
+ - node_js: '0.8'
+ env: NPM_LEGACY=true
+ - node_js: '0.10'
+ env: NPM_LEGACY=true
+ - node_js: '0.11'
+ env: NPM_LEGACY=true
+ - node_js: '0.12'
+ env: NPM_LEGACY=true
+ - node_js: 1
+ env: NPM_LEGACY=true
+ - node_js: 2
+ env: NPM_LEGACY=true
+ - node_js: 3
+ env: NPM_LEGACY=true
+ - node_js: 4
+ - node_js: 5
+ - node_js: 6
+ - node_js: 7
+ - node_js: 8
+ - node_js: 9
+script: "npm run test"
+env:
+ global:
+ - secure: rE2Vvo7vnjabYNULNyLFxOyt98BoJexDqsiOnfiD6kLYYsiQGfr/sbZkPMOFm9qfQG7pjqx+zZWZjGSswhTt+626C0t/njXqug7Yps4c3dFblzGfreQHp7wNX5TFsvrxd6dAowVasMp61sJcRnB2w8cUzoe3RAYUDHyiHktwqMc=
+ - secure: g9YINaKAdMatsJ28G9jCGbSaguXCyxSTy+pBO6Ch0Cf57ZLOTka3HqDj8p3nV28LUIHZ3ut5WO43CeYKwt4AUtLpBS3a0dndHdY6D83uY6b2qh5hXlrcbeQTq2cvw2y95F7hm4D1kwrgZ7ViqaKggRcEupAL69YbJnxeUDKWEdI=
diff --git a/node_modules/readable-stream/CONTRIBUTING.md b/node_modules/readable-stream/CONTRIBUTING.md
new file mode 100644
index 0000000..f478d58
--- /dev/null
+++ b/node_modules/readable-stream/CONTRIBUTING.md
@@ -0,0 +1,38 @@
+# Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+* (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+* (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+* (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+* (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+## Moderation Policy
+
+The [Node.js Moderation Policy] applies to this WG.
+
+## Code of Conduct
+
+The [Node.js Code of Conduct][] applies to this WG.
+
+[Node.js Code of Conduct]:
+https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md
+[Node.js Moderation Policy]:
+https://github.com/nodejs/TSC/blob/master/Moderation-Policy.md
diff --git a/node_modules/readable-stream/GOVERNANCE.md b/node_modules/readable-stream/GOVERNANCE.md
new file mode 100644
index 0000000..16ffb93
--- /dev/null
+++ b/node_modules/readable-stream/GOVERNANCE.md
@@ -0,0 +1,136 @@
+### Streams Working Group
+
+The Node.js Streams is jointly governed by a Working Group
+(WG)
+that is responsible for high-level guidance of the project.
+
+The WG has final authority over this project including:
+
+* Technical direction
+* Project governance and process (including this policy)
+* Contribution policy
+* GitHub repository hosting
+* Conduct guidelines
+* Maintaining the list of additional Collaborators
+
+For the current list of WG members, see the project
+[README.md](./README.md#current-project-team-members).
+
+### Collaborators
+
+The readable-stream GitHub repository is
+maintained by the WG and additional Collaborators who are added by the
+WG on an ongoing basis.
+
+Individuals making significant and valuable contributions are made
+Collaborators and given commit-access to the project. These
+individuals are identified by the WG and their addition as
+Collaborators is discussed during the WG meeting.
+
+_Note:_ If you make a significant contribution and are not considered
+for commit-access log an issue or contact a WG member directly and it
+will be brought up in the next WG meeting.
+
+Modifications of the contents of the readable-stream repository are
+made on
+a collaborative basis. Anybody with a GitHub account may propose a
+modification via pull request and it will be considered by the project
+Collaborators. All pull requests must be reviewed and accepted by a
+Collaborator with sufficient expertise who is able to take full
+responsibility for the change. In the case of pull requests proposed
+by an existing Collaborator, an additional Collaborator is required
+for sign-off. Consensus should be sought if additional Collaborators
+participate and there is disagreement around a particular
+modification. See _Consensus Seeking Process_ below for further detail
+on the consensus model used for governance.
+
+Collaborators may opt to elevate significant or controversial
+modifications, or modifications that have not found consensus to the
+WG for discussion by assigning the ***WG-agenda*** tag to a pull
+request or issue. The WG should serve as the final arbiter where
+required.
+
+For the current list of Collaborators, see the project
+[README.md](./README.md#members).
+
+### WG Membership
+
+WG seats are not time-limited. There is no fixed size of the WG.
+However, the expected target is between 6 and 12, to ensure adequate
+coverage of important areas of expertise, balanced with the ability to
+make decisions efficiently.
+
+There is no specific set of requirements or qualifications for WG
+membership beyond these rules.
+
+The WG may add additional members to the WG by unanimous consensus.
+
+A WG member may be removed from the WG by voluntary resignation, or by
+unanimous consensus of all other WG members.
+
+Changes to WG membership should be posted in the agenda, and may be
+suggested as any other agenda item (see "WG Meetings" below).
+
+If an addition or removal is proposed during a meeting, and the full
+WG is not in attendance to participate, then the addition or removal
+is added to the agenda for the subsequent meeting. This is to ensure
+that all members are given the opportunity to participate in all
+membership decisions. If a WG member is unable to attend a meeting
+where a planned membership decision is being made, then their consent
+is assumed.
+
+No more than 1/3 of the WG members may be affiliated with the same
+employer. If removal or resignation of a WG member, or a change of
+employment by a WG member, creates a situation where more than 1/3 of
+the WG membership shares an employer, then the situation must be
+immediately remedied by the resignation or removal of one or more WG
+members affiliated with the over-represented employer(s).
+
+### WG Meetings
+
+The WG meets occasionally on a Google Hangout On Air. A designated moderator
+approved by the WG runs the meeting. Each meeting should be
+published to YouTube.
+
+Items are added to the WG agenda that are considered contentious or
+are modifications of governance, contribution policy, WG membership,
+or release process.
+
+The intention of the agenda is not to approve or review all patches;
+that should happen continuously on GitHub and be handled by the larger
+group of Collaborators.
+
+Any community member or contributor can ask that something be added to
+the next meeting's agenda by logging a GitHub Issue. Any Collaborator,
+WG member or the moderator can add the item to the agenda by adding
+the ***WG-agenda*** tag to the issue.
+
+Prior to each WG meeting the moderator will share the Agenda with
+members of the WG. WG members can add any items they like to the
+agenda at the beginning of each meeting. The moderator and the WG
+cannot veto or remove items.
+
+The WG may invite persons or representatives from certain projects to
+participate in a non-voting capacity.
+
+The moderator is responsible for summarizing the discussion of each
+agenda item and sends it as a pull request after the meeting.
+
+### Consensus Seeking Process
+
+The WG follows a
+[Consensus
+Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making)
+decision-making model.
+
+When an agenda item has appeared to reach a consensus the moderator
+will ask "Does anyone object?" as a final call for dissent from the
+consensus.
+
+If an agenda item cannot reach a consensus a WG member can call for
+either a closing vote or a vote to table the issue to the next
+meeting. The call for a vote must be seconded by a majority of the WG
+or else the discussion will continue. Simple majority wins.
+
+Note that changes to WG membership require a majority consensus. See
+"WG Membership" above.
diff --git a/node_modules/readable-stream/LICENSE b/node_modules/readable-stream/LICENSE
new file mode 100644
index 0000000..2873b3b
--- /dev/null
+++ b/node_modules/readable-stream/LICENSE
@@ -0,0 +1,47 @@
+Node.js is licensed for use as follows:
+
+"""
+Copyright Node.js contributors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
+This license applies to parts of Node.js originating from the
+https://github.com/joyent/node repository:
+
+"""
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
diff --git a/node_modules/readable-stream/README.md b/node_modules/readable-stream/README.md
new file mode 100644
index 0000000..23fe3f3
--- /dev/null
+++ b/node_modules/readable-stream/README.md
@@ -0,0 +1,58 @@
+# readable-stream
+
+***Node-core v8.11.1 streams for userland*** [](https://travis-ci.org/nodejs/readable-stream)
+
+
+[](https://nodei.co/npm/readable-stream/)
+[](https://nodei.co/npm/readable-stream/)
+
+
+[](https://saucelabs.com/u/readable-stream)
+
+```bash
+npm install --save readable-stream
+```
+
+***Node-core streams for userland***
+
+This package is a mirror of the Streams2 and Streams3 implementations in
+Node-core.
+
+Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v8.11.1/docs/api/stream.html).
+
+If you want to guarantee a stable streams base, regardless of what version of
+Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).
+
+As of version 2.0.0 **readable-stream** uses semantic versioning.
+
+# Streams Working Group
+
+`readable-stream` is maintained by the Streams Working Group, which
+oversees the development and maintenance of the Streams API within
+Node.js. The responsibilities of the Streams Working Group include:
+
+* Addressing stream issues on the Node.js issue tracker.
+* Authoring and editing stream documentation within the Node.js project.
+* Reviewing changes to stream subclasses within the Node.js project.
+* Redirecting changes to streams from the Node.js project to this
+ project.
+* Assisting in the implementation of stream providers within Node.js.
+* Recommending versions of `readable-stream` to be included in Node.js.
+* Messaging about the future of streams to give the community advance
+ notice of changes.
+
+
+## Team Members
+
+* **Chris Dickinson** ([@chrisdickinson](https://github.com/chrisdickinson)) <christopher.s.dickinson@gmail.com>
+ - Release GPG key: 9554F04D7259F04124DE6B476D5A82AC7E37093B
+* **Calvin Metcalf** ([@calvinmetcalf](https://github.com/calvinmetcalf)) <calvin.metcalf@gmail.com>
+ - Release GPG key: F3EF5F62A87FC27A22E643F714CE4FF5015AA242
+* **Rod Vagg** ([@rvagg](https://github.com/rvagg)) <rod@vagg.org>
+ - Release GPG key: DD8F2338BAE7501E3DD5AC78C273792F7D83545D
+* **Sam Newman** ([@sonewman](https://github.com/sonewman)) <newmansam@outlook.com>
+* **Mathias Buus** ([@mafintosh](https://github.com/mafintosh)) <mathiasbuus@gmail.com>
+* **Domenic Denicola** ([@domenic](https://github.com/domenic)) <d@domenic.me>
+* **Matteo Collina** ([@mcollina](https://github.com/mcollina)) <matteo.collina@gmail.com>
+ - Release GPG key: 3ABC01543F22DD2239285CDD818674489FBC127E
+* **Irina Shestak** ([@lrlna](https://github.com/lrlna)) <shestak.irina@gmail.com>
diff --git a/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md b/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md
new file mode 100644
index 0000000..83275f1
--- /dev/null
+++ b/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md
@@ -0,0 +1,60 @@
+# streams WG Meeting 2015-01-30
+
+## Links
+
+* **Google Hangouts Video**: http://www.youtube.com/watch?v=I9nDOSGfwZg
+* **GitHub Issue**: https://github.com/iojs/readable-stream/issues/106
+* **Original Minutes Google Doc**: https://docs.google.com/document/d/17aTgLnjMXIrfjgNaTUnHQO7m3xgzHR2VXBTmi03Qii4/
+
+## Agenda
+
+Extracted from https://github.com/iojs/readable-stream/labels/wg-agenda prior to meeting.
+
+* adopt a charter [#105](https://github.com/iojs/readable-stream/issues/105)
+* release and versioning strategy [#101](https://github.com/iojs/readable-stream/issues/101)
+* simpler stream creation [#102](https://github.com/iojs/readable-stream/issues/102)
+* proposal: deprecate implicit flowing of streams [#99](https://github.com/iojs/readable-stream/issues/99)
+
+## Minutes
+
+### adopt a charter
+
+* group: +1's all around
+
+### What versioning scheme should be adopted?
+* group: +1’s 3.0.0
+* domenic+group: pulling in patches from other sources where appropriate
+* mikeal: version independently, suggesting versions for io.js
+* mikeal+domenic: work with TC to notify in advance of changes
+simpler stream creation
+
+### streamline creation of streams
+* sam: streamline creation of streams
+* domenic: nice simple solution posted
+ but, we lose the opportunity to change the model
+ may not be backwards incompatible (double check keys)
+
+ **action item:** domenic will check
+
+### remove implicit flowing of streams on(‘data’)
+* add isFlowing / isPaused
+* mikeal: worrying that we’re documenting polyfill methods – confuses users
+* domenic: more reflective API is probably good, with warning labels for users
+* new section for mad scientists (reflective stream access)
+* calvin: name the “third state”
+* mikeal: maybe borrow the name from whatwg?
+* domenic: we’re missing the “third state”
+* consensus: kind of difficult to name the third state
+* mikeal: figure out differences in states / compat
+* mathias: always flow on data – eliminates third state
+ * explore what it breaks
+
+**action items:**
+* ask isaac for ability to list packages by what public io.js APIs they use (esp. Stream)
+* ask rod/build for infrastructure
+* **chris**: explore the “flow on data” approach
+* add isPaused/isFlowing
+* add new docs section
+* move isPaused to that section
+
+
diff --git a/node_modules/readable-stream/duplex-browser.js b/node_modules/readable-stream/duplex-browser.js
new file mode 100644
index 0000000..f8b2db8
--- /dev/null
+++ b/node_modules/readable-stream/duplex-browser.js
@@ -0,0 +1 @@
+module.exports = require('./lib/_stream_duplex.js');
diff --git a/node_modules/readable-stream/duplex.js b/node_modules/readable-stream/duplex.js
new file mode 100644
index 0000000..46924cb
--- /dev/null
+++ b/node_modules/readable-stream/duplex.js
@@ -0,0 +1 @@
+module.exports = require('./readable').Duplex
diff --git a/node_modules/readable-stream/lib/_stream_duplex.js b/node_modules/readable-stream/lib/_stream_duplex.js
new file mode 100644
index 0000000..57003c3
--- /dev/null
+++ b/node_modules/readable-stream/lib/_stream_duplex.js
@@ -0,0 +1,131 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// a duplex stream is just a stream that is both readable and writable.
+// Since JS doesn't have multiple prototypal inheritance, this class
+// prototypally inherits from Readable, and then parasitically from
+// Writable.
+
+'use strict';
+
+/**/
+
+var pna = require('process-nextick-args');
+/**/
+
+/**/
+var objectKeys = Object.keys || function (obj) {
+ var keys = [];
+ for (var key in obj) {
+ keys.push(key);
+ }return keys;
+};
+/**/
+
+module.exports = Duplex;
+
+/**/
+var util = Object.create(require('core-util-is'));
+util.inherits = require('inherits');
+/**/
+
+var Readable = require('./_stream_readable');
+var Writable = require('./_stream_writable');
+
+util.inherits(Duplex, Readable);
+
+{
+ // avoid scope creep, the keys array can then be collected
+ var keys = objectKeys(Writable.prototype);
+ for (var v = 0; v < keys.length; v++) {
+ var method = keys[v];
+ if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
+ }
+}
+
+function Duplex(options) {
+ if (!(this instanceof Duplex)) return new Duplex(options);
+
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ if (options && options.readable === false) this.readable = false;
+
+ if (options && options.writable === false) this.writable = false;
+
+ this.allowHalfOpen = true;
+ if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;
+
+ this.once('end', onend);
+}
+
+Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
+ // making it explicit this property is not enumerable
+ // because otherwise some prototype manipulation in
+ // userland will fail
+ enumerable: false,
+ get: function () {
+ return this._writableState.highWaterMark;
+ }
+});
+
+// the no-half-open enforcer
+function onend() {
+ // if we allow half-open state, or if the writable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._writableState.ended) return;
+
+ // no more data can be written.
+ // But allow more writes to happen in this tick.
+ pna.nextTick(onEndNT, this);
+}
+
+function onEndNT(self) {
+ self.end();
+}
+
+Object.defineProperty(Duplex.prototype, 'destroyed', {
+ get: function () {
+ if (this._readableState === undefined || this._writableState === undefined) {
+ return false;
+ }
+ return this._readableState.destroyed && this._writableState.destroyed;
+ },
+ set: function (value) {
+ // we ignore the value if the stream
+ // has not been initialized yet
+ if (this._readableState === undefined || this._writableState === undefined) {
+ return;
+ }
+
+ // backward compatibility, the user is explicitly
+ // managing destroyed
+ this._readableState.destroyed = value;
+ this._writableState.destroyed = value;
+ }
+});
+
+Duplex.prototype._destroy = function (err, cb) {
+ this.push(null);
+ this.end();
+
+ pna.nextTick(cb, err);
+};
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/_stream_passthrough.js b/node_modules/readable-stream/lib/_stream_passthrough.js
new file mode 100644
index 0000000..612edb4
--- /dev/null
+++ b/node_modules/readable-stream/lib/_stream_passthrough.js
@@ -0,0 +1,47 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// a passthrough stream.
+// basically just the most minimal sort of Transform stream.
+// Every written chunk gets output as-is.
+
+'use strict';
+
+module.exports = PassThrough;
+
+var Transform = require('./_stream_transform');
+
+/**/
+var util = Object.create(require('core-util-is'));
+util.inherits = require('inherits');
+/**/
+
+util.inherits(PassThrough, Transform);
+
+function PassThrough(options) {
+ if (!(this instanceof PassThrough)) return new PassThrough(options);
+
+ Transform.call(this, options);
+}
+
+PassThrough.prototype._transform = function (chunk, encoding, cb) {
+ cb(null, chunk);
+};
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/_stream_readable.js b/node_modules/readable-stream/lib/_stream_readable.js
new file mode 100644
index 0000000..0f80764
--- /dev/null
+++ b/node_modules/readable-stream/lib/_stream_readable.js
@@ -0,0 +1,1019 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+/**/
+
+var pna = require('process-nextick-args');
+/**/
+
+module.exports = Readable;
+
+/**/
+var isArray = require('isarray');
+/**/
+
+/**/
+var Duplex;
+/**/
+
+Readable.ReadableState = ReadableState;
+
+/**/
+var EE = require('events').EventEmitter;
+
+var EElistenerCount = function (emitter, type) {
+ return emitter.listeners(type).length;
+};
+/**/
+
+/**/
+var Stream = require('./internal/streams/stream');
+/**/
+
+/**/
+
+var Buffer = require('safe-buffer').Buffer;
+var OurUint8Array = global.Uint8Array || function () {};
+function _uint8ArrayToBuffer(chunk) {
+ return Buffer.from(chunk);
+}
+function _isUint8Array(obj) {
+ return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
+}
+
+/**/
+
+/**/
+var util = Object.create(require('core-util-is'));
+util.inherits = require('inherits');
+/**/
+
+/**/
+var debugUtil = require('util');
+var debug = void 0;
+if (debugUtil && debugUtil.debuglog) {
+ debug = debugUtil.debuglog('stream');
+} else {
+ debug = function () {};
+}
+/**/
+
+var BufferList = require('./internal/streams/BufferList');
+var destroyImpl = require('./internal/streams/destroy');
+var StringDecoder;
+
+util.inherits(Readable, Stream);
+
+var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];
+
+function prependListener(emitter, event, fn) {
+ // Sadly this is not cacheable as some libraries bundle their own
+ // event emitter implementation with them.
+ if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);
+
+ // This is a hack to make sure that our error handler is attached before any
+ // userland ones. NEVER DO THIS. This is here only because this code needs
+ // to continue to work with older versions of Node.js that do not include
+ // the prependListener() method. The goal is to eventually remove this hack.
+ if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];
+}
+
+function ReadableState(options, stream) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ options = options || {};
+
+ // Duplex streams are both readable and writable, but share
+ // the same options object.
+ // However, some cases require setting options to different
+ // values for the readable and the writable sides of the duplex stream.
+ // These options can be provided separately as readableXXX and writableXXX.
+ var isDuplex = stream instanceof Duplex;
+
+ // object stream flag. Used to make read(n) ignore n and to
+ // make all the buffer merging and length checks go away
+ this.objectMode = !!options.objectMode;
+
+ if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;
+
+ // the point at which it stops calling _read() to fill the buffer
+ // Note: 0 is a valid value, means "don't call _read preemptively ever"
+ var hwm = options.highWaterMark;
+ var readableHwm = options.readableHighWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+
+ if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = Math.floor(this.highWaterMark);
+
+ // A linked list is used to store data chunks instead of an array because the
+ // linked list can remove elements from the beginning faster than
+ // array.shift()
+ this.buffer = new BufferList();
+ this.length = 0;
+ this.pipes = null;
+ this.pipesCount = 0;
+ this.flowing = null;
+ this.ended = false;
+ this.endEmitted = false;
+ this.reading = false;
+
+ // a flag to be able to tell if the event 'readable'/'data' is emitted
+ // immediately, or on a later tick. We set this to true at first, because
+ // any actions that shouldn't happen until "later" should generally also
+ // not happen before the first read call.
+ this.sync = true;
+
+ // whenever we return null, then we set a flag to say
+ // that we're awaiting a 'readable' event emission.
+ this.needReadable = false;
+ this.emittedReadable = false;
+ this.readableListening = false;
+ this.resumeScheduled = false;
+
+ // has it been destroyed
+ this.destroyed = false;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // the number of writers that are awaiting a drain event in .pipe()s
+ this.awaitDrain = 0;
+
+ // if true, a maybeReadMore has been scheduled
+ this.readingMore = false;
+
+ this.decoder = null;
+ this.encoding = null;
+ if (options.encoding) {
+ if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
+ this.decoder = new StringDecoder(options.encoding);
+ this.encoding = options.encoding;
+ }
+}
+
+function Readable(options) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ if (!(this instanceof Readable)) return new Readable(options);
+
+ this._readableState = new ReadableState(options, this);
+
+ // legacy
+ this.readable = true;
+
+ if (options) {
+ if (typeof options.read === 'function') this._read = options.read;
+
+ if (typeof options.destroy === 'function') this._destroy = options.destroy;
+ }
+
+ Stream.call(this);
+}
+
+Object.defineProperty(Readable.prototype, 'destroyed', {
+ get: function () {
+ if (this._readableState === undefined) {
+ return false;
+ }
+ return this._readableState.destroyed;
+ },
+ set: function (value) {
+ // we ignore the value if the stream
+ // has not been initialized yet
+ if (!this._readableState) {
+ return;
+ }
+
+ // backward compatibility, the user is explicitly
+ // managing destroyed
+ this._readableState.destroyed = value;
+ }
+});
+
+Readable.prototype.destroy = destroyImpl.destroy;
+Readable.prototype._undestroy = destroyImpl.undestroy;
+Readable.prototype._destroy = function (err, cb) {
+ this.push(null);
+ cb(err);
+};
+
+// Manually shove something into the read() buffer.
+// This returns true if the highWaterMark has not been hit yet,
+// similar to how Writable.write() returns true if you should
+// write() some more.
+Readable.prototype.push = function (chunk, encoding) {
+ var state = this._readableState;
+ var skipChunkCheck;
+
+ if (!state.objectMode) {
+ if (typeof chunk === 'string') {
+ encoding = encoding || state.defaultEncoding;
+ if (encoding !== state.encoding) {
+ chunk = Buffer.from(chunk, encoding);
+ encoding = '';
+ }
+ skipChunkCheck = true;
+ }
+ } else {
+ skipChunkCheck = true;
+ }
+
+ return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);
+};
+
+// Unshift should *always* be something directly out of read()
+Readable.prototype.unshift = function (chunk) {
+ return readableAddChunk(this, chunk, null, true, false);
+};
+
+function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {
+ var state = stream._readableState;
+ if (chunk === null) {
+ state.reading = false;
+ onEofChunk(stream, state);
+ } else {
+ var er;
+ if (!skipChunkCheck) er = chunkInvalid(state, chunk);
+ if (er) {
+ stream.emit('error', er);
+ } else if (state.objectMode || chunk && chunk.length > 0) {
+ if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {
+ chunk = _uint8ArrayToBuffer(chunk);
+ }
+
+ if (addToFront) {
+ if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);
+ } else if (state.ended) {
+ stream.emit('error', new Error('stream.push() after EOF'));
+ } else {
+ state.reading = false;
+ if (state.decoder && !encoding) {
+ chunk = state.decoder.write(chunk);
+ if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);
+ } else {
+ addChunk(stream, state, chunk, false);
+ }
+ }
+ } else if (!addToFront) {
+ state.reading = false;
+ }
+ }
+
+ return needMoreData(state);
+}
+
+function addChunk(stream, state, chunk, addToFront) {
+ if (state.flowing && state.length === 0 && !state.sync) {
+ stream.emit('data', chunk);
+ stream.read(0);
+ } else {
+ // update the buffer info.
+ state.length += state.objectMode ? 1 : chunk.length;
+ if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);
+
+ if (state.needReadable) emitReadable(stream);
+ }
+ maybeReadMore(stream, state);
+}
+
+function chunkInvalid(state, chunk) {
+ var er;
+ if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ return er;
+}
+
+// if it's past the high water mark, we can push in some more.
+// Also, if we have no data yet, we can stand some
+// more bytes. This is to work around cases where hwm=0,
+// such as the repl. Also, if the push() triggered a
+// readable event, and the user called read(largeNumber) such that
+// needReadable was set, then we ought to push more, so that another
+// 'readable' event will be triggered.
+function needMoreData(state) {
+ return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);
+}
+
+Readable.prototype.isPaused = function () {
+ return this._readableState.flowing === false;
+};
+
+// backwards compatibility.
+Readable.prototype.setEncoding = function (enc) {
+ if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
+ this._readableState.decoder = new StringDecoder(enc);
+ this._readableState.encoding = enc;
+ return this;
+};
+
+// Don't raise the hwm > 8MB
+var MAX_HWM = 0x800000;
+function computeNewHighWaterMark(n) {
+ if (n >= MAX_HWM) {
+ n = MAX_HWM;
+ } else {
+ // Get the next highest power of 2 to prevent increasing hwm excessively in
+ // tiny amounts
+ n--;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ n++;
+ }
+ return n;
+}
+
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function howMuchToRead(n, state) {
+ if (n <= 0 || state.length === 0 && state.ended) return 0;
+ if (state.objectMode) return 1;
+ if (n !== n) {
+ // Only flow one buffer at a time
+ if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;
+ }
+ // If we're asking for more than the current hwm, then raise the hwm.
+ if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
+ if (n <= state.length) return n;
+ // Don't have enough
+ if (!state.ended) {
+ state.needReadable = true;
+ return 0;
+ }
+ return state.length;
+}
+
+// you can override either this method, or the async _read(n) below.
+Readable.prototype.read = function (n) {
+ debug('read', n);
+ n = parseInt(n, 10);
+ var state = this._readableState;
+ var nOrig = n;
+
+ if (n !== 0) state.emittedReadable = false;
+
+ // if we're doing read(0) to trigger a readable event, but we
+ // already have a bunch of data in the buffer, then just trigger
+ // the 'readable' event and move on.
+ if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {
+ debug('read: emitReadable', state.length, state.ended);
+ if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);
+ return null;
+ }
+
+ n = howMuchToRead(n, state);
+
+ // if we've ended, and we're now clear, then finish it up.
+ if (n === 0 && state.ended) {
+ if (state.length === 0) endReadable(this);
+ return null;
+ }
+
+ // All the actual chunk generation logic needs to be
+ // *below* the call to _read. The reason is that in certain
+ // synthetic stream cases, such as passthrough streams, _read
+ // may be a completely synchronous operation which may change
+ // the state of the read buffer, providing enough data when
+ // before there was *not* enough.
+ //
+ // So, the steps are:
+ // 1. Figure out what the state of things will be after we do
+ // a read from the buffer.
+ //
+ // 2. If that resulting state will trigger a _read, then call _read.
+ // Note that this may be asynchronous, or synchronous. Yes, it is
+ // deeply ugly to write APIs this way, but that still doesn't mean
+ // that the Readable class should behave improperly, as streams are
+ // designed to be sync/async agnostic.
+ // Take note if the _read call is sync or async (ie, if the read call
+ // has returned yet), so that we know whether or not it's safe to emit
+ // 'readable' etc.
+ //
+ // 3. Actually pull the requested chunks out of the buffer and return.
+
+ // if we need a readable event, then we need to do some reading.
+ var doRead = state.needReadable;
+ debug('need readable', doRead);
+
+ // if we currently have less than the highWaterMark, then also read some
+ if (state.length === 0 || state.length - n < state.highWaterMark) {
+ doRead = true;
+ debug('length less than watermark', doRead);
+ }
+
+ // however, if we've ended, then there's no point, and if we're already
+ // reading, then it's unnecessary.
+ if (state.ended || state.reading) {
+ doRead = false;
+ debug('reading or ended', doRead);
+ } else if (doRead) {
+ debug('do read');
+ state.reading = true;
+ state.sync = true;
+ // if the length is currently zero, then we *need* a readable event.
+ if (state.length === 0) state.needReadable = true;
+ // call internal read method
+ this._read(state.highWaterMark);
+ state.sync = false;
+ // If _read pushed data synchronously, then `reading` will be false,
+ // and we need to re-evaluate how much data we can return to the user.
+ if (!state.reading) n = howMuchToRead(nOrig, state);
+ }
+
+ var ret;
+ if (n > 0) ret = fromList(n, state);else ret = null;
+
+ if (ret === null) {
+ state.needReadable = true;
+ n = 0;
+ } else {
+ state.length -= n;
+ }
+
+ if (state.length === 0) {
+ // If we have nothing in the buffer, then we want to know
+ // as soon as we *do* get something into the buffer.
+ if (!state.ended) state.needReadable = true;
+
+ // If we tried to read() past the EOF, then emit end on the next tick.
+ if (nOrig !== n && state.ended) endReadable(this);
+ }
+
+ if (ret !== null) this.emit('data', ret);
+
+ return ret;
+};
+
+function onEofChunk(stream, state) {
+ if (state.ended) return;
+ if (state.decoder) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length) {
+ state.buffer.push(chunk);
+ state.length += state.objectMode ? 1 : chunk.length;
+ }
+ }
+ state.ended = true;
+
+ // emit 'readable' now to make sure it gets picked up.
+ emitReadable(stream);
+}
+
+// Don't emit readable right away in sync mode, because this can trigger
+// another read() call => stack overflow. This way, it might trigger
+// a nextTick recursion warning, but that's not so bad.
+function emitReadable(stream) {
+ var state = stream._readableState;
+ state.needReadable = false;
+ if (!state.emittedReadable) {
+ debug('emitReadable', state.flowing);
+ state.emittedReadable = true;
+ if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream);
+ }
+}
+
+function emitReadable_(stream) {
+ debug('emit readable');
+ stream.emit('readable');
+ flow(stream);
+}
+
+// at this point, the user has presumably seen the 'readable' event,
+// and called read() to consume some data. that may have triggered
+// in turn another _read(n) call, in which case reading = true if
+// it's in progress.
+// However, if we're not ended, or reading, and the length < hwm,
+// then go ahead and try to read some more preemptively.
+function maybeReadMore(stream, state) {
+ if (!state.readingMore) {
+ state.readingMore = true;
+ pna.nextTick(maybeReadMore_, stream, state);
+ }
+}
+
+function maybeReadMore_(stream, state) {
+ var len = state.length;
+ while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {
+ debug('maybeReadMore read 0');
+ stream.read(0);
+ if (len === state.length)
+ // didn't get any data, stop spinning.
+ break;else len = state.length;
+ }
+ state.readingMore = false;
+}
+
+// abstract method. to be overridden in specific implementation classes.
+// call cb(er, data) where data is <= n in length.
+// for virtual (non-string, non-buffer) streams, "length" is somewhat
+// arbitrary, and perhaps not very meaningful.
+Readable.prototype._read = function (n) {
+ this.emit('error', new Error('_read() is not implemented'));
+};
+
+Readable.prototype.pipe = function (dest, pipeOpts) {
+ var src = this;
+ var state = this._readableState;
+
+ switch (state.pipesCount) {
+ case 0:
+ state.pipes = dest;
+ break;
+ case 1:
+ state.pipes = [state.pipes, dest];
+ break;
+ default:
+ state.pipes.push(dest);
+ break;
+ }
+ state.pipesCount += 1;
+ debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
+
+ var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;
+
+ var endFn = doEnd ? onend : unpipe;
+ if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn);
+
+ dest.on('unpipe', onunpipe);
+ function onunpipe(readable, unpipeInfo) {
+ debug('onunpipe');
+ if (readable === src) {
+ if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
+ unpipeInfo.hasUnpiped = true;
+ cleanup();
+ }
+ }
+ }
+
+ function onend() {
+ debug('onend');
+ dest.end();
+ }
+
+ // when the dest drains, it reduces the awaitDrain counter
+ // on the source. This would be more elegant with a .once()
+ // handler in flow(), but adding and removing repeatedly is
+ // too slow.
+ var ondrain = pipeOnDrain(src);
+ dest.on('drain', ondrain);
+
+ var cleanedUp = false;
+ function cleanup() {
+ debug('cleanup');
+ // cleanup event handlers once the pipe is broken
+ dest.removeListener('close', onclose);
+ dest.removeListener('finish', onfinish);
+ dest.removeListener('drain', ondrain);
+ dest.removeListener('error', onerror);
+ dest.removeListener('unpipe', onunpipe);
+ src.removeListener('end', onend);
+ src.removeListener('end', unpipe);
+ src.removeListener('data', ondata);
+
+ cleanedUp = true;
+
+ // if the reader is waiting for a drain event from this
+ // specific writer, then it would cause it to never start
+ // flowing again.
+ // So, if this is awaiting a drain, then we just call it now.
+ // If we don't know, then assume that we are waiting for one.
+ if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
+ }
+
+ // If the user pushes more data while we're writing to dest then we'll end up
+ // in ondata again. However, we only want to increase awaitDrain once because
+ // dest will only emit one 'drain' event for the multiple writes.
+ // => Introduce a guard on increasing awaitDrain.
+ var increasedAwaitDrain = false;
+ src.on('data', ondata);
+ function ondata(chunk) {
+ debug('ondata');
+ increasedAwaitDrain = false;
+ var ret = dest.write(chunk);
+ if (false === ret && !increasedAwaitDrain) {
+ // If the user unpiped during `dest.write()`, it is possible
+ // to get stuck in a permanently paused state if that write
+ // also returned false.
+ // => Check whether `dest` is still a piping destination.
+ if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
+ debug('false write response, pause', src._readableState.awaitDrain);
+ src._readableState.awaitDrain++;
+ increasedAwaitDrain = true;
+ }
+ src.pause();
+ }
+ }
+
+ // if the dest has an error, then stop piping into it.
+ // however, don't suppress the throwing behavior for this.
+ function onerror(er) {
+ debug('onerror', er);
+ unpipe();
+ dest.removeListener('error', onerror);
+ if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);
+ }
+
+ // Make sure our error handler is attached before userland ones.
+ prependListener(dest, 'error', onerror);
+
+ // Both close and finish should trigger unpipe, but only once.
+ function onclose() {
+ dest.removeListener('finish', onfinish);
+ unpipe();
+ }
+ dest.once('close', onclose);
+ function onfinish() {
+ debug('onfinish');
+ dest.removeListener('close', onclose);
+ unpipe();
+ }
+ dest.once('finish', onfinish);
+
+ function unpipe() {
+ debug('unpipe');
+ src.unpipe(dest);
+ }
+
+ // tell the dest that it's being piped to
+ dest.emit('pipe', src);
+
+ // start the flow if it hasn't been started already.
+ if (!state.flowing) {
+ debug('pipe resume');
+ src.resume();
+ }
+
+ return dest;
+};
+
+function pipeOnDrain(src) {
+ return function () {
+ var state = src._readableState;
+ debug('pipeOnDrain', state.awaitDrain);
+ if (state.awaitDrain) state.awaitDrain--;
+ if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
+ state.flowing = true;
+ flow(src);
+ }
+ };
+}
+
+Readable.prototype.unpipe = function (dest) {
+ var state = this._readableState;
+ var unpipeInfo = { hasUnpiped: false };
+
+ // if we're not piping anywhere, then do nothing.
+ if (state.pipesCount === 0) return this;
+
+ // just one destination. most common case.
+ if (state.pipesCount === 1) {
+ // passed in one, but it's not the right one.
+ if (dest && dest !== state.pipes) return this;
+
+ if (!dest) dest = state.pipes;
+
+ // got a match.
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+ if (dest) dest.emit('unpipe', this, unpipeInfo);
+ return this;
+ }
+
+ // slow case. multiple pipe destinations.
+
+ if (!dest) {
+ // remove all.
+ var dests = state.pipes;
+ var len = state.pipesCount;
+ state.pipes = null;
+ state.pipesCount = 0;
+ state.flowing = false;
+
+ for (var i = 0; i < len; i++) {
+ dests[i].emit('unpipe', this, unpipeInfo);
+ }return this;
+ }
+
+ // try to find the right one.
+ var index = indexOf(state.pipes, dest);
+ if (index === -1) return this;
+
+ state.pipes.splice(index, 1);
+ state.pipesCount -= 1;
+ if (state.pipesCount === 1) state.pipes = state.pipes[0];
+
+ dest.emit('unpipe', this, unpipeInfo);
+
+ return this;
+};
+
+// set up data events if they are asked for
+// Ensure readable listeners eventually get something
+Readable.prototype.on = function (ev, fn) {
+ var res = Stream.prototype.on.call(this, ev, fn);
+
+ if (ev === 'data') {
+ // Start flowing on next tick if stream isn't explicitly paused
+ if (this._readableState.flowing !== false) this.resume();
+ } else if (ev === 'readable') {
+ var state = this._readableState;
+ if (!state.endEmitted && !state.readableListening) {
+ state.readableListening = state.needReadable = true;
+ state.emittedReadable = false;
+ if (!state.reading) {
+ pna.nextTick(nReadingNextTick, this);
+ } else if (state.length) {
+ emitReadable(this);
+ }
+ }
+ }
+
+ return res;
+};
+Readable.prototype.addListener = Readable.prototype.on;
+
+function nReadingNextTick(self) {
+ debug('readable nexttick read 0');
+ self.read(0);
+}
+
+// pause() and resume() are remnants of the legacy readable stream API
+// If the user uses them, then switch into old mode.
+Readable.prototype.resume = function () {
+ var state = this._readableState;
+ if (!state.flowing) {
+ debug('resume');
+ state.flowing = true;
+ resume(this, state);
+ }
+ return this;
+};
+
+function resume(stream, state) {
+ if (!state.resumeScheduled) {
+ state.resumeScheduled = true;
+ pna.nextTick(resume_, stream, state);
+ }
+}
+
+function resume_(stream, state) {
+ if (!state.reading) {
+ debug('resume read 0');
+ stream.read(0);
+ }
+
+ state.resumeScheduled = false;
+ state.awaitDrain = 0;
+ stream.emit('resume');
+ flow(stream);
+ if (state.flowing && !state.reading) stream.read(0);
+}
+
+Readable.prototype.pause = function () {
+ debug('call pause flowing=%j', this._readableState.flowing);
+ if (false !== this._readableState.flowing) {
+ debug('pause');
+ this._readableState.flowing = false;
+ this.emit('pause');
+ }
+ return this;
+};
+
+function flow(stream) {
+ var state = stream._readableState;
+ debug('flow', state.flowing);
+ while (state.flowing && stream.read() !== null) {}
+}
+
+// wrap an old-style stream as the async data source.
+// This is *not* part of the readable stream interface.
+// It is an ugly unfortunate mess of history.
+Readable.prototype.wrap = function (stream) {
+ var _this = this;
+
+ var state = this._readableState;
+ var paused = false;
+
+ stream.on('end', function () {
+ debug('wrapped end');
+ if (state.decoder && !state.ended) {
+ var chunk = state.decoder.end();
+ if (chunk && chunk.length) _this.push(chunk);
+ }
+
+ _this.push(null);
+ });
+
+ stream.on('data', function (chunk) {
+ debug('wrapped data');
+ if (state.decoder) chunk = state.decoder.write(chunk);
+
+ // don't skip over falsy values in objectMode
+ if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;
+
+ var ret = _this.push(chunk);
+ if (!ret) {
+ paused = true;
+ stream.pause();
+ }
+ });
+
+ // proxy all the other methods.
+ // important when wrapping filters and duplexes.
+ for (var i in stream) {
+ if (this[i] === undefined && typeof stream[i] === 'function') {
+ this[i] = function (method) {
+ return function () {
+ return stream[method].apply(stream, arguments);
+ };
+ }(i);
+ }
+ }
+
+ // proxy certain important events.
+ for (var n = 0; n < kProxyEvents.length; n++) {
+ stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));
+ }
+
+ // when we try to consume some more bytes, simply unpause the
+ // underlying stream.
+ this._read = function (n) {
+ debug('wrapped _read', n);
+ if (paused) {
+ paused = false;
+ stream.resume();
+ }
+ };
+
+ return this;
+};
+
+Object.defineProperty(Readable.prototype, 'readableHighWaterMark', {
+ // making it explicit this property is not enumerable
+ // because otherwise some prototype manipulation in
+ // userland will fail
+ enumerable: false,
+ get: function () {
+ return this._readableState.highWaterMark;
+ }
+});
+
+// exposed for testing purposes only.
+Readable._fromList = fromList;
+
+// Pluck off n bytes from an array of buffers.
+// Length is the combined lengths of all the buffers in the list.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function fromList(n, state) {
+ // nothing buffered
+ if (state.length === 0) return null;
+
+ var ret;
+ if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {
+ // read it all, truncate the list
+ if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);
+ state.buffer.clear();
+ } else {
+ // read part of list
+ ret = fromListPartial(n, state.buffer, state.decoder);
+ }
+
+ return ret;
+}
+
+// Extracts only enough buffered data to satisfy the amount requested.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function fromListPartial(n, list, hasStrings) {
+ var ret;
+ if (n < list.head.data.length) {
+ // slice is the same for buffers and strings
+ ret = list.head.data.slice(0, n);
+ list.head.data = list.head.data.slice(n);
+ } else if (n === list.head.data.length) {
+ // first chunk is a perfect match
+ ret = list.shift();
+ } else {
+ // result spans more than one buffer
+ ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);
+ }
+ return ret;
+}
+
+// Copies a specified amount of characters from the list of buffered data
+// chunks.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function copyFromBufferString(n, list) {
+ var p = list.head;
+ var c = 1;
+ var ret = p.data;
+ n -= ret.length;
+ while (p = p.next) {
+ var str = p.data;
+ var nb = n > str.length ? str.length : n;
+ if (nb === str.length) ret += str;else ret += str.slice(0, n);
+ n -= nb;
+ if (n === 0) {
+ if (nb === str.length) {
+ ++c;
+ if (p.next) list.head = p.next;else list.head = list.tail = null;
+ } else {
+ list.head = p;
+ p.data = str.slice(nb);
+ }
+ break;
+ }
+ ++c;
+ }
+ list.length -= c;
+ return ret;
+}
+
+// Copies a specified amount of bytes from the list of buffered data chunks.
+// This function is designed to be inlinable, so please take care when making
+// changes to the function body.
+function copyFromBuffer(n, list) {
+ var ret = Buffer.allocUnsafe(n);
+ var p = list.head;
+ var c = 1;
+ p.data.copy(ret);
+ n -= p.data.length;
+ while (p = p.next) {
+ var buf = p.data;
+ var nb = n > buf.length ? buf.length : n;
+ buf.copy(ret, ret.length - n, 0, nb);
+ n -= nb;
+ if (n === 0) {
+ if (nb === buf.length) {
+ ++c;
+ if (p.next) list.head = p.next;else list.head = list.tail = null;
+ } else {
+ list.head = p;
+ p.data = buf.slice(nb);
+ }
+ break;
+ }
+ ++c;
+ }
+ list.length -= c;
+ return ret;
+}
+
+function endReadable(stream) {
+ var state = stream._readableState;
+
+ // If we get here before consuming all the bytes, then that is a
+ // bug in node. Should never happen.
+ if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream');
+
+ if (!state.endEmitted) {
+ state.ended = true;
+ pna.nextTick(endReadableNT, state, stream);
+ }
+}
+
+function endReadableNT(state, stream) {
+ // Check that we didn't get one last unshift.
+ if (!state.endEmitted && state.length === 0) {
+ state.endEmitted = true;
+ stream.readable = false;
+ stream.emit('end');
+ }
+}
+
+function indexOf(xs, x) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ if (xs[i] === x) return i;
+ }
+ return -1;
+}
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/_stream_transform.js b/node_modules/readable-stream/lib/_stream_transform.js
new file mode 100644
index 0000000..fcfc105
--- /dev/null
+++ b/node_modules/readable-stream/lib/_stream_transform.js
@@ -0,0 +1,214 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// a transform stream is a readable/writable stream where you do
+// something with the data. Sometimes it's called a "filter",
+// but that's not a great name for it, since that implies a thing where
+// some bits pass through, and others are simply ignored. (That would
+// be a valid example of a transform, of course.)
+//
+// While the output is causally related to the input, it's not a
+// necessarily symmetric or synchronous transformation. For example,
+// a zlib stream might take multiple plain-text writes(), and then
+// emit a single compressed chunk some time in the future.
+//
+// Here's how this works:
+//
+// The Transform stream has all the aspects of the readable and writable
+// stream classes. When you write(chunk), that calls _write(chunk,cb)
+// internally, and returns false if there's a lot of pending writes
+// buffered up. When you call read(), that calls _read(n) until
+// there's enough pending readable data buffered up.
+//
+// In a transform stream, the written data is placed in a buffer. When
+// _read(n) is called, it transforms the queued up data, calling the
+// buffered _write cb's as it consumes chunks. If consuming a single
+// written chunk would result in multiple output chunks, then the first
+// outputted bit calls the readcb, and subsequent chunks just go into
+// the read buffer, and will cause it to emit 'readable' if necessary.
+//
+// This way, back-pressure is actually determined by the reading side,
+// since _read has to be called to start processing a new chunk. However,
+// a pathological inflate type of transform can cause excessive buffering
+// here. For example, imagine a stream where every byte of input is
+// interpreted as an integer from 0-255, and then results in that many
+// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
+// 1kb of data being output. In this case, you could write a very small
+// amount of input, and end up with a very large amount of output. In
+// such a pathological inflating mechanism, there'd be no way to tell
+// the system to stop doing the transform. A single 4MB write could
+// cause the system to run out of memory.
+//
+// However, even in such a pathological case, only a single written chunk
+// would be consumed, and then the rest would wait (un-transformed) until
+// the results of the previous transformed chunk were consumed.
+
+'use strict';
+
+module.exports = Transform;
+
+var Duplex = require('./_stream_duplex');
+
+/**/
+var util = Object.create(require('core-util-is'));
+util.inherits = require('inherits');
+/**/
+
+util.inherits(Transform, Duplex);
+
+function afterTransform(er, data) {
+ var ts = this._transformState;
+ ts.transforming = false;
+
+ var cb = ts.writecb;
+
+ if (!cb) {
+ return this.emit('error', new Error('write callback called multiple times'));
+ }
+
+ ts.writechunk = null;
+ ts.writecb = null;
+
+ if (data != null) // single equals check for both `null` and `undefined`
+ this.push(data);
+
+ cb(er);
+
+ var rs = this._readableState;
+ rs.reading = false;
+ if (rs.needReadable || rs.length < rs.highWaterMark) {
+ this._read(rs.highWaterMark);
+ }
+}
+
+function Transform(options) {
+ if (!(this instanceof Transform)) return new Transform(options);
+
+ Duplex.call(this, options);
+
+ this._transformState = {
+ afterTransform: afterTransform.bind(this),
+ needTransform: false,
+ transforming: false,
+ writecb: null,
+ writechunk: null,
+ writeencoding: null
+ };
+
+ // start out asking for a readable event once data is transformed.
+ this._readableState.needReadable = true;
+
+ // we have implemented the _read method, and done the other things
+ // that Readable wants before the first _read call, so unset the
+ // sync guard flag.
+ this._readableState.sync = false;
+
+ if (options) {
+ if (typeof options.transform === 'function') this._transform = options.transform;
+
+ if (typeof options.flush === 'function') this._flush = options.flush;
+ }
+
+ // When the writable side finishes, then flush out anything remaining.
+ this.on('prefinish', prefinish);
+}
+
+function prefinish() {
+ var _this = this;
+
+ if (typeof this._flush === 'function') {
+ this._flush(function (er, data) {
+ done(_this, er, data);
+ });
+ } else {
+ done(this, null, null);
+ }
+}
+
+Transform.prototype.push = function (chunk, encoding) {
+ this._transformState.needTransform = false;
+ return Duplex.prototype.push.call(this, chunk, encoding);
+};
+
+// This is the part where you do stuff!
+// override this function in implementation classes.
+// 'chunk' is an input chunk.
+//
+// Call `push(newChunk)` to pass along transformed output
+// to the readable side. You may call 'push' zero or more times.
+//
+// Call `cb(err)` when you are done with this chunk. If you pass
+// an error, then that'll put the hurt on the whole operation. If you
+// never call cb(), then you'll never get another chunk.
+Transform.prototype._transform = function (chunk, encoding, cb) {
+ throw new Error('_transform() is not implemented');
+};
+
+Transform.prototype._write = function (chunk, encoding, cb) {
+ var ts = this._transformState;
+ ts.writecb = cb;
+ ts.writechunk = chunk;
+ ts.writeencoding = encoding;
+ if (!ts.transforming) {
+ var rs = this._readableState;
+ if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
+ }
+};
+
+// Doesn't matter what the args are here.
+// _transform does all the work.
+// That we got here means that the readable side wants more data.
+Transform.prototype._read = function (n) {
+ var ts = this._transformState;
+
+ if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
+ ts.transforming = true;
+ this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
+ } else {
+ // mark that we need a transform, so that any data that comes in
+ // will get processed, now that we've asked for it.
+ ts.needTransform = true;
+ }
+};
+
+Transform.prototype._destroy = function (err, cb) {
+ var _this2 = this;
+
+ Duplex.prototype._destroy.call(this, err, function (err2) {
+ cb(err2);
+ _this2.emit('close');
+ });
+};
+
+function done(stream, er, data) {
+ if (er) return stream.emit('error', er);
+
+ if (data != null) // single equals check for both `null` and `undefined`
+ stream.push(data);
+
+ // if there's nothing in the write buffer, then that means
+ // that nothing more will ever be provided
+ if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0');
+
+ if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming');
+
+ return stream.push(null);
+}
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/_stream_writable.js b/node_modules/readable-stream/lib/_stream_writable.js
new file mode 100644
index 0000000..b0b0220
--- /dev/null
+++ b/node_modules/readable-stream/lib/_stream_writable.js
@@ -0,0 +1,687 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// A bit simpler than readable streams.
+// Implement an async ._write(chunk, encoding, cb), and it'll handle all
+// the drain event emission and buffering.
+
+'use strict';
+
+/**/
+
+var pna = require('process-nextick-args');
+/**/
+
+module.exports = Writable;
+
+/* */
+function WriteReq(chunk, encoding, cb) {
+ this.chunk = chunk;
+ this.encoding = encoding;
+ this.callback = cb;
+ this.next = null;
+}
+
+// It seems a linked list but it is not
+// there will be only 2 of these for each stream
+function CorkedRequest(state) {
+ var _this = this;
+
+ this.next = null;
+ this.entry = null;
+ this.finish = function () {
+ onCorkedFinish(_this, state);
+ };
+}
+/* */
+
+/**/
+var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;
+/**/
+
+/**/
+var Duplex;
+/**/
+
+Writable.WritableState = WritableState;
+
+/**/
+var util = Object.create(require('core-util-is'));
+util.inherits = require('inherits');
+/**/
+
+/**/
+var internalUtil = {
+ deprecate: require('util-deprecate')
+};
+/**/
+
+/**/
+var Stream = require('./internal/streams/stream');
+/**/
+
+/**/
+
+var Buffer = require('safe-buffer').Buffer;
+var OurUint8Array = global.Uint8Array || function () {};
+function _uint8ArrayToBuffer(chunk) {
+ return Buffer.from(chunk);
+}
+function _isUint8Array(obj) {
+ return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
+}
+
+/**/
+
+var destroyImpl = require('./internal/streams/destroy');
+
+util.inherits(Writable, Stream);
+
+function nop() {}
+
+function WritableState(options, stream) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ options = options || {};
+
+ // Duplex streams are both readable and writable, but share
+ // the same options object.
+ // However, some cases require setting options to different
+ // values for the readable and the writable sides of the duplex stream.
+ // These options can be provided separately as readableXXX and writableXXX.
+ var isDuplex = stream instanceof Duplex;
+
+ // object stream flag to indicate whether or not this stream
+ // contains buffers or objects.
+ this.objectMode = !!options.objectMode;
+
+ if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
+
+ // the point at which write() starts returning false
+ // Note: 0 is a valid value, means that we always return false if
+ // the entire buffer is not flushed immediately on write()
+ var hwm = options.highWaterMark;
+ var writableHwm = options.writableHighWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+
+ if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = Math.floor(this.highWaterMark);
+
+ // if _final has been called
+ this.finalCalled = false;
+
+ // drain event flag.
+ this.needDrain = false;
+ // at the start of calling end()
+ this.ending = false;
+ // when end() has been called, and returned
+ this.ended = false;
+ // when 'finish' is emitted
+ this.finished = false;
+
+ // has it been destroyed
+ this.destroyed = false;
+
+ // should we decode strings into buffers before passing to _write?
+ // this is here so that some node-core streams can optimize string
+ // handling at a lower level.
+ var noDecode = options.decodeStrings === false;
+ this.decodeStrings = !noDecode;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // not an actual buffer we keep track of, but a measurement
+ // of how much we're waiting to get pushed to some underlying
+ // socket or file.
+ this.length = 0;
+
+ // a flag to see when we're in the middle of a write.
+ this.writing = false;
+
+ // when true all writes will be buffered until .uncork() call
+ this.corked = 0;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // a flag to know if we're processing previously buffered items, which
+ // may call the _write() callback in the same tick, so that we don't
+ // end up in an overlapped onwrite situation.
+ this.bufferProcessing = false;
+
+ // the callback that's passed to _write(chunk,cb)
+ this.onwrite = function (er) {
+ onwrite(stream, er);
+ };
+
+ // the callback that the user supplies to write(chunk,encoding,cb)
+ this.writecb = null;
+
+ // the amount that is being written when _write is called.
+ this.writelen = 0;
+
+ this.bufferedRequest = null;
+ this.lastBufferedRequest = null;
+
+ // number of pending user-supplied write callbacks
+ // this must be 0 before 'finish' can be emitted
+ this.pendingcb = 0;
+
+ // emit prefinish if the only thing we're waiting for is _write cbs
+ // This is relevant for synchronous Transform streams
+ this.prefinished = false;
+
+ // True if the error was already emitted and should not be thrown again
+ this.errorEmitted = false;
+
+ // count buffered requests
+ this.bufferedRequestCount = 0;
+
+ // allocate the first CorkedRequest, there is always
+ // one allocated and free to use, and we maintain at most two
+ this.corkedRequestsFree = new CorkedRequest(this);
+}
+
+WritableState.prototype.getBuffer = function getBuffer() {
+ var current = this.bufferedRequest;
+ var out = [];
+ while (current) {
+ out.push(current);
+ current = current.next;
+ }
+ return out;
+};
+
+(function () {
+ try {
+ Object.defineProperty(WritableState.prototype, 'buffer', {
+ get: internalUtil.deprecate(function () {
+ return this.getBuffer();
+ }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')
+ });
+ } catch (_) {}
+})();
+
+// Test _writableState for inheritance to account for Duplex streams,
+// whose prototype chain only points to Readable.
+var realHasInstance;
+if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
+ realHasInstance = Function.prototype[Symbol.hasInstance];
+ Object.defineProperty(Writable, Symbol.hasInstance, {
+ value: function (object) {
+ if (realHasInstance.call(this, object)) return true;
+ if (this !== Writable) return false;
+
+ return object && object._writableState instanceof WritableState;
+ }
+ });
+} else {
+ realHasInstance = function (object) {
+ return object instanceof this;
+ };
+}
+
+function Writable(options) {
+ Duplex = Duplex || require('./_stream_duplex');
+
+ // Writable ctor is applied to Duplexes, too.
+ // `realHasInstance` is necessary because using plain `instanceof`
+ // would return false, as no `_writableState` property is attached.
+
+ // Trying to use the custom `instanceof` for Writable here will also break the
+ // Node.js LazyTransform implementation, which has a non-trivial getter for
+ // `_writableState` that would lead to infinite recursion.
+ if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {
+ return new Writable(options);
+ }
+
+ this._writableState = new WritableState(options, this);
+
+ // legacy.
+ this.writable = true;
+
+ if (options) {
+ if (typeof options.write === 'function') this._write = options.write;
+
+ if (typeof options.writev === 'function') this._writev = options.writev;
+
+ if (typeof options.destroy === 'function') this._destroy = options.destroy;
+
+ if (typeof options.final === 'function') this._final = options.final;
+ }
+
+ Stream.call(this);
+}
+
+// Otherwise people can pipe Writable streams, which is just wrong.
+Writable.prototype.pipe = function () {
+ this.emit('error', new Error('Cannot pipe, not readable'));
+};
+
+function writeAfterEnd(stream, cb) {
+ var er = new Error('write after end');
+ // TODO: defer error events consistently everywhere, not just the cb
+ stream.emit('error', er);
+ pna.nextTick(cb, er);
+}
+
+// Checks that a user-supplied chunk is valid, especially for the particular
+// mode the stream is in. Currently this means that `null` is never accepted
+// and undefined/non-string values are only allowed in object mode.
+function validChunk(stream, state, chunk, cb) {
+ var valid = true;
+ var er = false;
+
+ if (chunk === null) {
+ er = new TypeError('May not write null values to stream');
+ } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ if (er) {
+ stream.emit('error', er);
+ pna.nextTick(cb, er);
+ valid = false;
+ }
+ return valid;
+}
+
+Writable.prototype.write = function (chunk, encoding, cb) {
+ var state = this._writableState;
+ var ret = false;
+ var isBuf = !state.objectMode && _isUint8Array(chunk);
+
+ if (isBuf && !Buffer.isBuffer(chunk)) {
+ chunk = _uint8ArrayToBuffer(chunk);
+ }
+
+ if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
+
+ if (typeof cb !== 'function') cb = nop;
+
+ if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {
+ state.pendingcb++;
+ ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
+ }
+
+ return ret;
+};
+
+Writable.prototype.cork = function () {
+ var state = this._writableState;
+
+ state.corked++;
+};
+
+Writable.prototype.uncork = function () {
+ var state = this._writableState;
+
+ if (state.corked) {
+ state.corked--;
+
+ if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
+ }
+};
+
+Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
+ // node::ParseEncoding() requires lower case.
+ if (typeof encoding === 'string') encoding = encoding.toLowerCase();
+ if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
+ this._writableState.defaultEncoding = encoding;
+ return this;
+};
+
+function decodeChunk(state, chunk, encoding) {
+ if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
+ chunk = Buffer.from(chunk, encoding);
+ }
+ return chunk;
+}
+
+Object.defineProperty(Writable.prototype, 'writableHighWaterMark', {
+ // making it explicit this property is not enumerable
+ // because otherwise some prototype manipulation in
+ // userland will fail
+ enumerable: false,
+ get: function () {
+ return this._writableState.highWaterMark;
+ }
+});
+
+// if we're already writing something, then just put this
+// in the queue, and wait our turn. Otherwise, call _write
+// If we return false, then we need a drain event, so set that flag.
+function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
+ if (!isBuf) {
+ var newChunk = decodeChunk(state, chunk, encoding);
+ if (chunk !== newChunk) {
+ isBuf = true;
+ encoding = 'buffer';
+ chunk = newChunk;
+ }
+ }
+ var len = state.objectMode ? 1 : chunk.length;
+
+ state.length += len;
+
+ var ret = state.length < state.highWaterMark;
+ // we must ensure that previous needDrain will not be reset to false.
+ if (!ret) state.needDrain = true;
+
+ if (state.writing || state.corked) {
+ var last = state.lastBufferedRequest;
+ state.lastBufferedRequest = {
+ chunk: chunk,
+ encoding: encoding,
+ isBuf: isBuf,
+ callback: cb,
+ next: null
+ };
+ if (last) {
+ last.next = state.lastBufferedRequest;
+ } else {
+ state.bufferedRequest = state.lastBufferedRequest;
+ }
+ state.bufferedRequestCount += 1;
+ } else {
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ }
+
+ return ret;
+}
+
+function doWrite(stream, state, writev, len, chunk, encoding, cb) {
+ state.writelen = len;
+ state.writecb = cb;
+ state.writing = true;
+ state.sync = true;
+ if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
+ state.sync = false;
+}
+
+function onwriteError(stream, state, sync, er, cb) {
+ --state.pendingcb;
+
+ if (sync) {
+ // defer the callback if we are being called synchronously
+ // to avoid piling up things on the stack
+ pna.nextTick(cb, er);
+ // this can emit finish, and it will always happen
+ // after error
+ pna.nextTick(finishMaybe, stream, state);
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+ } else {
+ // the caller expect this to happen before if
+ // it is async
+ cb(er);
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+ // this can emit finish, but finish must
+ // always follow error
+ finishMaybe(stream, state);
+ }
+}
+
+function onwriteStateUpdate(state) {
+ state.writing = false;
+ state.writecb = null;
+ state.length -= state.writelen;
+ state.writelen = 0;
+}
+
+function onwrite(stream, er) {
+ var state = stream._writableState;
+ var sync = state.sync;
+ var cb = state.writecb;
+
+ onwriteStateUpdate(state);
+
+ if (er) onwriteError(stream, state, sync, er, cb);else {
+ // Check if we're actually ready to finish, but don't emit yet
+ var finished = needFinish(state);
+
+ if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
+ clearBuffer(stream, state);
+ }
+
+ if (sync) {
+ /**/
+ asyncWrite(afterWrite, stream, state, finished, cb);
+ /**/
+ } else {
+ afterWrite(stream, state, finished, cb);
+ }
+ }
+}
+
+function afterWrite(stream, state, finished, cb) {
+ if (!finished) onwriteDrain(stream, state);
+ state.pendingcb--;
+ cb();
+ finishMaybe(stream, state);
+}
+
+// Must force callback to be called on nextTick, so that we don't
+// emit 'drain' before the write() consumer gets the 'false' return
+// value, and has a chance to attach a 'drain' listener.
+function onwriteDrain(stream, state) {
+ if (state.length === 0 && state.needDrain) {
+ state.needDrain = false;
+ stream.emit('drain');
+ }
+}
+
+// if there's something in the buffer waiting, then process it
+function clearBuffer(stream, state) {
+ state.bufferProcessing = true;
+ var entry = state.bufferedRequest;
+
+ if (stream._writev && entry && entry.next) {
+ // Fast case, write everything using _writev()
+ var l = state.bufferedRequestCount;
+ var buffer = new Array(l);
+ var holder = state.corkedRequestsFree;
+ holder.entry = entry;
+
+ var count = 0;
+ var allBuffers = true;
+ while (entry) {
+ buffer[count] = entry;
+ if (!entry.isBuf) allBuffers = false;
+ entry = entry.next;
+ count += 1;
+ }
+ buffer.allBuffers = allBuffers;
+
+ doWrite(stream, state, true, state.length, buffer, '', holder.finish);
+
+ // doWrite is almost always async, defer these to save a bit of time
+ // as the hot path ends with doWrite
+ state.pendingcb++;
+ state.lastBufferedRequest = null;
+ if (holder.next) {
+ state.corkedRequestsFree = holder.next;
+ holder.next = null;
+ } else {
+ state.corkedRequestsFree = new CorkedRequest(state);
+ }
+ state.bufferedRequestCount = 0;
+ } else {
+ // Slow case, write chunks one-by-one
+ while (entry) {
+ var chunk = entry.chunk;
+ var encoding = entry.encoding;
+ var cb = entry.callback;
+ var len = state.objectMode ? 1 : chunk.length;
+
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ entry = entry.next;
+ state.bufferedRequestCount--;
+ // if we didn't call the onwrite immediately, then
+ // it means that we need to wait until it does.
+ // also, that means that the chunk and cb are currently
+ // being processed, so move the buffer counter past them.
+ if (state.writing) {
+ break;
+ }
+ }
+
+ if (entry === null) state.lastBufferedRequest = null;
+ }
+
+ state.bufferedRequest = entry;
+ state.bufferProcessing = false;
+}
+
+Writable.prototype._write = function (chunk, encoding, cb) {
+ cb(new Error('_write() is not implemented'));
+};
+
+Writable.prototype._writev = null;
+
+Writable.prototype.end = function (chunk, encoding, cb) {
+ var state = this._writableState;
+
+ if (typeof chunk === 'function') {
+ cb = chunk;
+ chunk = null;
+ encoding = null;
+ } else if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
+
+ // .end() fully uncorks
+ if (state.corked) {
+ state.corked = 1;
+ this.uncork();
+ }
+
+ // ignore unnecessary end() calls.
+ if (!state.ending && !state.finished) endWritable(this, state, cb);
+};
+
+function needFinish(state) {
+ return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
+}
+function callFinal(stream, state) {
+ stream._final(function (err) {
+ state.pendingcb--;
+ if (err) {
+ stream.emit('error', err);
+ }
+ state.prefinished = true;
+ stream.emit('prefinish');
+ finishMaybe(stream, state);
+ });
+}
+function prefinish(stream, state) {
+ if (!state.prefinished && !state.finalCalled) {
+ if (typeof stream._final === 'function') {
+ state.pendingcb++;
+ state.finalCalled = true;
+ pna.nextTick(callFinal, stream, state);
+ } else {
+ state.prefinished = true;
+ stream.emit('prefinish');
+ }
+ }
+}
+
+function finishMaybe(stream, state) {
+ var need = needFinish(state);
+ if (need) {
+ prefinish(stream, state);
+ if (state.pendingcb === 0) {
+ state.finished = true;
+ stream.emit('finish');
+ }
+ }
+ return need;
+}
+
+function endWritable(stream, state, cb) {
+ state.ending = true;
+ finishMaybe(stream, state);
+ if (cb) {
+ if (state.finished) pna.nextTick(cb);else stream.once('finish', cb);
+ }
+ state.ended = true;
+ stream.writable = false;
+}
+
+function onCorkedFinish(corkReq, state, err) {
+ var entry = corkReq.entry;
+ corkReq.entry = null;
+ while (entry) {
+ var cb = entry.callback;
+ state.pendingcb--;
+ cb(err);
+ entry = entry.next;
+ }
+ if (state.corkedRequestsFree) {
+ state.corkedRequestsFree.next = corkReq;
+ } else {
+ state.corkedRequestsFree = corkReq;
+ }
+}
+
+Object.defineProperty(Writable.prototype, 'destroyed', {
+ get: function () {
+ if (this._writableState === undefined) {
+ return false;
+ }
+ return this._writableState.destroyed;
+ },
+ set: function (value) {
+ // we ignore the value if the stream
+ // has not been initialized yet
+ if (!this._writableState) {
+ return;
+ }
+
+ // backward compatibility, the user is explicitly
+ // managing destroyed
+ this._writableState.destroyed = value;
+ }
+});
+
+Writable.prototype.destroy = destroyImpl.destroy;
+Writable.prototype._undestroy = destroyImpl.undestroy;
+Writable.prototype._destroy = function (err, cb) {
+ this.end();
+ cb(err);
+};
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/internal/streams/BufferList.js b/node_modules/readable-stream/lib/internal/streams/BufferList.js
new file mode 100644
index 0000000..aefc68b
--- /dev/null
+++ b/node_modules/readable-stream/lib/internal/streams/BufferList.js
@@ -0,0 +1,79 @@
+'use strict';
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Buffer = require('safe-buffer').Buffer;
+var util = require('util');
+
+function copyBuffer(src, target, offset) {
+ src.copy(target, offset);
+}
+
+module.exports = function () {
+ function BufferList() {
+ _classCallCheck(this, BufferList);
+
+ this.head = null;
+ this.tail = null;
+ this.length = 0;
+ }
+
+ BufferList.prototype.push = function push(v) {
+ var entry = { data: v, next: null };
+ if (this.length > 0) this.tail.next = entry;else this.head = entry;
+ this.tail = entry;
+ ++this.length;
+ };
+
+ BufferList.prototype.unshift = function unshift(v) {
+ var entry = { data: v, next: this.head };
+ if (this.length === 0) this.tail = entry;
+ this.head = entry;
+ ++this.length;
+ };
+
+ BufferList.prototype.shift = function shift() {
+ if (this.length === 0) return;
+ var ret = this.head.data;
+ if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
+ --this.length;
+ return ret;
+ };
+
+ BufferList.prototype.clear = function clear() {
+ this.head = this.tail = null;
+ this.length = 0;
+ };
+
+ BufferList.prototype.join = function join(s) {
+ if (this.length === 0) return '';
+ var p = this.head;
+ var ret = '' + p.data;
+ while (p = p.next) {
+ ret += s + p.data;
+ }return ret;
+ };
+
+ BufferList.prototype.concat = function concat(n) {
+ if (this.length === 0) return Buffer.alloc(0);
+ if (this.length === 1) return this.head.data;
+ var ret = Buffer.allocUnsafe(n >>> 0);
+ var p = this.head;
+ var i = 0;
+ while (p) {
+ copyBuffer(p.data, ret, i);
+ i += p.data.length;
+ p = p.next;
+ }
+ return ret;
+ };
+
+ return BufferList;
+}();
+
+if (util && util.inspect && util.inspect.custom) {
+ module.exports.prototype[util.inspect.custom] = function () {
+ var obj = util.inspect({ length: this.length });
+ return this.constructor.name + ' ' + obj;
+ };
+}
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/internal/streams/destroy.js b/node_modules/readable-stream/lib/internal/streams/destroy.js
new file mode 100644
index 0000000..5a0a0d8
--- /dev/null
+++ b/node_modules/readable-stream/lib/internal/streams/destroy.js
@@ -0,0 +1,74 @@
+'use strict';
+
+/**/
+
+var pna = require('process-nextick-args');
+/**/
+
+// undocumented cb() API, needed for core, not for public API
+function destroy(err, cb) {
+ var _this = this;
+
+ var readableDestroyed = this._readableState && this._readableState.destroyed;
+ var writableDestroyed = this._writableState && this._writableState.destroyed;
+
+ if (readableDestroyed || writableDestroyed) {
+ if (cb) {
+ cb(err);
+ } else if (err && (!this._writableState || !this._writableState.errorEmitted)) {
+ pna.nextTick(emitErrorNT, this, err);
+ }
+ return this;
+ }
+
+ // we set destroyed to true before firing error callbacks in order
+ // to make it re-entrance safe in case destroy() is called within callbacks
+
+ if (this._readableState) {
+ this._readableState.destroyed = true;
+ }
+
+ // if this is a duplex stream mark the writable part as destroyed as well
+ if (this._writableState) {
+ this._writableState.destroyed = true;
+ }
+
+ this._destroy(err || null, function (err) {
+ if (!cb && err) {
+ pna.nextTick(emitErrorNT, _this, err);
+ if (_this._writableState) {
+ _this._writableState.errorEmitted = true;
+ }
+ } else if (cb) {
+ cb(err);
+ }
+ });
+
+ return this;
+}
+
+function undestroy() {
+ if (this._readableState) {
+ this._readableState.destroyed = false;
+ this._readableState.reading = false;
+ this._readableState.ended = false;
+ this._readableState.endEmitted = false;
+ }
+
+ if (this._writableState) {
+ this._writableState.destroyed = false;
+ this._writableState.ended = false;
+ this._writableState.ending = false;
+ this._writableState.finished = false;
+ this._writableState.errorEmitted = false;
+ }
+}
+
+function emitErrorNT(self, err) {
+ self.emit('error', err);
+}
+
+module.exports = {
+ destroy: destroy,
+ undestroy: undestroy
+};
\ No newline at end of file
diff --git a/node_modules/readable-stream/lib/internal/streams/stream-browser.js b/node_modules/readable-stream/lib/internal/streams/stream-browser.js
new file mode 100644
index 0000000..9332a3f
--- /dev/null
+++ b/node_modules/readable-stream/lib/internal/streams/stream-browser.js
@@ -0,0 +1 @@
+module.exports = require('events').EventEmitter;
diff --git a/node_modules/readable-stream/lib/internal/streams/stream.js b/node_modules/readable-stream/lib/internal/streams/stream.js
new file mode 100644
index 0000000..ce2ad5b
--- /dev/null
+++ b/node_modules/readable-stream/lib/internal/streams/stream.js
@@ -0,0 +1 @@
+module.exports = require('stream');
diff --git a/node_modules/readable-stream/package.json b/node_modules/readable-stream/package.json
new file mode 100644
index 0000000..e397f49
--- /dev/null
+++ b/node_modules/readable-stream/package.json
@@ -0,0 +1,134 @@
+{
+ "_args": [
+ [
+ "readable-stream@^2.3.5",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/bl"
+ ]
+ ],
+ "_from": "readable-stream@>=2.3.5 <3.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "readable-stream@2.3.7",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/readable-stream",
+ "_nodeVersion": "10.17.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/readable-stream_2.3.7_1578244418937_0.3738956004243521"
+ },
+ "_npmUser": {
+ "email": "hello@matteocollina.com",
+ "name": "matteo.collina"
+ },
+ "_npmVersion": "6.13.4",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "readable-stream",
+ "raw": "readable-stream@^2.3.5",
+ "rawSpec": "^2.3.5",
+ "scope": null,
+ "spec": ">=2.3.5 <3.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/bl"
+ ],
+ "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "_shasum": "1eca1cf711aef814c04f62252a36a62f6cb23b57",
+ "_shrinkwrap": null,
+ "_spec": "readable-stream@^2.3.5",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/bl",
+ "browser": {
+ "./duplex.js": "./duplex-browser.js",
+ "./lib/internal/streams/stream.js": "./lib/internal/streams/stream-browser.js",
+ "./readable.js": "./readable-browser.js",
+ "./writable.js": "./writable-browser.js",
+ "util": false
+ },
+ "bugs": {
+ "url": "https://github.com/nodejs/readable-stream/issues"
+ },
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "description": "Streams3, a user-land copy of the stream library from Node.js",
+ "devDependencies": {
+ "assert": "^1.4.0",
+ "babel-polyfill": "^6.9.1",
+ "buffer": "^4.9.0",
+ "lolex": "^2.3.2",
+ "nyc": "^6.4.0",
+ "tap": "^0.7.0",
+ "tape": "^4.8.0"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 24,
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeEhlDCRA9TVsSAnZWagAAUqkP/33VFphjNq5vk5/8TqHZ\n6T6ItDSwoY1VyDEuN26uFHRBZRXztM5BC5spq5q8h/KcQiVxshlTjL+PoXI9\nFgXB1kkm57NY95FhCYcVlDw4QmBl1IRlzVWglN/0J2YQ+wSpYiXLXTcWSAp9\nPt5Abrb68H22oI8+KqQ+T9WTFyDG75yTJHFWBQyXcYG98OU/v0bk3nnB/Oh6\nztpy2pD5EayiEY81YTJ6vySHIKYxAySWdesIO9gQKwaqDdQRmfvsaEra90vf\n5St+XpRx1M0oPFCBjjj6aEhRgvq5rRm81GUQOKFvIWZacFFgdwpqJn1kzCrM\n6tQKONWApacjucn2FeAOwPno1HRQ3/T4NzWVwUcc4fuwi6fXa1E0zcalRSws\nlfuL+mtQkxv7fPanzqZu8J542hgss81ZahaHR1p/d705GTkdiZV3CYBN2O/a\nQDSCgjPUAQpyfOUlkSsNnB8GNWGU3hVOabsSpH3BPrGlMdBm4ML9ZiSaSn1c\nqb/EldTv0pGkwfx4+uOxH8QXMZLwd7nKMluEoBZQtFeAEIiaFwqgV1rB9Pi9\ncBPAMrDIlwlHV9CxOHiH/WsVBb0Uc/vBeRerEpgaEP3iglkkF3w4kaD3PRhG\n9GTiyJcjpDQugMRZehfcQODpj5mlYpYgSxK1xkRQ137BTZ4Px4T+lgYM16Nl\nQ1gV\r\n=Ka0O\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "1eca1cf711aef814c04f62252a36a62f6cb23b57",
+ "tarball": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "unpackedSize": 87719
+ },
+ "gitHead": "2eb8861e029107b7e079e22c826835cad6ae7854",
+ "homepage": "https://github.com/nodejs/readable-stream#readme",
+ "keywords": [
+ "pipe",
+ "readable",
+ "stream"
+ ],
+ "license": "MIT",
+ "main": "readable.js",
+ "maintainers": [
+ {
+ "name": "cwmma",
+ "email": "calvin.metcalf@gmail.com"
+ },
+ {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ },
+ {
+ "name": "matteo.collina",
+ "email": "hello@matteocollina.com"
+ },
+ {
+ "name": "nodejs-foundation",
+ "email": "build@iojs.org"
+ },
+ {
+ "name": "rvagg",
+ "email": "r@va.gg"
+ },
+ {
+ "name": "tootallnate",
+ "email": "nathan@tootallnate.net"
+ }
+ ],
+ "name": "readable-stream",
+ "nyc": {
+ "include": [
+ "lib/**.js"
+ ]
+ },
+ "optionalDependencies": {},
+ "readme": "# readable-stream\n\n***Node-core v8.11.1 streams for userland*** [](https://travis-ci.org/nodejs/readable-stream)\n\n\n[](https://nodei.co/npm/readable-stream/)\n[](https://nodei.co/npm/readable-stream/)\n\n\n[](https://saucelabs.com/u/readable-stream)\n\n```bash\nnpm install --save readable-stream\n```\n\n***Node-core streams for userland***\n\nThis package is a mirror of the Streams2 and Streams3 implementations in\nNode-core.\n\nFull documentation may be found on the [Node.js website](https://nodejs.org/dist/v8.11.1/docs/api/stream.html).\n\nIf you want to guarantee a stable streams base, regardless of what version of\nNode you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *\"stream\"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).\n\nAs of version 2.0.0 **readable-stream** uses semantic versioning.\n\n# Streams Working Group\n\n`readable-stream` is maintained by the Streams Working Group, which\noversees the development and maintenance of the Streams API within\nNode.js. The responsibilities of the Streams Working Group include:\n\n* Addressing stream issues on the Node.js issue tracker.\n* Authoring and editing stream documentation within the Node.js project.\n* Reviewing changes to stream subclasses within the Node.js project.\n* Redirecting changes to streams from the Node.js project to this\n project.\n* Assisting in the implementation of stream providers within Node.js.\n* Recommending versions of `readable-stream` to be included in Node.js.\n* Messaging about the future of streams to give the community advance\n notice of changes.\n\n\n## Team Members\n\n* **Chris Dickinson** ([@chrisdickinson](https://github.com/chrisdickinson)) <christopher.s.dickinson@gmail.com>\n - Release GPG key: 9554F04D7259F04124DE6B476D5A82AC7E37093B\n* **Calvin Metcalf** ([@calvinmetcalf](https://github.com/calvinmetcalf)) <calvin.metcalf@gmail.com>\n - Release GPG key: F3EF5F62A87FC27A22E643F714CE4FF5015AA242\n* **Rod Vagg** ([@rvagg](https://github.com/rvagg)) <rod@vagg.org>\n - Release GPG key: DD8F2338BAE7501E3DD5AC78C273792F7D83545D\n* **Sam Newman** ([@sonewman](https://github.com/sonewman)) <newmansam@outlook.com>\n* **Mathias Buus** ([@mafintosh](https://github.com/mafintosh)) <mathiasbuus@gmail.com>\n* **Domenic Denicola** ([@domenic](https://github.com/domenic)) <d@domenic.me>\n* **Matteo Collina** ([@mcollina](https://github.com/mcollina)) <matteo.collina@gmail.com>\n - Release GPG key: 3ABC01543F22DD2239285CDD818674489FBC127E\n* **Irina Shestak** ([@lrlna](https://github.com/lrlna)) <shestak.irina@gmail.com>\n",
+ "readmeFilename": "README.md",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/readable-stream.git"
+ },
+ "scripts": {
+ "ci": "tap test/parallel/*.js test/ours/*.js --tap | tee test.tap && node test/verify-dependencies.js",
+ "cover": "nyc npm test",
+ "report": "nyc report --reporter=lcov",
+ "test": "tap test/parallel/*.js test/ours/*.js && node test/verify-dependencies.js"
+ },
+ "version": "2.3.7"
+}
diff --git a/node_modules/readable-stream/passthrough.js b/node_modules/readable-stream/passthrough.js
new file mode 100644
index 0000000..ffd791d
--- /dev/null
+++ b/node_modules/readable-stream/passthrough.js
@@ -0,0 +1 @@
+module.exports = require('./readable').PassThrough
diff --git a/node_modules/readable-stream/readable-browser.js b/node_modules/readable-stream/readable-browser.js
new file mode 100644
index 0000000..e503725
--- /dev/null
+++ b/node_modules/readable-stream/readable-browser.js
@@ -0,0 +1,7 @@
+exports = module.exports = require('./lib/_stream_readable.js');
+exports.Stream = exports;
+exports.Readable = exports;
+exports.Writable = require('./lib/_stream_writable.js');
+exports.Duplex = require('./lib/_stream_duplex.js');
+exports.Transform = require('./lib/_stream_transform.js');
+exports.PassThrough = require('./lib/_stream_passthrough.js');
diff --git a/node_modules/readable-stream/readable.js b/node_modules/readable-stream/readable.js
new file mode 100644
index 0000000..ec89ec5
--- /dev/null
+++ b/node_modules/readable-stream/readable.js
@@ -0,0 +1,19 @@
+var Stream = require('stream');
+if (process.env.READABLE_STREAM === 'disable' && Stream) {
+ module.exports = Stream;
+ exports = module.exports = Stream.Readable;
+ exports.Readable = Stream.Readable;
+ exports.Writable = Stream.Writable;
+ exports.Duplex = Stream.Duplex;
+ exports.Transform = Stream.Transform;
+ exports.PassThrough = Stream.PassThrough;
+ exports.Stream = Stream;
+} else {
+ exports = module.exports = require('./lib/_stream_readable.js');
+ exports.Stream = Stream || exports;
+ exports.Readable = exports;
+ exports.Writable = require('./lib/_stream_writable.js');
+ exports.Duplex = require('./lib/_stream_duplex.js');
+ exports.Transform = require('./lib/_stream_transform.js');
+ exports.PassThrough = require('./lib/_stream_passthrough.js');
+}
diff --git a/node_modules/readable-stream/transform.js b/node_modules/readable-stream/transform.js
new file mode 100644
index 0000000..b1baba2
--- /dev/null
+++ b/node_modules/readable-stream/transform.js
@@ -0,0 +1 @@
+module.exports = require('./readable').Transform
diff --git a/node_modules/readable-stream/writable-browser.js b/node_modules/readable-stream/writable-browser.js
new file mode 100644
index 0000000..ebdde6a
--- /dev/null
+++ b/node_modules/readable-stream/writable-browser.js
@@ -0,0 +1 @@
+module.exports = require('./lib/_stream_writable.js');
diff --git a/node_modules/readable-stream/writable.js b/node_modules/readable-stream/writable.js
new file mode 100644
index 0000000..3211a6f
--- /dev/null
+++ b/node_modules/readable-stream/writable.js
@@ -0,0 +1,8 @@
+var Stream = require("stream")
+var Writable = require("./lib/_stream_writable.js")
+
+if (process.env.READABLE_STREAM === 'disable') {
+ module.exports = Stream && Stream.Writable || Writable
+} else {
+ module.exports = Writable
+}
diff --git a/node_modules/regexp-clone/.travis.yml b/node_modules/regexp-clone/.travis.yml
new file mode 100644
index 0000000..220a17b
--- /dev/null
+++ b/node_modules/regexp-clone/.travis.yml
@@ -0,0 +1,14 @@
+sudo: false
+language: node_js
+node_js:
+ - 8
+ - 10
+ - 12
+matrix:
+ include:
+ - node_js: "13"
+ env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
+ allow_failures:
+ # Allow the nightly installs to fail
+ - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
+script: "npm test"
diff --git a/node_modules/regexp-clone/History.md b/node_modules/regexp-clone/History.md
new file mode 100644
index 0000000..0beedfc
--- /dev/null
+++ b/node_modules/regexp-clone/History.md
@@ -0,0 +1,5 @@
+
+0.0.1 / 2013-04-17
+==================
+
+ * initial commit
diff --git a/node_modules/regexp-clone/LICENSE b/node_modules/regexp-clone/LICENSE
new file mode 100644
index 0000000..98c7c89
--- /dev/null
+++ b/node_modules/regexp-clone/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2013 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/regexp-clone/Makefile b/node_modules/regexp-clone/Makefile
new file mode 100644
index 0000000..6c8fb75
--- /dev/null
+++ b/node_modules/regexp-clone/Makefile
@@ -0,0 +1,5 @@
+
+test:
+ @./node_modules/.bin/mocha $(T) --async-only $(TESTS)
+
+.PHONY: test
diff --git a/node_modules/regexp-clone/README.md b/node_modules/regexp-clone/README.md
new file mode 100644
index 0000000..4a16bad
--- /dev/null
+++ b/node_modules/regexp-clone/README.md
@@ -0,0 +1,42 @@
+#regexp-clone
+==============
+
+Clones RegExps with flag and `lastIndex` preservation.
+
+```js
+const regexpClone = require('regexp-clone');
+
+const a = /somethin/misguy;
+console.log(a.global); // true
+console.log(a.ignoreCase); // true
+console.log(a.multiline); // true
+console.log(a.dotAll); // true
+console.log(a.unicode); // true
+console.log(a.sticky); // true
+
+const b = regexpClone(a);
+console.log(b.global); // true
+console.log(b.ignoreCase); // true
+console.log(b.multiline); // true
+console.log(b.dotAll); // true
+console.log(b.unicode); // true
+console.log(b.sticky); // true
+
+const c = /hi/g;
+c.test('this string hi there');
+assert.strictEqual(c.lastIndex, 3);
+
+const d = regexpClone(c);
+assert.strictEqual(d.lastIndex, 3);
+d.test('this string hi there');
+assert.strictEqual(d.lastIndex, 14);
+assert.strictEqual(c.lastIndex, 3);
+```
+
+```
+npm install regexp-clone
+```
+
+## License
+
+[MIT](https://github.com/aheckmann/regexp-clone/blob/master/LICENSE)
diff --git a/node_modules/regexp-clone/index.js b/node_modules/regexp-clone/index.js
new file mode 100644
index 0000000..19512b3
--- /dev/null
+++ b/node_modules/regexp-clone/index.js
@@ -0,0 +1,27 @@
+
+const toString = Object.prototype.toString;
+
+function isRegExp (o) {
+ return 'object' == typeof o
+ && '[object RegExp]' == toString.call(o);
+}
+
+module.exports = exports = function (regexp) {
+ if (!isRegExp(regexp)) {
+ throw new TypeError('Not a RegExp');
+ }
+
+ const flags = [];
+ if (regexp.global) flags.push('g');
+ if (regexp.multiline) flags.push('m');
+ if (regexp.ignoreCase) flags.push('i');
+ if (regexp.dotAll) flags.push('s');
+ if (regexp.unicode) flags.push('u');
+ if (regexp.sticky) flags.push('y');
+ const result = new RegExp(regexp.source, flags.join(''));
+ if (typeof regexp.lastIndex === 'number') {
+ result.lastIndex = regexp.lastIndex;
+ }
+ return result;
+}
+
diff --git a/node_modules/regexp-clone/package.json b/node_modules/regexp-clone/package.json
new file mode 100644
index 0000000..251cf8c
--- /dev/null
+++ b/node_modules/regexp-clone/package.json
@@ -0,0 +1,88 @@
+{
+ "_args": [
+ [
+ "regexp-clone@1.0.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "regexp-clone@1.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "regexp-clone@1.0.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/regexp-clone",
+ "_nodeVersion": "8.11.1",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/regexp-clone_1.0.0_1559924183831_0.5688403913827789"
+ },
+ "_npmUser": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "aaron"
+ },
+ "_npmVersion": "6.4.1",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "regexp-clone",
+ "raw": "regexp-clone@1.0.0",
+ "rawSpec": "1.0.0",
+ "scope": null,
+ "spec": "1.0.0",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose",
+ "/mquery"
+ ],
+ "_resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
+ "_shasum": "222db967623277056260b992626354a04ce9bf63",
+ "_shrinkwrap": null,
+ "_spec": "regexp-clone@1.0.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "Aaron Heckmann"
+ },
+ "bugs": {
+ "url": "https://github.com/aheckmann/regexp-clone/issues"
+ },
+ "dependencies": {},
+ "description": "Clone RegExps with options",
+ "devDependencies": {
+ "mocha": "^6.1.4"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 8,
+ "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc+o3YCRA9TVsSAnZWagAA3AIP/2KDC2gc+RGGbFIYd9ry\nyOQOAerddsljWU6KvBf8yhOWMGSf7pq72Mn5Uv8lWBF5WyVH+0ttAJg7EbOJ\nSWhHtjPi6u/whh0z6UkAwSl4iVHBcXgJkJ/b1O5yadYCK/LPpj+UpceOT3m1\n0WhcJ0zzTzJHGgu4K1jY4ifdcsP80evUerAgEPndyiLUFtUEpSPnL9PoMOTp\nnh0vUmLneba5hbQjtYcRa5O1AtYfHrRxS2zKIhlbhJNOEQzcd8bBXZBvNlX4\nInO0pS9VwnPfGc54hEwHdWZCNsc+UA4MDRyRjTS0yWwdSQUoUhQgwP7gzhhc\nA7YtmrULg8luuoQx6suHbqptbEg89+wHnjE+4DyAomzD78uGX/xry2fKEKk6\nTZdNHaQNtWLAW8g/J3Sy4jAIVHtMnUP8xxLoUF0k6+Fi8YHK7LX7CXzS/XiH\nXhI+ia8nY//lsECn0AGzVYToS/QXpl1ibqG90tuuahDsf0TBp+OHULF35bOm\nAn+C8icNsS8quXMLF+TKRGOIj6x3xiiUKOtMPSvTU/plUgip8ZNoVg/sKUvL\n0WTvNK/n9wN9QLL/spbJlerPGasqrObkZnolp3jYn6aR/9SXeVxrwmBBbl84\ngvLCwu1993AUJCLYu0/s6OYlmJUOpPlCgOh+J0HOrvjPrSUSUSf6qS9TiRI6\nJLbh\r\n=hWxH\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "222db967623277056260b992626354a04ce9bf63",
+ "tarball": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
+ "unpackedSize": 7395
+ },
+ "gitHead": "561e4dc5fe5e192a71f5a9c877f7c5b881394d5c",
+ "homepage": "https://github.com/aheckmann/regexp-clone#readme",
+ "keywords": [
+ "RegExp",
+ "clone"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "aaron",
+ "email": "aaron.heckmann+github@gmail.com"
+ }
+ ],
+ "name": "regexp-clone",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aheckmann/regexp-clone.git"
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "version": "1.0.0"
+}
diff --git a/node_modules/regexp-clone/test/index.js b/node_modules/regexp-clone/test/index.js
new file mode 100644
index 0000000..ceaea28
--- /dev/null
+++ b/node_modules/regexp-clone/test/index.js
@@ -0,0 +1,171 @@
+
+const assert = require('assert')
+const clone = require('../');
+
+describe('regexp-clone', function(){
+ function hasEqualSource (a, b) {
+ assert.ok(a !== b);
+ assert.equal(a.source, b.source);
+ }
+
+ function isIgnoreCase (a) {
+ assert.ok(a.ignoreCase);
+ }
+
+ function isGlobal (a) {
+ assert.ok(a.global);
+ }
+
+ function isMultiline (a) {
+ assert.ok(a.multiline);
+ }
+
+ function isDotAll (a) {
+ assert.ok(a.dotAll);
+ }
+
+ function isUnicode (a) {
+ assert.ok(a.unicode);
+ }
+
+ function isSticky(a) {
+ assert.ok(a.sticky);
+ }
+
+ function testFlag (a, method) {
+ const b = clone(a);
+ hasEqualSource(a, b);
+ method(a);
+ method(b);
+ }
+
+ function lastIndex(a) {
+ a.test('this string hi there');
+ assert.strictEqual(a.lastIndex, 3);
+ const b = clone(a);
+ assert.strictEqual(b.lastIndex, 3);
+ assert.strictEqual(a.lastIndex, 3);
+ b.test('this string hi there');
+ assert.strictEqual(b.lastIndex, 14);
+ assert.strictEqual(a.lastIndex, 3);
+ }
+
+ function allFlags(a) {
+ const b = clone(a);
+ hasEqualSource(a, b);
+ testFlag(b, isIgnoreCase);
+ testFlag(b, isGlobal);
+ testFlag(b, isMultiline);
+ testFlag(b, isDotAll);
+ testFlag(b, isUnicode);
+ testFlag(b, isSticky);
+ }
+
+ function noFlags(a) {
+ const b = clone(a);
+ hasEqualSource(a, b);
+ assert.ok(!b.ignoreCase);
+ assert.ok(!b.global);
+ assert.ok(!b.multiline);
+ assert.ok(!b.dotAll);
+ assert.ok(!b.unicode);
+ assert.ok(!b.sticky);
+ }
+
+ describe('literals', function(){
+ it('ignoreCase flag', function(done){
+ const a = /hello/i;
+ testFlag(a, isIgnoreCase);
+ done();
+ })
+ it('global flag', function(done){
+ const a = /hello/g;
+ testFlag(a, isGlobal);
+ done();
+ })
+ it('multiline flag', function(done){
+ const a = /hello/m;
+ testFlag(a, isMultiline);
+ done();
+ })
+ it('dotAll flag', function(done){
+ const a = /hello/s;
+ testFlag(a, isDotAll);
+ done();
+ })
+ it('unicode flag', function(done){
+ const a = /hello/u;
+ testFlag(a, isUnicode);
+ done();
+ })
+ it('sticky flag', function(done){
+ const a = /hello/y;
+ testFlag(a, isSticky);
+ done();
+ })
+ it('no flags', function(done){
+ const a = /hello/;
+ noFlags(a);
+ done();
+ })
+ it('all flags', function(done){
+ const a = /hello/gimsuy;
+ allFlags(a);
+ done();
+ })
+ it('lastIndex', function(done) {
+ const a = /hi/g;
+ lastIndex(a);
+ done();
+ })
+ })
+
+ describe('instances', function(){
+ it('ignoreCase flag', function(done){
+ const a = new RegExp('hello', 'i');
+ testFlag(a, isIgnoreCase);
+ done();
+ })
+ it('global flag', function(done){
+ const a = new RegExp('hello', 'g');
+ testFlag(a, isGlobal);
+ done();
+ })
+ it('multiline flag', function(done){
+ const a = new RegExp('hello', 'm');
+ testFlag(a, isMultiline);
+ done();
+ })
+ it('dotAll flag', function(done){
+ const a = new RegExp('hello', 's');
+ testFlag(a, isDotAll);
+ done();
+ })
+ it('unicode flag', function(done){
+ const a = new RegExp('hello', 'u');
+ testFlag(a, isUnicode);
+ done();
+ })
+ it('sticky flag', function(done){
+ const a = new RegExp('hello', 'y');
+ testFlag(a, isSticky);
+ done();
+ })
+ it('no flags', function(done){
+ const a = new RegExp('hmm');
+ noFlags(a);
+ done();
+ })
+ it('all flags', function(done){
+ const a = new RegExp('hello', 'misguy');
+ allFlags(a);
+ done();
+ })
+ it('lastIndex', function(done) {
+ const a = new RegExp('hi', 'g');
+ lastIndex(a);
+ done();
+ })
+ })
+})
+
diff --git a/node_modules/require_optional/.npmignore b/node_modules/require_optional/.npmignore
new file mode 100644
index 0000000..e920c16
--- /dev/null
+++ b/node_modules/require_optional/.npmignore
@@ -0,0 +1,33 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+node_modules
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
diff --git a/node_modules/require_optional/.travis.yml b/node_modules/require_optional/.travis.yml
new file mode 100644
index 0000000..72903c3
--- /dev/null
+++ b/node_modules/require_optional/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+node_js:
+ - "0.10"
+ - "0.12"
+ - "4"
+ - "6"
+ - "7"
+ - "8"
+sudo: false
diff --git a/node_modules/require_optional/HISTORY.md b/node_modules/require_optional/HISTORY.md
new file mode 100644
index 0000000..7bee02f
--- /dev/null
+++ b/node_modules/require_optional/HISTORY.md
@@ -0,0 +1,7 @@
+1.0.1 03-02-2016
+================
+* Fix dependency resolution issue when a component in peerOptionalDependencies is installed at the level of the module declaring in peerOptionalDependencies.
+
+1.0.0 03-02-2016
+================
+* Initial release allowing us to optionally resolve dependencies in the package.json file under the peerOptionalDependencies tag.
\ No newline at end of file
diff --git a/node_modules/require_optional/LICENSE b/node_modules/require_optional/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/node_modules/require_optional/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/node_modules/require_optional/README.md b/node_modules/require_optional/README.md
new file mode 100644
index 0000000..c0323f0
--- /dev/null
+++ b/node_modules/require_optional/README.md
@@ -0,0 +1,2 @@
+# require_optional
+Work around the problem that we do not have a optionalPeerDependencies concept in node.js making it a hassle to optionally include native modules
diff --git a/node_modules/require_optional/index.js b/node_modules/require_optional/index.js
new file mode 100644
index 0000000..3710319
--- /dev/null
+++ b/node_modules/require_optional/index.js
@@ -0,0 +1,128 @@
+var path = require('path'),
+ fs = require('fs'),
+ f = require('util').format,
+ resolveFrom = require('resolve-from'),
+ semver = require('semver');
+
+var exists = fs.existsSync || path.existsSync;
+
+// Find the location of a package.json file near or above the given location
+var find_package_json = function(location) {
+ var found = false;
+
+ while(!found) {
+ if (exists(location + '/package.json')) {
+ found = location;
+ } else if (location !== '/') {
+ location = path.dirname(location);
+ } else {
+ return false;
+ }
+ }
+
+ return location;
+}
+
+// Find the package.json object of the module closest up the module call tree that contains name in that module's peerOptionalDependencies
+var find_package_json_with_name = function(name) {
+ // Walk up the module call tree until we find a module containing name in its peerOptionalDependencies
+ var currentModule = module;
+ var found = false;
+ while (currentModule) {
+ // Check currentModule has a package.json
+ location = currentModule.filename;
+ var location = find_package_json(location)
+ if (!location) {
+ currentModule = currentModule.parent;
+ continue;
+ }
+
+ // Read the package.json file
+ var object = JSON.parse(fs.readFileSync(f('%s/package.json', location)));
+ // Is the name defined by interal file references
+ var parts = name.split(/\//);
+
+ // Check whether this package.json contains peerOptionalDependencies containing the name we're searching for
+ if (!object.peerOptionalDependencies || (object.peerOptionalDependencies && !object.peerOptionalDependencies[parts[0]])) {
+ currentModule = currentModule.parent;
+ continue;
+ }
+ found = true;
+ break;
+ }
+
+ // Check whether name has been found in currentModule's peerOptionalDependencies
+ if (!found) {
+ throw new Error(f('no optional dependency [%s] defined in peerOptionalDependencies in any package.json', parts[0]));
+ }
+
+ return {
+ object: object,
+ parts: parts
+ }
+}
+
+var require_optional = function(name, options) {
+ options = options || {};
+ options.strict = typeof options.strict == 'boolean' ? options.strict : true;
+
+ var res = find_package_json_with_name(name)
+ var object = res.object;
+ var parts = res.parts;
+
+ // Unpack the expected version
+ var expectedVersions = object.peerOptionalDependencies[parts[0]];
+ // The resolved package
+ var moduleEntry = undefined;
+ // Module file
+ var moduleEntryFile = name;
+
+ try {
+ // Validate if it's possible to read the module
+ moduleEntry = require(moduleEntryFile);
+ } catch(err) {
+ // Attempt to resolve in top level package
+ try {
+ // Get the module entry file
+ moduleEntryFile = resolveFrom(process.cwd(), name);
+ if(moduleEntryFile == null) return undefined;
+ // Attempt to resolve the module
+ moduleEntry = require(moduleEntryFile);
+ } catch(err) {
+ if(err.code === 'MODULE_NOT_FOUND') return undefined;
+ }
+ }
+
+ // Resolve the location of the module's package.json file
+ var location = find_package_json(require.resolve(moduleEntryFile));
+ if(!location) {
+ throw new Error('package.json can not be located');
+ }
+
+ // Read the module file
+ var dependentOnModule = JSON.parse(fs.readFileSync(f('%s/package.json', location)));
+ // Get the version
+ var version = dependentOnModule.version;
+ // Validate if the found module satisfies the version id
+ if(semver.satisfies(version, expectedVersions) == false
+ && options.strict) {
+ var error = new Error(f('optional dependency [%s] found but version [%s] did not satisfy constraint [%s]', parts[0], version, expectedVersions));
+ error.code = 'OPTIONAL_MODULE_NOT_FOUND';
+ throw error;
+ }
+
+ // Satifies the module requirement
+ return moduleEntry;
+}
+
+require_optional.exists = function(name) {
+ try {
+ var m = require_optional(name);
+ if(m === undefined) return false;
+ return true;
+ } catch(err) {
+ return false;
+ }
+}
+
+module.exports = require_optional;
diff --git a/node_modules/require_optional/package.json b/node_modules/require_optional/package.json
new file mode 100644
index 0000000..a67c41b
--- /dev/null
+++ b/node_modules/require_optional/package.json
@@ -0,0 +1,95 @@
+{
+ "_args": [
+ [
+ "require_optional@^1.0.1",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongodb"
+ ]
+ ],
+ "_from": "require_optional@>=1.0.1 <2.0.0",
+ "_id": "require_optional@1.0.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/require_optional",
+ "_nodeVersion": "8.1.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/require_optional-1.0.1.tgz_1497424160858_0.9788372260518372"
+ },
+ "_npmUser": {
+ "email": "christkv@gmail.com",
+ "name": "christkv"
+ },
+ "_npmVersion": "5.0.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "require_optional",
+ "raw": "require_optional@^1.0.1",
+ "rawSpec": "^1.0.1",
+ "scope": null,
+ "spec": ">=1.0.1 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/mongodb"
+ ],
+ "_resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
+ "_shasum": "4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e",
+ "_shrinkwrap": null,
+ "_spec": "require_optional@^1.0.1",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongodb",
+ "author": {
+ "name": "Christian Kvalheim Amor"
+ },
+ "bugs": {
+ "url": "https://github.com/christkv/require_optional/issues"
+ },
+ "dependencies": {
+ "resolve-from": "^2.0.0",
+ "semver": "^5.1.0"
+ },
+ "description": "Allows you declare optionalPeerDependencies that can be satisfied by the top level module but ignored if they are not.",
+ "devDependencies": {
+ "bson": "0.4.21",
+ "co": "4.6.0",
+ "es6-promise": "^3.0.2",
+ "mocha": "^2.4.5"
+ },
+ "directories": {},
+ "dist": {
+ "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
+ "shasum": "4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e",
+ "tarball": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz"
+ },
+ "gitHead": "4e10f508d3d27ae4f967b0ab48dcb869bc9b6727",
+ "homepage": "https://github.com/christkv/require_optional",
+ "keywords": [
+ "optional",
+ "optionalPeerDependencies",
+ "require"
+ ],
+ "license": "Apache-2.0",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "christkv",
+ "email": "christkv@gmail.com"
+ }
+ ],
+ "name": "require_optional",
+ "optionalDependencies": {},
+ "peerOptionalDependencies": {
+ "bson": "0.4.21",
+ "co": ">=5.6.0",
+ "es6-promise": "^3.0.2",
+ "es6-promise2": "^4.0.2"
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/christkv/require_optional.git"
+ },
+ "scripts": {
+ "test": "mocha"
+ },
+ "version": "1.0.1"
+}
diff --git a/node_modules/require_optional/test/nestedTest/index.js b/node_modules/require_optional/test/nestedTest/index.js
new file mode 100644
index 0000000..76de2ab
--- /dev/null
+++ b/node_modules/require_optional/test/nestedTest/index.js
@@ -0,0 +1,8 @@
+var require_optional = require('../../')
+
+function findPackage(packageName) {
+ var pkg = require_optional(packageName);
+ return pkg;
+}
+
+module.exports.findPackage = findPackage
diff --git a/node_modules/require_optional/test/nestedTest/package.json b/node_modules/require_optional/test/nestedTest/package.json
new file mode 100644
index 0000000..4c456a6
--- /dev/null
+++ b/node_modules/require_optional/test/nestedTest/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "nestedtest",
+ "version": "1.0.0",
+ "description": "A dummy package that facilitates testing that require_optional correctly walks up the module call stack",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Sebastian Hallum Clarke",
+ "license": "ISC"
+}
diff --git a/node_modules/require_optional/test/require_optional_tests.js b/node_modules/require_optional/test/require_optional_tests.js
new file mode 100644
index 0000000..c9cc2a3
--- /dev/null
+++ b/node_modules/require_optional/test/require_optional_tests.js
@@ -0,0 +1,59 @@
+var assert = require('assert'),
+ require_optional = require('../'),
+ nestedTest = require('./nestedTest');
+
+describe('Require Optional', function() {
+ describe('top level require', function() {
+ it('should correctly require co library', function() {
+ var promise = require_optional('es6-promise');
+ assert.ok(promise);
+ });
+
+ it('should fail to require es6-promise library', function() {
+ try {
+ require_optional('co');
+ } catch(e) {
+ assert.equal('OPTIONAL_MODULE_NOT_FOUND', e.code);
+ return;
+ }
+
+ assert.ok(false);
+ });
+
+ it('should ignore optional library not defined', function() {
+ assert.equal(undefined, require_optional('es6-promise2'));
+ });
+ });
+
+ describe('internal module file require', function() {
+ it('should correctly require co library', function() {
+ var Long = require_optional('bson/lib/bson/long.js');
+ assert.ok(Long);
+ });
+ });
+
+ describe('top level resolve', function() {
+ it('should correctly use exists method', function() {
+ assert.equal(false, require_optional.exists('co'));
+ assert.equal(true, require_optional.exists('es6-promise'));
+ assert.equal(true, require_optional.exists('bson/lib/bson/long.js'));
+ assert.equal(false, require_optional.exists('es6-promise2'));
+ });
+ });
+
+ describe('require_optional inside dependencies', function() {
+ it('should correctly walk up module call stack searching for peerOptionalDependencies', function() {
+ assert.ok(nestedTest.findPackage('bson'))
+ });
+ it('should return null when a package is defined in top-level package.json but not installed', function() {
+ assert.equal(null, nestedTest.findPackage('es6-promise2'))
+ });
+ it('should error when searching for an optional dependency that is not defined in any ancestor package.json', function() {
+ try {
+ nestedTest.findPackage('bison')
+ } catch (err) {
+ assert.equal(err.message, 'no optional dependency [bison] defined in peerOptionalDependencies in any package.json')
+ }
+ })
+ });
+});
diff --git a/node_modules/resolve-from/index.js b/node_modules/resolve-from/index.js
new file mode 100644
index 0000000..434159f
--- /dev/null
+++ b/node_modules/resolve-from/index.js
@@ -0,0 +1,23 @@
+'use strict';
+var path = require('path');
+var Module = require('module');
+
+module.exports = function (fromDir, moduleId) {
+ if (typeof fromDir !== 'string' || typeof moduleId !== 'string') {
+ throw new TypeError('Expected `fromDir` and `moduleId` to be a string');
+ }
+
+ fromDir = path.resolve(fromDir);
+
+ var fromFile = path.join(fromDir, 'noop.js');
+
+ try {
+ return Module._resolveFilename(moduleId, {
+ id: fromFile,
+ filename: fromFile,
+ paths: Module._nodeModulePaths(fromDir)
+ });
+ } catch (err) {
+ return null;
+ }
+};
diff --git a/node_modules/resolve-from/license b/node_modules/resolve-from/license
new file mode 100644
index 0000000..654d0bf
--- /dev/null
+++ b/node_modules/resolve-from/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus (sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/resolve-from/package.json b/node_modules/resolve-from/package.json
new file mode 100644
index 0000000..168425c
--- /dev/null
+++ b/node_modules/resolve-from/package.json
@@ -0,0 +1,90 @@
+{
+ "_args": [
+ [
+ "resolve-from@^2.0.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/require_optional"
+ ]
+ ],
+ "_from": "resolve-from@>=2.0.0 <3.0.0",
+ "_id": "resolve-from@2.0.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/resolve-from",
+ "_nodeVersion": "4.2.1",
+ "_npmUser": {
+ "email": "sindresorhus@gmail.com",
+ "name": "sindresorhus"
+ },
+ "_npmVersion": "2.14.7",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "resolve-from",
+ "raw": "resolve-from@^2.0.0",
+ "rawSpec": "^2.0.0",
+ "scope": null,
+ "spec": ">=2.0.0 <3.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/require_optional"
+ ],
+ "_resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
+ "_shasum": "9480ab20e94ffa1d9e80a804c7ea147611966b57",
+ "_shrinkwrap": null,
+ "_spec": "resolve-from@^2.0.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/require_optional",
+ "author": {
+ "email": "sindresorhus@gmail.com",
+ "name": "Sindre Sorhus",
+ "url": "sindresorhus.com"
+ },
+ "bugs": {
+ "url": "https://github.com/sindresorhus/resolve-from/issues"
+ },
+ "dependencies": {},
+ "description": "Resolve the path of a module like require.resolve() but from a given path",
+ "devDependencies": {
+ "ava": "*",
+ "xo": "*"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "9480ab20e94ffa1d9e80a804c7ea147611966b57",
+ "tarball": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "files": [
+ "index.js"
+ ],
+ "gitHead": "583e0f8df06e1bc4d1c96d8d4f2484c745f522c3",
+ "homepage": "https://github.com/sindresorhus/resolve-from",
+ "keywords": [
+ "from",
+ "like",
+ "module",
+ "path",
+ "path",
+ "require",
+ "resolve"
+ ],
+ "license": "MIT",
+ "maintainers": [
+ {
+ "name": "sindresorhus",
+ "email": "sindresorhus@gmail.com"
+ }
+ ],
+ "name": "resolve-from",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/sindresorhus/resolve-from.git"
+ },
+ "scripts": {
+ "test": "xo && ava"
+ },
+ "version": "2.0.0"
+}
diff --git a/node_modules/resolve-from/readme.md b/node_modules/resolve-from/readme.md
new file mode 100644
index 0000000..bb4ca91
--- /dev/null
+++ b/node_modules/resolve-from/readme.md
@@ -0,0 +1,58 @@
+# resolve-from [](https://travis-ci.org/sindresorhus/resolve-from)
+
+> Resolve the path of a module like [`require.resolve()`](http://nodejs.org/api/globals.html#globals_require_resolve) but from a given path
+
+Unlike `require.resolve()` it returns `null` instead of throwing when the module can't be found.
+
+
+## Install
+
+```
+$ npm install --save resolve-from
+```
+
+
+## Usage
+
+```js
+const resolveFrom = require('resolve-from');
+
+// there's a file at `./foo/bar.js`
+
+resolveFrom('foo', './bar');
+//=> '/Users/sindresorhus/dev/test/foo/bar.js'
+```
+
+
+## API
+
+### resolveFrom(fromDir, moduleId)
+
+#### fromDir
+
+Type: `string`
+
+Directory to resolve from.
+
+#### moduleId
+
+Type: `string`
+
+What you would use in `require()`.
+
+
+## Tip
+
+Create a partial using a bound function if you want to require from the same `fromDir` multiple times:
+
+```js
+const resolveFromFoo = resolveFrom.bind(null, 'foo');
+
+resolveFromFoo('./bar');
+resolveFromFoo('./baz');
+```
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/node_modules/saslprep/.editorconfig b/node_modules/saslprep/.editorconfig
new file mode 100644
index 0000000..d1d8a41
--- /dev/null
+++ b/node_modules/saslprep/.editorconfig
@@ -0,0 +1,10 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/node_modules/saslprep/.gitattributes b/node_modules/saslprep/.gitattributes
new file mode 100644
index 0000000..3ba4536
--- /dev/null
+++ b/node_modules/saslprep/.gitattributes
@@ -0,0 +1 @@
+*.mem binary
diff --git a/node_modules/saslprep/.travis.yml b/node_modules/saslprep/.travis.yml
new file mode 100644
index 0000000..0bca826
--- /dev/null
+++ b/node_modules/saslprep/.travis.yml
@@ -0,0 +1,10 @@
+sudo: false
+language: node_js
+node_js:
+ - "6"
+ - "8"
+ - "10"
+ - "12"
+
+before_install:
+- npm install -g npm@6
diff --git a/node_modules/saslprep/CHANGELOG.md b/node_modules/saslprep/CHANGELOG.md
new file mode 100644
index 0000000..7798078
--- /dev/null
+++ b/node_modules/saslprep/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Change Log
+All notable changes to the "saslprep" package will be documented in this file.
+
+## [1.0.3] - 2019-05-01
+
+- Correctly get code points >U+FFFF ([#5](https://github.com/reklatsmasters/saslprep/pull/5))
+- Fix perfomance downgrades from [#5](https://github.com/reklatsmasters/saslprep/pull/5).
+
+## [1.0.2] - 2018-09-13
+
+- Reduced initialization time ([#3](https://github.com/reklatsmasters/saslprep/issues/3))
+
+## [1.0.1] - 2018-06-20
+
+- Reduced stack overhead of range creation ([#2](https://github.com/reklatsmasters/saslprep/pull/2))
+
+## [1.0.0] - 2017-06-21
+
+- First release
diff --git a/node_modules/saslprep/LICENSE b/node_modules/saslprep/LICENSE
new file mode 100644
index 0000000..481c7a5
--- /dev/null
+++ b/node_modules/saslprep/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2014 Dmitry Tsvettsikh
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/node_modules/saslprep/code-points.mem b/node_modules/saslprep/code-points.mem
new file mode 100644
index 0000000000000000000000000000000000000000..4781b066802688bdf954d2e89bcfac967db29c09
GIT binary patch
literal 419864
zcmeI*O^9Si9RTop)4e+(t{DX(dsufSM8xBQfdsOo2lf&{@FWO&5cZ;Y@FWHe%nKV~
z@sxvzw;c53DIgdRk!c;t<{;##B4%51h#=^gL^8Y6+hx^z-92x{*9;3Umv`GA&vUy%enler!HTQKkA3&c=OSJMn7j|JGjl-d;Iey^#7>ZH0(RWYm^YJNA>kJ59aOu`p6X{MHRe9bu8cD2oYvN=9*ybv
z%TyjdGTZ46aN&^<{xI6U)O2~U(!G+Yl0gPYRjbu8Wx~a<(#z+pIGvPkC#O7E&NgnV
zIeue)&FW_ULfI&__U^^i@bTrer0O33=x2+%W4?Qo^)pjbsxinkv-K<<-Z9O6ZEyaQ
zcB_@u#{%W}q9N0;ypzw%<*<}a^^Ob|R8?1xx0U*l{Mfi-J@SG5+xHJnzAqkVA73p)
zfWWZ=`LSE4W4mY|K!5-N0t5&UATSizd-XW}{r>FO4Bx#OzCAE{nLD@VvjcA?1PBnA
ze}O7c;{B8P-)Ji&@Gu01QMDYyI+%*sOCglv+~@Yqqm#Pz_SKwJ*n6ekt-IE7xb$i{
z#vJ7-%1?!2rG0Ri^X0*sx?FU--CIQw%Y*Zsb~)W#QAMFvj~+Qsr{Zh=QgU=xwFC$d
zAV7cs0RjXF5FkK+009C72oNAZfB*pkrx2*aLB}2IZvhtFBipAEvDq7W9J^}&<>l~&
z=Z6hT7u&hviF4icy{;$Z#$Rfh)bDEDcnTt22oNAJj{^NkPm$UP5FkK+009C72oNAZ
zfB*pk1PBlya5e=N=WpRu-1tFH?r+Uep=aLS_2t}!1M%`E=_N&nH;IH{&FT4
zVA2E#5FkK+009C72oNAZfB*pk1PBlyK!5-N0tDtqVE;Gx53TDIQTIm
zIQs(S*`MN>nqk~d)2W{+PVszkrlxK(QxGVpFoq#!SYT-_Rh1zb5B|v}x
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5;&ITaB9pVN)CECK`w5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&USSSJU|ApFaizPsS009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7csfjJcr|DV&1wJZVz2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5LhUI)_PiQ
zY@~%+y~PqBK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=E{5NI_*|FQ%K5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?Yzp*ebJ}K2fB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72s8ykSewfEzdsXvos!llv!K)XN+!bACMEW{kJW7s~i{EW^`xUX5|{=UXrRtoY&_gwz<
zRvE$%TJf3i_%h&Xxb|Z>^W9wXR6Vl#j!mc_rtE>35?{Z6IbwcGK;>nSRoF
zHt&;$O2P80zs-^hqp)?4qhw2`7#YP=_?Tw>wDeltgbe?$_^GM=@
z?HoDm9erzgM=HMNFC|BJRZD;X0RjXF5FkK+009C72oNAZfB*pk1PBlya0-DOe>pzY
z-vZ3vILv9#>4l5=+gV#xaVim;YNYBg{{HIj=YJUg^!l*j-g~>b;hnpk&0)>Sr{)*n
zj_ut&1&%HR2oRWKfn%Q^H4q>`fB*pk1PBlyK!5-N0t5&UAVA>E3Jm7>U0X{dK!5-N
z0t5&U__zX7c= character.codePointAt(0);
+const first = x => x[0];
+const last = x => x[x.length - 1];
+
+/**
+ * Convert provided string into an array of Unicode Code Points.
+ * Based on https://stackoverflow.com/a/21409165/1556249
+ * and https://www.npmjs.com/package/code-point-at.
+ * @param {string} input
+ * @returns {number[]}
+ */
+function toCodePoints(input) {
+ const codepoints = [];
+ const size = input.length;
+
+ for (let i = 0; i < size; i += 1) {
+ const before = input.charCodeAt(i);
+
+ if (before >= 0xd800 && before <= 0xdbff && size > i + 1) {
+ const next = input.charCodeAt(i + 1);
+
+ if (next >= 0xdc00 && next <= 0xdfff) {
+ codepoints.push((before - 0xd800) * 0x400 + next - 0xdc00 + 0x10000);
+ i += 1;
+ continue;
+ }
+ }
+
+ codepoints.push(before);
+ }
+
+ return codepoints;
+}
+
+/**
+ * SASLprep.
+ * @param {string} input
+ * @param {Object} opts
+ * @param {boolean} opts.allowUnassigned
+ * @returns {string}
+ */
+function saslprep(input, opts = {}) {
+ if (typeof input !== 'string') {
+ throw new TypeError('Expected string.');
+ }
+
+ if (input.length === 0) {
+ return '';
+ }
+
+ // 1. Map
+ const mapped_input = toCodePoints(input)
+ // 1.1 mapping to space
+ .map(character => (mapping2space.get(character) ? 0x20 : character))
+ // 1.2 mapping to nothing
+ .filter(character => !mapping2nothing.get(character));
+
+ // 2. Normalize
+ const normalized_input = String.fromCodePoint
+ .apply(null, mapped_input)
+ .normalize('NFKC');
+
+ const normalized_map = toCodePoints(normalized_input);
+
+ // 3. Prohibit
+ const hasProhibited = normalized_map.some(character =>
+ prohibited_characters.get(character)
+ );
+
+ if (hasProhibited) {
+ throw new Error(
+ 'Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3'
+ );
+ }
+
+ // Unassigned Code Points
+ if (opts.allowUnassigned !== true) {
+ const hasUnassigned = normalized_map.some(character =>
+ unassigned_code_points.get(character)
+ );
+
+ if (hasUnassigned) {
+ throw new Error(
+ 'Unassigned code point, see https://tools.ietf.org/html/rfc4013#section-2.5'
+ );
+ }
+ }
+
+ // 4. check bidi
+
+ const hasBidiRAL = normalized_map.some(character =>
+ bidirectional_r_al.get(character)
+ );
+
+ const hasBidiL = normalized_map.some(character =>
+ bidirectional_l.get(character)
+ );
+
+ // 4.1 If a string contains any RandALCat character, the string MUST NOT
+ // contain any LCat character.
+ if (hasBidiRAL && hasBidiL) {
+ throw new Error(
+ 'String must not contain RandALCat and LCat at the same time,' +
+ ' see https://tools.ietf.org/html/rfc3454#section-6'
+ );
+ }
+
+ /**
+ * 4.2 If a string contains any RandALCat character, a RandALCat
+ * character MUST be the first character of the string, and a
+ * RandALCat character MUST be the last character of the string.
+ */
+
+ const isFirstBidiRAL = bidirectional_r_al.get(
+ getCodePoint(first(normalized_input))
+ );
+ const isLastBidiRAL = bidirectional_r_al.get(
+ getCodePoint(last(normalized_input))
+ );
+
+ if (hasBidiRAL && !(isFirstBidiRAL && isLastBidiRAL)) {
+ throw new Error(
+ 'Bidirectional RandALCat character must be the first and the last' +
+ ' character of the string, see https://tools.ietf.org/html/rfc3454#section-6'
+ );
+ }
+
+ return normalized_input;
+}
diff --git a/node_modules/saslprep/lib/code-points.js b/node_modules/saslprep/lib/code-points.js
new file mode 100644
index 0000000..222182c
--- /dev/null
+++ b/node_modules/saslprep/lib/code-points.js
@@ -0,0 +1,996 @@
+'use strict';
+
+const { range } = require('./util');
+
+/**
+ * A.1 Unassigned code points in Unicode 3.2
+ * @link https://tools.ietf.org/html/rfc3454#appendix-A.1
+ */
+const unassigned_code_points = new Set([
+ 0x0221,
+ ...range(0x0234, 0x024f),
+ ...range(0x02ae, 0x02af),
+ ...range(0x02ef, 0x02ff),
+ ...range(0x0350, 0x035f),
+ ...range(0x0370, 0x0373),
+ ...range(0x0376, 0x0379),
+ ...range(0x037b, 0x037d),
+ ...range(0x037f, 0x0383),
+ 0x038b,
+ 0x038d,
+ 0x03a2,
+ 0x03cf,
+ ...range(0x03f7, 0x03ff),
+ 0x0487,
+ 0x04cf,
+ ...range(0x04f6, 0x04f7),
+ ...range(0x04fa, 0x04ff),
+ ...range(0x0510, 0x0530),
+ ...range(0x0557, 0x0558),
+ 0x0560,
+ 0x0588,
+ ...range(0x058b, 0x0590),
+ 0x05a2,
+ 0x05ba,
+ ...range(0x05c5, 0x05cf),
+ ...range(0x05eb, 0x05ef),
+ ...range(0x05f5, 0x060b),
+ ...range(0x060d, 0x061a),
+ ...range(0x061c, 0x061e),
+ 0x0620,
+ ...range(0x063b, 0x063f),
+ ...range(0x0656, 0x065f),
+ ...range(0x06ee, 0x06ef),
+ 0x06ff,
+ 0x070e,
+ ...range(0x072d, 0x072f),
+ ...range(0x074b, 0x077f),
+ ...range(0x07b2, 0x0900),
+ 0x0904,
+ ...range(0x093a, 0x093b),
+ ...range(0x094e, 0x094f),
+ ...range(0x0955, 0x0957),
+ ...range(0x0971, 0x0980),
+ 0x0984,
+ ...range(0x098d, 0x098e),
+ ...range(0x0991, 0x0992),
+ 0x09a9,
+ 0x09b1,
+ ...range(0x09b3, 0x09b5),
+ ...range(0x09ba, 0x09bb),
+ 0x09bd,
+ ...range(0x09c5, 0x09c6),
+ ...range(0x09c9, 0x09ca),
+ ...range(0x09ce, 0x09d6),
+ ...range(0x09d8, 0x09db),
+ 0x09de,
+ ...range(0x09e4, 0x09e5),
+ ...range(0x09fb, 0x0a01),
+ ...range(0x0a03, 0x0a04),
+ ...range(0x0a0b, 0x0a0e),
+ ...range(0x0a11, 0x0a12),
+ 0x0a29,
+ 0x0a31,
+ 0x0a34,
+ 0x0a37,
+ ...range(0x0a3a, 0x0a3b),
+ 0x0a3d,
+ ...range(0x0a43, 0x0a46),
+ ...range(0x0a49, 0x0a4a),
+ ...range(0x0a4e, 0x0a58),
+ 0x0a5d,
+ ...range(0x0a5f, 0x0a65),
+ ...range(0x0a75, 0x0a80),
+ 0x0a84,
+ 0x0a8c,
+ 0x0a8e,
+ 0x0a92,
+ 0x0aa9,
+ 0x0ab1,
+ 0x0ab4,
+ ...range(0x0aba, 0x0abb),
+ 0x0ac6,
+ 0x0aca,
+ ...range(0x0ace, 0x0acf),
+ ...range(0x0ad1, 0x0adf),
+ ...range(0x0ae1, 0x0ae5),
+ ...range(0x0af0, 0x0b00),
+ 0x0b04,
+ ...range(0x0b0d, 0x0b0e),
+ ...range(0x0b11, 0x0b12),
+ 0x0b29,
+ 0x0b31,
+ ...range(0x0b34, 0x0b35),
+ ...range(0x0b3a, 0x0b3b),
+ ...range(0x0b44, 0x0b46),
+ ...range(0x0b49, 0x0b4a),
+ ...range(0x0b4e, 0x0b55),
+ ...range(0x0b58, 0x0b5b),
+ 0x0b5e,
+ ...range(0x0b62, 0x0b65),
+ ...range(0x0b71, 0x0b81),
+ 0x0b84,
+ ...range(0x0b8b, 0x0b8d),
+ 0x0b91,
+ ...range(0x0b96, 0x0b98),
+ 0x0b9b,
+ 0x0b9d,
+ ...range(0x0ba0, 0x0ba2),
+ ...range(0x0ba5, 0x0ba7),
+ ...range(0x0bab, 0x0bad),
+ 0x0bb6,
+ ...range(0x0bba, 0x0bbd),
+ ...range(0x0bc3, 0x0bc5),
+ 0x0bc9,
+ ...range(0x0bce, 0x0bd6),
+ ...range(0x0bd8, 0x0be6),
+ ...range(0x0bf3, 0x0c00),
+ 0x0c04,
+ 0x0c0d,
+ 0x0c11,
+ 0x0c29,
+ 0x0c34,
+ ...range(0x0c3a, 0x0c3d),
+ 0x0c45,
+ 0x0c49,
+ ...range(0x0c4e, 0x0c54),
+ ...range(0x0c57, 0x0c5f),
+ ...range(0x0c62, 0x0c65),
+ ...range(0x0c70, 0x0c81),
+ 0x0c84,
+ 0x0c8d,
+ 0x0c91,
+ 0x0ca9,
+ 0x0cb4,
+ ...range(0x0cba, 0x0cbd),
+ 0x0cc5,
+ 0x0cc9,
+ ...range(0x0cce, 0x0cd4),
+ ...range(0x0cd7, 0x0cdd),
+ 0x0cdf,
+ ...range(0x0ce2, 0x0ce5),
+ ...range(0x0cf0, 0x0d01),
+ 0x0d04,
+ 0x0d0d,
+ 0x0d11,
+ 0x0d29,
+ ...range(0x0d3a, 0x0d3d),
+ ...range(0x0d44, 0x0d45),
+ 0x0d49,
+ ...range(0x0d4e, 0x0d56),
+ ...range(0x0d58, 0x0d5f),
+ ...range(0x0d62, 0x0d65),
+ ...range(0x0d70, 0x0d81),
+ 0x0d84,
+ ...range(0x0d97, 0x0d99),
+ 0x0db2,
+ 0x0dbc,
+ ...range(0x0dbe, 0x0dbf),
+ ...range(0x0dc7, 0x0dc9),
+ ...range(0x0dcb, 0x0dce),
+ 0x0dd5,
+ 0x0dd7,
+ ...range(0x0de0, 0x0df1),
+ ...range(0x0df5, 0x0e00),
+ ...range(0x0e3b, 0x0e3e),
+ ...range(0x0e5c, 0x0e80),
+ 0x0e83,
+ ...range(0x0e85, 0x0e86),
+ 0x0e89,
+ ...range(0x0e8b, 0x0e8c),
+ ...range(0x0e8e, 0x0e93),
+ 0x0e98,
+ 0x0ea0,
+ 0x0ea4,
+ 0x0ea6,
+ ...range(0x0ea8, 0x0ea9),
+ 0x0eac,
+ 0x0eba,
+ ...range(0x0ebe, 0x0ebf),
+ 0x0ec5,
+ 0x0ec7,
+ ...range(0x0ece, 0x0ecf),
+ ...range(0x0eda, 0x0edb),
+ ...range(0x0ede, 0x0eff),
+ 0x0f48,
+ ...range(0x0f6b, 0x0f70),
+ ...range(0x0f8c, 0x0f8f),
+ 0x0f98,
+ 0x0fbd,
+ ...range(0x0fcd, 0x0fce),
+ ...range(0x0fd0, 0x0fff),
+ 0x1022,
+ 0x1028,
+ 0x102b,
+ ...range(0x1033, 0x1035),
+ ...range(0x103a, 0x103f),
+ ...range(0x105a, 0x109f),
+ ...range(0x10c6, 0x10cf),
+ ...range(0x10f9, 0x10fa),
+ ...range(0x10fc, 0x10ff),
+ ...range(0x115a, 0x115e),
+ ...range(0x11a3, 0x11a7),
+ ...range(0x11fa, 0x11ff),
+ 0x1207,
+ 0x1247,
+ 0x1249,
+ ...range(0x124e, 0x124f),
+ 0x1257,
+ 0x1259,
+ ...range(0x125e, 0x125f),
+ 0x1287,
+ 0x1289,
+ ...range(0x128e, 0x128f),
+ 0x12af,
+ 0x12b1,
+ ...range(0x12b6, 0x12b7),
+ 0x12bf,
+ 0x12c1,
+ ...range(0x12c6, 0x12c7),
+ 0x12cf,
+ 0x12d7,
+ 0x12ef,
+ 0x130f,
+ 0x1311,
+ ...range(0x1316, 0x1317),
+ 0x131f,
+ 0x1347,
+ ...range(0x135b, 0x1360),
+ ...range(0x137d, 0x139f),
+ ...range(0x13f5, 0x1400),
+ ...range(0x1677, 0x167f),
+ ...range(0x169d, 0x169f),
+ ...range(0x16f1, 0x16ff),
+ 0x170d,
+ ...range(0x1715, 0x171f),
+ ...range(0x1737, 0x173f),
+ ...range(0x1754, 0x175f),
+ 0x176d,
+ 0x1771,
+ ...range(0x1774, 0x177f),
+ ...range(0x17dd, 0x17df),
+ ...range(0x17ea, 0x17ff),
+ 0x180f,
+ ...range(0x181a, 0x181f),
+ ...range(0x1878, 0x187f),
+ ...range(0x18aa, 0x1dff),
+ ...range(0x1e9c, 0x1e9f),
+ ...range(0x1efa, 0x1eff),
+ ...range(0x1f16, 0x1f17),
+ ...range(0x1f1e, 0x1f1f),
+ ...range(0x1f46, 0x1f47),
+ ...range(0x1f4e, 0x1f4f),
+ 0x1f58,
+ 0x1f5a,
+ 0x1f5c,
+ 0x1f5e,
+ ...range(0x1f7e, 0x1f7f),
+ 0x1fb5,
+ 0x1fc5,
+ ...range(0x1fd4, 0x1fd5),
+ 0x1fdc,
+ ...range(0x1ff0, 0x1ff1),
+ 0x1ff5,
+ 0x1fff,
+ ...range(0x2053, 0x2056),
+ ...range(0x2058, 0x205e),
+ ...range(0x2064, 0x2069),
+ ...range(0x2072, 0x2073),
+ ...range(0x208f, 0x209f),
+ ...range(0x20b2, 0x20cf),
+ ...range(0x20eb, 0x20ff),
+ ...range(0x213b, 0x213c),
+ ...range(0x214c, 0x2152),
+ ...range(0x2184, 0x218f),
+ ...range(0x23cf, 0x23ff),
+ ...range(0x2427, 0x243f),
+ ...range(0x244b, 0x245f),
+ 0x24ff,
+ ...range(0x2614, 0x2615),
+ 0x2618,
+ ...range(0x267e, 0x267f),
+ ...range(0x268a, 0x2700),
+ 0x2705,
+ ...range(0x270a, 0x270b),
+ 0x2728,
+ 0x274c,
+ 0x274e,
+ ...range(0x2753, 0x2755),
+ 0x2757,
+ ...range(0x275f, 0x2760),
+ ...range(0x2795, 0x2797),
+ 0x27b0,
+ ...range(0x27bf, 0x27cf),
+ ...range(0x27ec, 0x27ef),
+ ...range(0x2b00, 0x2e7f),
+ 0x2e9a,
+ ...range(0x2ef4, 0x2eff),
+ ...range(0x2fd6, 0x2fef),
+ ...range(0x2ffc, 0x2fff),
+ 0x3040,
+ ...range(0x3097, 0x3098),
+ ...range(0x3100, 0x3104),
+ ...range(0x312d, 0x3130),
+ 0x318f,
+ ...range(0x31b8, 0x31ef),
+ ...range(0x321d, 0x321f),
+ ...range(0x3244, 0x3250),
+ ...range(0x327c, 0x327e),
+ ...range(0x32cc, 0x32cf),
+ 0x32ff,
+ ...range(0x3377, 0x337a),
+ ...range(0x33de, 0x33df),
+ 0x33ff,
+ ...range(0x4db6, 0x4dff),
+ ...range(0x9fa6, 0x9fff),
+ ...range(0xa48d, 0xa48f),
+ ...range(0xa4c7, 0xabff),
+ ...range(0xd7a4, 0xd7ff),
+ ...range(0xfa2e, 0xfa2f),
+ ...range(0xfa6b, 0xfaff),
+ ...range(0xfb07, 0xfb12),
+ ...range(0xfb18, 0xfb1c),
+ 0xfb37,
+ 0xfb3d,
+ 0xfb3f,
+ 0xfb42,
+ 0xfb45,
+ ...range(0xfbb2, 0xfbd2),
+ ...range(0xfd40, 0xfd4f),
+ ...range(0xfd90, 0xfd91),
+ ...range(0xfdc8, 0xfdcf),
+ ...range(0xfdfd, 0xfdff),
+ ...range(0xfe10, 0xfe1f),
+ ...range(0xfe24, 0xfe2f),
+ ...range(0xfe47, 0xfe48),
+ 0xfe53,
+ 0xfe67,
+ ...range(0xfe6c, 0xfe6f),
+ 0xfe75,
+ ...range(0xfefd, 0xfefe),
+ 0xff00,
+ ...range(0xffbf, 0xffc1),
+ ...range(0xffc8, 0xffc9),
+ ...range(0xffd0, 0xffd1),
+ ...range(0xffd8, 0xffd9),
+ ...range(0xffdd, 0xffdf),
+ 0xffe7,
+ ...range(0xffef, 0xfff8),
+ ...range(0x10000, 0x102ff),
+ 0x1031f,
+ ...range(0x10324, 0x1032f),
+ ...range(0x1034b, 0x103ff),
+ ...range(0x10426, 0x10427),
+ ...range(0x1044e, 0x1cfff),
+ ...range(0x1d0f6, 0x1d0ff),
+ ...range(0x1d127, 0x1d129),
+ ...range(0x1d1de, 0x1d3ff),
+ 0x1d455,
+ 0x1d49d,
+ ...range(0x1d4a0, 0x1d4a1),
+ ...range(0x1d4a3, 0x1d4a4),
+ ...range(0x1d4a7, 0x1d4a8),
+ 0x1d4ad,
+ 0x1d4ba,
+ 0x1d4bc,
+ 0x1d4c1,
+ 0x1d4c4,
+ 0x1d506,
+ ...range(0x1d50b, 0x1d50c),
+ 0x1d515,
+ 0x1d51d,
+ 0x1d53a,
+ 0x1d53f,
+ 0x1d545,
+ ...range(0x1d547, 0x1d549),
+ 0x1d551,
+ ...range(0x1d6a4, 0x1d6a7),
+ ...range(0x1d7ca, 0x1d7cd),
+ ...range(0x1d800, 0x1fffd),
+ ...range(0x2a6d7, 0x2f7ff),
+ ...range(0x2fa1e, 0x2fffd),
+ ...range(0x30000, 0x3fffd),
+ ...range(0x40000, 0x4fffd),
+ ...range(0x50000, 0x5fffd),
+ ...range(0x60000, 0x6fffd),
+ ...range(0x70000, 0x7fffd),
+ ...range(0x80000, 0x8fffd),
+ ...range(0x90000, 0x9fffd),
+ ...range(0xa0000, 0xafffd),
+ ...range(0xb0000, 0xbfffd),
+ ...range(0xc0000, 0xcfffd),
+ ...range(0xd0000, 0xdfffd),
+ 0xe0000,
+ ...range(0xe0002, 0xe001f),
+ ...range(0xe0080, 0xefffd),
+]);
+
+/**
+ * B.1 Commonly mapped to nothing
+ * @link https://tools.ietf.org/html/rfc3454#appendix-B.1
+ */
+const commonly_mapped_to_nothing = new Set([
+ 0x00ad,
+ 0x034f,
+ 0x1806,
+ 0x180b,
+ 0x180c,
+ 0x180d,
+ 0x200b,
+ 0x200c,
+ 0x200d,
+ 0x2060,
+ 0xfe00,
+ 0xfe01,
+ 0xfe02,
+ 0xfe03,
+ 0xfe04,
+ 0xfe05,
+ 0xfe06,
+ 0xfe07,
+ 0xfe08,
+ 0xfe09,
+ 0xfe0a,
+ 0xfe0b,
+ 0xfe0c,
+ 0xfe0d,
+ 0xfe0e,
+ 0xfe0f,
+ 0xfeff,
+]);
+
+/**
+ * C.1.2 Non-ASCII space characters
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.1.2
+ */
+const non_ASCII_space_characters = new Set([
+ 0x00a0 /* NO-BREAK SPACE */,
+ 0x1680 /* OGHAM SPACE MARK */,
+ 0x2000 /* EN QUAD */,
+ 0x2001 /* EM QUAD */,
+ 0x2002 /* EN SPACE */,
+ 0x2003 /* EM SPACE */,
+ 0x2004 /* THREE-PER-EM SPACE */,
+ 0x2005 /* FOUR-PER-EM SPACE */,
+ 0x2006 /* SIX-PER-EM SPACE */,
+ 0x2007 /* FIGURE SPACE */,
+ 0x2008 /* PUNCTUATION SPACE */,
+ 0x2009 /* THIN SPACE */,
+ 0x200a /* HAIR SPACE */,
+ 0x200b /* ZERO WIDTH SPACE */,
+ 0x202f /* NARROW NO-BREAK SPACE */,
+ 0x205f /* MEDIUM MATHEMATICAL SPACE */,
+ 0x3000 /* IDEOGRAPHIC SPACE */,
+]);
+
+/**
+ * 2.3. Prohibited Output
+ * @type {Set}
+ */
+const prohibited_characters = new Set([
+ ...non_ASCII_space_characters,
+
+ /**
+ * C.2.1 ASCII control characters
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.2.1
+ */
+ ...range(0, 0x001f) /* [CONTROL CHARACTERS] */,
+ 0x007f /* DELETE */,
+
+ /**
+ * C.2.2 Non-ASCII control characters
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.2.2
+ */
+ ...range(0x0080, 0x009f) /* [CONTROL CHARACTERS] */,
+ 0x06dd /* ARABIC END OF AYAH */,
+ 0x070f /* SYRIAC ABBREVIATION MARK */,
+ 0x180e /* MONGOLIAN VOWEL SEPARATOR */,
+ 0x200c /* ZERO WIDTH NON-JOINER */,
+ 0x200d /* ZERO WIDTH JOINER */,
+ 0x2028 /* LINE SEPARATOR */,
+ 0x2029 /* PARAGRAPH SEPARATOR */,
+ 0x2060 /* WORD JOINER */,
+ 0x2061 /* FUNCTION APPLICATION */,
+ 0x2062 /* INVISIBLE TIMES */,
+ 0x2063 /* INVISIBLE SEPARATOR */,
+ ...range(0x206a, 0x206f) /* [CONTROL CHARACTERS] */,
+ 0xfeff /* ZERO WIDTH NO-BREAK SPACE */,
+ ...range(0xfff9, 0xfffc) /* [CONTROL CHARACTERS] */,
+ ...range(0x1d173, 0x1d17a) /* [MUSICAL CONTROL CHARACTERS] */,
+
+ /**
+ * C.3 Private use
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.3
+ */
+ ...range(0xe000, 0xf8ff) /* [PRIVATE USE, PLANE 0] */,
+ ...range(0xf0000, 0xffffd) /* [PRIVATE USE, PLANE 15] */,
+ ...range(0x100000, 0x10fffd) /* [PRIVATE USE, PLANE 16] */,
+
+ /**
+ * C.4 Non-character code points
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.4
+ */
+ ...range(0xfdd0, 0xfdef) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xfffe, 0xffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x1fffe, 0x1ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x2fffe, 0x2ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x3fffe, 0x3ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x4fffe, 0x4ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x5fffe, 0x5ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x6fffe, 0x6ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x7fffe, 0x7ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x8fffe, 0x8ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x9fffe, 0x9ffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xafffe, 0xaffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xbfffe, 0xbffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xcfffe, 0xcffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xdfffe, 0xdffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0xefffe, 0xeffff) /* [NONCHARACTER CODE POINTS] */,
+ ...range(0x10fffe, 0x10ffff) /* [NONCHARACTER CODE POINTS] */,
+
+ /**
+ * C.5 Surrogate codes
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.5
+ */
+ ...range(0xd800, 0xdfff),
+
+ /**
+ * C.6 Inappropriate for plain text
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.6
+ */
+ 0xfff9 /* INTERLINEAR ANNOTATION ANCHOR */,
+ 0xfffa /* INTERLINEAR ANNOTATION SEPARATOR */,
+ 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */,
+ 0xfffc /* OBJECT REPLACEMENT CHARACTER */,
+ 0xfffd /* REPLACEMENT CHARACTER */,
+
+ /**
+ * C.7 Inappropriate for canonical representation
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.7
+ */
+ ...range(0x2ff0, 0x2ffb) /* [IDEOGRAPHIC DESCRIPTION CHARACTERS] */,
+
+ /**
+ * C.8 Change display properties or are deprecated
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.8
+ */
+ 0x0340 /* COMBINING GRAVE TONE MARK */,
+ 0x0341 /* COMBINING ACUTE TONE MARK */,
+ 0x200e /* LEFT-TO-RIGHT MARK */,
+ 0x200f /* RIGHT-TO-LEFT MARK */,
+ 0x202a /* LEFT-TO-RIGHT EMBEDDING */,
+ 0x202b /* RIGHT-TO-LEFT EMBEDDING */,
+ 0x202c /* POP DIRECTIONAL FORMATTING */,
+ 0x202d /* LEFT-TO-RIGHT OVERRIDE */,
+ 0x202e /* RIGHT-TO-LEFT OVERRIDE */,
+ 0x206a /* INHIBIT SYMMETRIC SWAPPING */,
+ 0x206b /* ACTIVATE SYMMETRIC SWAPPING */,
+ 0x206c /* INHIBIT ARABIC FORM SHAPING */,
+ 0x206d /* ACTIVATE ARABIC FORM SHAPING */,
+ 0x206e /* NATIONAL DIGIT SHAPES */,
+ 0x206f /* NOMINAL DIGIT SHAPES */,
+
+ /**
+ * C.9 Tagging characters
+ * @link https://tools.ietf.org/html/rfc3454#appendix-C.9
+ */
+ 0xe0001 /* LANGUAGE TAG */,
+ ...range(0xe0020, 0xe007f) /* [TAGGING CHARACTERS] */,
+]);
+
+/**
+ * D.1 Characters with bidirectional property "R" or "AL"
+ * @link https://tools.ietf.org/html/rfc3454#appendix-D.1
+ */
+const bidirectional_r_al = new Set([
+ 0x05be,
+ 0x05c0,
+ 0x05c3,
+ ...range(0x05d0, 0x05ea),
+ ...range(0x05f0, 0x05f4),
+ 0x061b,
+ 0x061f,
+ ...range(0x0621, 0x063a),
+ ...range(0x0640, 0x064a),
+ ...range(0x066d, 0x066f),
+ ...range(0x0671, 0x06d5),
+ 0x06dd,
+ ...range(0x06e5, 0x06e6),
+ ...range(0x06fa, 0x06fe),
+ ...range(0x0700, 0x070d),
+ 0x0710,
+ ...range(0x0712, 0x072c),
+ ...range(0x0780, 0x07a5),
+ 0x07b1,
+ 0x200f,
+ 0xfb1d,
+ ...range(0xfb1f, 0xfb28),
+ ...range(0xfb2a, 0xfb36),
+ ...range(0xfb38, 0xfb3c),
+ 0xfb3e,
+ ...range(0xfb40, 0xfb41),
+ ...range(0xfb43, 0xfb44),
+ ...range(0xfb46, 0xfbb1),
+ ...range(0xfbd3, 0xfd3d),
+ ...range(0xfd50, 0xfd8f),
+ ...range(0xfd92, 0xfdc7),
+ ...range(0xfdf0, 0xfdfc),
+ ...range(0xfe70, 0xfe74),
+ ...range(0xfe76, 0xfefc),
+]);
+
+/**
+ * D.2 Characters with bidirectional property "L"
+ * @link https://tools.ietf.org/html/rfc3454#appendix-D.2
+ */
+const bidirectional_l = new Set([
+ ...range(0x0041, 0x005a),
+ ...range(0x0061, 0x007a),
+ 0x00aa,
+ 0x00b5,
+ 0x00ba,
+ ...range(0x00c0, 0x00d6),
+ ...range(0x00d8, 0x00f6),
+ ...range(0x00f8, 0x0220),
+ ...range(0x0222, 0x0233),
+ ...range(0x0250, 0x02ad),
+ ...range(0x02b0, 0x02b8),
+ ...range(0x02bb, 0x02c1),
+ ...range(0x02d0, 0x02d1),
+ ...range(0x02e0, 0x02e4),
+ 0x02ee,
+ 0x037a,
+ 0x0386,
+ ...range(0x0388, 0x038a),
+ 0x038c,
+ ...range(0x038e, 0x03a1),
+ ...range(0x03a3, 0x03ce),
+ ...range(0x03d0, 0x03f5),
+ ...range(0x0400, 0x0482),
+ ...range(0x048a, 0x04ce),
+ ...range(0x04d0, 0x04f5),
+ ...range(0x04f8, 0x04f9),
+ ...range(0x0500, 0x050f),
+ ...range(0x0531, 0x0556),
+ ...range(0x0559, 0x055f),
+ ...range(0x0561, 0x0587),
+ 0x0589,
+ 0x0903,
+ ...range(0x0905, 0x0939),
+ ...range(0x093d, 0x0940),
+ ...range(0x0949, 0x094c),
+ 0x0950,
+ ...range(0x0958, 0x0961),
+ ...range(0x0964, 0x0970),
+ ...range(0x0982, 0x0983),
+ ...range(0x0985, 0x098c),
+ ...range(0x098f, 0x0990),
+ ...range(0x0993, 0x09a8),
+ ...range(0x09aa, 0x09b0),
+ 0x09b2,
+ ...range(0x09b6, 0x09b9),
+ ...range(0x09be, 0x09c0),
+ ...range(0x09c7, 0x09c8),
+ ...range(0x09cb, 0x09cc),
+ 0x09d7,
+ ...range(0x09dc, 0x09dd),
+ ...range(0x09df, 0x09e1),
+ ...range(0x09e6, 0x09f1),
+ ...range(0x09f4, 0x09fa),
+ ...range(0x0a05, 0x0a0a),
+ ...range(0x0a0f, 0x0a10),
+ ...range(0x0a13, 0x0a28),
+ ...range(0x0a2a, 0x0a30),
+ ...range(0x0a32, 0x0a33),
+ ...range(0x0a35, 0x0a36),
+ ...range(0x0a38, 0x0a39),
+ ...range(0x0a3e, 0x0a40),
+ ...range(0x0a59, 0x0a5c),
+ 0x0a5e,
+ ...range(0x0a66, 0x0a6f),
+ ...range(0x0a72, 0x0a74),
+ 0x0a83,
+ ...range(0x0a85, 0x0a8b),
+ 0x0a8d,
+ ...range(0x0a8f, 0x0a91),
+ ...range(0x0a93, 0x0aa8),
+ ...range(0x0aaa, 0x0ab0),
+ ...range(0x0ab2, 0x0ab3),
+ ...range(0x0ab5, 0x0ab9),
+ ...range(0x0abd, 0x0ac0),
+ 0x0ac9,
+ ...range(0x0acb, 0x0acc),
+ 0x0ad0,
+ 0x0ae0,
+ ...range(0x0ae6, 0x0aef),
+ ...range(0x0b02, 0x0b03),
+ ...range(0x0b05, 0x0b0c),
+ ...range(0x0b0f, 0x0b10),
+ ...range(0x0b13, 0x0b28),
+ ...range(0x0b2a, 0x0b30),
+ ...range(0x0b32, 0x0b33),
+ ...range(0x0b36, 0x0b39),
+ ...range(0x0b3d, 0x0b3e),
+ 0x0b40,
+ ...range(0x0b47, 0x0b48),
+ ...range(0x0b4b, 0x0b4c),
+ 0x0b57,
+ ...range(0x0b5c, 0x0b5d),
+ ...range(0x0b5f, 0x0b61),
+ ...range(0x0b66, 0x0b70),
+ 0x0b83,
+ ...range(0x0b85, 0x0b8a),
+ ...range(0x0b8e, 0x0b90),
+ ...range(0x0b92, 0x0b95),
+ ...range(0x0b99, 0x0b9a),
+ 0x0b9c,
+ ...range(0x0b9e, 0x0b9f),
+ ...range(0x0ba3, 0x0ba4),
+ ...range(0x0ba8, 0x0baa),
+ ...range(0x0bae, 0x0bb5),
+ ...range(0x0bb7, 0x0bb9),
+ ...range(0x0bbe, 0x0bbf),
+ ...range(0x0bc1, 0x0bc2),
+ ...range(0x0bc6, 0x0bc8),
+ ...range(0x0bca, 0x0bcc),
+ 0x0bd7,
+ ...range(0x0be7, 0x0bf2),
+ ...range(0x0c01, 0x0c03),
+ ...range(0x0c05, 0x0c0c),
+ ...range(0x0c0e, 0x0c10),
+ ...range(0x0c12, 0x0c28),
+ ...range(0x0c2a, 0x0c33),
+ ...range(0x0c35, 0x0c39),
+ ...range(0x0c41, 0x0c44),
+ ...range(0x0c60, 0x0c61),
+ ...range(0x0c66, 0x0c6f),
+ ...range(0x0c82, 0x0c83),
+ ...range(0x0c85, 0x0c8c),
+ ...range(0x0c8e, 0x0c90),
+ ...range(0x0c92, 0x0ca8),
+ ...range(0x0caa, 0x0cb3),
+ ...range(0x0cb5, 0x0cb9),
+ 0x0cbe,
+ ...range(0x0cc0, 0x0cc4),
+ ...range(0x0cc7, 0x0cc8),
+ ...range(0x0cca, 0x0ccb),
+ ...range(0x0cd5, 0x0cd6),
+ 0x0cde,
+ ...range(0x0ce0, 0x0ce1),
+ ...range(0x0ce6, 0x0cef),
+ ...range(0x0d02, 0x0d03),
+ ...range(0x0d05, 0x0d0c),
+ ...range(0x0d0e, 0x0d10),
+ ...range(0x0d12, 0x0d28),
+ ...range(0x0d2a, 0x0d39),
+ ...range(0x0d3e, 0x0d40),
+ ...range(0x0d46, 0x0d48),
+ ...range(0x0d4a, 0x0d4c),
+ 0x0d57,
+ ...range(0x0d60, 0x0d61),
+ ...range(0x0d66, 0x0d6f),
+ ...range(0x0d82, 0x0d83),
+ ...range(0x0d85, 0x0d96),
+ ...range(0x0d9a, 0x0db1),
+ ...range(0x0db3, 0x0dbb),
+ 0x0dbd,
+ ...range(0x0dc0, 0x0dc6),
+ ...range(0x0dcf, 0x0dd1),
+ ...range(0x0dd8, 0x0ddf),
+ ...range(0x0df2, 0x0df4),
+ ...range(0x0e01, 0x0e30),
+ ...range(0x0e32, 0x0e33),
+ ...range(0x0e40, 0x0e46),
+ ...range(0x0e4f, 0x0e5b),
+ ...range(0x0e81, 0x0e82),
+ 0x0e84,
+ ...range(0x0e87, 0x0e88),
+ 0x0e8a,
+ 0x0e8d,
+ ...range(0x0e94, 0x0e97),
+ ...range(0x0e99, 0x0e9f),
+ ...range(0x0ea1, 0x0ea3),
+ 0x0ea5,
+ 0x0ea7,
+ ...range(0x0eaa, 0x0eab),
+ ...range(0x0ead, 0x0eb0),
+ ...range(0x0eb2, 0x0eb3),
+ 0x0ebd,
+ ...range(0x0ec0, 0x0ec4),
+ 0x0ec6,
+ ...range(0x0ed0, 0x0ed9),
+ ...range(0x0edc, 0x0edd),
+ ...range(0x0f00, 0x0f17),
+ ...range(0x0f1a, 0x0f34),
+ 0x0f36,
+ 0x0f38,
+ ...range(0x0f3e, 0x0f47),
+ ...range(0x0f49, 0x0f6a),
+ 0x0f7f,
+ 0x0f85,
+ ...range(0x0f88, 0x0f8b),
+ ...range(0x0fbe, 0x0fc5),
+ ...range(0x0fc7, 0x0fcc),
+ 0x0fcf,
+ ...range(0x1000, 0x1021),
+ ...range(0x1023, 0x1027),
+ ...range(0x1029, 0x102a),
+ 0x102c,
+ 0x1031,
+ 0x1038,
+ ...range(0x1040, 0x1057),
+ ...range(0x10a0, 0x10c5),
+ ...range(0x10d0, 0x10f8),
+ 0x10fb,
+ ...range(0x1100, 0x1159),
+ ...range(0x115f, 0x11a2),
+ ...range(0x11a8, 0x11f9),
+ ...range(0x1200, 0x1206),
+ ...range(0x1208, 0x1246),
+ 0x1248,
+ ...range(0x124a, 0x124d),
+ ...range(0x1250, 0x1256),
+ 0x1258,
+ ...range(0x125a, 0x125d),
+ ...range(0x1260, 0x1286),
+ 0x1288,
+ ...range(0x128a, 0x128d),
+ ...range(0x1290, 0x12ae),
+ 0x12b0,
+ ...range(0x12b2, 0x12b5),
+ ...range(0x12b8, 0x12be),
+ 0x12c0,
+ ...range(0x12c2, 0x12c5),
+ ...range(0x12c8, 0x12ce),
+ ...range(0x12d0, 0x12d6),
+ ...range(0x12d8, 0x12ee),
+ ...range(0x12f0, 0x130e),
+ 0x1310,
+ ...range(0x1312, 0x1315),
+ ...range(0x1318, 0x131e),
+ ...range(0x1320, 0x1346),
+ ...range(0x1348, 0x135a),
+ ...range(0x1361, 0x137c),
+ ...range(0x13a0, 0x13f4),
+ ...range(0x1401, 0x1676),
+ ...range(0x1681, 0x169a),
+ ...range(0x16a0, 0x16f0),
+ ...range(0x1700, 0x170c),
+ ...range(0x170e, 0x1711),
+ ...range(0x1720, 0x1731),
+ ...range(0x1735, 0x1736),
+ ...range(0x1740, 0x1751),
+ ...range(0x1760, 0x176c),
+ ...range(0x176e, 0x1770),
+ ...range(0x1780, 0x17b6),
+ ...range(0x17be, 0x17c5),
+ ...range(0x17c7, 0x17c8),
+ ...range(0x17d4, 0x17da),
+ 0x17dc,
+ ...range(0x17e0, 0x17e9),
+ ...range(0x1810, 0x1819),
+ ...range(0x1820, 0x1877),
+ ...range(0x1880, 0x18a8),
+ ...range(0x1e00, 0x1e9b),
+ ...range(0x1ea0, 0x1ef9),
+ ...range(0x1f00, 0x1f15),
+ ...range(0x1f18, 0x1f1d),
+ ...range(0x1f20, 0x1f45),
+ ...range(0x1f48, 0x1f4d),
+ ...range(0x1f50, 0x1f57),
+ 0x1f59,
+ 0x1f5b,
+ 0x1f5d,
+ ...range(0x1f5f, 0x1f7d),
+ ...range(0x1f80, 0x1fb4),
+ ...range(0x1fb6, 0x1fbc),
+ 0x1fbe,
+ ...range(0x1fc2, 0x1fc4),
+ ...range(0x1fc6, 0x1fcc),
+ ...range(0x1fd0, 0x1fd3),
+ ...range(0x1fd6, 0x1fdb),
+ ...range(0x1fe0, 0x1fec),
+ ...range(0x1ff2, 0x1ff4),
+ ...range(0x1ff6, 0x1ffc),
+ 0x200e,
+ 0x2071,
+ 0x207f,
+ 0x2102,
+ 0x2107,
+ ...range(0x210a, 0x2113),
+ 0x2115,
+ ...range(0x2119, 0x211d),
+ 0x2124,
+ 0x2126,
+ 0x2128,
+ ...range(0x212a, 0x212d),
+ ...range(0x212f, 0x2131),
+ ...range(0x2133, 0x2139),
+ ...range(0x213d, 0x213f),
+ ...range(0x2145, 0x2149),
+ ...range(0x2160, 0x2183),
+ ...range(0x2336, 0x237a),
+ 0x2395,
+ ...range(0x249c, 0x24e9),
+ ...range(0x3005, 0x3007),
+ ...range(0x3021, 0x3029),
+ ...range(0x3031, 0x3035),
+ ...range(0x3038, 0x303c),
+ ...range(0x3041, 0x3096),
+ ...range(0x309d, 0x309f),
+ ...range(0x30a1, 0x30fa),
+ ...range(0x30fc, 0x30ff),
+ ...range(0x3105, 0x312c),
+ ...range(0x3131, 0x318e),
+ ...range(0x3190, 0x31b7),
+ ...range(0x31f0, 0x321c),
+ ...range(0x3220, 0x3243),
+ ...range(0x3260, 0x327b),
+ ...range(0x327f, 0x32b0),
+ ...range(0x32c0, 0x32cb),
+ ...range(0x32d0, 0x32fe),
+ ...range(0x3300, 0x3376),
+ ...range(0x337b, 0x33dd),
+ ...range(0x33e0, 0x33fe),
+ ...range(0x3400, 0x4db5),
+ ...range(0x4e00, 0x9fa5),
+ ...range(0xa000, 0xa48c),
+ ...range(0xac00, 0xd7a3),
+ ...range(0xd800, 0xfa2d),
+ ...range(0xfa30, 0xfa6a),
+ ...range(0xfb00, 0xfb06),
+ ...range(0xfb13, 0xfb17),
+ ...range(0xff21, 0xff3a),
+ ...range(0xff41, 0xff5a),
+ ...range(0xff66, 0xffbe),
+ ...range(0xffc2, 0xffc7),
+ ...range(0xffca, 0xffcf),
+ ...range(0xffd2, 0xffd7),
+ ...range(0xffda, 0xffdc),
+ ...range(0x10300, 0x1031e),
+ ...range(0x10320, 0x10323),
+ ...range(0x10330, 0x1034a),
+ ...range(0x10400, 0x10425),
+ ...range(0x10428, 0x1044d),
+ ...range(0x1d000, 0x1d0f5),
+ ...range(0x1d100, 0x1d126),
+ ...range(0x1d12a, 0x1d166),
+ ...range(0x1d16a, 0x1d172),
+ ...range(0x1d183, 0x1d184),
+ ...range(0x1d18c, 0x1d1a9),
+ ...range(0x1d1ae, 0x1d1dd),
+ ...range(0x1d400, 0x1d454),
+ ...range(0x1d456, 0x1d49c),
+ ...range(0x1d49e, 0x1d49f),
+ 0x1d4a2,
+ ...range(0x1d4a5, 0x1d4a6),
+ ...range(0x1d4a9, 0x1d4ac),
+ ...range(0x1d4ae, 0x1d4b9),
+ 0x1d4bb,
+ ...range(0x1d4bd, 0x1d4c0),
+ ...range(0x1d4c2, 0x1d4c3),
+ ...range(0x1d4c5, 0x1d505),
+ ...range(0x1d507, 0x1d50a),
+ ...range(0x1d50d, 0x1d514),
+ ...range(0x1d516, 0x1d51c),
+ ...range(0x1d51e, 0x1d539),
+ ...range(0x1d53b, 0x1d53e),
+ ...range(0x1d540, 0x1d544),
+ 0x1d546,
+ ...range(0x1d54a, 0x1d550),
+ ...range(0x1d552, 0x1d6a3),
+ ...range(0x1d6a8, 0x1d7c9),
+ ...range(0x20000, 0x2a6d6),
+ ...range(0x2f800, 0x2fa1d),
+ ...range(0xf0000, 0xffffd),
+ ...range(0x100000, 0x10fffd),
+]);
+
+module.exports = {
+ unassigned_code_points,
+ commonly_mapped_to_nothing,
+ non_ASCII_space_characters,
+ prohibited_characters,
+ bidirectional_r_al,
+ bidirectional_l,
+};
diff --git a/node_modules/saslprep/lib/memory-code-points.js b/node_modules/saslprep/lib/memory-code-points.js
new file mode 100644
index 0000000..cb0289c
--- /dev/null
+++ b/node_modules/saslprep/lib/memory-code-points.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const bitfield = require('sparse-bitfield');
+
+/* eslint-disable-next-line security/detect-non-literal-fs-filename */
+const memory = fs.readFileSync(path.resolve(__dirname, '../code-points.mem'));
+let offset = 0;
+
+/**
+ * Loads each code points sequence from buffer.
+ * @returns {bitfield}
+ */
+function read() {
+ const size = memory.readUInt32BE(offset);
+ offset += 4;
+
+ const codepoints = memory.slice(offset, offset + size);
+ offset += size;
+
+ return bitfield({ buffer: codepoints });
+}
+
+const unassigned_code_points = read();
+const commonly_mapped_to_nothing = read();
+const non_ASCII_space_characters = read();
+const prohibited_characters = read();
+const bidirectional_r_al = read();
+const bidirectional_l = read();
+
+module.exports = {
+ unassigned_code_points,
+ commonly_mapped_to_nothing,
+ non_ASCII_space_characters,
+ prohibited_characters,
+ bidirectional_r_al,
+ bidirectional_l,
+};
diff --git a/node_modules/saslprep/lib/util.js b/node_modules/saslprep/lib/util.js
new file mode 100644
index 0000000..506bdc9
--- /dev/null
+++ b/node_modules/saslprep/lib/util.js
@@ -0,0 +1,21 @@
+'use strict';
+
+/**
+ * Create an array of numbers.
+ * @param {number} from
+ * @param {number} to
+ * @returns {number[]}
+ */
+function range(from, to) {
+ // TODO: make this inlined.
+ const list = new Array(to - from + 1);
+
+ for (let i = 0; i < list.length; i += 1) {
+ list[i] = from + i;
+ }
+ return list;
+}
+
+module.exports = {
+ range,
+};
diff --git a/node_modules/saslprep/package.json b/node_modules/saslprep/package.json
new file mode 100644
index 0000000..7a46093
--- /dev/null
+++ b/node_modules/saslprep/package.json
@@ -0,0 +1,132 @@
+{
+ "_args": [
+ [
+ "saslprep@^1.0.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongodb"
+ ]
+ ],
+ "_from": "saslprep@>=1.0.0 <2.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "saslprep@1.0.3",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/saslprep",
+ "_nodeVersion": "10.15.3",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/saslprep_1.0.3_1556674884466_0.07047389393212589"
+ },
+ "_npmUser": {
+ "email": "me@reklatsmasters.com",
+ "name": "reklatsmasters"
+ },
+ "_npmVersion": "6.9.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "saslprep",
+ "raw": "saslprep@^1.0.0",
+ "rawSpec": "^1.0.0",
+ "scope": null,
+ "spec": ">=1.0.0 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/mongodb"
+ ],
+ "_resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+ "_shasum": "4c02f946b56cf54297e347ba1093e7acac4cf226",
+ "_shrinkwrap": null,
+ "_spec": "saslprep@^1.0.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongodb",
+ "author": {
+ "email": "me@reklatsmasters.com",
+ "name": "Dmitry Tsvettsikh"
+ },
+ "bugs": {
+ "url": "https://github.com/reklatsmasters/saslprep/issues"
+ },
+ "dependencies": {
+ "sparse-bitfield": "^3.0.3"
+ },
+ "description": "SASLprep: Stringprep Profile for User Names and Passwords, rfc4013.",
+ "devDependencies": {
+ "@nodertc/eslint-config": "^0.2.1",
+ "eslint": "^5.16.0",
+ "jest": "^23.6.0",
+ "prettier": "^1.14.3"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 15,
+ "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcyPlFCRA9TVsSAnZWagAAGwEQAI2hXgJaXeA22S1buqWG\nL386Js0nlwRwaORWjlIvLhjqw+qKN5yKk02WosIXlK8uncLqrSyrf3fhPR15\n2PkJH+BYSvK4//643vfLrc0oaQCzd7ka+xqam8uRbhtaOv58yt3NSdSsBrA6\nyGSu9UaTvICJcronKePmiR8b7mOKt2f5s2zYLtgcaZ1YEpQlrwYZeCzyXGtq\no66e3QuK1CAw0Ng3U8LJd8385GsdyDyDhn6KWpaU5nPJN0iZkJPay/jpI8pn\nJQ+07yeC1Lzy/9SxPHfilmTwqp9lWMeiixx0Pef4d+fCfA2IpJPYHHKyHv/Z\nJv58PCAifi0WDz+n91XrNaZtEgBOtn1a/I/nu9lGF3Ooq4JrGVDHxqNSf4i6\n4f8LTl0ItUrF1rMqou3h3T7FZplkOjPDqfkh8I/lDldBZBS2buuyKxLTKb0J\nMUWZCm0IhpuJdBTMfvivNV2Z+S2Q8kJEZiY9mx62WfYGtK74aeCDX68Hvwne\nPdLmRtHtsRxiYLeAVR80Xd5XNft04qnGXsT+pVm9ekLNUzmN0KrI+dQCiq5n\nh5oOdVqm1loUxz4u09sVqzSmZi0EwbvxKKjv/xYLe41hgvejOnAYs6tDg+Cq\n+cL9h7kaTPOWXtRQTAm8WoMw0nOU3lEKhIkXYAIbAEZDAlYXuNw/VQi304qH\nG0UA\r\n=EEo6\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "4c02f946b56cf54297e347ba1093e7acac4cf226",
+ "tarball": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+ "unpackedSize": 457546
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "eslintConfig": {
+ "extends": "@nodertc",
+ "overrides": [
+ {
+ "files": [
+ "test/*.js"
+ ],
+ "env": {
+ "jest": true
+ },
+ "rules": {
+ "require-jsdoc": "off"
+ }
+ }
+ ],
+ "rules": {
+ "camelcase": "off",
+ "no-continue": "off"
+ }
+ },
+ "gitHead": "4ad8884b461a6a8e496d6e648ad5da0a1b43cb42",
+ "homepage": "https://github.com/reklatsmasters/saslprep#readme",
+ "jest": {
+ "modulePaths": [
+ ""
+ ],
+ "testMatch": [
+ "**/test/*.js"
+ ],
+ "testPathIgnorePatterns": [
+ "/node_modules/"
+ ]
+ },
+ "keywords": [
+ "4013",
+ "rfc4013",
+ "sasl",
+ "saslprep",
+ "stringprep"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "reklatsmasters",
+ "email": "me@reklatsmasters.com"
+ }
+ ],
+ "name": "saslprep",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/reklatsmasters/saslprep.git"
+ },
+ "scripts": {
+ "gen-code-points": "node generate-code-points.js > code-points.mem",
+ "lint": "npx eslint --quiet .",
+ "test": "npm run lint && npm run unit-test",
+ "unit-test": "npx jest"
+ },
+ "version": "1.0.3"
+}
diff --git a/node_modules/saslprep/readme.md b/node_modules/saslprep/readme.md
new file mode 100644
index 0000000..8ff3d70
--- /dev/null
+++ b/node_modules/saslprep/readme.md
@@ -0,0 +1,31 @@
+# saslprep
+[](https://travis-ci.org/reklatsmasters/saslprep)
+[](https://npmjs.org/package/saslprep)
+[](https://npmjs.org/package/saslprep)
+[](https://npmjs.org/package/saslprep)
+[](https://npmjs.org/package/saslprep)
+
+Stringprep Profile for User Names and Passwords, [rfc4013](https://tools.ietf.org/html/rfc4013)
+
+### Usage
+
+```js
+const saslprep = require('saslprep')
+
+saslprep('password\u00AD') // password
+saslprep('password\u0007') // Error: prohibited character
+```
+
+### API
+
+##### `saslprep(input: String, opts: Options): String`
+
+Normalize user name or password.
+
+##### `Options.allowUnassigned: bool`
+
+A special behavior for unassigned code points, see https://tools.ietf.org/html/rfc4013#section-2.5. Disabled by default.
+
+## License
+
+MIT, 2017-2019 (c) Dmitriy Tsvettsikh
diff --git a/node_modules/saslprep/test/index.js b/node_modules/saslprep/test/index.js
new file mode 100644
index 0000000..80c71af
--- /dev/null
+++ b/node_modules/saslprep/test/index.js
@@ -0,0 +1,76 @@
+'use strict';
+
+const saslprep = require('..');
+
+const chr = String.fromCodePoint;
+
+test('should work with liatin letters', () => {
+ const str = 'user';
+ expect(saslprep(str)).toEqual(str);
+});
+
+test('should work be case preserved', () => {
+ const str = 'USER';
+ expect(saslprep(str)).toEqual(str);
+});
+
+test('should work with high code points (> U+FFFF)', () => {
+ const str = '\uD83D\uDE00';
+ expect(saslprep(str, { allowUnassigned: true })).toEqual(str);
+});
+
+test('should remove `mapped to nothing` characters', () => {
+ expect(saslprep('I\u00ADX')).toEqual('IX');
+});
+
+test('should replace `Non-ASCII space characters` with space', () => {
+ expect(saslprep('a\u00A0b')).toEqual('a\u0020b');
+});
+
+test('should normalize as NFKC', () => {
+ expect(saslprep('\u00AA')).toEqual('a');
+ expect(saslprep('\u2168')).toEqual('IX');
+});
+
+test('should throws when prohibited characters', () => {
+ // C.2.1 ASCII control characters
+ expect(() => saslprep('a\u007Fb')).toThrow();
+
+ // C.2.2 Non-ASCII control characters
+ expect(() => saslprep('a\u06DDb')).toThrow();
+
+ // C.3 Private use
+ expect(() => saslprep('a\uE000b')).toThrow();
+
+ // C.4 Non-character code points
+ expect(() => saslprep(`a${chr(0x1fffe)}b`)).toThrow();
+
+ // C.5 Surrogate codes
+ expect(() => saslprep('a\uD800b')).toThrow();
+
+ // C.6 Inappropriate for plain text
+ expect(() => saslprep('a\uFFF9b')).toThrow();
+
+ // C.7 Inappropriate for canonical representation
+ expect(() => saslprep('a\u2FF0b')).toThrow();
+
+ // C.8 Change display properties or are deprecated
+ expect(() => saslprep('a\u200Eb')).toThrow();
+
+ // C.9 Tagging characters
+ expect(() => saslprep(`a${chr(0xe0001)}b`)).toThrow();
+});
+
+test('should not containt RandALCat and LCat bidi', () => {
+ expect(() => saslprep('a\u06DD\u00AAb')).toThrow();
+});
+
+test('RandALCat should be first and last', () => {
+ expect(() => saslprep('\u0627\u0031\u0628')).not.toThrow();
+ expect(() => saslprep('\u0627\u0031')).toThrow();
+});
+
+test('should handle unassigned code points', () => {
+ expect(() => saslprep('a\u0487')).toThrow();
+ expect(() => saslprep('a\u0487', { allowUnassigned: true })).not.toThrow();
+});
diff --git a/node_modules/saslprep/test/util.js b/node_modules/saslprep/test/util.js
new file mode 100644
index 0000000..355db3f
--- /dev/null
+++ b/node_modules/saslprep/test/util.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const { setFlagsFromString } = require('v8');
+const { range } = require('../lib/util');
+
+// 984 by default.
+setFlagsFromString('--stack_size=500');
+
+test('should work', () => {
+ const list = range(1, 3);
+ expect(list).toEqual([1, 2, 3]);
+});
+
+test('should work for large ranges', () => {
+ expect(() => range(1, 1e6)).not.toThrow();
+});
diff --git a/node_modules/semver/CHANGELOG.md b/node_modules/semver/CHANGELOG.md
new file mode 100644
index 0000000..66304fd
--- /dev/null
+++ b/node_modules/semver/CHANGELOG.md
@@ -0,0 +1,39 @@
+# changes log
+
+## 5.7
+
+* Add `minVersion` method
+
+## 5.6
+
+* Move boolean `loose` param to an options object, with
+ backwards-compatibility protection.
+* Add ability to opt out of special prerelease version handling with
+ the `includePrerelease` option flag.
+
+## 5.5
+
+* Add version coercion capabilities
+
+## 5.4
+
+* Add intersection checking
+
+## 5.3
+
+* Add `minSatisfying` method
+
+## 5.2
+
+* Add `prerelease(v)` that returns prerelease components
+
+## 5.1
+
+* Add Backus-Naur for ranges
+* Remove excessively cute inspection methods
+
+## 5.0
+
+* Remove AMD/Browserified build artifacts
+* Fix ltr and gtr when using the `*` range
+* Fix for range `*` with a prerelease identifier
diff --git a/node_modules/semver/LICENSE b/node_modules/semver/LICENSE
new file mode 100644
index 0000000..19129e3
--- /dev/null
+++ b/node_modules/semver/LICENSE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/node_modules/semver/README.md b/node_modules/semver/README.md
new file mode 100644
index 0000000..f8dfa5a
--- /dev/null
+++ b/node_modules/semver/README.md
@@ -0,0 +1,412 @@
+semver(1) -- The semantic versioner for npm
+===========================================
+
+## Install
+
+```bash
+npm install --save semver
+````
+
+## Usage
+
+As a node module:
+
+```js
+const semver = require('semver')
+
+semver.valid('1.2.3') // '1.2.3'
+semver.valid('a.b.c') // null
+semver.clean(' =v1.2.3 ') // '1.2.3'
+semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
+semver.gt('1.2.3', '9.8.7') // false
+semver.lt('1.2.3', '9.8.7') // true
+semver.minVersion('>=1.0.0') // '1.0.0'
+semver.valid(semver.coerce('v2')) // '2.0.0'
+semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'
+```
+
+As a command-line utility:
+
+```
+$ semver -h
+
+A JavaScript implementation of the https://semver.org/ specification
+Copyright Isaac Z. Schlueter
+
+Usage: semver [options] [ [...]]
+Prints valid versions sorted by SemVer precedence
+
+Options:
+-r --range
+ Print versions that match the specified range.
+
+-i --increment []
+ Increment a version by the specified level. Level can
+ be one of: major, minor, patch, premajor, preminor,
+ prepatch, or prerelease. Default level is 'patch'.
+ Only one version may be specified.
+
+--preid
+ Identifier to be used to prefix premajor, preminor,
+ prepatch or prerelease version increments.
+
+-l --loose
+ Interpret versions and ranges loosely
+
+-p --include-prerelease
+ Always include prerelease versions in range matching
+
+-c --coerce
+ Coerce a string into SemVer if possible
+ (does not imply --loose)
+
+Program exits successfully if any valid version satisfies
+all supplied ranges, and prints all satisfying versions.
+
+If no satisfying versions are found, then exits failure.
+
+Versions are printed in ascending order, so supplying
+multiple versions to the utility will just sort them.
+```
+
+## Versions
+
+A "version" is described by the `v2.0.0` specification found at
+.
+
+A leading `"="` or `"v"` character is stripped off and ignored.
+
+## Ranges
+
+A `version range` is a set of `comparators` which specify versions
+that satisfy the range.
+
+A `comparator` is composed of an `operator` and a `version`. The set
+of primitive `operators` is:
+
+* `<` Less than
+* `<=` Less than or equal to
+* `>` Greater than
+* `>=` Greater than or equal to
+* `=` Equal. If no operator is specified, then equality is assumed,
+ so this operator is optional, but MAY be included.
+
+For example, the comparator `>=1.2.7` would match the versions
+`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
+or `1.1.0`.
+
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.
+
+A range is composed of one or more comparator sets, joined by `||`. A
+version matches a range if and only if every comparator in at least
+one of the `||`-separated comparator sets is satisfied by the version.
+
+For example, the range `>=1.2.7 <1.3.0` would match the versions
+`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
+or `1.1.0`.
+
+The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
+`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
+
+### Prerelease Tags
+
+If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
+it will only be allowed to satisfy comparator sets if at least one
+comparator with the same `[major, minor, patch]` tuple also has a
+prerelease tag.
+
+For example, the range `>1.2.3-alpha.3` would be allowed to match the
+version `1.2.3-alpha.7`, but it would *not* be satisfied by
+`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
+than" `1.2.3-alpha.3` according to the SemVer sort rules. The version
+range only accepts prerelease tags on the `1.2.3` version. The
+version `3.4.5` *would* satisfy the range, because it does not have a
+prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
+
+The purpose for this behavior is twofold. First, prerelease versions
+frequently are updated very quickly, and contain many breaking changes
+that are (by the author's design) not yet fit for public consumption.
+Therefore, by default, they are excluded from range matching
+semantics.
+
+Second, a user who has opted into using a prerelease version has
+clearly indicated the intent to use *that specific* set of
+alpha/beta/rc versions. By including a prerelease tag in the range,
+the user is indicating that they are aware of the risk. However, it
+is still not appropriate to assume that they have opted into taking a
+similar risk on the *next* set of prerelease versions.
+
+Note that this behavior can be suppressed (treating all prerelease
+versions as if they were normal versions, for the purpose of range
+matching) by setting the `includePrerelease` flag on the options
+object to any
+[functions](https://github.com/npm/node-semver#functions) that do
+range matching.
+
+#### Prerelease Identifiers
+
+The method `.inc` takes an additional `identifier` string argument that
+will append the value of the string as a prerelease identifier:
+
+```javascript
+semver.inc('1.2.3', 'prerelease', 'beta')
+// '1.2.4-beta.0'
+```
+
+command-line example:
+
+```bash
+$ semver 1.2.3 -i prerelease --preid beta
+1.2.4-beta.0
+```
+
+Which then can be used to increment further:
+
+```bash
+$ semver 1.2.4-beta.0 -i prerelease
+1.2.4-beta.1
+```
+
+### Advanced Range Syntax
+
+Advanced range syntax desugars to primitive comparators in
+deterministic ways.
+
+Advanced ranges may be combined in the same way as primitive
+comparators using white space or `||`.
+
+#### Hyphen Ranges `X.Y.Z - A.B.C`
+
+Specifies an inclusive set.
+
+* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
+
+If a partial version is provided as the first version in the inclusive
+range, then the missing pieces are replaced with zeroes.
+
+* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
+
+If a partial version is provided as the second version in the
+inclusive range, then all versions that start with the supplied parts
+of the tuple are accepted, but nothing that would be greater than the
+provided tuple parts.
+
+* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
+* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
+
+#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
+
+Any of `X`, `x`, or `*` may be used to "stand in" for one of the
+numeric values in the `[major, minor, patch]` tuple.
+
+* `*` := `>=0.0.0` (Any version satisfies)
+* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
+* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
+
+A partial version range is treated as an X-Range, so the special
+character is in fact optional.
+
+* `""` (empty string) := `*` := `>=0.0.0`
+* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
+* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
+
+#### Tilde Ranges `~1.2.3` `~1.2` `~1`
+
+Allows patch-level changes if a minor version is specified on the
+comparator. Allows minor-level changes if not.
+
+* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
+* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
+* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
+* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
+* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
+* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
+* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
+ the `1.2.3` version will be allowed, if they are greater than or
+ equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
+ `1.2.4-beta.2` would not, because it is a prerelease of a
+ different `[major, minor, patch]` tuple.
+
+#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
+
+Allows changes that do not modify the left-most non-zero digit in the
+`[major, minor, patch]` tuple. In other words, this allows patch and
+minor updates for versions `1.0.0` and above, patch updates for
+versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
+
+Many authors treat a `0.x` version as if the `x` were the major
+"breaking-change" indicator.
+
+Caret ranges are ideal when an author may make breaking changes
+between `0.2.4` and `0.3.0` releases, which is a common practice.
+However, it presumes that there will *not* be breaking changes between
+`0.2.4` and `0.2.5`. It allows for changes that are presumed to be
+additive (but non-breaking), according to commonly observed practices.
+
+* `^1.2.3` := `>=1.2.3 <2.0.0`
+* `^0.2.3` := `>=0.2.3 <0.3.0`
+* `^0.0.3` := `>=0.0.3 <0.0.4`
+* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
+ the `1.2.3` version will be allowed, if they are greater than or
+ equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
+ `1.2.4-beta.2` would not, because it is a prerelease of a
+ different `[major, minor, patch]` tuple.
+* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the
+ `0.0.3` version *only* will be allowed, if they are greater than or
+ equal to `beta`. So, `0.0.3-pr.2` would be allowed.
+
+When parsing caret ranges, a missing `patch` value desugars to the
+number `0`, but will allow flexibility within that value, even if the
+major and minor versions are both `0`.
+
+* `^1.2.x` := `>=1.2.0 <2.0.0`
+* `^0.0.x` := `>=0.0.0 <0.1.0`
+* `^0.0` := `>=0.0.0 <0.1.0`
+
+A missing `minor` and `patch` values will desugar to zero, but also
+allow flexibility within those values, even if the major version is
+zero.
+
+* `^1.x` := `>=1.0.0 <2.0.0`
+* `^0.x` := `>=0.0.0 <1.0.0`
+
+### Range Grammar
+
+Putting all this together, here is a Backus-Naur grammar for ranges,
+for the benefit of parser authors:
+
+```bnf
+range-set ::= range ( logical-or range ) *
+logical-or ::= ( ' ' ) * '||' ( ' ' ) *
+range ::= hyphen | simple ( ' ' simple ) * | ''
+hyphen ::= partial ' - ' partial
+simple ::= primitive | partial | tilde | caret
+primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
+partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
+xr ::= 'x' | 'X' | '*' | nr
+nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
+tilde ::= '~' partial
+caret ::= '^' partial
+qualifier ::= ( '-' pre )? ( '+' build )?
+pre ::= parts
+build ::= parts
+parts ::= part ( '.' part ) *
+part ::= nr | [-0-9A-Za-z]+
+```
+
+## Functions
+
+All methods and classes take a final `options` object argument. All
+options in this object are `false` by default. The options supported
+are:
+
+- `loose` Be more forgiving about not-quite-valid semver strings.
+ (Any resulting output will always be 100% strict compliant, of
+ course.) For backwards compatibility reasons, if the `options`
+ argument is a boolean value instead of an object, it is interpreted
+ to be the `loose` param.
+- `includePrerelease` Set to suppress the [default
+ behavior](https://github.com/npm/node-semver#prerelease-tags) of
+ excluding prerelease tagged versions from ranges unless they are
+ explicitly opted into.
+
+Strict-mode Comparators and Ranges will be strict about the SemVer
+strings that they parse.
+
+* `valid(v)`: Return the parsed version, or null if it's not valid.
+* `inc(v, release)`: Return the version incremented by the release
+ type (`major`, `premajor`, `minor`, `preminor`, `patch`,
+ `prepatch`, or `prerelease`), or null if it's not valid
+ * `premajor` in one call will bump the version up to the next major
+ version and down to a prerelease of that major version.
+ `preminor`, and `prepatch` work the same way.
+ * If called from a non-prerelease version, the `prerelease` will work the
+ same as `prepatch`. It increments the patch version, then makes a
+ prerelease. If the input version is already a prerelease it simply
+ increments it.
+* `prerelease(v)`: Returns an array of prerelease components, or null
+ if none exist. Example: `prerelease('1.2.3-alpha.1') -> ['alpha', 1]`
+* `major(v)`: Return the major version number.
+* `minor(v)`: Return the minor version number.
+* `patch(v)`: Return the patch version number.
+* `intersects(r1, r2, loose)`: Return true if the two supplied ranges
+ or comparators intersect.
+* `parse(v)`: Attempt to parse a string as a semantic version, returning either
+ a `SemVer` object or `null`.
+
+### Comparison
+
+* `gt(v1, v2)`: `v1 > v2`
+* `gte(v1, v2)`: `v1 >= v2`
+* `lt(v1, v2)`: `v1 < v2`
+* `lte(v1, v2)`: `v1 <= v2`
+* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,
+ even if they're not the exact same string. You already know how to
+ compare strings.
+* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.
+* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call
+ the corresponding function above. `"==="` and `"!=="` do simple
+ string comparison, but are included for completeness. Throws if an
+ invalid comparison string is provided.
+* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if
+ `v2` is greater. Sorts in ascending order if passed to `Array.sort()`.
+* `rcompare(v1, v2)`: The reverse of compare. Sorts an array of versions
+ in descending order when passed to `Array.sort()`.
+* `diff(v1, v2)`: Returns difference between two versions by the release type
+ (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),
+ or null if the versions are the same.
+
+### Comparators
+
+* `intersects(comparator)`: Return true if the comparators intersect
+
+### Ranges
+
+* `validRange(range)`: Return the valid range or null if it's not valid
+* `satisfies(version, range)`: Return true if the version satisfies the
+ range.
+* `maxSatisfying(versions, range)`: Return the highest version in the list
+ that satisfies the range, or `null` if none of them do.
+* `minSatisfying(versions, range)`: Return the lowest version in the list
+ that satisfies the range, or `null` if none of them do.
+* `minVersion(range)`: Return the lowest version that can possibly match
+ the given range.
+* `gtr(version, range)`: Return `true` if version is greater than all the
+ versions possible in the range.
+* `ltr(version, range)`: Return `true` if version is less than all the
+ versions possible in the range.
+* `outside(version, range, hilo)`: Return true if the version is outside
+ the bounds of the range in either the high or low direction. The
+ `hilo` argument must be either the string `'>'` or `'<'`. (This is
+ the function called by `gtr` and `ltr`.)
+* `intersects(range)`: Return true if any of the ranges comparators intersect
+
+Note that, since ranges may be non-contiguous, a version might not be
+greater than a range, less than a range, *or* satisfy a range! For
+example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`
+until `2.0.0`, so the version `1.2.10` would not be greater than the
+range (because `2.0.1` satisfies, which is higher), nor less than the
+range (since `1.2.8` satisfies, which is lower), and it also does not
+satisfy the range.
+
+If you want to know if a version satisfies or does not satisfy a
+range, use the `satisfies(version, range)` function.
+
+### Coercion
+
+* `coerce(version)`: Coerces a string to semver if possible
+
+This aims to provide a very forgiving translation of a non-semver string to
+semver. It looks for the first digit in a string, and consumes all
+remaining characters which satisfy at least a partial semver (e.g., `1`,
+`1.2`, `1.2.3`) up to the max permitted length (256 characters). Longer
+versions are simply truncated (`4.6.3.9.2-alpha2` becomes `4.6.3`). All
+surrounding text is simply ignored (`v3.4 replaces v3.3.1` becomes
+`3.4.0`). Only text which lacks digits will fail coercion (`version one`
+is not valid). The maximum length for any semver component considered for
+coercion is 16 characters; longer components will be ignored
+(`10000000000000000.4.7.4` becomes `4.7.4`). The maximum value for any
+semver component is `Number.MAX_SAFE_INTEGER || (2**53 - 1)`; higher value
+components are invalid (`9999999999999999.4.7.4` is likely invalid).
diff --git a/node_modules/semver/bin/semver b/node_modules/semver/bin/semver
new file mode 100755
index 0000000..801e77f
--- /dev/null
+++ b/node_modules/semver/bin/semver
@@ -0,0 +1,160 @@
+#!/usr/bin/env node
+// Standalone semver comparison program.
+// Exits successfully and prints matching version(s) if
+// any supplied version is valid and passes all tests.
+
+var argv = process.argv.slice(2)
+
+var versions = []
+
+var range = []
+
+var inc = null
+
+var version = require('../package.json').version
+
+var loose = false
+
+var includePrerelease = false
+
+var coerce = false
+
+var identifier
+
+var semver = require('../semver')
+
+var reverse = false
+
+var options = {}
+
+main()
+
+function main () {
+ if (!argv.length) return help()
+ while (argv.length) {
+ var a = argv.shift()
+ var indexOfEqualSign = a.indexOf('=')
+ if (indexOfEqualSign !== -1) {
+ a = a.slice(0, indexOfEqualSign)
+ argv.unshift(a.slice(indexOfEqualSign + 1))
+ }
+ switch (a) {
+ case '-rv': case '-rev': case '--rev': case '--reverse':
+ reverse = true
+ break
+ case '-l': case '--loose':
+ loose = true
+ break
+ case '-p': case '--include-prerelease':
+ includePrerelease = true
+ break
+ case '-v': case '--version':
+ versions.push(argv.shift())
+ break
+ case '-i': case '--inc': case '--increment':
+ switch (argv[0]) {
+ case 'major': case 'minor': case 'patch': case 'prerelease':
+ case 'premajor': case 'preminor': case 'prepatch':
+ inc = argv.shift()
+ break
+ default:
+ inc = 'patch'
+ break
+ }
+ break
+ case '--preid':
+ identifier = argv.shift()
+ break
+ case '-r': case '--range':
+ range.push(argv.shift())
+ break
+ case '-c': case '--coerce':
+ coerce = true
+ break
+ case '-h': case '--help': case '-?':
+ return help()
+ default:
+ versions.push(a)
+ break
+ }
+ }
+
+ var options = { loose: loose, includePrerelease: includePrerelease }
+
+ versions = versions.map(function (v) {
+ return coerce ? (semver.coerce(v) || { version: v }).version : v
+ }).filter(function (v) {
+ return semver.valid(v)
+ })
+ if (!versions.length) return fail()
+ if (inc && (versions.length !== 1 || range.length)) { return failInc() }
+
+ for (var i = 0, l = range.length; i < l; i++) {
+ versions = versions.filter(function (v) {
+ return semver.satisfies(v, range[i], options)
+ })
+ if (!versions.length) return fail()
+ }
+ return success(versions)
+}
+
+function failInc () {
+ console.error('--inc can only be used on a single version with no range')
+ fail()
+}
+
+function fail () { process.exit(1) }
+
+function success () {
+ var compare = reverse ? 'rcompare' : 'compare'
+ versions.sort(function (a, b) {
+ return semver[compare](a, b, options)
+ }).map(function (v) {
+ return semver.clean(v, options)
+ }).map(function (v) {
+ return inc ? semver.inc(v, inc, options, identifier) : v
+ }).forEach(function (v, i, _) { console.log(v) })
+}
+
+function help () {
+ console.log(['SemVer ' + version,
+ '',
+ 'A JavaScript implementation of the https://semver.org/ specification',
+ 'Copyright Isaac Z. Schlueter',
+ '',
+ 'Usage: semver [options] [ [...]]',
+ 'Prints valid versions sorted by SemVer precedence',
+ '',
+ 'Options:',
+ '-r --range ',
+ ' Print versions that match the specified range.',
+ '',
+ '-i --increment []',
+ ' Increment a version by the specified level. Level can',
+ ' be one of: major, minor, patch, premajor, preminor,',
+ " prepatch, or prerelease. Default level is 'patch'.",
+ ' Only one version may be specified.',
+ '',
+ '--preid ',
+ ' Identifier to be used to prefix premajor, preminor,',
+ ' prepatch or prerelease version increments.',
+ '',
+ '-l --loose',
+ ' Interpret versions and ranges loosely',
+ '',
+ '-p --include-prerelease',
+ ' Always include prerelease versions in range matching',
+ '',
+ '-c --coerce',
+ ' Coerce a string into SemVer if possible',
+ ' (does not imply --loose)',
+ '',
+ 'Program exits successfully if any valid version satisfies',
+ 'all supplied ranges, and prints all satisfying versions.',
+ '',
+ 'If no satisfying versions are found, then exits failure.',
+ '',
+ 'Versions are printed in ascending order, so supplying',
+ 'multiple versions to the utility will just sort them.'
+ ].join('\n'))
+}
diff --git a/node_modules/semver/package.json b/node_modules/semver/package.json
new file mode 100644
index 0000000..058bf10
--- /dev/null
+++ b/node_modules/semver/package.json
@@ -0,0 +1,109 @@
+{
+ "_args": [
+ [
+ "semver@^5.1.0",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/require_optional"
+ ]
+ ],
+ "_from": "semver@>=5.1.0 <6.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "semver@5.7.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/semver",
+ "_nodeVersion": "12.6.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/semver_5.7.1_1565627294887_0.7867378282056998"
+ },
+ "_npmUser": {
+ "email": "i@izs.me",
+ "name": "isaacs"
+ },
+ "_npmVersion": "6.10.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "semver",
+ "raw": "semver@^5.1.0",
+ "rawSpec": "^5.1.0",
+ "scope": null,
+ "spec": ">=5.1.0 <6.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/require_optional"
+ ],
+ "_resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "_shasum": "a954f931aeba508d307bbf069eff0c01c96116f7",
+ "_shrinkwrap": null,
+ "_spec": "semver@^5.1.0",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/require_optional",
+ "bin": {
+ "semver": "./bin/semver"
+ },
+ "bugs": {
+ "url": "https://github.com/npm/node-semver/issues"
+ },
+ "dependencies": {},
+ "description": "The semantic version parser used by npm.",
+ "devDependencies": {
+ "tap": "^13.0.0-rc.18"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 7,
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdUZOfCRA9TVsSAnZWagAALOoQAIryFFr3APbQy7JtFRVQ\nZWyRM6KerD0BuRsiDj8Z+krefX6/DJ4CghE3P3dYwSyJI3irUOLblY2Je6S3\nQPnQLOdT2R0uC/mOnZ5xfu5ok88KkXwc2UQdsot+u+FCMerbv+XPHnOi2T+Q\nhYYuOP26jX74MdZJr5LrXZsBppEeypVCGEi/k5B+L0AM2EPBVzrhfl7+OjqT\nIRao2JvxOBpF6D6p1Q+x48yGcPGWH5qnSeaXFBnH7lzJD64IJPb5c5oA57AX\ndy1NFbQ1bFLZ++7RwQ4dsZlC614/58fCrasdepTQkFxKGv6Glz0TxdrsEqyE\nRPuP0on337QcRwNRB7buoVkBE1gNTc3x9yisJRNBMzfOaPiEg1rQdnN9pr8o\nOvespmkE2SbTGU5zJA3cy7O/4IAK5epBzsWuqLSnA4aOXEb1zlmVW4Q7pSAY\nYXE1G2OB/LMMCcs947/6PR78q9sa7+Hw6nqg0GV4lrJhCFVYezRVCsY7GNay\nJ/GzPB/PaffK1fzLUG1eg1USItnh2QmDnnF2fYpqIN96IgaJ4YN3mlOzLnM8\nJ+/p1cyHeGZI1gT8HVq3XOZXgsl/gtF4zTyfwx2YNnM9E8FCKttKF9AYHH9p\n9EpwbiSSMREq4B19wt0Uy88NxZDgqHcz+MVgUNREWopxOXnD5Ka1M7TIxV3z\nkEbC\r\n=hYf4\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "a954f931aeba508d307bbf069eff0c01c96116f7",
+ "tarball": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "unpackedSize": 61578
+ },
+ "gitHead": "c83c18cf84f9ccaea3431c929bb285fd168c01e4",
+ "homepage": "https://github.com/npm/node-semver#readme",
+ "license": "ISC",
+ "main": "semver.js",
+ "maintainers": [
+ {
+ "name": "adam_baldwin",
+ "email": "evilpacket@gmail.com"
+ },
+ {
+ "name": "ahmadnassri",
+ "email": "ahmad@ahmadnassri.com"
+ },
+ {
+ "name": "annekimsey",
+ "email": "anne@npmjs.com"
+ },
+ {
+ "name": "claudiahdz",
+ "email": "cghr1990@gmail.com"
+ },
+ {
+ "name": "darcyclarke",
+ "email": "darcy@darcyclarke.me"
+ },
+ {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ }
+ ],
+ "name": "semver",
+ "optionalDependencies": {},
+ "readme": "semver(1) -- The semantic versioner for npm\n===========================================\n\n## Install\n\n```bash\nnpm install --save semver\n````\n\n## Usage\n\nAs a node module:\n\n```js\nconst semver = require('semver')\n\nsemver.valid('1.2.3') // '1.2.3'\nsemver.valid('a.b.c') // null\nsemver.clean(' =v1.2.3 ') // '1.2.3'\nsemver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true\nsemver.gt('1.2.3', '9.8.7') // false\nsemver.lt('1.2.3', '9.8.7') // true\nsemver.minVersion('>=1.0.0') // '1.0.0'\nsemver.valid(semver.coerce('v2')) // '2.0.0'\nsemver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'\n```\n\nAs a command-line utility:\n\n```\n$ semver -h\n\nA JavaScript implementation of the https://semver.org/ specification\nCopyright Isaac Z. Schlueter\n\nUsage: semver [options] [ [...]]\nPrints valid versions sorted by SemVer precedence\n\nOptions:\n-r --range \n Print versions that match the specified range.\n\n-i --increment []\n Increment a version by the specified level. Level can\n be one of: major, minor, patch, premajor, preminor,\n prepatch, or prerelease. Default level is 'patch'.\n Only one version may be specified.\n\n--preid \n Identifier to be used to prefix premajor, preminor,\n prepatch or prerelease version increments.\n\n-l --loose\n Interpret versions and ranges loosely\n\n-p --include-prerelease\n Always include prerelease versions in range matching\n\n-c --coerce\n Coerce a string into SemVer if possible\n (does not imply --loose)\n\nProgram exits successfully if any valid version satisfies\nall supplied ranges, and prints all satisfying versions.\n\nIf no satisfying versions are found, then exits failure.\n\nVersions are printed in ascending order, so supplying\nmultiple versions to the utility will just sort them.\n```\n\n## Versions\n\nA \"version\" is described by the `v2.0.0` specification found at\n.\n\nA leading `\"=\"` or `\"v\"` character is stripped off and ignored.\n\n## Ranges\n\nA `version range` is a set of `comparators` which specify versions\nthat satisfy the range.\n\nA `comparator` is composed of an `operator` and a `version`. The set\nof primitive `operators` is:\n\n* `<` Less than\n* `<=` Less than or equal to\n* `>` Greater than\n* `>=` Greater than or equal to\n* `=` Equal. If no operator is specified, then equality is assumed,\n so this operator is optional, but MAY be included.\n\nFor example, the comparator `>=1.2.7` would match the versions\n`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`\nor `1.1.0`.\n\nComparators can be joined by whitespace to form a `comparator set`,\nwhich is satisfied by the **intersection** of all of the comparators\nit includes.\n\nA range is composed of one or more comparator sets, joined by `||`. A\nversion matches a range if and only if every comparator in at least\none of the `||`-separated comparator sets is satisfied by the version.\n\nFor example, the range `>=1.2.7 <1.3.0` would match the versions\n`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,\nor `1.1.0`.\n\nThe range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,\n`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.\n\n### Prerelease Tags\n\nIf a version has a prerelease tag (for example, `1.2.3-alpha.3`) then\nit will only be allowed to satisfy comparator sets if at least one\ncomparator with the same `[major, minor, patch]` tuple also has a\nprerelease tag.\n\nFor example, the range `>1.2.3-alpha.3` would be allowed to match the\nversion `1.2.3-alpha.7`, but it would *not* be satisfied by\n`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically \"greater\nthan\" `1.2.3-alpha.3` according to the SemVer sort rules. The version\nrange only accepts prerelease tags on the `1.2.3` version. The\nversion `3.4.5` *would* satisfy the range, because it does not have a\nprerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.\n\nThe purpose for this behavior is twofold. First, prerelease versions\nfrequently are updated very quickly, and contain many breaking changes\nthat are (by the author's design) not yet fit for public consumption.\nTherefore, by default, they are excluded from range matching\nsemantics.\n\nSecond, a user who has opted into using a prerelease version has\nclearly indicated the intent to use *that specific* set of\nalpha/beta/rc versions. By including a prerelease tag in the range,\nthe user is indicating that they are aware of the risk. However, it\nis still not appropriate to assume that they have opted into taking a\nsimilar risk on the *next* set of prerelease versions.\n\nNote that this behavior can be suppressed (treating all prerelease\nversions as if they were normal versions, for the purpose of range\nmatching) by setting the `includePrerelease` flag on the options\nobject to any\n[functions](https://github.com/npm/node-semver#functions) that do\nrange matching.\n\n#### Prerelease Identifiers\n\nThe method `.inc` takes an additional `identifier` string argument that\nwill append the value of the string as a prerelease identifier:\n\n```javascript\nsemver.inc('1.2.3', 'prerelease', 'beta')\n// '1.2.4-beta.0'\n```\n\ncommand-line example:\n\n```bash\n$ semver 1.2.3 -i prerelease --preid beta\n1.2.4-beta.0\n```\n\nWhich then can be used to increment further:\n\n```bash\n$ semver 1.2.4-beta.0 -i prerelease\n1.2.4-beta.1\n```\n\n### Advanced Range Syntax\n\nAdvanced range syntax desugars to primitive comparators in\ndeterministic ways.\n\nAdvanced ranges may be combined in the same way as primitive\ncomparators using white space or `||`.\n\n#### Hyphen Ranges `X.Y.Z - A.B.C`\n\nSpecifies an inclusive set.\n\n* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`\n\nIf a partial version is provided as the first version in the inclusive\nrange, then the missing pieces are replaced with zeroes.\n\n* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`\n\nIf a partial version is provided as the second version in the\ninclusive range, then all versions that start with the supplied parts\nof the tuple are accepted, but nothing that would be greater than the\nprovided tuple parts.\n\n* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`\n* `1.2.3 - 2` := `>=1.2.3 <3.0.0`\n\n#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`\n\nAny of `X`, `x`, or `*` may be used to \"stand in\" for one of the\nnumeric values in the `[major, minor, patch]` tuple.\n\n* `*` := `>=0.0.0` (Any version satisfies)\n* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)\n* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)\n\nA partial version range is treated as an X-Range, so the special\ncharacter is in fact optional.\n\n* `\"\"` (empty string) := `*` := `>=0.0.0`\n* `1` := `1.x.x` := `>=1.0.0 <2.0.0`\n* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`\n\n#### Tilde Ranges `~1.2.3` `~1.2` `~1`\n\nAllows patch-level changes if a minor version is specified on the\ncomparator. Allows minor-level changes if not.\n\n* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`\n* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)\n* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)\n* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`\n* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)\n* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)\n* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in\n the `1.2.3` version will be allowed, if they are greater than or\n equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but\n `1.2.4-beta.2` would not, because it is a prerelease of a\n different `[major, minor, patch]` tuple.\n\n#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`\n\nAllows changes that do not modify the left-most non-zero digit in the\n`[major, minor, patch]` tuple. In other words, this allows patch and\nminor updates for versions `1.0.0` and above, patch updates for\nversions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.\n\nMany authors treat a `0.x` version as if the `x` were the major\n\"breaking-change\" indicator.\n\nCaret ranges are ideal when an author may make breaking changes\nbetween `0.2.4` and `0.3.0` releases, which is a common practice.\nHowever, it presumes that there will *not* be breaking changes between\n`0.2.4` and `0.2.5`. It allows for changes that are presumed to be\nadditive (but non-breaking), according to commonly observed practices.\n\n* `^1.2.3` := `>=1.2.3 <2.0.0`\n* `^0.2.3` := `>=0.2.3 <0.3.0`\n* `^0.0.3` := `>=0.0.3 <0.0.4`\n* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in\n the `1.2.3` version will be allowed, if they are greater than or\n equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but\n `1.2.4-beta.2` would not, because it is a prerelease of a\n different `[major, minor, patch]` tuple.\n* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the\n `0.0.3` version *only* will be allowed, if they are greater than or\n equal to `beta`. So, `0.0.3-pr.2` would be allowed.\n\nWhen parsing caret ranges, a missing `patch` value desugars to the\nnumber `0`, but will allow flexibility within that value, even if the\nmajor and minor versions are both `0`.\n\n* `^1.2.x` := `>=1.2.0 <2.0.0`\n* `^0.0.x` := `>=0.0.0 <0.1.0`\n* `^0.0` := `>=0.0.0 <0.1.0`\n\nA missing `minor` and `patch` values will desugar to zero, but also\nallow flexibility within those values, even if the major version is\nzero.\n\n* `^1.x` := `>=1.0.0 <2.0.0`\n* `^0.x` := `>=0.0.0 <1.0.0`\n\n### Range Grammar\n\nPutting all this together, here is a Backus-Naur grammar for ranges,\nfor the benefit of parser authors:\n\n```bnf\nrange-set ::= range ( logical-or range ) *\nlogical-or ::= ( ' ' ) * '||' ( ' ' ) *\nrange ::= hyphen | simple ( ' ' simple ) * | ''\nhyphen ::= partial ' - ' partial\nsimple ::= primitive | partial | tilde | caret\nprimitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial\npartial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?\nxr ::= 'x' | 'X' | '*' | nr\nnr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *\ntilde ::= '~' partial\ncaret ::= '^' partial\nqualifier ::= ( '-' pre )? ( '+' build )?\npre ::= parts\nbuild ::= parts\nparts ::= part ( '.' part ) *\npart ::= nr | [-0-9A-Za-z]+\n```\n\n## Functions\n\nAll methods and classes take a final `options` object argument. All\noptions in this object are `false` by default. The options supported\nare:\n\n- `loose` Be more forgiving about not-quite-valid semver strings.\n (Any resulting output will always be 100% strict compliant, of\n course.) For backwards compatibility reasons, if the `options`\n argument is a boolean value instead of an object, it is interpreted\n to be the `loose` param.\n- `includePrerelease` Set to suppress the [default\n behavior](https://github.com/npm/node-semver#prerelease-tags) of\n excluding prerelease tagged versions from ranges unless they are\n explicitly opted into.\n\nStrict-mode Comparators and Ranges will be strict about the SemVer\nstrings that they parse.\n\n* `valid(v)`: Return the parsed version, or null if it's not valid.\n* `inc(v, release)`: Return the version incremented by the release\n type (`major`, `premajor`, `minor`, `preminor`, `patch`,\n `prepatch`, or `prerelease`), or null if it's not valid\n * `premajor` in one call will bump the version up to the next major\n version and down to a prerelease of that major version.\n `preminor`, and `prepatch` work the same way.\n * If called from a non-prerelease version, the `prerelease` will work the\n same as `prepatch`. It increments the patch version, then makes a\n prerelease. If the input version is already a prerelease it simply\n increments it.\n* `prerelease(v)`: Returns an array of prerelease components, or null\n if none exist. Example: `prerelease('1.2.3-alpha.1') -> ['alpha', 1]`\n* `major(v)`: Return the major version number.\n* `minor(v)`: Return the minor version number.\n* `patch(v)`: Return the patch version number.\n* `intersects(r1, r2, loose)`: Return true if the two supplied ranges\n or comparators intersect.\n* `parse(v)`: Attempt to parse a string as a semantic version, returning either\n a `SemVer` object or `null`.\n\n### Comparison\n\n* `gt(v1, v2)`: `v1 > v2`\n* `gte(v1, v2)`: `v1 >= v2`\n* `lt(v1, v2)`: `v1 < v2`\n* `lte(v1, v2)`: `v1 <= v2`\n* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,\n even if they're not the exact same string. You already know how to\n compare strings.\n* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.\n* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call\n the corresponding function above. `\"===\"` and `\"!==\"` do simple\n string comparison, but are included for completeness. Throws if an\n invalid comparison string is provided.\n* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if\n `v2` is greater. Sorts in ascending order if passed to `Array.sort()`.\n* `rcompare(v1, v2)`: The reverse of compare. Sorts an array of versions\n in descending order when passed to `Array.sort()`.\n* `diff(v1, v2)`: Returns difference between two versions by the release type\n (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),\n or null if the versions are the same.\n\n### Comparators\n\n* `intersects(comparator)`: Return true if the comparators intersect\n\n### Ranges\n\n* `validRange(range)`: Return the valid range or null if it's not valid\n* `satisfies(version, range)`: Return true if the version satisfies the\n range.\n* `maxSatisfying(versions, range)`: Return the highest version in the list\n that satisfies the range, or `null` if none of them do.\n* `minSatisfying(versions, range)`: Return the lowest version in the list\n that satisfies the range, or `null` if none of them do.\n* `minVersion(range)`: Return the lowest version that can possibly match\n the given range.\n* `gtr(version, range)`: Return `true` if version is greater than all the\n versions possible in the range.\n* `ltr(version, range)`: Return `true` if version is less than all the\n versions possible in the range.\n* `outside(version, range, hilo)`: Return true if the version is outside\n the bounds of the range in either the high or low direction. The\n `hilo` argument must be either the string `'>'` or `'<'`. (This is\n the function called by `gtr` and `ltr`.)\n* `intersects(range)`: Return true if any of the ranges comparators intersect\n\nNote that, since ranges may be non-contiguous, a version might not be\ngreater than a range, less than a range, *or* satisfy a range! For\nexample, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`\nuntil `2.0.0`, so the version `1.2.10` would not be greater than the\nrange (because `2.0.1` satisfies, which is higher), nor less than the\nrange (since `1.2.8` satisfies, which is lower), and it also does not\nsatisfy the range.\n\nIf you want to know if a version satisfies or does not satisfy a\nrange, use the `satisfies(version, range)` function.\n\n### Coercion\n\n* `coerce(version)`: Coerces a string to semver if possible\n\nThis aims to provide a very forgiving translation of a non-semver string to\nsemver. It looks for the first digit in a string, and consumes all\nremaining characters which satisfy at least a partial semver (e.g., `1`,\n`1.2`, `1.2.3`) up to the max permitted length (256 characters). Longer\nversions are simply truncated (`4.6.3.9.2-alpha2` becomes `4.6.3`). All\nsurrounding text is simply ignored (`v3.4 replaces v3.3.1` becomes\n`3.4.0`). Only text which lacks digits will fail coercion (`version one`\nis not valid). The maximum length for any semver component considered for\ncoercion is 16 characters; longer components will be ignored\n(`10000000000000000.4.7.4` becomes `4.7.4`). The maximum value for any\nsemver component is `Number.MAX_SAFE_INTEGER || (2**53 - 1)`; higher value\ncomponents are invalid (`9999999999999999.4.7.4` is likely invalid).\n",
+ "readmeFilename": "README.md",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/npm/node-semver.git"
+ },
+ "scripts": {
+ "postpublish": "git push origin --all; git push origin --tags",
+ "postversion": "npm publish",
+ "preversion": "npm test",
+ "test": "tap"
+ },
+ "tap": {
+ "check-coverage": true
+ },
+ "version": "5.7.1"
+}
diff --git a/node_modules/semver/range.bnf b/node_modules/semver/range.bnf
new file mode 100644
index 0000000..d4c6ae0
--- /dev/null
+++ b/node_modules/semver/range.bnf
@@ -0,0 +1,16 @@
+range-set ::= range ( logical-or range ) *
+logical-or ::= ( ' ' ) * '||' ( ' ' ) *
+range ::= hyphen | simple ( ' ' simple ) * | ''
+hyphen ::= partial ' - ' partial
+simple ::= primitive | partial | tilde | caret
+primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
+partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
+xr ::= 'x' | 'X' | '*' | nr
+nr ::= '0' | [1-9] ( [0-9] ) *
+tilde ::= '~' partial
+caret ::= '^' partial
+qualifier ::= ( '-' pre )? ( '+' build )?
+pre ::= parts
+build ::= parts
+parts ::= part ( '.' part ) *
+part ::= nr | [-0-9A-Za-z]+
diff --git a/node_modules/semver/semver.js b/node_modules/semver/semver.js
new file mode 100644
index 0000000..d315d5d
--- /dev/null
+++ b/node_modules/semver/semver.js
@@ -0,0 +1,1483 @@
+exports = module.exports = SemVer
+
+var debug
+/* istanbul ignore next */
+if (typeof process === 'object' &&
+ process.env &&
+ process.env.NODE_DEBUG &&
+ /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
+ debug = function () {
+ var args = Array.prototype.slice.call(arguments, 0)
+ args.unshift('SEMVER')
+ console.log.apply(console, args)
+ }
+} else {
+ debug = function () {}
+}
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0'
+
+var MAX_LENGTH = 256
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
+ /* istanbul ignore next */ 9007199254740991
+
+// Max safe segment length for coercion.
+var MAX_SAFE_COMPONENT_LENGTH = 16
+
+// The actual regexps go on exports.re
+var re = exports.re = []
+var src = exports.src = []
+var R = 0
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+var NUMERICIDENTIFIER = R++
+src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'
+var NUMERICIDENTIFIERLOOSE = R++
+src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+var NONNUMERICIDENTIFIER = R++
+src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+var MAINVERSION = R++
+src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+ '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+ '(' + src[NUMERICIDENTIFIER] + ')'
+
+var MAINVERSIONLOOSE = R++
+src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+ '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+ '(' + src[NUMERICIDENTIFIERLOOSE] + ')'
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+var PRERELEASEIDENTIFIER = R++
+src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
+ '|' + src[NONNUMERICIDENTIFIER] + ')'
+
+var PRERELEASEIDENTIFIERLOOSE = R++
+src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
+ '|' + src[NONNUMERICIDENTIFIER] + ')'
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+var PRERELEASE = R++
+src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
+ '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'
+
+var PRERELEASELOOSE = R++
+src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
+ '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+var BUILDIDENTIFIER = R++
+src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+var BUILD = R++
+src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
+ '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups. The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+var FULL = R++
+var FULLPLAIN = 'v?' + src[MAINVERSION] +
+ src[PRERELEASE] + '?' +
+ src[BUILD] + '?'
+
+src[FULL] = '^' + FULLPLAIN + '$'
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
+ src[PRERELEASELOOSE] + '?' +
+ src[BUILD] + '?'
+
+var LOOSE = R++
+src[LOOSE] = '^' + LOOSEPLAIN + '$'
+
+var GTLT = R++
+src[GTLT] = '((?:<|>)?=?)'
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+var XRANGEIDENTIFIERLOOSE = R++
+src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
+var XRANGEIDENTIFIER = R++
+src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'
+
+var XRANGEPLAIN = R++
+src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
+ '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+ '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+ '(?:' + src[PRERELEASE] + ')?' +
+ src[BUILD] + '?' +
+ ')?)?'
+
+var XRANGEPLAINLOOSE = R++
+src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+ '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+ '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+ '(?:' + src[PRERELEASELOOSE] + ')?' +
+ src[BUILD] + '?' +
+ ')?)?'
+
+var XRANGE = R++
+src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'
+var XRANGELOOSE = R++
+src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'
+
+// Coercion.
+// Extract anything that could conceivably be a part of a valid semver
+var COERCE = R++
+src[COERCE] = '(?:^|[^\\d])' +
+ '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' +
+ '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
+ '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
+ '(?:$|[^\\d])'
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+var LONETILDE = R++
+src[LONETILDE] = '(?:~>?)'
+
+var TILDETRIM = R++
+src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'
+re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g')
+var tildeTrimReplace = '$1~'
+
+var TILDE = R++
+src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'
+var TILDELOOSE = R++
+src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+var LONECARET = R++
+src[LONECARET] = '(?:\\^)'
+
+var CARETTRIM = R++
+src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'
+re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g')
+var caretTrimReplace = '$1^'
+
+var CARET = R++
+src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'
+var CARETLOOSE = R++
+src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+var COMPARATORLOOSE = R++
+src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'
+var COMPARATOR = R++
+src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+var COMPARATORTRIM = R++
+src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
+ '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'
+
+// this one has to use the /g flag
+re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g')
+var comparatorTrimReplace = '$1$2$3'
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+var HYPHENRANGE = R++
+src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
+ '\\s+-\\s+' +
+ '(' + src[XRANGEPLAIN] + ')' +
+ '\\s*$'
+
+var HYPHENRANGELOOSE = R++
+src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
+ '\\s+-\\s+' +
+ '(' + src[XRANGEPLAINLOOSE] + ')' +
+ '\\s*$'
+
+// Star ranges basically just allow anything at all.
+var STAR = R++
+src[STAR] = '(<|>)?=?\\s*\\*'
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+ debug(i, src[i])
+ if (!re[i]) {
+ re[i] = new RegExp(src[i])
+ }
+}
+
+exports.parse = parse
+function parse (version, options) {
+ if (!options || typeof options !== 'object') {
+ options = {
+ loose: !!options,
+ includePrerelease: false
+ }
+ }
+
+ if (version instanceof SemVer) {
+ return version
+ }
+
+ if (typeof version !== 'string') {
+ return null
+ }
+
+ if (version.length > MAX_LENGTH) {
+ return null
+ }
+
+ var r = options.loose ? re[LOOSE] : re[FULL]
+ if (!r.test(version)) {
+ return null
+ }
+
+ try {
+ return new SemVer(version, options)
+ } catch (er) {
+ return null
+ }
+}
+
+exports.valid = valid
+function valid (version, options) {
+ var v = parse(version, options)
+ return v ? v.version : null
+}
+
+exports.clean = clean
+function clean (version, options) {
+ var s = parse(version.trim().replace(/^[=v]+/, ''), options)
+ return s ? s.version : null
+}
+
+exports.SemVer = SemVer
+
+function SemVer (version, options) {
+ if (!options || typeof options !== 'object') {
+ options = {
+ loose: !!options,
+ includePrerelease: false
+ }
+ }
+ if (version instanceof SemVer) {
+ if (version.loose === options.loose) {
+ return version
+ } else {
+ version = version.version
+ }
+ } else if (typeof version !== 'string') {
+ throw new TypeError('Invalid Version: ' + version)
+ }
+
+ if (version.length > MAX_LENGTH) {
+ throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+ }
+
+ if (!(this instanceof SemVer)) {
+ return new SemVer(version, options)
+ }
+
+ debug('SemVer', version, options)
+ this.options = options
+ this.loose = !!options.loose
+
+ var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL])
+
+ if (!m) {
+ throw new TypeError('Invalid Version: ' + version)
+ }
+
+ this.raw = version
+
+ // these are actually numbers
+ this.major = +m[1]
+ this.minor = +m[2]
+ this.patch = +m[3]
+
+ if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
+ throw new TypeError('Invalid major version')
+ }
+
+ if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
+ throw new TypeError('Invalid minor version')
+ }
+
+ if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
+ throw new TypeError('Invalid patch version')
+ }
+
+ // numberify any prerelease numeric ids
+ if (!m[4]) {
+ this.prerelease = []
+ } else {
+ this.prerelease = m[4].split('.').map(function (id) {
+ if (/^[0-9]+$/.test(id)) {
+ var num = +id
+ if (num >= 0 && num < MAX_SAFE_INTEGER) {
+ return num
+ }
+ }
+ return id
+ })
+ }
+
+ this.build = m[5] ? m[5].split('.') : []
+ this.format()
+}
+
+SemVer.prototype.format = function () {
+ this.version = this.major + '.' + this.minor + '.' + this.patch
+ if (this.prerelease.length) {
+ this.version += '-' + this.prerelease.join('.')
+ }
+ return this.version
+}
+
+SemVer.prototype.toString = function () {
+ return this.version
+}
+
+SemVer.prototype.compare = function (other) {
+ debug('SemVer.compare', this.version, this.options, other)
+ if (!(other instanceof SemVer)) {
+ other = new SemVer(other, this.options)
+ }
+
+ return this.compareMain(other) || this.comparePre(other)
+}
+
+SemVer.prototype.compareMain = function (other) {
+ if (!(other instanceof SemVer)) {
+ other = new SemVer(other, this.options)
+ }
+
+ return compareIdentifiers(this.major, other.major) ||
+ compareIdentifiers(this.minor, other.minor) ||
+ compareIdentifiers(this.patch, other.patch)
+}
+
+SemVer.prototype.comparePre = function (other) {
+ if (!(other instanceof SemVer)) {
+ other = new SemVer(other, this.options)
+ }
+
+ // NOT having a prerelease is > having one
+ if (this.prerelease.length && !other.prerelease.length) {
+ return -1
+ } else if (!this.prerelease.length && other.prerelease.length) {
+ return 1
+ } else if (!this.prerelease.length && !other.prerelease.length) {
+ return 0
+ }
+
+ var i = 0
+ do {
+ var a = this.prerelease[i]
+ var b = other.prerelease[i]
+ debug('prerelease compare', i, a, b)
+ if (a === undefined && b === undefined) {
+ return 0
+ } else if (b === undefined) {
+ return 1
+ } else if (a === undefined) {
+ return -1
+ } else if (a === b) {
+ continue
+ } else {
+ return compareIdentifiers(a, b)
+ }
+ } while (++i)
+}
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function (release, identifier) {
+ switch (release) {
+ case 'premajor':
+ this.prerelease.length = 0
+ this.patch = 0
+ this.minor = 0
+ this.major++
+ this.inc('pre', identifier)
+ break
+ case 'preminor':
+ this.prerelease.length = 0
+ this.patch = 0
+ this.minor++
+ this.inc('pre', identifier)
+ break
+ case 'prepatch':
+ // If this is already a prerelease, it will bump to the next version
+ // drop any prereleases that might already exist, since they are not
+ // relevant at this point.
+ this.prerelease.length = 0
+ this.inc('patch', identifier)
+ this.inc('pre', identifier)
+ break
+ // If the input is a non-prerelease version, this acts the same as
+ // prepatch.
+ case 'prerelease':
+ if (this.prerelease.length === 0) {
+ this.inc('patch', identifier)
+ }
+ this.inc('pre', identifier)
+ break
+
+ case 'major':
+ // If this is a pre-major version, bump up to the same major version.
+ // Otherwise increment major.
+ // 1.0.0-5 bumps to 1.0.0
+ // 1.1.0 bumps to 2.0.0
+ if (this.minor !== 0 ||
+ this.patch !== 0 ||
+ this.prerelease.length === 0) {
+ this.major++
+ }
+ this.minor = 0
+ this.patch = 0
+ this.prerelease = []
+ break
+ case 'minor':
+ // If this is a pre-minor version, bump up to the same minor version.
+ // Otherwise increment minor.
+ // 1.2.0-5 bumps to 1.2.0
+ // 1.2.1 bumps to 1.3.0
+ if (this.patch !== 0 || this.prerelease.length === 0) {
+ this.minor++
+ }
+ this.patch = 0
+ this.prerelease = []
+ break
+ case 'patch':
+ // If this is not a pre-release version, it will increment the patch.
+ // If it is a pre-release it will bump up to the same patch version.
+ // 1.2.0-5 patches to 1.2.0
+ // 1.2.0 patches to 1.2.1
+ if (this.prerelease.length === 0) {
+ this.patch++
+ }
+ this.prerelease = []
+ break
+ // This probably shouldn't be used publicly.
+ // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+ case 'pre':
+ if (this.prerelease.length === 0) {
+ this.prerelease = [0]
+ } else {
+ var i = this.prerelease.length
+ while (--i >= 0) {
+ if (typeof this.prerelease[i] === 'number') {
+ this.prerelease[i]++
+ i = -2
+ }
+ }
+ if (i === -1) {
+ // didn't increment anything
+ this.prerelease.push(0)
+ }
+ }
+ if (identifier) {
+ // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+ // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+ if (this.prerelease[0] === identifier) {
+ if (isNaN(this.prerelease[1])) {
+ this.prerelease = [identifier, 0]
+ }
+ } else {
+ this.prerelease = [identifier, 0]
+ }
+ }
+ break
+
+ default:
+ throw new Error('invalid increment argument: ' + release)
+ }
+ this.format()
+ this.raw = this.version
+ return this
+}
+
+exports.inc = inc
+function inc (version, release, loose, identifier) {
+ if (typeof (loose) === 'string') {
+ identifier = loose
+ loose = undefined
+ }
+
+ try {
+ return new SemVer(version, loose).inc(release, identifier).version
+ } catch (er) {
+ return null
+ }
+}
+
+exports.diff = diff
+function diff (version1, version2) {
+ if (eq(version1, version2)) {
+ return null
+ } else {
+ var v1 = parse(version1)
+ var v2 = parse(version2)
+ var prefix = ''
+ if (v1.prerelease.length || v2.prerelease.length) {
+ prefix = 'pre'
+ var defaultResult = 'prerelease'
+ }
+ for (var key in v1) {
+ if (key === 'major' || key === 'minor' || key === 'patch') {
+ if (v1[key] !== v2[key]) {
+ return prefix + key
+ }
+ }
+ }
+ return defaultResult // may be undefined
+ }
+}
+
+exports.compareIdentifiers = compareIdentifiers
+
+var numeric = /^[0-9]+$/
+function compareIdentifiers (a, b) {
+ var anum = numeric.test(a)
+ var bnum = numeric.test(b)
+
+ if (anum && bnum) {
+ a = +a
+ b = +b
+ }
+
+ return a === b ? 0
+ : (anum && !bnum) ? -1
+ : (bnum && !anum) ? 1
+ : a < b ? -1
+ : 1
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers
+function rcompareIdentifiers (a, b) {
+ return compareIdentifiers(b, a)
+}
+
+exports.major = major
+function major (a, loose) {
+ return new SemVer(a, loose).major
+}
+
+exports.minor = minor
+function minor (a, loose) {
+ return new SemVer(a, loose).minor
+}
+
+exports.patch = patch
+function patch (a, loose) {
+ return new SemVer(a, loose).patch
+}
+
+exports.compare = compare
+function compare (a, b, loose) {
+ return new SemVer(a, loose).compare(new SemVer(b, loose))
+}
+
+exports.compareLoose = compareLoose
+function compareLoose (a, b) {
+ return compare(a, b, true)
+}
+
+exports.rcompare = rcompare
+function rcompare (a, b, loose) {
+ return compare(b, a, loose)
+}
+
+exports.sort = sort
+function sort (list, loose) {
+ return list.sort(function (a, b) {
+ return exports.compare(a, b, loose)
+ })
+}
+
+exports.rsort = rsort
+function rsort (list, loose) {
+ return list.sort(function (a, b) {
+ return exports.rcompare(a, b, loose)
+ })
+}
+
+exports.gt = gt
+function gt (a, b, loose) {
+ return compare(a, b, loose) > 0
+}
+
+exports.lt = lt
+function lt (a, b, loose) {
+ return compare(a, b, loose) < 0
+}
+
+exports.eq = eq
+function eq (a, b, loose) {
+ return compare(a, b, loose) === 0
+}
+
+exports.neq = neq
+function neq (a, b, loose) {
+ return compare(a, b, loose) !== 0
+}
+
+exports.gte = gte
+function gte (a, b, loose) {
+ return compare(a, b, loose) >= 0
+}
+
+exports.lte = lte
+function lte (a, b, loose) {
+ return compare(a, b, loose) <= 0
+}
+
+exports.cmp = cmp
+function cmp (a, op, b, loose) {
+ switch (op) {
+ case '===':
+ if (typeof a === 'object')
+ a = a.version
+ if (typeof b === 'object')
+ b = b.version
+ return a === b
+
+ case '!==':
+ if (typeof a === 'object')
+ a = a.version
+ if (typeof b === 'object')
+ b = b.version
+ return a !== b
+
+ case '':
+ case '=':
+ case '==':
+ return eq(a, b, loose)
+
+ case '!=':
+ return neq(a, b, loose)
+
+ case '>':
+ return gt(a, b, loose)
+
+ case '>=':
+ return gte(a, b, loose)
+
+ case '<':
+ return lt(a, b, loose)
+
+ case '<=':
+ return lte(a, b, loose)
+
+ default:
+ throw new TypeError('Invalid operator: ' + op)
+ }
+}
+
+exports.Comparator = Comparator
+function Comparator (comp, options) {
+ if (!options || typeof options !== 'object') {
+ options = {
+ loose: !!options,
+ includePrerelease: false
+ }
+ }
+
+ if (comp instanceof Comparator) {
+ if (comp.loose === !!options.loose) {
+ return comp
+ } else {
+ comp = comp.value
+ }
+ }
+
+ if (!(this instanceof Comparator)) {
+ return new Comparator(comp, options)
+ }
+
+ debug('comparator', comp, options)
+ this.options = options
+ this.loose = !!options.loose
+ this.parse(comp)
+
+ if (this.semver === ANY) {
+ this.value = ''
+ } else {
+ this.value = this.operator + this.semver.version
+ }
+
+ debug('comp', this)
+}
+
+var ANY = {}
+Comparator.prototype.parse = function (comp) {
+ var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
+ var m = comp.match(r)
+
+ if (!m) {
+ throw new TypeError('Invalid comparator: ' + comp)
+ }
+
+ this.operator = m[1]
+ if (this.operator === '=') {
+ this.operator = ''
+ }
+
+ // if it literally is just '>' or '' then allow anything.
+ if (!m[2]) {
+ this.semver = ANY
+ } else {
+ this.semver = new SemVer(m[2], this.options.loose)
+ }
+}
+
+Comparator.prototype.toString = function () {
+ return this.value
+}
+
+Comparator.prototype.test = function (version) {
+ debug('Comparator.test', version, this.options.loose)
+
+ if (this.semver === ANY) {
+ return true
+ }
+
+ if (typeof version === 'string') {
+ version = new SemVer(version, this.options)
+ }
+
+ return cmp(version, this.operator, this.semver, this.options)
+}
+
+Comparator.prototype.intersects = function (comp, options) {
+ if (!(comp instanceof Comparator)) {
+ throw new TypeError('a Comparator is required')
+ }
+
+ if (!options || typeof options !== 'object') {
+ options = {
+ loose: !!options,
+ includePrerelease: false
+ }
+ }
+
+ var rangeTmp
+
+ if (this.operator === '') {
+ rangeTmp = new Range(comp.value, options)
+ return satisfies(this.value, rangeTmp, options)
+ } else if (comp.operator === '') {
+ rangeTmp = new Range(this.value, options)
+ return satisfies(comp.semver, rangeTmp, options)
+ }
+
+ var sameDirectionIncreasing =
+ (this.operator === '>=' || this.operator === '>') &&
+ (comp.operator === '>=' || comp.operator === '>')
+ var sameDirectionDecreasing =
+ (this.operator === '<=' || this.operator === '<') &&
+ (comp.operator === '<=' || comp.operator === '<')
+ var sameSemVer = this.semver.version === comp.semver.version
+ var differentDirectionsInclusive =
+ (this.operator === '>=' || this.operator === '<=') &&
+ (comp.operator === '>=' || comp.operator === '<=')
+ var oppositeDirectionsLessThan =
+ cmp(this.semver, '<', comp.semver, options) &&
+ ((this.operator === '>=' || this.operator === '>') &&
+ (comp.operator === '<=' || comp.operator === '<'))
+ var oppositeDirectionsGreaterThan =
+ cmp(this.semver, '>', comp.semver, options) &&
+ ((this.operator === '<=' || this.operator === '<') &&
+ (comp.operator === '>=' || comp.operator === '>'))
+
+ return sameDirectionIncreasing || sameDirectionDecreasing ||
+ (sameSemVer && differentDirectionsInclusive) ||
+ oppositeDirectionsLessThan || oppositeDirectionsGreaterThan
+}
+
+exports.Range = Range
+function Range (range, options) {
+ if (!options || typeof options !== 'object') {
+ options = {
+ loose: !!options,
+ includePrerelease: false
+ }
+ }
+
+ if (range instanceof Range) {
+ if (range.loose === !!options.loose &&
+ range.includePrerelease === !!options.includePrerelease) {
+ return range
+ } else {
+ return new Range(range.raw, options)
+ }
+ }
+
+ if (range instanceof Comparator) {
+ return new Range(range.value, options)
+ }
+
+ if (!(this instanceof Range)) {
+ return new Range(range, options)
+ }
+
+ this.options = options
+ this.loose = !!options.loose
+ this.includePrerelease = !!options.includePrerelease
+
+ // First, split based on boolean or ||
+ this.raw = range
+ this.set = range.split(/\s*\|\|\s*/).map(function (range) {
+ return this.parseRange(range.trim())
+ }, this).filter(function (c) {
+ // throw out any that are not relevant for whatever reason
+ return c.length
+ })
+
+ if (!this.set.length) {
+ throw new TypeError('Invalid SemVer Range: ' + range)
+ }
+
+ this.format()
+}
+
+Range.prototype.format = function () {
+ this.range = this.set.map(function (comps) {
+ return comps.join(' ').trim()
+ }).join('||').trim()
+ return this.range
+}
+
+Range.prototype.toString = function () {
+ return this.range
+}
+
+Range.prototype.parseRange = function (range) {
+ var loose = this.options.loose
+ range = range.trim()
+ // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+ var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]
+ range = range.replace(hr, hyphenReplace)
+ debug('hyphen replace', range)
+ // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+ range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace)
+ debug('comparator trim', range, re[COMPARATORTRIM])
+
+ // `~ 1.2.3` => `~1.2.3`
+ range = range.replace(re[TILDETRIM], tildeTrimReplace)
+
+ // `^ 1.2.3` => `^1.2.3`
+ range = range.replace(re[CARETTRIM], caretTrimReplace)
+
+ // normalize spaces
+ range = range.split(/\s+/).join(' ')
+
+ // At this point, the range is completely trimmed and
+ // ready to be split into comparators.
+
+ var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
+ var set = range.split(' ').map(function (comp) {
+ return parseComparator(comp, this.options)
+ }, this).join(' ').split(/\s+/)
+ if (this.options.loose) {
+ // in loose mode, throw out any that are not valid comparators
+ set = set.filter(function (comp) {
+ return !!comp.match(compRe)
+ })
+ }
+ set = set.map(function (comp) {
+ return new Comparator(comp, this.options)
+ }, this)
+
+ return set
+}
+
+Range.prototype.intersects = function (range, options) {
+ if (!(range instanceof Range)) {
+ throw new TypeError('a Range is required')
+ }
+
+ return this.set.some(function (thisComparators) {
+ return thisComparators.every(function (thisComparator) {
+ return range.set.some(function (rangeComparators) {
+ return rangeComparators.every(function (rangeComparator) {
+ return thisComparator.intersects(rangeComparator, options)
+ })
+ })
+ })
+ })
+}
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators
+function toComparators (range, options) {
+ return new Range(range, options).set.map(function (comp) {
+ return comp.map(function (c) {
+ return c.value
+ }).join(' ').trim().split(' ')
+ })
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator (comp, options) {
+ debug('comp', comp, options)
+ comp = replaceCarets(comp, options)
+ debug('caret', comp)
+ comp = replaceTildes(comp, options)
+ debug('tildes', comp)
+ comp = replaceXRanges(comp, options)
+ debug('xrange', comp)
+ comp = replaceStars(comp, options)
+ debug('stars', comp)
+ return comp
+}
+
+function isX (id) {
+ return !id || id.toLowerCase() === 'x' || id === '*'
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes (comp, options) {
+ return comp.trim().split(/\s+/).map(function (comp) {
+ return replaceTilde(comp, options)
+ }).join(' ')
+}
+
+function replaceTilde (comp, options) {
+ var r = options.loose ? re[TILDELOOSE] : re[TILDE]
+ return comp.replace(r, function (_, M, m, p, pr) {
+ debug('tilde', comp, _, M, m, p, pr)
+ var ret
+
+ if (isX(M)) {
+ ret = ''
+ } else if (isX(m)) {
+ ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
+ } else if (isX(p)) {
+ // ~1.2 == >=1.2.0 <1.3.0
+ ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
+ } else if (pr) {
+ debug('replaceTilde pr', pr)
+ ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+ ' <' + M + '.' + (+m + 1) + '.0'
+ } else {
+ // ~1.2.3 == >=1.2.3 <1.3.0
+ ret = '>=' + M + '.' + m + '.' + p +
+ ' <' + M + '.' + (+m + 1) + '.0'
+ }
+
+ debug('tilde return', ret)
+ return ret
+ })
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets (comp, options) {
+ return comp.trim().split(/\s+/).map(function (comp) {
+ return replaceCaret(comp, options)
+ }).join(' ')
+}
+
+function replaceCaret (comp, options) {
+ debug('caret', comp, options)
+ var r = options.loose ? re[CARETLOOSE] : re[CARET]
+ return comp.replace(r, function (_, M, m, p, pr) {
+ debug('caret', comp, _, M, m, p, pr)
+ var ret
+
+ if (isX(M)) {
+ ret = ''
+ } else if (isX(m)) {
+ ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
+ } else if (isX(p)) {
+ if (M === '0') {
+ ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
+ } else {
+ ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
+ }
+ } else if (pr) {
+ debug('replaceCaret pr', pr)
+ if (M === '0') {
+ if (m === '0') {
+ ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+ ' <' + M + '.' + m + '.' + (+p + 1)
+ } else {
+ ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+ ' <' + M + '.' + (+m + 1) + '.0'
+ }
+ } else {
+ ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
+ ' <' + (+M + 1) + '.0.0'
+ }
+ } else {
+ debug('no pr')
+ if (M === '0') {
+ if (m === '0') {
+ ret = '>=' + M + '.' + m + '.' + p +
+ ' <' + M + '.' + m + '.' + (+p + 1)
+ } else {
+ ret = '>=' + M + '.' + m + '.' + p +
+ ' <' + M + '.' + (+m + 1) + '.0'
+ }
+ } else {
+ ret = '>=' + M + '.' + m + '.' + p +
+ ' <' + (+M + 1) + '.0.0'
+ }
+ }
+
+ debug('caret return', ret)
+ return ret
+ })
+}
+
+function replaceXRanges (comp, options) {
+ debug('replaceXRanges', comp, options)
+ return comp.split(/\s+/).map(function (comp) {
+ return replaceXRange(comp, options)
+ }).join(' ')
+}
+
+function replaceXRange (comp, options) {
+ comp = comp.trim()
+ var r = options.loose ? re[XRANGELOOSE] : re[XRANGE]
+ return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
+ debug('xRange', comp, ret, gtlt, M, m, p, pr)
+ var xM = isX(M)
+ var xm = xM || isX(m)
+ var xp = xm || isX(p)
+ var anyX = xp
+
+ if (gtlt === '=' && anyX) {
+ gtlt = ''
+ }
+
+ if (xM) {
+ if (gtlt === '>' || gtlt === '<') {
+ // nothing is allowed
+ ret = '<0.0.0'
+ } else {
+ // nothing is forbidden
+ ret = '*'
+ }
+ } else if (gtlt && anyX) {
+ // we know patch is an x, because we have any x at all.
+ // replace X with 0
+ if (xm) {
+ m = 0
+ }
+ p = 0
+
+ if (gtlt === '>') {
+ // >1 => >=2.0.0
+ // >1.2 => >=1.3.0
+ // >1.2.3 => >= 1.2.4
+ gtlt = '>='
+ if (xm) {
+ M = +M + 1
+ m = 0
+ p = 0
+ } else {
+ m = +m + 1
+ p = 0
+ }
+ } else if (gtlt === '<=') {
+ // <=0.7.x is actually <0.8.0, since any 0.7.x should
+ // pass. Similarly, <=7.x is actually <8.0.0, etc.
+ gtlt = '<'
+ if (xm) {
+ M = +M + 1
+ } else {
+ m = +m + 1
+ }
+ }
+
+ ret = gtlt + M + '.' + m + '.' + p
+ } else if (xm) {
+ ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
+ } else if (xp) {
+ ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
+ }
+
+ debug('xRange return', ret)
+
+ return ret
+ })
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars (comp, options) {
+ debug('replaceStars', comp, options)
+ // Looseness is ignored here. star is always as loose as it gets!
+ return comp.trim().replace(re[STAR], '')
+}
+
+// This function is passed to string.replace(re[HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace ($0,
+ from, fM, fm, fp, fpr, fb,
+ to, tM, tm, tp, tpr, tb) {
+ if (isX(fM)) {
+ from = ''
+ } else if (isX(fm)) {
+ from = '>=' + fM + '.0.0'
+ } else if (isX(fp)) {
+ from = '>=' + fM + '.' + fm + '.0'
+ } else {
+ from = '>=' + from
+ }
+
+ if (isX(tM)) {
+ to = ''
+ } else if (isX(tm)) {
+ to = '<' + (+tM + 1) + '.0.0'
+ } else if (isX(tp)) {
+ to = '<' + tM + '.' + (+tm + 1) + '.0'
+ } else if (tpr) {
+ to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
+ } else {
+ to = '<=' + to
+ }
+
+ return (from + ' ' + to).trim()
+}
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function (version) {
+ if (!version) {
+ return false
+ }
+
+ if (typeof version === 'string') {
+ version = new SemVer(version, this.options)
+ }
+
+ for (var i = 0; i < this.set.length; i++) {
+ if (testSet(this.set[i], version, this.options)) {
+ return true
+ }
+ }
+ return false
+}
+
+function testSet (set, version, options) {
+ for (var i = 0; i < set.length; i++) {
+ if (!set[i].test(version)) {
+ return false
+ }
+ }
+
+ if (version.prerelease.length && !options.includePrerelease) {
+ // Find the set of versions that are allowed to have prereleases
+ // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+ // That should allow `1.2.3-pr.2` to pass.
+ // However, `1.2.4-alpha.notready` should NOT be allowed,
+ // even though it's within the range set by the comparators.
+ for (i = 0; i < set.length; i++) {
+ debug(set[i].semver)
+ if (set[i].semver === ANY) {
+ continue
+ }
+
+ if (set[i].semver.prerelease.length > 0) {
+ var allowed = set[i].semver
+ if (allowed.major === version.major &&
+ allowed.minor === version.minor &&
+ allowed.patch === version.patch) {
+ return true
+ }
+ }
+ }
+
+ // Version has a -pre, but it's not one of the ones we like.
+ return false
+ }
+
+ return true
+}
+
+exports.satisfies = satisfies
+function satisfies (version, range, options) {
+ try {
+ range = new Range(range, options)
+ } catch (er) {
+ return false
+ }
+ return range.test(version)
+}
+
+exports.maxSatisfying = maxSatisfying
+function maxSatisfying (versions, range, options) {
+ var max = null
+ var maxSV = null
+ try {
+ var rangeObj = new Range(range, options)
+ } catch (er) {
+ return null
+ }
+ versions.forEach(function (v) {
+ if (rangeObj.test(v)) {
+ // satisfies(v, range, options)
+ if (!max || maxSV.compare(v) === -1) {
+ // compare(max, v, true)
+ max = v
+ maxSV = new SemVer(max, options)
+ }
+ }
+ })
+ return max
+}
+
+exports.minSatisfying = minSatisfying
+function minSatisfying (versions, range, options) {
+ var min = null
+ var minSV = null
+ try {
+ var rangeObj = new Range(range, options)
+ } catch (er) {
+ return null
+ }
+ versions.forEach(function (v) {
+ if (rangeObj.test(v)) {
+ // satisfies(v, range, options)
+ if (!min || minSV.compare(v) === 1) {
+ // compare(min, v, true)
+ min = v
+ minSV = new SemVer(min, options)
+ }
+ }
+ })
+ return min
+}
+
+exports.minVersion = minVersion
+function minVersion (range, loose) {
+ range = new Range(range, loose)
+
+ var minver = new SemVer('0.0.0')
+ if (range.test(minver)) {
+ return minver
+ }
+
+ minver = new SemVer('0.0.0-0')
+ if (range.test(minver)) {
+ return minver
+ }
+
+ minver = null
+ for (var i = 0; i < range.set.length; ++i) {
+ var comparators = range.set[i]
+
+ comparators.forEach(function (comparator) {
+ // Clone to avoid manipulating the comparator's semver object.
+ var compver = new SemVer(comparator.semver.version)
+ switch (comparator.operator) {
+ case '>':
+ if (compver.prerelease.length === 0) {
+ compver.patch++
+ } else {
+ compver.prerelease.push(0)
+ }
+ compver.raw = compver.format()
+ /* fallthrough */
+ case '':
+ case '>=':
+ if (!minver || gt(minver, compver)) {
+ minver = compver
+ }
+ break
+ case '<':
+ case '<=':
+ /* Ignore maximum versions */
+ break
+ /* istanbul ignore next */
+ default:
+ throw new Error('Unexpected operation: ' + comparator.operator)
+ }
+ })
+ }
+
+ if (minver && range.test(minver)) {
+ return minver
+ }
+
+ return null
+}
+
+exports.validRange = validRange
+function validRange (range, options) {
+ try {
+ // Return '*' instead of '' so that truthiness works.
+ // This will throw if it's invalid anyway
+ return new Range(range, options).range || '*'
+ } catch (er) {
+ return null
+ }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr
+function ltr (version, range, options) {
+ return outside(version, range, '<', options)
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr
+function gtr (version, range, options) {
+ return outside(version, range, '>', options)
+}
+
+exports.outside = outside
+function outside (version, range, hilo, options) {
+ version = new SemVer(version, options)
+ range = new Range(range, options)
+
+ var gtfn, ltefn, ltfn, comp, ecomp
+ switch (hilo) {
+ case '>':
+ gtfn = gt
+ ltefn = lte
+ ltfn = lt
+ comp = '>'
+ ecomp = '>='
+ break
+ case '<':
+ gtfn = lt
+ ltefn = gte
+ ltfn = gt
+ comp = '<'
+ ecomp = '<='
+ break
+ default:
+ throw new TypeError('Must provide a hilo val of "<" or ">"')
+ }
+
+ // If it satisifes the range it is not outside
+ if (satisfies(version, range, options)) {
+ return false
+ }
+
+ // From now on, variable terms are as if we're in "gtr" mode.
+ // but note that everything is flipped for the "ltr" function.
+
+ for (var i = 0; i < range.set.length; ++i) {
+ var comparators = range.set[i]
+
+ var high = null
+ var low = null
+
+ comparators.forEach(function (comparator) {
+ if (comparator.semver === ANY) {
+ comparator = new Comparator('>=0.0.0')
+ }
+ high = high || comparator
+ low = low || comparator
+ if (gtfn(comparator.semver, high.semver, options)) {
+ high = comparator
+ } else if (ltfn(comparator.semver, low.semver, options)) {
+ low = comparator
+ }
+ })
+
+ // If the edge version comparator has a operator then our version
+ // isn't outside it
+ if (high.operator === comp || high.operator === ecomp) {
+ return false
+ }
+
+ // If the lowest version comparator has an operator and our version
+ // is less than it then it isn't higher than the range
+ if ((!low.operator || low.operator === comp) &&
+ ltefn(version, low.semver)) {
+ return false
+ } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+ return false
+ }
+ }
+ return true
+}
+
+exports.prerelease = prerelease
+function prerelease (version, options) {
+ var parsed = parse(version, options)
+ return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
+}
+
+exports.intersects = intersects
+function intersects (r1, r2, options) {
+ r1 = new Range(r1, options)
+ r2 = new Range(r2, options)
+ return r1.intersects(r2)
+}
+
+exports.coerce = coerce
+function coerce (version) {
+ if (version instanceof SemVer) {
+ return version
+ }
+
+ if (typeof version !== 'string') {
+ return null
+ }
+
+ var match = version.match(re[COERCE])
+
+ if (match == null) {
+ return null
+ }
+
+ return parse(match[1] +
+ '.' + (match[2] || '0') +
+ '.' + (match[3] || '0'))
+}
diff --git a/node_modules/sift/.babelrc b/node_modules/sift/.babelrc
new file mode 100644
index 0000000..af0f0c3
--- /dev/null
+++ b/node_modules/sift/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets": ["es2015"]
+}
\ No newline at end of file
diff --git a/node_modules/sift/.coveralls.yml b/node_modules/sift/.coveralls.yml
new file mode 100644
index 0000000..cf5a2d6
--- /dev/null
+++ b/node_modules/sift/.coveralls.yml
@@ -0,0 +1 @@
+repo_token: dYtQuNe9CVSGoA5LVadgT3lomowKzEgav
\ No newline at end of file
diff --git a/node_modules/sift/.travis.yml b/node_modules/sift/.travis.yml
new file mode 100755
index 0000000..28c8002
--- /dev/null
+++ b/node_modules/sift/.travis.yml
@@ -0,0 +1,13 @@
+language: node_js
+node_js:
+ - 0.10
+
+script: npm run test-coveralls
+
+notifications:
+ email:
+ - craig.j.condon@gmail.com
+
+branches:
+ only:
+ - master
diff --git a/node_modules/sift/MIT-LICENSE.txt b/node_modules/sift/MIT-LICENSE.txt
new file mode 100644
index 0000000..c080d2e
--- /dev/null
+++ b/node_modules/sift/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2015 Craig Condon
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/sift/README.md b/node_modules/sift/README.md
new file mode 100755
index 0000000..b89d828
--- /dev/null
+++ b/node_modules/sift/README.md
@@ -0,0 +1,417 @@
+## validate objects & filter arrays with mongodb queries
+[](https://secure.travis-ci.org/crcn/sift.js)
+
+
+
+**For extended documentation, checkout http://docs.mongodb.org/manual/reference/operator/query/**
+
+## Features:
+
+- Supported operators: [$in](#in), [$nin](#nin), [$exists](#exists), [$gte](#gte), [$gt](#gt), [$lte](#lte), [$lt](#lt), [$eq](#eq), [$ne](#ne), [$mod](#mod), [$all](#all), [$and](#and), [$or](#or), [$nor](#nor), [$not](#not), [$size](#size), [$type](#type), [$regex](#regex), [$where](#where), [$elemMatch](#elemmatch)
+- Regexp searches
+- Function filtering
+- sub object searching
+- dot notation searching
+- Supports node.js, and web
+- Small (2 kb minified) library
+- Custom Expressions
+- filtering of immutable datastructures
+
+
+
+## Node.js Examples
+
+```javascript
+
+import sift from 'sift';
+
+//intersecting arrays
+var sifted = sift({ $in: ['hello','world'] }, ['hello','sifted','array!']); //['hello']
+
+//regexp filter
+var sifted = sift(/^j/, ['craig','john','jake']); //['john','jake']
+
+
+//A *sifter* is returned if the second parameter is omitted
+var testQuery = sift({
+
+ //you can also filter against functions
+ name: function(value) {
+ return value.length == 5;
+ }
+});
+
+//filtered: [{ name: 'craig' }]
+[{
+ name: 'craig',
+},
+{
+ name: 'john'
+},
+{
+ name: 'jake'
+}].filter(testQuery);
+
+
+//you can test *single values* against your custom sifter
+testQuery({ name: 'sarah' }); //true
+testQuery({ name: 'tim' }); //false\
+```
+
+## Browser Examples
+```html
+
+
+
+
+
+
+
+
+```
+
+## API
+
+### .sift(filter[, array][, selectorFn])
+
+- `filter` - the filter to use against the target array
+- `array` - sifts against target array. Without this, a function is returned
+- `selectorFn` - selector for the values within the array.
+
+With an array:
+
+```javascript
+sift({$exists:true}, ['craig',null]); //['craig']
+```
+
+Without an array, a sifter is returned:
+
+```javascript
+var siftExists = sift({$exists:true});
+
+siftExists('craig'); //true
+siftExists(null); //false
+['craig',null].filter(siftExists); //['craig']
+```
+
+With a selector:
+
+```javascript
+var sifter = sift({$exists:true}, function(user) {
+ return !!user.name;
+});
+
+
+sifter([
+ {
+ name: "Craig"
+ },
+ {
+ name: null
+ }
+])
+```
+
+With your sifter, you can also **test** values:
+
+```javascript
+siftExists(null); //false
+siftExists('craig'); //true
+```
+
+
+## Supported Operators:
+
+See MongoDB's [advanced queries](http://www.mongodb.org/display/DOCS/Advanced+Queries) for more info.
+
+### $in
+
+array value must be *$in* the given query:
+
+Intersecting two arrays:
+
+```javascript
+//filtered: ['Brazil']
+sift({ $in: ['Costa Rica','Brazil'] }, ['Brazil','Haiti','Peru','Chile']);
+```
+
+Here's another example. This acts more like the $or operator:
+
+```javascript
+sift({ location: { $in: ['Costa Rica','Brazil'] } }, [ { name: 'Craig', location: 'Brazil' } ]);
+```
+
+### $nin
+
+Opposite of $in:
+
+```javascript
+//filtered: ['Haiti','Peru','Chile']
+sift({ $nin: ['Costa Rica','Brazil'] }, ['Brazil','Haiti','Peru','Chile']);
+```
+
+### $exists
+
+Checks if whether a value exists:
+
+```javascript
+//filtered: ['Craig','Tim']
+sift({ $exists: true }, ['Craig',null,'Tim']);
+```
+
+You can also filter out values that don't exist
+
+```javascript
+//filtered: [{ name: 'Craig', city: 'Minneapolis' }]
+sift({ city: { $exists: false } }, [ { name: 'Craig', city: 'Minneapolis' }, { name: 'Tim' }]);
+```
+
+### $gte
+
+Checks if a number is >= value:
+
+```javascript
+//filtered: [2, 3]
+sift({ $gte: 2 }, [0, 1, 2, 3]);
+```
+
+### $gt
+
+Checks if a number is > value:
+
+```javascript
+//filtered: [3]
+sift({ $gt: 2 }, [0, 1, 2, 3]);
+```
+
+### $lte
+
+Checks if a number is <= value.
+
+```javascript
+//filtered: [0, 1, 2]
+sift({ $lte: 2 }, [0, 1, 2, 3]);
+```
+
+### $lt
+
+Checks if number is < value.
+
+```javascript
+//filtered: [0, 1]
+sift({ $lt: 2 }, [0, 1, 2, 3]);
+```
+
+### $eq
+
+Checks if `query === value`. Note that **$eq can be omitted**. For **$eq**, and **$ne**
+
+```javascript
+//filtered: [{ state: 'MN' }]
+sift({ state: {$eq: 'MN' }}, [{ state: 'MN' }, { state: 'CA' }, { state: 'WI' }]);
+```
+
+Or:
+
+```javascript
+//filtered: [{ state: 'MN' }]
+sift({ state: 'MN' }, [{ state: 'MN' }, { state: 'CA' }, { state: 'WI' }]);
+```
+
+### $ne
+
+Checks if `query !== value`.
+
+```javascript
+//filtered: [{ state: 'CA' }, { state: 'WI'}]
+sift({ state: {$ne: 'MN' }}, [{ state: 'MN' }, { state: 'CA' }, { state: 'WI' }]);
+```
+
+### $mod
+
+Modulus:
+
+```javascript
+//filtered: [300, 600]
+sift({ $mod: [3, 0] }, [100, 200, 300, 400, 500, 600]);
+```
+
+### $all
+
+values must match **everything** in array:
+
+```javascript
+//filtered: [ { tags: ['books','programming','travel' ]} ]
+sift({ tags: {$all: ['books','programming'] }}, [
+{ tags: ['books','programming','travel' ] },
+{ tags: ['travel','cooking'] } ]);
+```
+
+### $and
+
+ability to use an array of expressions. All expressions must test true.
+
+```javascript
+//filtered: [ { name: 'Craig', state: 'MN' }]
+
+sift({ $and: [ { name: 'Craig' }, { state: 'MN' } ] }, [
+{ name: 'Craig', state: 'MN' },
+{ name: 'Tim', state: 'MN' },
+{ name: 'Joe', state: 'CA' } ]);
+```
+
+### $or
+
+OR array of expressions.
+
+```javascript
+//filtered: [ { name: 'Craig', state: 'MN' }, { name: 'Tim', state: 'MN' }]
+sift({ $or: [ { name: 'Craig' }, { state: 'MN' } ] }, [
+{ name: 'Craig', state: 'MN' },
+{ name: 'Tim', state: 'MN' },
+{ name: 'Joe', state: 'CA' } ]);
+```
+
+### $nor
+
+opposite of or:
+
+```javascript
+//filtered: [ { name: 'Tim', state: 'MN' }, { name: 'Joe', state: 'CA' }]
+sift({ $nor: [ { name: 'Craig' }, { state: 'MN' } ] }, [
+{ name: 'Craig', state: 'MN' },
+{ name: 'Tim', state: 'MN' },
+{ name: 'Joe', state: 'CA' } ]);
+```
+
+
+### $size
+
+Matches an array - must match given size:
+
+```javascript
+//filtered: ['food','cooking']
+sift({ tags: { $size: 2 } }, [ { tags: ['food','cooking'] }, { tags: ['traveling'] }]);
+```
+
+### $type
+
+Matches a values based on the type
+
+```javascript
+sift({ $type: Date }, [new Date(), 4342, 'hello world']); //returns single date
+sift({ $type: String }, [new Date(), 4342, 'hello world']); //returns ['hello world']
+```
+
+### $regex
+
+Matches values based on the given regular expression
+
+```javascript
+sift({ $regex: /^f/i, $nin: ["frank"] }, ["frank", "fred", "sam", "frost"]); // ["fred", "frost"]
+sift({ $regex: "^f", $options: "i", $nin: ["frank"] }, ["frank", "fred", "sam", "frost"]); // ["fred", "frost"]
+```
+
+### $where
+
+Matches based on some javascript comparison
+
+```javascript
+sift({ $where: "this.name === 'frank'" }, [{name:'frank'},{name:'joe'}]); // ["frank"]
+sift({
+ $where: function() {
+ return this.name === "frank"
+ }
+}, [{name:'frank'},{name:'joe'}]); // ["frank"]
+```
+
+### $elemMatch
+
+Matches elements of array
+
+```javascript
+var bills = [{
+ month: 'july',
+ casts: [{
+ id: 1,
+ value: 200
+ },{
+ id: 2,
+ value: 1000
+ }]
+},
+{
+ month: 'august',
+ casts: [{
+ id: 3,
+ value: 1000,
+ }, {
+ id: 4,
+ value: 4000
+ }]
+}];
+
+var result = sift({
+ casts: {$elemMatch:{
+ value: {$gt: 1000}
+ }}
+}, bills); // {month:'august', casts:[{id:3, value: 1000},{id: 4, value: 4000}]}
+```
+
+### $not
+
+Not expression:
+
+```javascript
+sift({$not:{$in:['craig','tim']}}, ['craig','tim','jake']); //['jake']
+sift({$not:{$size:5}}, ['craig','tim','jake']); //['tim','jake']
+```
+
+## sub object Searching
+
+
+```javascript
+var people = [{
+ name: 'craig',
+ address: {
+ city: 'Minneapolis'
+ }
+},
+{
+ name: 'tim',
+ address: {
+ city: 'St. Paul'
+ }
+}];
+
+var sifted = sift({ address: { city: 'Minneapolis' }}, people); // count = 1
+
+//or
+var sifted = sift({'address.city': 'minneapolis'}, people);//count = 1
+```
+
+
+## Get index of first matching element
+
+Get the index (0-based) of first matching element in target array. Returns `-1` if no match is found.
+
+```javascript
+import {indexOf as siftIndexOf} from 'sift';
+var people = [{
+ name: 'craig',
+ address: {
+ city: 'Minneapolis'
+ }
+},
+{
+ name: 'tim',
+ address: {
+ city: 'St. Paul'
+ }
+}];
+
+var index = siftIndexOf({ address: { city: 'Minneapolis' }}, people); // index = 0
+```
diff --git a/node_modules/sift/bower.json b/node_modules/sift/bower.json
new file mode 100644
index 0000000..ceae6b7
--- /dev/null
+++ b/node_modules/sift/bower.json
@@ -0,0 +1,21 @@
+{
+ "name": "sift",
+ "version": "3.2.0",
+ "authors": [
+ "Craig Condon "
+ ],
+ "description": "mongodb query style array filtering",
+ "main": "sift.min.js",
+ "moduleType": [],
+ "license": "MIT",
+ "homepage": "https://github.com/crcn/sift.js",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "benchmark",
+ "webpack.js",
+ "package.json"
+ ]
+}
diff --git a/node_modules/sift/changelog.md b/node_modules/sift/changelog.md
new file mode 100644
index 0000000..ff230e8
--- /dev/null
+++ b/node_modules/sift/changelog.md
@@ -0,0 +1,25 @@
+### 7.0.0
+
+- Remove global `*.use()` function.
+- converted to ES6
+
+### 3.3.x
+
+- `$in` now uses `toString()` when evaluating objects. Fixes #116.
+
+#### 2.x
+
+- `use()` now uses a different format:
+
+```javascript
+sift.use({
+ $operator: function(a) {
+ return function(b) {
+ // compare here
+ };
+ }
+})
+```
+
+- all operators are traversable now
+- fix #58.
diff --git a/node_modules/sift/coverage/coverage.json b/node_modules/sift/coverage/coverage.json
new file mode 100644
index 0000000..ee223e5
--- /dev/null
+++ b/node_modules/sift/coverage/coverage.json
@@ -0,0 +1 @@
+{"/Users/crcn/Developer/public/sift.js/sift.js":{"path":"/Users/crcn/Developer/public/sift.js/sift.js","s":{"1":1,"2":1,"3":1480,"4":1,"5":3068,"6":1,"7":1895,"8":36,"9":1859,"10":45,"11":1814,"12":27,"13":1787,"14":1,"15":1341,"16":1,"17":7,"18":509,"19":474,"20":35,"21":59,"22":23,"23":12,"24":1,"25":1,"26":57,"27":53,"28":4,"29":6,"30":2,"31":2,"32":1,"33":1076,"34":1,"35":399,"36":59,"37":34,"38":15,"39":24,"40":10,"41":10,"42":99,"43":10,"44":11,"45":8,"46":89,"47":89,"48":8,"49":12,"50":1,"51":88,"52":22,"53":24,"54":1,"55":87,"56":169,"57":169,"58":169,"59":34,"60":53,"61":2,"62":22,"63":15,"64":13,"65":18,"66":7,"67":32,"68":64,"69":21,"70":11,"71":10,"72":58,"73":98,"74":27,"75":31,"76":41,"77":6,"78":11,"79":6,"80":5,"81":25,"82":1,"83":236,"84":19,"85":41,"86":217,"87":1,"88":216,"89":1,"90":3,"91":215,"92":4,"93":5,"94":211,"95":406,"96":18,"97":10,"98":6,"99":4,"100":2,"101":4,"102":21,"103":3,"104":5,"105":8,"106":1,"107":8,"108":15,"109":15,"110":5,"111":3,"112":1,"113":378,"114":1,"115":215,"116":215,"117":215,"118":179,"119":179,"120":36,"121":36,"122":36,"123":114,"124":114,"125":114,"126":8,"127":106,"128":36,"129":1,"130":706,"131":293,"132":293,"133":413,"134":413,"135":41,"136":119,"137":372,"138":1,"139":92,"140":1,"141":413,"142":1,"143":443,"144":443,"145":215,"146":443,"147":443,"148":458,"149":458,"150":2,"151":456,"152":363,"153":294,"154":363,"155":93,"156":1,"157":92,"158":442,"159":1,"160":306,"161":305,"162":3,"163":4,"164":305,"165":1,"166":135,"167":1,"168":1,"169":135,"170":1,"171":413,"172":134,"173":33,"174":101,"175":1,"176":4,"177":1,"178":3,"179":3,"180":3,"181":1,"182":2,"183":1,"184":489,"185":126,"186":363,"187":284,"188":151,"189":133,"190":133,"191":1,"192":1,"193":1,"194":1,"195":1,"196":0},"b":{"1":[36,1859],"2":[45,1814],"3":[27,1787],"4":[1814,1628],"5":[12,1329],"6":[474,35],"7":[509,36],"8":[23,36],"9":[53,4],"10":[57,4],"11":[2,4],"12":[10,89],"13":[8,3],"14":[8,81],"15":[89,85],"16":[1,11],"17":[12,7],"18":[22,66],"19":[1,23],"20":[34,135],"21":[169,37,36],"22":[12,1],"23":[12,11],"24":[6,1],"25":[21,43],"26":[27,71],"27":[41,30],"28":[6,5],"29":[19,217],"30":[41,25],"31":[1,216],"32":[1,215],"33":[216,1],"34":[3,1],"35":[4,211],"36":[2,1],"37":[5,10],"38":[179,36],"39":[36,36,36],"40":[8,106],"41":[293,413],"42":[706,414],"43":[41,372],"44":[413,45],"45":[413,413],"46":[215,228],"47":[443,413],"48":[2,456],"49":[363,93],"50":[294,69],"51":[1,92],"52":[427,15],"53":[3,302],"54":[1,134],"55":[33,101],"56":[1,3],"57":[3,0],"58":[126,363],"59":[284,79],"60":[151,133],"61":[133,0],"62":[1,0],"63":[1,1],"64":[0,1]},"f":{"1":1,"2":1480,"3":3068,"4":1895,"5":1341,"6":7,"7":509,"8":1,"9":57,"10":1076,"11":399,"12":59,"13":34,"14":15,"15":24,"16":10,"17":10,"18":99,"19":22,"20":15,"21":13,"22":18,"23":7,"24":32,"25":10,"26":58,"27":41,"28":6,"29":11,"30":25,"31":236,"32":41,"33":3,"34":5,"35":406,"36":18,"37":10,"38":6,"39":4,"40":2,"41":4,"42":21,"43":3,"44":5,"45":8,"46":8,"47":378,"48":215,"49":706,"50":92,"51":413,"52":443,"53":306,"54":4,"55":135,"56":413,"57":4,"58":2,"59":489},"fnMap":{"1":{"name":"(anonymous_1)","line":10,"loc":{"start":{"line":10,"column":1},"end":{"line":10,"column":12}}},"2":{"name":"isFunction","line":17,"loc":{"start":{"line":17,"column":2},"end":{"line":17,"column":29}}},"3":{"name":"isArray","line":24,"loc":{"start":{"line":24,"column":2},"end":{"line":24,"column":26}}},"4":{"name":"comparable","line":31,"loc":{"start":{"line":31,"column":2},"end":{"line":31,"column":29}}},"5":{"name":"get","line":43,"loc":{"start":{"line":43,"column":2},"end":{"line":43,"column":25}}},"6":{"name":"or","line":50,"loc":{"start":{"line":50,"column":2},"end":{"line":50,"column":25}}},"7":{"name":"(anonymous_7)","line":51,"loc":{"start":{"line":51,"column":11},"end":{"line":51,"column":26}}},"8":{"name":"and","line":65,"loc":{"start":{"line":65,"column":2},"end":{"line":65,"column":26}}},"9":{"name":"(anonymous_9)","line":66,"loc":{"start":{"line":66,"column":11},"end":{"line":66,"column":26}}},"10":{"name":"validate","line":77,"loc":{"start":{"line":77,"column":2},"end":{"line":77,"column":40}}},"11":{"name":"(anonymous_11)","line":86,"loc":{"start":{"line":86,"column":12},"end":{"line":86,"column":27}}},"12":{"name":"(anonymous_12)","line":93,"loc":{"start":{"line":93,"column":13},"end":{"line":93,"column":28}}},"13":{"name":"(anonymous_13)","line":100,"loc":{"start":{"line":100,"column":12},"end":{"line":100,"column":27}}},"14":{"name":"(anonymous_14)","line":107,"loc":{"start":{"line":107,"column":13},"end":{"line":107,"column":28}}},"15":{"name":"(anonymous_15)","line":114,"loc":{"start":{"line":114,"column":12},"end":{"line":114,"column":27}}},"16":{"name":"(anonymous_16)","line":121,"loc":{"start":{"line":121,"column":13},"end":{"line":121,"column":28}}},"17":{"name":"(anonymous_17)","line":128,"loc":{"start":{"line":128,"column":13},"end":{"line":128,"column":28}}},"18":{"name":"(anonymous_18)","line":135,"loc":{"start":{"line":135,"column":9},"end":{"line":135,"column":24}}},"19":{"name":"(anonymous_19)","line":185,"loc":{"start":{"line":185,"column":10},"end":{"line":185,"column":31}}},"20":{"name":"(anonymous_20)","line":192,"loc":{"start":{"line":192,"column":10},"end":{"line":192,"column":31}}},"21":{"name":"(anonymous_21)","line":199,"loc":{"start":{"line":199,"column":11},"end":{"line":199,"column":26}}},"22":{"name":"(anonymous_22)","line":206,"loc":{"start":{"line":206,"column":10},"end":{"line":206,"column":31}}},"23":{"name":"(anonymous_23)","line":213,"loc":{"start":{"line":213,"column":11},"end":{"line":213,"column":26}}},"24":{"name":"(anonymous_24)","line":220,"loc":{"start":{"line":220,"column":9},"end":{"line":220,"column":30}}},"25":{"name":"(anonymous_25)","line":228,"loc":{"start":{"line":228,"column":10},"end":{"line":228,"column":31}}},"26":{"name":"(anonymous_26)","line":235,"loc":{"start":{"line":235,"column":10},"end":{"line":235,"column":31}}},"27":{"name":"(anonymous_27)","line":247,"loc":{"start":{"line":247,"column":15},"end":{"line":247,"column":30}}},"28":{"name":"(anonymous_28)","line":254,"loc":{"start":{"line":254,"column":12},"end":{"line":254,"column":33}}},"29":{"name":"(anonymous_29)","line":261,"loc":{"start":{"line":261,"column":16},"end":{"line":261,"column":37}}},"30":{"name":"(anonymous_30)","line":271,"loc":{"start":{"line":271,"column":13},"end":{"line":271,"column":34}}},"31":{"name":"(anonymous_31)","line":284,"loc":{"start":{"line":284,"column":9},"end":{"line":284,"column":21}}},"32":{"name":"(anonymous_32)","line":287,"loc":{"start":{"line":287,"column":15},"end":{"line":287,"column":27}}},"33":{"name":"(anonymous_33)","line":294,"loc":{"start":{"line":294,"column":15},"end":{"line":294,"column":27}}},"34":{"name":"(anonymous_34)","line":298,"loc":{"start":{"line":298,"column":15},"end":{"line":298,"column":26}}},"35":{"name":"(anonymous_35)","line":304,"loc":{"start":{"line":304,"column":13},"end":{"line":304,"column":25}}},"36":{"name":"(anonymous_36)","line":312,"loc":{"start":{"line":312,"column":9},"end":{"line":312,"column":21}}},"37":{"name":"(anonymous_37)","line":319,"loc":{"start":{"line":319,"column":10},"end":{"line":319,"column":22}}},"38":{"name":"(anonymous_38)","line":326,"loc":{"start":{"line":326,"column":10},"end":{"line":326,"column":22}}},"39":{"name":"(anonymous_39)","line":333,"loc":{"start":{"line":333,"column":9},"end":{"line":333,"column":21}}},"40":{"name":"(anonymous_40)","line":340,"loc":{"start":{"line":340,"column":10},"end":{"line":340,"column":22}}},"41":{"name":"(anonymous_41)","line":347,"loc":{"start":{"line":347,"column":10},"end":{"line":347,"column":22}}},"42":{"name":"(anonymous_42)","line":354,"loc":{"start":{"line":354,"column":12},"end":{"line":354,"column":31}}},"43":{"name":"(anonymous_43)","line":361,"loc":{"start":{"line":361,"column":12},"end":{"line":361,"column":24}}},"44":{"name":"(anonymous_44)","line":368,"loc":{"start":{"line":368,"column":16},"end":{"line":368,"column":28}}},"45":{"name":"(anonymous_45)","line":375,"loc":{"start":{"line":375,"column":13},"end":{"line":375,"column":25}}},"46":{"name":"search","line":383,"loc":{"start":{"line":383,"column":2},"end":{"line":383,"column":36}}},"47":{"name":"createValidator","line":398,"loc":{"start":{"line":398,"column":2},"end":{"line":398,"column":40}}},"48":{"name":"nestedValidator","line":405,"loc":{"start":{"line":405,"column":2},"end":{"line":405,"column":33}}},"49":{"name":"findValues","line":432,"loc":{"start":{"line":432,"column":2},"end":{"line":432,"column":63}}},"50":{"name":"createNestedValidator","line":457,"loc":{"start":{"line":457,"column":2},"end":{"line":457,"column":48}}},"51":{"name":"isVanillaObject","line":465,"loc":{"start":{"line":465,"column":2},"end":{"line":465,"column":34}}},"52":{"name":"parse","line":469,"loc":{"start":{"line":469,"column":2},"end":{"line":469,"column":24}}},"53":{"name":"createRootValidator","line":503,"loc":{"start":{"line":503,"column":2},"end":{"line":503,"column":46}}},"54":{"name":"(anonymous_54)","line":508,"loc":{"start":{"line":508,"column":11},"end":{"line":508,"column":32}}},"55":{"name":"sift","line":519,"loc":{"start":{"line":519,"column":2},"end":{"line":519,"column":38}}},"56":{"name":"filter","line":528,"loc":{"start":{"line":528,"column":4},"end":{"line":528,"column":29}}},"57":{"name":"(anonymous_57)","line":542,"loc":{"start":{"line":542,"column":13},"end":{"line":542,"column":30}}},"58":{"name":"(anonymous_58)","line":555,"loc":{"start":{"line":555,"column":17},"end":{"line":555,"column":48}}},"59":{"name":"(anonymous_59)","line":562,"loc":{"start":{"line":562,"column":17},"end":{"line":562,"column":32}}}},"statementMap":{"1":{"start":{"line":10,"column":0},"end":{"line":588,"column":5}},"2":{"start":{"line":17,"column":2},"end":{"line":19,"column":3}},"3":{"start":{"line":18,"column":4},"end":{"line":18,"column":39}},"4":{"start":{"line":24,"column":2},"end":{"line":26,"column":3}},"5":{"start":{"line":25,"column":4},"end":{"line":25,"column":70}},"6":{"start":{"line":31,"column":2},"end":{"line":41,"column":3}},"7":{"start":{"line":32,"column":4},"end":{"line":40,"column":5}},"8":{"start":{"line":33,"column":6},"end":{"line":33,"column":29}},"9":{"start":{"line":34,"column":11},"end":{"line":40,"column":5}},"10":{"start":{"line":35,"column":6},"end":{"line":35,"column":35}},"11":{"start":{"line":36,"column":11},"end":{"line":40,"column":5}},"12":{"start":{"line":37,"column":6},"end":{"line":37,"column":28}},"13":{"start":{"line":39,"column":6},"end":{"line":39,"column":19}},"14":{"start":{"line":43,"column":2},"end":{"line":45,"column":3}},"15":{"start":{"line":44,"column":4},"end":{"line":44,"column":57}},"16":{"start":{"line":50,"column":2},"end":{"line":60,"column":3}},"17":{"start":{"line":51,"column":4},"end":{"line":59,"column":5}},"18":{"start":{"line":52,"column":6},"end":{"line":54,"column":7}},"19":{"start":{"line":53,"column":8},"end":{"line":53,"column":31}},"20":{"start":{"line":55,"column":6},"end":{"line":57,"column":7}},"21":{"start":{"line":56,"column":8},"end":{"line":56,"column":48}},"22":{"start":{"line":56,"column":36},"end":{"line":56,"column":48}},"23":{"start":{"line":58,"column":6},"end":{"line":58,"column":19}},"24":{"start":{"line":65,"column":2},"end":{"line":75,"column":3}},"25":{"start":{"line":66,"column":4},"end":{"line":74,"column":6}},"26":{"start":{"line":67,"column":6},"end":{"line":69,"column":7}},"27":{"start":{"line":68,"column":8},"end":{"line":68,"column":31}},"28":{"start":{"line":70,"column":6},"end":{"line":72,"column":7}},"29":{"start":{"line":71,"column":8},"end":{"line":71,"column":51}},"30":{"start":{"line":71,"column":38},"end":{"line":71,"column":51}},"31":{"start":{"line":73,"column":6},"end":{"line":73,"column":18}},"32":{"start":{"line":77,"column":2},"end":{"line":79,"column":3}},"33":{"start":{"line":78,"column":4},"end":{"line":78,"column":45}},"34":{"start":{"line":81,"column":2},"end":{"line":274,"column":4}},"35":{"start":{"line":87,"column":6},"end":{"line":87,"column":18}},"36":{"start":{"line":94,"column":6},"end":{"line":94,"column":19}},"37":{"start":{"line":101,"column":6},"end":{"line":101,"column":48}},"38":{"start":{"line":108,"column":6},"end":{"line":108,"column":49}},"39":{"start":{"line":115,"column":6},"end":{"line":115,"column":48}},"40":{"start":{"line":122,"column":6},"end":{"line":122,"column":49}},"41":{"start":{"line":129,"column":6},"end":{"line":129,"column":30}},"42":{"start":{"line":137,"column":6},"end":{"line":177,"column":7}},"43":{"start":{"line":138,"column":8},"end":{"line":142,"column":9}},"44":{"start":{"line":139,"column":10},"end":{"line":141,"column":11}},"45":{"start":{"line":140,"column":12},"end":{"line":140,"column":24}},"46":{"start":{"line":144,"column":8},"end":{"line":144,"column":40}},"47":{"start":{"line":145,"column":8},"end":{"line":151,"column":9}},"48":{"start":{"line":146,"column":10},"end":{"line":150,"column":11}},"49":{"start":{"line":147,"column":12},"end":{"line":149,"column":13}},"50":{"start":{"line":148,"column":14},"end":{"line":148,"column":26}},"51":{"start":{"line":157,"column":8},"end":{"line":163,"column":9}},"52":{"start":{"line":158,"column":10},"end":{"line":162,"column":11}},"53":{"start":{"line":159,"column":12},"end":{"line":161,"column":13}},"54":{"start":{"line":160,"column":14},"end":{"line":160,"column":26}},"55":{"start":{"line":168,"column":8},"end":{"line":174,"column":9}},"56":{"start":{"line":169,"column":10},"end":{"line":169,"column":68}},"57":{"start":{"line":170,"column":10},"end":{"line":170,"column":52}},"58":{"start":{"line":171,"column":10},"end":{"line":173,"column":11}},"59":{"start":{"line":172,"column":12},"end":{"line":172,"column":24}},"60":{"start":{"line":176,"column":8},"end":{"line":176,"column":41}},"61":{"start":{"line":179,"column":6},"end":{"line":179,"column":19}},"62":{"start":{"line":186,"column":6},"end":{"line":186,"column":40}},"63":{"start":{"line":193,"column":6},"end":{"line":193,"column":35}},"64":{"start":{"line":200,"column":6},"end":{"line":200,"column":72}},"65":{"start":{"line":207,"column":6},"end":{"line":207,"column":40}},"66":{"start":{"line":214,"column":6},"end":{"line":214,"column":40}},"67":{"start":{"line":221,"column":6},"end":{"line":221,"column":94}},"68":{"start":{"line":221,"column":48},"end":{"line":221,"column":94}},"69":{"start":{"line":221,"column":82},"end":{"line":221,"column":94}},"70":{"start":{"line":222,"column":6},"end":{"line":222,"column":19}},"71":{"start":{"line":229,"column":6},"end":{"line":229,"column":40}},"72":{"start":{"line":236,"column":6},"end":{"line":240,"column":7}},"73":{"start":{"line":237,"column":8},"end":{"line":239,"column":9}},"74":{"start":{"line":238,"column":10},"end":{"line":238,"column":23}},"75":{"start":{"line":241,"column":6},"end":{"line":241,"column":18}},"76":{"start":{"line":248,"column":6},"end":{"line":248,"column":48}},"77":{"start":{"line":255,"column":6},"end":{"line":255,"column":32}},"78":{"start":{"line":262,"column":6},"end":{"line":264,"column":7}},"79":{"start":{"line":263,"column":8},"end":{"line":263,"column":31}},"80":{"start":{"line":265,"column":6},"end":{"line":265,"column":34}},"81":{"start":{"line":272,"column":6},"end":{"line":272,"column":39}},"82":{"start":{"line":279,"column":2},"end":{"line":378,"column":4}},"83":{"start":{"line":286,"column":6},"end":{"line":302,"column":7}},"84":{"start":{"line":287,"column":8},"end":{"line":289,"column":10}},"85":{"start":{"line":288,"column":10},"end":{"line":288,"column":52}},"86":{"start":{"line":290,"column":13},"end":{"line":302,"column":7}},"87":{"start":{"line":291,"column":8},"end":{"line":291,"column":17}},"88":{"start":{"line":292,"column":13},"end":{"line":302,"column":7}},"89":{"start":{"line":294,"column":8},"end":{"line":296,"column":10}},"90":{"start":{"line":295,"column":10},"end":{"line":295,"column":43}},"91":{"start":{"line":297,"column":13},"end":{"line":302,"column":7}},"92":{"start":{"line":298,"column":8},"end":{"line":301,"column":9}},"93":{"start":{"line":300,"column":10},"end":{"line":300,"column":27}},"94":{"start":{"line":304,"column":6},"end":{"line":306,"column":8}},"95":{"start":{"line":305,"column":8},"end":{"line":305,"column":64}},"96":{"start":{"line":313,"column":6},"end":{"line":313,"column":28}},"97":{"start":{"line":320,"column":6},"end":{"line":320,"column":26}},"98":{"start":{"line":327,"column":6},"end":{"line":327,"column":29}},"99":{"start":{"line":334,"column":6},"end":{"line":334,"column":26}},"100":{"start":{"line":341,"column":6},"end":{"line":341,"column":26}},"101":{"start":{"line":348,"column":6},"end":{"line":348,"column":22}},"102":{"start":{"line":355,"column":6},"end":{"line":355,"column":43}},"103":{"start":{"line":362,"column":6},"end":{"line":362,"column":76}},"104":{"start":{"line":369,"column":6},"end":{"line":369,"column":22}},"105":{"start":{"line":376,"column":6},"end":{"line":376,"column":17}},"106":{"start":{"line":383,"column":2},"end":{"line":393,"column":3}},"107":{"start":{"line":385,"column":4},"end":{"line":390,"column":5}},"108":{"start":{"line":386,"column":6},"end":{"line":386,"column":33}},"109":{"start":{"line":387,"column":6},"end":{"line":389,"column":7}},"110":{"start":{"line":388,"column":8},"end":{"line":388,"column":17}},"111":{"start":{"line":392,"column":4},"end":{"line":392,"column":14}},"112":{"start":{"line":398,"column":2},"end":{"line":400,"column":3}},"113":{"start":{"line":399,"column":4},"end":{"line":399,"column":33}},"114":{"start":{"line":405,"column":2},"end":{"line":427,"column":3}},"115":{"start":{"line":406,"column":4},"end":{"line":406,"column":21}},"116":{"start":{"line":407,"column":4},"end":{"line":407,"column":37}},"117":{"start":{"line":409,"column":4},"end":{"line":412,"column":5}},"118":{"start":{"line":410,"column":6},"end":{"line":410,"column":28}},"119":{"start":{"line":411,"column":6},"end":{"line":411,"column":58}},"120":{"start":{"line":415,"column":4},"end":{"line":415,"column":63}},"121":{"start":{"line":416,"column":4},"end":{"line":416,"column":29}},"122":{"start":{"line":417,"column":4},"end":{"line":425,"column":5}},"123":{"start":{"line":418,"column":6},"end":{"line":418,"column":29}},"124":{"start":{"line":419,"column":6},"end":{"line":419,"column":68}},"125":{"start":{"line":420,"column":6},"end":{"line":424,"column":7}},"126":{"start":{"line":421,"column":8},"end":{"line":421,"column":28}},"127":{"start":{"line":423,"column":8},"end":{"line":423,"column":28}},"128":{"start":{"line":426,"column":4},"end":{"line":426,"column":20}},"129":{"start":{"line":432,"column":2},"end":{"line":452,"column":3}},"130":{"start":{"line":434,"column":4},"end":{"line":438,"column":5}},"131":{"start":{"line":436,"column":6},"end":{"line":436,"column":57}},"132":{"start":{"line":437,"column":6},"end":{"line":437,"column":13}},"133":{"start":{"line":440,"column":4},"end":{"line":440,"column":32}},"134":{"start":{"line":445,"column":4},"end":{"line":451,"column":5}},"135":{"start":{"line":446,"column":6},"end":{"line":448,"column":7}},"136":{"start":{"line":447,"column":8},"end":{"line":447,"column":69}},"137":{"start":{"line":450,"column":6},"end":{"line":450,"column":71}},"138":{"start":{"line":457,"column":2},"end":{"line":459,"column":3}},"139":{"start":{"line":458,"column":4},"end":{"line":458,"column":66}},"140":{"start":{"line":465,"column":2},"end":{"line":467,"column":3}},"141":{"start":{"line":466,"column":4},"end":{"line":466,"column":49}},"142":{"start":{"line":469,"column":2},"end":{"line":498,"column":3}},"143":{"start":{"line":470,"column":4},"end":{"line":470,"column":30}},"144":{"start":{"line":472,"column":4},"end":{"line":474,"column":5}},"145":{"start":{"line":473,"column":6},"end":{"line":473,"column":29}},"146":{"start":{"line":476,"column":4},"end":{"line":476,"column":24}},"147":{"start":{"line":478,"column":4},"end":{"line":495,"column":5}},"148":{"start":{"line":479,"column":6},"end":{"line":479,"column":25}},"149":{"start":{"line":481,"column":6},"end":{"line":483,"column":7}},"150":{"start":{"line":482,"column":8},"end":{"line":482,"column":17}},"151":{"start":{"line":485,"column":6},"end":{"line":494,"column":7}},"152":{"start":{"line":486,"column":8},"end":{"line":486,"column":53}},"153":{"start":{"line":486,"column":26},"end":{"line":486,"column":53}},"154":{"start":{"line":487,"column":8},"end":{"line":487,"column":72}},"155":{"start":{"line":490,"column":8},"end":{"line":492,"column":9}},"156":{"start":{"line":491,"column":10},"end":{"line":491,"column":54}},"157":{"start":{"line":493,"column":8},"end":{"line":493,"column":76}},"158":{"start":{"line":497,"column":4},"end":{"line":497,"column":97}},"159":{"start":{"line":503,"column":2},"end":{"line":514,"column":3}},"160":{"start":{"line":504,"column":4},"end":{"line":504,"column":33}},"161":{"start":{"line":505,"column":4},"end":{"line":512,"column":5}},"162":{"start":{"line":506,"column":6},"end":{"line":511,"column":8}},"163":{"start":{"line":509,"column":10},"end":{"line":509,"column":46}},"164":{"start":{"line":513,"column":4},"end":{"line":513,"column":21}},"165":{"start":{"line":519,"column":2},"end":{"line":537,"column":3}},"166":{"start":{"line":521,"column":4},"end":{"line":524,"column":5}},"167":{"start":{"line":522,"column":6},"end":{"line":522,"column":21}},"168":{"start":{"line":523,"column":6},"end":{"line":523,"column":22}},"169":{"start":{"line":526,"column":4},"end":{"line":526,"column":55}},"170":{"start":{"line":528,"column":4},"end":{"line":530,"column":5}},"171":{"start":{"line":529,"column":6},"end":{"line":529,"column":42}},"172":{"start":{"line":532,"column":4},"end":{"line":534,"column":5}},"173":{"start":{"line":533,"column":6},"end":{"line":533,"column":34}},"174":{"start":{"line":536,"column":4},"end":{"line":536,"column":18}},"175":{"start":{"line":542,"column":2},"end":{"line":550,"column":4}},"176":{"start":{"line":543,"column":4},"end":{"line":543,"column":48}},"177":{"start":{"line":543,"column":28},"end":{"line":543,"column":48}},"178":{"start":{"line":544,"column":4},"end":{"line":549,"column":5}},"179":{"start":{"line":546,"column":6},"end":{"line":548,"column":7}},"180":{"start":{"line":547,"column":8},"end":{"line":547,"column":37}},"181":{"start":{"line":555,"column":2},"end":{"line":557,"column":4}},"182":{"start":{"line":556,"column":4},"end":{"line":556,"column":61}},"183":{"start":{"line":562,"column":2},"end":{"line":572,"column":4}},"184":{"start":{"line":563,"column":4},"end":{"line":563,"column":23}},"185":{"start":{"line":563,"column":14},"end":{"line":563,"column":23}},"186":{"start":{"line":564,"column":4},"end":{"line":571,"column":5}},"187":{"start":{"line":565,"column":6},"end":{"line":567,"column":7}},"188":{"start":{"line":566,"column":8},"end":{"line":566,"column":17}},"189":{"start":{"line":568,"column":6},"end":{"line":570,"column":7}},"190":{"start":{"line":569,"column":8},"end":{"line":569,"column":18}},"191":{"start":{"line":575,"column":2},"end":{"line":582,"column":3},"skip":true},"192":{"start":{"line":576,"column":4},"end":{"line":578,"column":7},"skip":true},"193":{"start":{"line":580,"column":4},"end":{"line":580,"column":26},"skip":true},"194":{"start":{"line":581,"column":4},"end":{"line":581,"column":55},"skip":true},"195":{"start":{"line":585,"column":2},"end":{"line":587,"column":3},"skip":true},"196":{"start":{"line":586,"column":4},"end":{"line":586,"column":23},"skip":true}},"branchMap":{"1":{"line":32,"type":"if","locations":[{"start":{"line":32,"column":4},"end":{"line":32,"column":4}},{"start":{"line":32,"column":4},"end":{"line":32,"column":4}}]},"2":{"line":34,"type":"if","locations":[{"start":{"line":34,"column":11},"end":{"line":34,"column":11}},{"start":{"line":34,"column":11},"end":{"line":34,"column":11}}]},"3":{"line":36,"type":"if","locations":[{"start":{"line":36,"column":11},"end":{"line":36,"column":11}},{"start":{"line":36,"column":11},"end":{"line":36,"column":11}}]},"4":{"line":36,"type":"binary-expr","locations":[{"start":{"line":36,"column":15},"end":{"line":36,"column":20}},{"start":{"line":36,"column":24},"end":{"line":36,"column":58}}]},"5":{"line":44,"type":"cond-expr","locations":[{"start":{"line":44,"column":33},"end":{"line":44,"column":45}},{"start":{"line":44,"column":48},"end":{"line":44,"column":56}}]},"6":{"line":52,"type":"if","locations":[{"start":{"line":52,"column":6},"end":{"line":52,"column":6}},{"start":{"line":52,"column":6},"end":{"line":52,"column":6}}]},"7":{"line":52,"type":"binary-expr","locations":[{"start":{"line":52,"column":10},"end":{"line":52,"column":21}},{"start":{"line":52,"column":25},"end":{"line":52,"column":34}}]},"8":{"line":56,"type":"if","locations":[{"start":{"line":56,"column":8},"end":{"line":56,"column":8}},{"start":{"line":56,"column":8},"end":{"line":56,"column":8}}]},"9":{"line":67,"type":"if","locations":[{"start":{"line":67,"column":6},"end":{"line":67,"column":6}},{"start":{"line":67,"column":6},"end":{"line":67,"column":6}}]},"10":{"line":67,"type":"binary-expr","locations":[{"start":{"line":67,"column":10},"end":{"line":67,"column":21}},{"start":{"line":67,"column":25},"end":{"line":67,"column":34}}]},"11":{"line":71,"type":"if","locations":[{"start":{"line":71,"column":8},"end":{"line":71,"column":8}},{"start":{"line":71,"column":8},"end":{"line":71,"column":8}}]},"12":{"line":137,"type":"if","locations":[{"start":{"line":137,"column":6},"end":{"line":137,"column":6}},{"start":{"line":137,"column":6},"end":{"line":137,"column":6}}]},"13":{"line":139,"type":"if","locations":[{"start":{"line":139,"column":10},"end":{"line":139,"column":10}},{"start":{"line":139,"column":10},"end":{"line":139,"column":10}}]},"14":{"line":145,"type":"if","locations":[{"start":{"line":145,"column":8},"end":{"line":145,"column":8}},{"start":{"line":145,"column":8},"end":{"line":145,"column":8}}]},"15":{"line":145,"type":"binary-expr","locations":[{"start":{"line":145,"column":12},"end":{"line":145,"column":29}},{"start":{"line":145,"column":33},"end":{"line":145,"column":54}}]},"16":{"line":147,"type":"if","locations":[{"start":{"line":147,"column":12},"end":{"line":147,"column":12}},{"start":{"line":147,"column":12},"end":{"line":147,"column":12}}]},"17":{"line":147,"type":"binary-expr","locations":[{"start":{"line":147,"column":16},"end":{"line":147,"column":42}},{"start":{"line":147,"column":46},"end":{"line":147,"column":77}}]},"18":{"line":157,"type":"if","locations":[{"start":{"line":157,"column":8},"end":{"line":157,"column":8}},{"start":{"line":157,"column":8},"end":{"line":157,"column":8}}]},"19":{"line":159,"type":"if","locations":[{"start":{"line":159,"column":12},"end":{"line":159,"column":12}},{"start":{"line":159,"column":12},"end":{"line":159,"column":12}}]},"20":{"line":171,"type":"if","locations":[{"start":{"line":171,"column":10},"end":{"line":171,"column":10}},{"start":{"line":171,"column":10},"end":{"line":171,"column":10}}]},"21":{"line":171,"type":"binary-expr","locations":[{"start":{"line":171,"column":15},"end":{"line":171,"column":21}},{"start":{"line":171,"column":27},"end":{"line":171,"column":63}},{"start":{"line":171,"column":69},"end":{"line":171,"column":100}}]},"22":{"line":200,"type":"cond-expr","locations":[{"start":{"line":200,"column":27},"end":{"line":200,"column":63}},{"start":{"line":200,"column":66},"end":{"line":200,"column":71}}]},"23":{"line":200,"type":"binary-expr","locations":[{"start":{"line":200,"column":27},"end":{"line":200,"column":41}},{"start":{"line":200,"column":45},"end":{"line":200,"column":63}}]},"24":{"line":214,"type":"cond-expr","locations":[{"start":{"line":214,"column":17},"end":{"line":214,"column":31}},{"start":{"line":214,"column":34},"end":{"line":214,"column":39}}]},"25":{"line":221,"type":"if","locations":[{"start":{"line":221,"column":48},"end":{"line":221,"column":48}},{"start":{"line":221,"column":48},"end":{"line":221,"column":48}}]},"26":{"line":237,"type":"if","locations":[{"start":{"line":237,"column":8},"end":{"line":237,"column":8}},{"start":{"line":237,"column":8},"end":{"line":237,"column":8}}]},"27":{"line":248,"type":"binary-expr","locations":[{"start":{"line":248,"column":13},"end":{"line":248,"column":34}},{"start":{"line":248,"column":38},"end":{"line":248,"column":47}}]},"28":{"line":262,"type":"if","locations":[{"start":{"line":262,"column":6},"end":{"line":262,"column":6}},{"start":{"line":262,"column":6},"end":{"line":262,"column":6}}]},"29":{"line":286,"type":"if","locations":[{"start":{"line":286,"column":6},"end":{"line":286,"column":6}},{"start":{"line":286,"column":6},"end":{"line":286,"column":6}}]},"30":{"line":288,"type":"binary-expr","locations":[{"start":{"line":288,"column":17},"end":{"line":288,"column":38}},{"start":{"line":288,"column":42},"end":{"line":288,"column":51}}]},"31":{"line":290,"type":"if","locations":[{"start":{"line":290,"column":13},"end":{"line":290,"column":13}},{"start":{"line":290,"column":13},"end":{"line":290,"column":13}}]},"32":{"line":292,"type":"if","locations":[{"start":{"line":292,"column":13},"end":{"line":292,"column":13}},{"start":{"line":292,"column":13},"end":{"line":292,"column":13}}]},"33":{"line":292,"type":"binary-expr","locations":[{"start":{"line":292,"column":17},"end":{"line":292,"column":27}},{"start":{"line":292,"column":31},"end":{"line":292,"column":40}}]},"34":{"line":295,"type":"binary-expr","locations":[{"start":{"line":295,"column":18},"end":{"line":295,"column":28}},{"start":{"line":295,"column":32},"end":{"line":295,"column":41}}]},"35":{"line":297,"type":"if","locations":[{"start":{"line":297,"column":13},"end":{"line":297,"column":13}},{"start":{"line":297,"column":13},"end":{"line":297,"column":13}}]},"36":{"line":362,"type":"cond-expr","locations":[{"start":{"line":362,"column":37},"end":{"line":362,"column":71}},{"start":{"line":362,"column":74},"end":{"line":362,"column":75}}]},"37":{"line":387,"type":"if","locations":[{"start":{"line":387,"column":6},"end":{"line":387,"column":6}},{"start":{"line":387,"column":6},"end":{"line":387,"column":6}}]},"38":{"line":409,"type":"if","locations":[{"start":{"line":409,"column":4},"end":{"line":409,"column":4}},{"start":{"line":409,"column":4},"end":{"line":409,"column":4}}]},"39":{"line":415,"type":"binary-expr","locations":[{"start":{"line":415,"column":20},"end":{"line":415,"column":21}},{"start":{"line":415,"column":25},"end":{"line":415,"column":28}},{"start":{"line":415,"column":32},"end":{"line":415,"column":62}}]},"40":{"line":420,"type":"if","locations":[{"start":{"line":420,"column":6},"end":{"line":420,"column":6}},{"start":{"line":420,"column":6},"end":{"line":420,"column":6}}]},"41":{"line":434,"type":"if","locations":[{"start":{"line":434,"column":4},"end":{"line":434,"column":4}},{"start":{"line":434,"column":4},"end":{"line":434,"column":4}}]},"42":{"line":434,"type":"binary-expr","locations":[{"start":{"line":434,"column":8},"end":{"line":434,"column":32}},{"start":{"line":434,"column":36},"end":{"line":434,"column":53}}]},"43":{"line":445,"type":"if","locations":[{"start":{"line":445,"column":4},"end":{"line":445,"column":4}},{"start":{"line":445,"column":4},"end":{"line":445,"column":4}}]},"44":{"line":445,"type":"binary-expr","locations":[{"start":{"line":445,"column":8},"end":{"line":445,"column":24}},{"start":{"line":445,"column":28},"end":{"line":445,"column":44}}]},"45":{"line":466,"type":"binary-expr","locations":[{"start":{"line":466,"column":11},"end":{"line":466,"column":16}},{"start":{"line":466,"column":20},"end":{"line":466,"column":48}}]},"46":{"line":472,"type":"if","locations":[{"start":{"line":472,"column":4},"end":{"line":472,"column":4}},{"start":{"line":472,"column":4},"end":{"line":472,"column":4}}]},"47":{"line":472,"type":"binary-expr","locations":[{"start":{"line":472,"column":8},"end":{"line":472,"column":14}},{"start":{"line":472,"column":18},"end":{"line":472,"column":41}}]},"48":{"line":481,"type":"if","locations":[{"start":{"line":481,"column":6},"end":{"line":481,"column":6}},{"start":{"line":481,"column":6},"end":{"line":481,"column":6}}]},"49":{"line":485,"type":"if","locations":[{"start":{"line":485,"column":6},"end":{"line":485,"column":6}},{"start":{"line":485,"column":6},"end":{"line":485,"column":6}}]},"50":{"line":486,"type":"if","locations":[{"start":{"line":486,"column":8},"end":{"line":486,"column":8}},{"start":{"line":486,"column":8},"end":{"line":486,"column":8}}]},"51":{"line":490,"type":"if","locations":[{"start":{"line":490,"column":8},"end":{"line":490,"column":8}},{"start":{"line":490,"column":8},"end":{"line":490,"column":8}}]},"52":{"line":497,"type":"cond-expr","locations":[{"start":{"line":497,"column":37},"end":{"line":497,"column":50}},{"start":{"line":497,"column":53},"end":{"line":497,"column":96}}]},"53":{"line":505,"type":"if","locations":[{"start":{"line":505,"column":4},"end":{"line":505,"column":4}},{"start":{"line":505,"column":4},"end":{"line":505,"column":4}}]},"54":{"line":521,"type":"if","locations":[{"start":{"line":521,"column":4},"end":{"line":521,"column":4}},{"start":{"line":521,"column":4},"end":{"line":521,"column":4}}]},"55":{"line":532,"type":"if","locations":[{"start":{"line":532,"column":4},"end":{"line":532,"column":4}},{"start":{"line":532,"column":4},"end":{"line":532,"column":4}}]},"56":{"line":543,"type":"if","locations":[{"start":{"line":543,"column":4},"end":{"line":543,"column":4}},{"start":{"line":543,"column":4},"end":{"line":543,"column":4}}]},"57":{"line":546,"type":"if","locations":[{"start":{"line":546,"column":6},"end":{"line":546,"column":6}},{"start":{"line":546,"column":6},"end":{"line":546,"column":6},"skip":true}]},"58":{"line":563,"type":"if","locations":[{"start":{"line":563,"column":4},"end":{"line":563,"column":4}},{"start":{"line":563,"column":4},"end":{"line":563,"column":4}}]},"59":{"line":564,"type":"if","locations":[{"start":{"line":564,"column":4},"end":{"line":564,"column":4}},{"start":{"line":564,"column":4},"end":{"line":564,"column":4}}]},"60":{"line":565,"type":"if","locations":[{"start":{"line":565,"column":6},"end":{"line":565,"column":6}},{"start":{"line":565,"column":6},"end":{"line":565,"column":6}}]},"61":{"line":568,"type":"if","locations":[{"start":{"line":568,"column":6},"end":{"line":568,"column":6}},{"start":{"line":568,"column":6},"end":{"line":568,"column":6}}]},"62":{"line":575,"type":"if","locations":[{"start":{"line":575,"column":2},"end":{"line":575,"column":2},"skip":true},{"start":{"line":575,"column":2},"end":{"line":575,"column":2},"skip":true}]},"63":{"line":575,"type":"binary-expr","locations":[{"start":{"line":575,"column":6},"end":{"line":575,"column":35},"skip":true},{"start":{"line":575,"column":39},"end":{"line":575,"column":76},"skip":true}]},"64":{"line":585,"type":"if","locations":[{"start":{"line":585,"column":2},"end":{"line":585,"column":2},"skip":true},{"start":{"line":585,"column":2},"end":{"line":585,"column":2},"skip":true}]}}}}
\ No newline at end of file
diff --git a/node_modules/sift/coverage/lcov.info b/node_modules/sift/coverage/lcov.info
new file mode 100644
index 0000000..0401d42
--- /dev/null
+++ b/node_modules/sift/coverage/lcov.info
@@ -0,0 +1,446 @@
+TN:
+SF:/Users/crcn/Developer/public/sift.js/sift.js
+FN:10,(anonymous_1)
+FN:17,isFunction
+FN:24,isArray
+FN:31,comparable
+FN:43,get
+FN:50,or
+FN:51,(anonymous_7)
+FN:65,and
+FN:66,(anonymous_9)
+FN:77,validate
+FN:86,(anonymous_11)
+FN:93,(anonymous_12)
+FN:100,(anonymous_13)
+FN:107,(anonymous_14)
+FN:114,(anonymous_15)
+FN:121,(anonymous_16)
+FN:128,(anonymous_17)
+FN:135,(anonymous_18)
+FN:185,(anonymous_19)
+FN:192,(anonymous_20)
+FN:199,(anonymous_21)
+FN:206,(anonymous_22)
+FN:213,(anonymous_23)
+FN:220,(anonymous_24)
+FN:228,(anonymous_25)
+FN:235,(anonymous_26)
+FN:247,(anonymous_27)
+FN:254,(anonymous_28)
+FN:261,(anonymous_29)
+FN:271,(anonymous_30)
+FN:284,(anonymous_31)
+FN:287,(anonymous_32)
+FN:294,(anonymous_33)
+FN:298,(anonymous_34)
+FN:304,(anonymous_35)
+FN:312,(anonymous_36)
+FN:319,(anonymous_37)
+FN:326,(anonymous_38)
+FN:333,(anonymous_39)
+FN:340,(anonymous_40)
+FN:347,(anonymous_41)
+FN:354,(anonymous_42)
+FN:361,(anonymous_43)
+FN:368,(anonymous_44)
+FN:375,(anonymous_45)
+FN:383,search
+FN:398,createValidator
+FN:405,nestedValidator
+FN:432,findValues
+FN:457,createNestedValidator
+FN:465,isVanillaObject
+FN:469,parse
+FN:503,createRootValidator
+FN:508,(anonymous_54)
+FN:519,sift
+FN:528,filter
+FN:542,(anonymous_57)
+FN:555,(anonymous_58)
+FN:562,(anonymous_59)
+FNF:59
+FNH:59
+FNDA:1,(anonymous_1)
+FNDA:1480,isFunction
+FNDA:3068,isArray
+FNDA:1895,comparable
+FNDA:1341,get
+FNDA:7,or
+FNDA:509,(anonymous_7)
+FNDA:1,and
+FNDA:57,(anonymous_9)
+FNDA:1076,validate
+FNDA:399,(anonymous_11)
+FNDA:59,(anonymous_12)
+FNDA:34,(anonymous_13)
+FNDA:15,(anonymous_14)
+FNDA:24,(anonymous_15)
+FNDA:10,(anonymous_16)
+FNDA:10,(anonymous_17)
+FNDA:99,(anonymous_18)
+FNDA:22,(anonymous_19)
+FNDA:15,(anonymous_20)
+FNDA:13,(anonymous_21)
+FNDA:18,(anonymous_22)
+FNDA:7,(anonymous_23)
+FNDA:32,(anonymous_24)
+FNDA:10,(anonymous_25)
+FNDA:58,(anonymous_26)
+FNDA:41,(anonymous_27)
+FNDA:6,(anonymous_28)
+FNDA:11,(anonymous_29)
+FNDA:25,(anonymous_30)
+FNDA:236,(anonymous_31)
+FNDA:41,(anonymous_32)
+FNDA:3,(anonymous_33)
+FNDA:5,(anonymous_34)
+FNDA:406,(anonymous_35)
+FNDA:18,(anonymous_36)
+FNDA:10,(anonymous_37)
+FNDA:6,(anonymous_38)
+FNDA:4,(anonymous_39)
+FNDA:2,(anonymous_40)
+FNDA:4,(anonymous_41)
+FNDA:21,(anonymous_42)
+FNDA:3,(anonymous_43)
+FNDA:5,(anonymous_44)
+FNDA:8,(anonymous_45)
+FNDA:8,search
+FNDA:378,createValidator
+FNDA:215,nestedValidator
+FNDA:706,findValues
+FNDA:92,createNestedValidator
+FNDA:413,isVanillaObject
+FNDA:443,parse
+FNDA:306,createRootValidator
+FNDA:4,(anonymous_54)
+FNDA:135,sift
+FNDA:413,filter
+FNDA:4,(anonymous_57)
+FNDA:2,(anonymous_58)
+FNDA:489,(anonymous_59)
+DA:10,1
+DA:17,1
+DA:18,1480
+DA:24,1
+DA:25,3068
+DA:31,1
+DA:32,1895
+DA:33,36
+DA:34,1859
+DA:35,45
+DA:36,1814
+DA:37,27
+DA:39,1787
+DA:43,1
+DA:44,1341
+DA:50,1
+DA:51,7
+DA:52,509
+DA:53,474
+DA:55,35
+DA:56,59
+DA:58,12
+DA:65,1
+DA:66,1
+DA:67,57
+DA:68,53
+DA:70,4
+DA:71,6
+DA:73,2
+DA:77,1
+DA:78,1076
+DA:81,1
+DA:87,399
+DA:94,59
+DA:101,34
+DA:108,15
+DA:115,24
+DA:122,10
+DA:129,10
+DA:137,99
+DA:138,10
+DA:139,11
+DA:140,8
+DA:144,89
+DA:145,89
+DA:146,8
+DA:147,12
+DA:148,1
+DA:157,88
+DA:158,22
+DA:159,24
+DA:160,1
+DA:168,87
+DA:169,169
+DA:170,169
+DA:171,169
+DA:172,34
+DA:176,53
+DA:179,2
+DA:186,22
+DA:193,15
+DA:200,13
+DA:207,18
+DA:214,7
+DA:221,64
+DA:222,11
+DA:229,10
+DA:236,58
+DA:237,98
+DA:238,27
+DA:241,31
+DA:248,41
+DA:255,6
+DA:262,11
+DA:263,6
+DA:265,5
+DA:272,25
+DA:279,1
+DA:286,236
+DA:287,19
+DA:288,41
+DA:290,217
+DA:291,1
+DA:292,216
+DA:294,1
+DA:295,3
+DA:297,215
+DA:298,4
+DA:300,5
+DA:304,211
+DA:305,406
+DA:313,18
+DA:320,10
+DA:327,6
+DA:334,4
+DA:341,2
+DA:348,4
+DA:355,21
+DA:362,3
+DA:369,5
+DA:376,8
+DA:383,1
+DA:385,8
+DA:386,15
+DA:387,15
+DA:388,5
+DA:392,3
+DA:398,1
+DA:399,378
+DA:405,1
+DA:406,215
+DA:407,215
+DA:409,215
+DA:410,179
+DA:411,179
+DA:415,36
+DA:416,36
+DA:417,36
+DA:418,114
+DA:419,114
+DA:420,114
+DA:421,8
+DA:423,106
+DA:426,36
+DA:432,1
+DA:434,706
+DA:436,293
+DA:437,293
+DA:440,413
+DA:445,413
+DA:446,41
+DA:447,119
+DA:450,372
+DA:457,1
+DA:458,92
+DA:465,1
+DA:466,413
+DA:469,1
+DA:470,443
+DA:472,443
+DA:473,215
+DA:476,443
+DA:478,443
+DA:479,458
+DA:481,458
+DA:482,2
+DA:485,456
+DA:486,363
+DA:487,363
+DA:490,93
+DA:491,1
+DA:493,92
+DA:497,442
+DA:503,1
+DA:504,306
+DA:505,305
+DA:506,3
+DA:509,4
+DA:513,305
+DA:519,1
+DA:521,135
+DA:522,1
+DA:523,1
+DA:526,135
+DA:528,1
+DA:529,413
+DA:532,134
+DA:533,33
+DA:536,101
+DA:542,1
+DA:543,4
+DA:544,3
+DA:546,3
+DA:547,3
+DA:555,1
+DA:556,2
+DA:562,1
+DA:563,489
+DA:564,363
+DA:565,284
+DA:566,151
+DA:568,133
+DA:569,133
+DA:575,1
+DA:576,1
+DA:580,1
+DA:581,1
+DA:585,1
+DA:586,1
+LF:189
+LH:189
+BRDA:32,1,0,36
+BRDA:32,1,1,1859
+BRDA:34,2,0,45
+BRDA:34,2,1,1814
+BRDA:36,3,0,27
+BRDA:36,3,1,1787
+BRDA:36,4,0,1814
+BRDA:36,4,1,1628
+BRDA:44,5,0,12
+BRDA:44,5,1,1329
+BRDA:52,6,0,474
+BRDA:52,6,1,35
+BRDA:52,7,0,509
+BRDA:52,7,1,36
+BRDA:56,8,0,23
+BRDA:56,8,1,36
+BRDA:67,9,0,53
+BRDA:67,9,1,4
+BRDA:67,10,0,57
+BRDA:67,10,1,4
+BRDA:71,11,0,2
+BRDA:71,11,1,4
+BRDA:137,12,0,10
+BRDA:137,12,1,89
+BRDA:139,13,0,8
+BRDA:139,13,1,3
+BRDA:145,14,0,8
+BRDA:145,14,1,81
+BRDA:145,15,0,89
+BRDA:145,15,1,85
+BRDA:147,16,0,1
+BRDA:147,16,1,11
+BRDA:147,17,0,12
+BRDA:147,17,1,7
+BRDA:157,18,0,22
+BRDA:157,18,1,66
+BRDA:159,19,0,1
+BRDA:159,19,1,23
+BRDA:171,20,0,34
+BRDA:171,20,1,135
+BRDA:171,21,0,169
+BRDA:171,21,1,37
+BRDA:171,21,2,36
+BRDA:200,22,0,12
+BRDA:200,22,1,1
+BRDA:200,23,0,12
+BRDA:200,23,1,11
+BRDA:214,24,0,6
+BRDA:214,24,1,1
+BRDA:221,25,0,21
+BRDA:221,25,1,43
+BRDA:237,26,0,27
+BRDA:237,26,1,71
+BRDA:248,27,0,41
+BRDA:248,27,1,30
+BRDA:262,28,0,6
+BRDA:262,28,1,5
+BRDA:286,29,0,19
+BRDA:286,29,1,217
+BRDA:288,30,0,41
+BRDA:288,30,1,25
+BRDA:290,31,0,1
+BRDA:290,31,1,216
+BRDA:292,32,0,1
+BRDA:292,32,1,215
+BRDA:292,33,0,216
+BRDA:292,33,1,1
+BRDA:295,34,0,3
+BRDA:295,34,1,1
+BRDA:297,35,0,4
+BRDA:297,35,1,211
+BRDA:362,36,0,2
+BRDA:362,36,1,1
+BRDA:387,37,0,5
+BRDA:387,37,1,10
+BRDA:409,38,0,179
+BRDA:409,38,1,36
+BRDA:415,39,0,36
+BRDA:415,39,1,36
+BRDA:415,39,2,36
+BRDA:420,40,0,8
+BRDA:420,40,1,106
+BRDA:434,41,0,293
+BRDA:434,41,1,413
+BRDA:434,42,0,706
+BRDA:434,42,1,414
+BRDA:445,43,0,41
+BRDA:445,43,1,372
+BRDA:445,44,0,413
+BRDA:445,44,1,45
+BRDA:466,45,0,413
+BRDA:466,45,1,413
+BRDA:472,46,0,215
+BRDA:472,46,1,228
+BRDA:472,47,0,443
+BRDA:472,47,1,413
+BRDA:481,48,0,2
+BRDA:481,48,1,456
+BRDA:485,49,0,363
+BRDA:485,49,1,93
+BRDA:486,50,0,294
+BRDA:486,50,1,69
+BRDA:490,51,0,1
+BRDA:490,51,1,92
+BRDA:497,52,0,427
+BRDA:497,52,1,15
+BRDA:505,53,0,3
+BRDA:505,53,1,302
+BRDA:521,54,0,1
+BRDA:521,54,1,134
+BRDA:532,55,0,33
+BRDA:532,55,1,101
+BRDA:543,56,0,1
+BRDA:543,56,1,3
+BRDA:546,57,0,3
+BRDA:546,57,1,0
+BRDA:563,58,0,126
+BRDA:563,58,1,363
+BRDA:564,59,0,284
+BRDA:564,59,1,79
+BRDA:565,60,0,151
+BRDA:565,60,1,133
+BRDA:568,61,0,133
+BRDA:568,61,1,0
+BRDA:575,62,0,1
+BRDA:575,62,1,0
+BRDA:575,63,0,1
+BRDA:575,63,1,1
+BRDA:585,64,0,0
+BRDA:585,64,1,1
+BRF:130
+BRH:129
+end_of_record
diff --git a/node_modules/sift/gulpfile.js b/node_modules/sift/gulpfile.js
new file mode 100644
index 0000000..19cd650
--- /dev/null
+++ b/node_modules/sift/gulpfile.js
@@ -0,0 +1,154 @@
+var gulp = require("gulp");
+var istanbul = require("gulp-istanbul");
+var mocha = require("gulp-mocha");
+var plumber = require("gulp-plumber");
+var jshint = require("gulp-jshint");
+var uglify = require("gulp-uglify");
+var jscs = require("gulp-jscs");
+var coveralls = require("gulp-coveralls");
+var rename = require("gulp-rename");
+var options = require("yargs").argv;
+
+var pkg = require("./package");
+
+/**
+ */
+
+var paths = {
+ testFiles : ["test/**/*-test.js"],
+ appFiles : ["sift.js"],
+ allFiles : ["test/**/*-test.js", "sift.js"]
+};
+
+/**
+ */
+
+var mochaOptions = {
+ bail : options.bail !== 'false',
+ reporter : options.reporter || 'dot',
+ grep : options.grep || options.only,
+ timeout : 500
+}
+
+/**
+ */
+
+gulp.task("test-coverage", function (complete) {
+ gulp.
+ src(paths.appFiles).
+ pipe(istanbul()).
+ pipe(istanbul.hookRequire()).
+ on("finish", function () {
+ gulp.
+ src(paths.testFiles).
+ pipe(plumber()).
+ pipe(mocha(mochaOptions)).
+ pipe(istanbul.writeReports({
+ reporters: ["text","text-summary", "lcov"]
+ })).
+ on("end", complete);
+ });
+});
+
+/**
+ */
+
+gulp.task("test-coveralls", ["test-coverage"], function () {
+ return gulp.
+ src("coverage/**/lcov.info").
+ pipe(coveralls());
+});
+/**
+ */
+
+gulp.task("minify", function() {
+ return gulp.
+ src("./" + pkg.name + ".js").
+ pipe(uglify()).
+ pipe(rename(function(path) {
+ path.basename += ".min";
+ })).
+ pipe(gulp.dest("./"));
+});
+
+/**
+ */
+
+gulp.task("lint", function() {
+ return gulp.run(["jshint", "jscs"]);
+});
+
+/**
+ */
+
+gulp.task("jscs", function() {
+ return gulp.
+ src(paths.allFiles).
+ pipe(jscs({
+ "preset": "google",
+ "requireParenthesesAroundIIFE": true,
+ "maximumLineLength": 200,
+ "validateLineBreaks": "LF",
+ "validateIndentation": 2,
+ "validateQuoteMarks": "\"",
+
+ "disallowKeywords": ["with"],
+ "disallowSpacesInsideObjectBrackets": null,
+ "disallowImplicitTypeConversion": ["string"],
+ "requireCurlyBraces": [],
+
+ "safeContextKeyword": "self"
+ }));
+});
+
+/**
+ */
+
+gulp.task("jshint", function() {
+ return gulp.
+ src(paths.allFiles).
+ pipe(jshint({
+ es3: true,
+ evil: true
+ })).
+ pipe(jshint.reporter('default'));
+});
+
+/**
+ */
+
+gulp.task("test", function (complete) {
+ gulp.
+ src(paths.testFiles, { read: false }).
+ pipe(plumber()).
+ pipe(mocha(mochaOptions)).
+ on("error", complete).
+ on("end", complete);
+});
+
+var iofwatch = process.argv.indexOf("watch");
+
+/**
+ * runs previous tasks (1 or more)
+ */
+
+gulp.task("watch", function () {
+ gulp.watch(paths.allFiles, process.argv.slice(2, iofwatch));
+});
+
+/**
+ */
+
+gulp.task("default", function () {
+ return gulp.run("test-coverage");
+});
+
+/**
+ */
+
+gulp.doneCallback = function (err) {
+
+ // a bit hacky, but fixes issue with testing where process
+ // doesn't exist process. Also fixes case where timeout / interval are set (CC)
+ if (!~iofwatch) process.exit(err ? 1 : 0);
+};
diff --git a/node_modules/sift/index.d.ts b/node_modules/sift/index.d.ts
new file mode 100644
index 0000000..c650df9
--- /dev/null
+++ b/node_modules/sift/index.d.ts
@@ -0,0 +1,62 @@
+export type SupportedTypes = Array;
+export type KeyOrValue = T & T[0];
+
+export type ElemMatch = {
+ [P in keyof T]?: SiftQuery;
+}
+
+export type Query = {
+ $eq?: T[0];
+ $ne?: T[0];
+ $or?: Array>;
+ $gt?: T[0];
+ $gte?: T[0];
+ $lt?: T[0];
+ $lte?: T[0];
+ $mod?: number[];
+ $in?: Array>;
+ $nin?: Array>;
+ $not?: SiftQuery;
+ $type?: any;
+ $all?: Array>;
+ $size?: number;
+ $nor?: Array>;
+ $and?: Array>;
+ $regex?: RegExp | string;
+ $elemMatch?: ExternalQuery;
+ $exists?: boolean;
+ $where?: string | WhereFn;
+ $options?: "i" | "g" | "m" | "u";
+}
+
+export interface InternalQuery extends Query {
+}
+
+export type ExternalQuery = ElemMatch;
+
+export type WhereFn = (this: T[0], value: T[0], index: number, array: T) => boolean;
+
+export type FilterFn = (value: T, index?: number, array?: T[]) => boolean;
+
+export type SiftQuery = ExternalQuery & InternalQuery;
+
+export type PluginDefinition = {
+ [index: string]: (a: T, b: T) => boolean | number;
+}
+
+export type PluginFunction = (sift: Sift) => PluginDefinition;
+
+export type Exec = (array: T) => T;
+
+export interface Sift {
+ (query: RegExp, target: T, rawSelector?: any): T;
+ (query: SiftQuery, rawSelector: (item: T) => boolean): Exec;
+ (query: SiftQuery): FilterFn;
+ (query: SiftQuery, target: T, rawSelector?: any): T;
+ indexOf(query: SiftQuery, target: T, rawSelector?: any): number;
+ compare(a: T, b: K): 0 | -1 | 1;
+}
+
+
+declare const Sift: Sift
+export default Sift
diff --git a/node_modules/sift/lib/index.js b/node_modules/sift/lib/index.js
new file mode 100644
index 0000000..5362098
--- /dev/null
+++ b/node_modules/sift/lib/index.js
@@ -0,0 +1,568 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.default = sift;
+exports.indexOf = indexOf;
+exports.compare = compare;
+/*
+ *
+ * Copryright 2018, Craig Condon
+ * Licensed under MIT
+ *
+ * Filter JavaScript objects with mongodb queries
+ */
+
+/**
+ */
+
+function isFunction(value) {
+ return typeof value === 'function';
+}
+
+/**
+ */
+
+function isArray(value) {
+ return Object.prototype.toString.call(value) === '[object Array]';
+}
+
+/**
+ */
+
+function comparable(value) {
+ if (value instanceof Date) {
+ return value.getTime();
+ } else if (isArray(value)) {
+ return value.map(comparable);
+ } else if (value && typeof value.toJSON === 'function') {
+ return value.toJSON();
+ } else {
+ return value;
+ }
+}
+
+function get(obj, key) {
+ return isFunction(obj.get) ? obj.get(key) : obj[key];
+}
+
+/**
+ */
+
+function or(validator) {
+ return function (a, b) {
+ if (!isArray(b) || !b.length) {
+ return validator(a, b);
+ }
+ for (var i = 0, n = b.length; i < n; i++) {
+ if (validator(a, get(b, i))) return true;
+ }
+ return false;
+ };
+}
+
+/**
+ */
+
+function and(validator) {
+ return function (a, b) {
+ if (!isArray(b) || !b.length) {
+ return validator(a, b);
+ }
+ for (var i = 0, n = b.length; i < n; i++) {
+ if (!validator(a, get(b, i))) return false;
+ }
+ return true;
+ };
+}
+
+function validate(validator, b, k, o) {
+ return validator.v(validator.a, b, k, o);
+}
+
+var OPERATORS = {
+
+ /**
+ */
+
+ $eq: or(function (a, b) {
+ return a(b);
+ }),
+
+ /**
+ */
+
+ $ne: and(function (a, b) {
+ return !a(b);
+ }),
+
+ /**
+ */
+
+ $gt: or(function (a, b) {
+ return compare(comparable(b), a) > 0;
+ }),
+
+ /**
+ */
+
+ $gte: or(function (a, b) {
+ return compare(comparable(b), a) >= 0;
+ }),
+
+ /**
+ */
+
+ $lt: or(function (a, b) {
+ return compare(comparable(b), a) < 0;
+ }),
+
+ /**
+ */
+
+ $lte: or(function (a, b) {
+ return compare(comparable(b), a) <= 0;
+ }),
+
+ /**
+ */
+
+ $mod: or(function (a, b) {
+ return b % a[0] == a[1];
+ }),
+
+ /**
+ */
+
+ $in: function $in(a, b) {
+
+ if (b instanceof Array) {
+ for (var i = b.length; i--;) {
+ if (~a.indexOf(comparable(get(b, i)))) {
+ return true;
+ }
+ }
+ } else {
+ var comparableB = comparable(b);
+ if (comparableB === b && (typeof b === 'undefined' ? 'undefined' : _typeof(b)) === 'object') {
+ for (var i = a.length; i--;) {
+ if (String(a[i]) === String(b) && String(b) !== '[object Object]') {
+ return true;
+ }
+ }
+ }
+
+ /*
+ Handles documents that are undefined, whilst also
+ having a 'null' element in the parameters to $in.
+ */
+ if (typeof comparableB == 'undefined') {
+ for (var i = a.length; i--;) {
+ if (a[i] == null) {
+ return true;
+ }
+ }
+ }
+
+ /*
+ Handles the case of {'field': {$in: [/regexp1/, /regexp2/, ...]}}
+ */
+ for (var i = a.length; i--;) {
+ var validator = createRootValidator(get(a, i), undefined);
+ var result = validate(validator, b, i, a);
+ if (result && String(result) !== '[object Object]' && String(b) !== '[object Object]') {
+ return true;
+ }
+ }
+
+ return !!~a.indexOf(comparableB);
+ }
+
+ return false;
+ },
+
+ /**
+ */
+
+ $nin: function $nin(a, b, k, o) {
+ return !OPERATORS.$in(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $not: function $not(a, b, k, o) {
+ return !validate(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $type: function $type(a, b) {
+ return b != void 0 ? b instanceof a || b.constructor == a : false;
+ },
+
+ /**
+ */
+
+ $all: function $all(a, b, k, o) {
+ return OPERATORS.$and(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $size: function $size(a, b) {
+ return b ? a === b.length : false;
+ },
+
+ /**
+ */
+
+ $or: function $or(a, b, k, o) {
+ for (var i = 0, n = a.length; i < n; i++) {
+ if (validate(get(a, i), b, k, o)) return true;
+ }return false;
+ },
+
+ /**
+ */
+
+ $nor: function $nor(a, b, k, o) {
+ return !OPERATORS.$or(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $and: function $and(a, b, k, o) {
+ for (var i = 0, n = a.length; i < n; i++) {
+ if (!validate(get(a, i), b, k, o)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /**
+ */
+
+ $regex: or(function (a, b) {
+ return typeof b === 'string' && a.test(b);
+ }),
+
+ /**
+ */
+
+ $where: function $where(a, b, k, o) {
+ return a.call(b, b, k, o);
+ },
+
+ /**
+ */
+
+ $elemMatch: function $elemMatch(a, b, k, o) {
+ if (isArray(b)) {
+ return !!~search(b, a);
+ }
+ return validate(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $exists: function $exists(a, b, k, o) {
+ return o.hasOwnProperty(k) === a;
+ }
+};
+
+/**
+ */
+
+var prepare = {
+
+ /**
+ */
+
+ $eq: function $eq(a) {
+
+ if (a instanceof RegExp) {
+ return function (b) {
+ return typeof b === 'string' && a.test(b);
+ };
+ } else if (a instanceof Function) {
+ return a;
+ } else if (isArray(a) && !a.length) {
+ // Special case of a == []
+ return function (b) {
+ return isArray(b) && !b.length;
+ };
+ } else if (a === null) {
+ return function (b) {
+ //will match both null and undefined
+ return b == null;
+ };
+ }
+
+ return function (b) {
+ return compare(comparable(b), comparable(a)) === 0;
+ };
+ },
+
+ /**
+ */
+
+ $ne: function $ne(a) {
+ return prepare.$eq(a);
+ },
+
+ /**
+ */
+
+ $and: function $and(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $all: function $all(a) {
+ return prepare.$and(a);
+ },
+
+ /**
+ */
+
+ $or: function $or(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $nor: function $nor(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $not: function $not(a) {
+ return parse(a);
+ },
+
+ /**
+ */
+
+ $regex: function $regex(a, query) {
+ return new RegExp(a, query.$options);
+ },
+
+ /**
+ */
+
+ $where: function $where(a) {
+ return typeof a === 'string' ? new Function('obj', 'return ' + a) : a;
+ },
+
+ /**
+ */
+
+ $elemMatch: function $elemMatch(a) {
+ return parse(a);
+ },
+
+ /**
+ */
+
+ $exists: function $exists(a) {
+ return !!a;
+ }
+};
+
+/**
+ */
+
+function search(array, validator) {
+
+ for (var i = 0; i < array.length; i++) {
+ var result = get(array, i);
+ if (validate(validator, get(array, i))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ */
+
+function createValidator(a, validate) {
+ return { a: a, v: validate };
+}
+
+/**
+ */
+
+function nestedValidator(a, b) {
+ var values = [];
+ findValues(b, a.k, 0, b, values);
+
+ if (values.length === 1) {
+ var first = values[0];
+ return validate(a.nv, first[0], first[1], first[2]);
+ }
+
+ // If the query contains $ne, need to test all elements ANDed together
+ var inclusive = a && a.q && typeof a.q.$ne !== 'undefined';
+ var allValid = inclusive;
+ for (var i = 0; i < values.length; i++) {
+ var result = values[i];
+ var isValid = validate(a.nv, result[0], result[1], result[2]);
+ if (inclusive) {
+ allValid &= isValid;
+ } else {
+ allValid |= isValid;
+ }
+ }
+ return allValid;
+}
+
+/**
+ */
+
+function findValues(current, keypath, index, object, values) {
+
+ if (index === keypath.length || current == void 0) {
+
+ values.push([current, keypath[index - 1], object]);
+ return;
+ }
+
+ var k = get(keypath, index);
+
+ // ensure that if current is an array, that the current key
+ // is NOT an array index. This sort of thing needs to work:
+ // sift({'foo.0':42}, [{foo: [42]}]);
+ if (isArray(current) && isNaN(Number(k))) {
+ for (var i = 0, n = current.length; i < n; i++) {
+ findValues(get(current, i), keypath, index, current, values);
+ }
+ } else {
+ findValues(get(current, k), keypath, index + 1, current, values);
+ }
+}
+
+/**
+ */
+
+function createNestedValidator(keypath, a, q) {
+ return { a: { k: keypath, nv: a, q: q }, v: nestedValidator };
+}
+
+/**
+ * flatten the query
+ */
+
+function isVanillaObject(value) {
+ return value && value.constructor === Object;
+}
+
+function parse(query) {
+ query = comparable(query);
+
+ if (!query || !isVanillaObject(query)) {
+ // cross browser support
+ query = { $eq: query };
+ }
+
+ var validators = [];
+
+ for (var key in query) {
+ var a = query[key];
+
+ if (key === '$options') {
+ continue;
+ }
+
+ if (OPERATORS[key]) {
+ if (prepare[key]) a = prepare[key](a, query);
+ validators.push(createValidator(comparable(a), OPERATORS[key]));
+ } else {
+
+ if (key.charCodeAt(0) === 36) {
+ throw new Error('Unknown operation ' + key);
+ }
+ validators.push(createNestedValidator(key.split('.'), parse(a), a));
+ }
+ }
+
+ return validators.length === 1 ? validators[0] : createValidator(validators, OPERATORS.$and);
+}
+
+/**
+ */
+
+function createRootValidator(query, getter) {
+ var validator = parse(query);
+ if (getter) {
+ validator = {
+ a: validator,
+ v: function v(a, b, k, o) {
+ return validate(a, getter(b), k, o);
+ }
+ };
+ }
+ return validator;
+}
+
+/**
+ */
+
+function sift(query, array, getter) {
+
+ if (isFunction(array)) {
+ getter = array;
+ array = void 0;
+ }
+
+ var validator = createRootValidator(query, getter);
+
+ function filter(b, k, o) {
+ return validate(validator, b, k, o);
+ }
+
+ if (array) {
+ return array.filter(filter);
+ }
+
+ return filter;
+}
+
+/**
+ */
+
+function indexOf(query, array, getter) {
+ return search(array, createRootValidator(query, getter));
+};
+
+/**
+ */
+
+function compare(a, b) {
+ if (a === b) return 0;
+ if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) === (typeof b === 'undefined' ? 'undefined' : _typeof(b))) {
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ }
+};
+
diff --git a/node_modules/sift/package.json b/node_modules/sift/package.json
new file mode 100644
index 0000000..bc59399
--- /dev/null
+++ b/node_modules/sift/package.json
@@ -0,0 +1,102 @@
+{
+ "_args": [
+ [
+ "sift@7.0.1",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "sift@7.0.1",
+ "_hasShrinkwrap": false,
+ "_id": "sift@7.0.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/sift",
+ "_nodeVersion": "8.11.3",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/sift_7.0.1_1539289401909_0.5103757017251642"
+ },
+ "_npmUser": {
+ "email": "craig.j.condon@gmail.com",
+ "name": "crcn"
+ },
+ "_npmVersion": "5.6.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "sift",
+ "raw": "sift@7.0.1",
+ "rawSpec": "7.0.1",
+ "scope": null,
+ "spec": "7.0.1",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
+ "_shasum": "47d62c50b159d316f1372f8b53f9c10cd21a4b08",
+ "_shrinkwrap": null,
+ "_spec": "sift@7.0.1",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "craig.j.condon@gmail.com",
+ "name": "Craig Condon",
+ "url": "http://crcn.io"
+ },
+ "bugs": {
+ "url": "https://github.com/crcn/sift.js/issues"
+ },
+ "dependencies": {},
+ "description": "mongodb query style array filtering",
+ "devDependencies": {
+ "babel-cli": "^6.26.0",
+ "babel-core": "^6.26.3",
+ "babel-preset-es2015": "^6.24.1",
+ "babel-preset-es2015-loose": "^8.0.0",
+ "bson": "^3.0.2",
+ "immutable": "^3.7.6",
+ "mocha": "^5.2.0",
+ "webpack": "^4.20.2",
+ "webpack-cli": "^3.1.2",
+ "yargs": "^3.15.0"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 22,
+ "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbv7E6CRA9TVsSAnZWagAAEBcP/A76+LgrjbUvFsqIRlmi\nf8bo2+RPfTa2rq288QWFnGspyXJu4KLTE8W62Wi+K4nA41AXjIMl8LnbYyFs\n7mxyJndYBHsQnPzpsLQD2g+Kcs/HbHju8Q4qoaWeKAflL3/l9CVqy67zeq9G\ngOfx8oYxq8UmAQAxa9sWq0ewpWDGSh8qI6d+GkISYJnmlIpiEG47YldhqOjm\n0wk0e0PBsGw2rB+QJkVYgOw5/OoNbzgJeqgzZACc9f6KM9/LtY084nfhmZ+0\nk1+K7d+z0q3toTbL2xnr2eb7NM0AagCs2T2e/i0E6Ns1W5UaFUtGCz6x2hpG\ndZ5Uxo1HuPHJHuI73/OfCd5hltvI9uGT18lkWC4lIo3vPcCY9ymAlAP97sfG\nzJWk1gtS5zBpoEW7LJG9n4QP8umtsZ4eoyUUwXnmi/ucJa1wTWxoYkwWO7sP\nznQJwTgTm2RH7ZDibX7Fz7nXkyZ1VazW9znoWT/YNUmgU/1/en8iblsQ9foB\n4FfUhkcXoanuhzDPUq9UNpMwMWBbaIP8fmsKjKwbU8d5gr3qikZHOKeVBYWK\npKOkdpI5fMSbtv51ygkH1JxxZVatyY5Jnyi5AcIkxzaiByBVEuahpx1WNJqL\nxNX629qVIBQmgSfc+JMKnAvhhhIDi3o7m2vDDIQ12gcKaOFZXjJsTnh5qdyF\nKTMD\r\n=Rcqv\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "47d62c50b159d316f1372f8b53f9c10cd21a4b08",
+ "tarball": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
+ "unpackedSize": 248862
+ },
+ "engines": {},
+ "es2015": "./src/index.js",
+ "gitHead": "8b1f4b93cdde39d870426082886d1862a0e353bb",
+ "homepage": "https://github.com/crcn/sift.js#readme",
+ "license": "MIT",
+ "main": "./lib/index.js",
+ "maintainers": [
+ {
+ "name": "architectd",
+ "email": "craig.j.condon@gmail.com"
+ },
+ {
+ "name": "crcn",
+ "email": "craig.j.condon@gmail.com"
+ }
+ ],
+ "module": "./src/index.js",
+ "name": "sift",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/crcn/sift.js.git"
+ },
+ "scripts": {
+ "build": "mkdir -p lib; babel src/index.js > lib/index.js; webpack",
+ "test": "mocha ./test -R spec --compilers js:babel-core/register"
+ },
+ "typings": "./index.d.ts",
+ "version": "7.0.1"
+}
diff --git a/node_modules/sift/sift.min.js b/node_modules/sift/sift.min.js
new file mode 100644
index 0000000..f82b7ae
--- /dev/null
+++ b/node_modules/sift/sift.min.js
@@ -0,0 +1 @@
+!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.sift=t():n.sift=t()}(window,function(){return function(n){var t={};function r(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:e})},r.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},r.t=function(n,t){if(1&t&&(n=r(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var o in n)r.d(e,o,function(t){return n[t]}.bind(null,o));return e},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=0)}([function(n,t,r){n.exports=r(1)},function(n,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};function o(n){return"function"==typeof n}function u(n){return"[object Array]"===Object.prototype.toString.call(n)}function i(n){return n instanceof Date?n.getTime():u(n)?n.map(i):n&&"function"==typeof n.toJSON?n.toJSON():n}function f(n,t){return o(n.get)?n.get(t):n[t]}function c(n){return function(t,r){if(!u(r)||!r.length)return n(t,r);for(var e=0,o=r.length;e0}),$gte:c(function(n,t){return b(i(t),n)>=0}),$lt:c(function(n,t){return b(i(t),n)<0}),$lte:c(function(n,t){return b(i(t),n)<=0}),$mod:c(function(n,t){return t%n[0]==n[1]}),$in:function(n,t){if(!(t instanceof Array)){var r=i(t);if(r===t&&"object"===(void 0===t?"undefined":e(t)))for(u=n.length;u--;)if(String(n[u])===String(t)&&"[object Object]"!==String(t))return!0;if(void 0===r)for(u=n.length;u--;)if(null==n[u])return!0;for(u=n.length;u--;){var o=l(y(f(n,u),void 0),t,u,n);if(o&&"[object Object]"!==String(o)&&"[object Object]"!==String(t))return!0}return!!~n.indexOf(r)}for(var u=t.length;u--;)if(~n.indexOf(i(f(t,u))))return!0;return!1},$nin:function(n,t,r,e){return!a.$in(n,t,r,e)},$not:function(n,t,r,e){return!l(n,t,r,e)},$type:function(n,t){return void 0!=t&&(t instanceof n||t.constructor==n)},$all:function(n,t,r,e){return a.$and(n,t,r,e)},$size:function(n,t){return!!t&&n===t.length},$or:function(n,t,r,e){for(var o=0,u=n.length;ot)return 1;if(n 0;
+ }),
+
+ /**
+ */
+
+ $gte: or(function(a, b) {
+ return compare(comparable(b), a) >= 0;
+ }),
+
+ /**
+ */
+
+ $lt: or(function(a, b) {
+ return compare(comparable(b), a) < 0;
+ }),
+
+ /**
+ */
+
+ $lte: or(function(a, b) {
+ return compare(comparable(b), a) <= 0;
+ }),
+
+ /**
+ */
+
+ $mod: or(function(a, b) {
+ return b % a[0] == a[1];
+ }),
+
+ /**
+ */
+
+ $in: function(a, b) {
+
+ if (b instanceof Array) {
+ for (var i = b.length; i--;) {
+ if (~a.indexOf(comparable(get(b, i)))) {
+ return true;
+ }
+ }
+ } else {
+ var comparableB = comparable(b);
+ if (comparableB === b && typeof b === 'object') {
+ for (var i = a.length; i--;) {
+ if (String(a[i]) === String(b) && String(b) !== '[object Object]') {
+ return true;
+ }
+ }
+ }
+
+ /*
+ Handles documents that are undefined, whilst also
+ having a 'null' element in the parameters to $in.
+ */
+ if (typeof comparableB == 'undefined') {
+ for (var i = a.length; i--;) {
+ if (a[i] == null) {
+ return true;
+ }
+ }
+ }
+
+ /*
+ Handles the case of {'field': {$in: [/regexp1/, /regexp2/, ...]}}
+ */
+ for (var i = a.length; i--;) {
+ var validator = createRootValidator(get(a, i), undefined);
+ var result = validate(validator, b, i, a);
+ if ((result) && (String(result) !== '[object Object]') && (String(b) !== '[object Object]')) {
+ return true;
+ }
+ }
+
+ return !!~a.indexOf(comparableB);
+ }
+
+ return false;
+ },
+
+ /**
+ */
+
+ $nin: function(a, b, k, o) {
+ return !OPERATORS.$in(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $not: function(a, b, k, o) {
+ return !validate(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $type: function(a, b) {
+ return b != void 0 ? b instanceof a || b.constructor == a : false;
+ },
+
+ /**
+ */
+
+ $all: function(a, b, k, o) {
+ return OPERATORS.$and(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $size: function(a, b) {
+ return b ? a === b.length : false;
+ },
+
+ /**
+ */
+
+ $or: function(a, b, k, o) {
+ for (var i = 0, n = a.length; i < n; i++) if (validate(get(a, i), b, k, o)) return true;
+ return false;
+ },
+
+ /**
+ */
+
+ $nor: function(a, b, k, o) {
+ return !OPERATORS.$or(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $and: function(a, b, k, o) {
+ for (var i = 0, n = a.length; i < n; i++) {
+ if (!validate(get(a, i), b, k, o)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /**
+ */
+
+ $regex: or(function(a, b) {
+ return typeof b === 'string' && a.test(b);
+ }),
+
+ /**
+ */
+
+ $where: function(a, b, k, o) {
+ return a.call(b, b, k, o);
+ },
+
+ /**
+ */
+
+ $elemMatch: function(a, b, k, o) {
+ if (isArray(b)) {
+ return !!~search(b, a);
+ }
+ return validate(a, b, k, o);
+ },
+
+ /**
+ */
+
+ $exists: function(a, b, k, o) {
+ return o.hasOwnProperty(k) === a;
+ }
+};
+
+/**
+ */
+
+var prepare = {
+
+ /**
+ */
+
+ $eq: function(a) {
+
+ if (a instanceof RegExp) {
+ return function(b) {
+ return typeof b === 'string' && a.test(b);
+ };
+ } else if (a instanceof Function) {
+ return a;
+ } else if (isArray(a) && !a.length) {
+ // Special case of a == []
+ return function(b) {
+ return (isArray(b) && !b.length);
+ };
+ } else if (a === null){
+ return function(b){
+ //will match both null and undefined
+ return b == null;
+ }
+ }
+
+ return function(b) {
+ return compare(comparable(b), comparable(a)) === 0;
+ };
+ },
+
+ /**
+ */
+
+ $ne: function(a) {
+ return prepare.$eq(a);
+ },
+
+ /**
+ */
+
+ $and: function(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $all: function(a) {
+ return prepare.$and(a);
+ },
+
+ /**
+ */
+
+ $or: function(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $nor: function(a) {
+ return a.map(parse);
+ },
+
+ /**
+ */
+
+ $not: function(a) {
+ return parse(a);
+ },
+
+ /**
+ */
+
+ $regex: function(a, query) {
+ return new RegExp(a, query.$options);
+ },
+
+ /**
+ */
+
+ $where: function(a) {
+ return typeof a === 'string' ? new Function('obj', 'return ' + a) : a;
+ },
+
+ /**
+ */
+
+ $elemMatch: function(a) {
+ return parse(a);
+ },
+
+ /**
+ */
+
+ $exists: function(a) {
+ return !!a;
+ }
+};
+
+/**
+ */
+
+function search(array, validator) {
+
+ for (var i = 0; i < array.length; i++) {
+ var result = get(array, i);
+ if (validate(validator, get(array, i))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ */
+
+function createValidator(a, validate) {
+ return { a: a, v: validate };
+}
+
+/**
+ */
+
+function nestedValidator(a, b) {
+ var values = [];
+ findValues(b, a.k, 0, b, values);
+
+ if (values.length === 1) {
+ var first = values[0];
+ return validate(a.nv, first[0], first[1], first[2]);
+ }
+
+ // If the query contains $ne, need to test all elements ANDed together
+ var inclusive = a && a.q && typeof a.q.$ne !== 'undefined';
+ var allValid = inclusive;
+ for (var i = 0; i < values.length; i++) {
+ var result = values[i];
+ var isValid = validate(a.nv, result[0], result[1], result[2]);
+ if (inclusive) {
+ allValid &= isValid;
+ } else {
+ allValid |= isValid;
+ }
+ }
+ return allValid;
+}
+
+/**
+ */
+
+function findValues(current, keypath, index, object, values) {
+
+ if (index === keypath.length || current == void 0) {
+
+ values.push([current, keypath[index - 1], object]);
+ return;
+ }
+
+ var k = get(keypath, index);
+
+ // ensure that if current is an array, that the current key
+ // is NOT an array index. This sort of thing needs to work:
+ // sift({'foo.0':42}, [{foo: [42]}]);
+ if (isArray(current) && isNaN(Number(k))) {
+ for (var i = 0, n = current.length; i < n; i++) {
+ findValues(get(current, i), keypath, index, current, values);
+ }
+ } else {
+ findValues(get(current, k), keypath, index + 1, current, values);
+ }
+}
+
+/**
+ */
+
+function createNestedValidator(keypath, a, q) {
+ return { a: { k: keypath, nv: a, q: q }, v: nestedValidator };
+}
+
+/**
+ * flatten the query
+ */
+
+function isVanillaObject(value) {
+ return value && value.constructor === Object;
+}
+
+function parse(query) {
+ query = comparable(query);
+
+ if (!query || !isVanillaObject(query)) { // cross browser support
+ query = { $eq: query };
+ }
+
+ var validators = [];
+
+ for (var key in query) {
+ var a = query[key];
+
+ if (key === '$options') {
+ continue;
+ }
+
+ if (OPERATORS[key]) {
+ if (prepare[key]) a = prepare[key](a, query);
+ validators.push(createValidator(comparable(a), OPERATORS[key]));
+ } else {
+
+ if (key.charCodeAt(0) === 36) {
+ throw new Error('Unknown operation ' + key);
+ }
+ validators.push(createNestedValidator(key.split('.'), parse(a), a));
+ }
+ }
+
+ return validators.length === 1 ? validators[0] : createValidator(validators, OPERATORS.$and);
+}
+
+/**
+ */
+
+function createRootValidator(query, getter) {
+ var validator = parse(query);
+ if (getter) {
+ validator = {
+ a: validator,
+ v: function(a, b, k, o) {
+ return validate(a, getter(b), k, o);
+ }
+ };
+ }
+ return validator;
+}
+
+/**
+ */
+
+export default function sift(query, array, getter) {
+
+ if (isFunction(array)) {
+ getter = array;
+ array = void 0;
+ }
+
+ var validator = createRootValidator(query, getter);
+
+ function filter(b, k, o) {
+ return validate(validator, b, k, o);
+ }
+
+ if (array) {
+ return array.filter(filter);
+ }
+
+ return filter;
+}
+
+/**
+ */
+
+export function indexOf(query, array, getter) {
+ return search(array, createRootValidator(query, getter));
+};
+
+/**
+ */
+
+export function compare(a, b) {
+ if(a===b) return 0;
+ if(typeof a === typeof b) {
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ }
+};
\ No newline at end of file
diff --git a/node_modules/sift/test/basic-test.js b/node_modules/sift/test/basic-test.js
new file mode 100644
index 0000000..799f0d0
--- /dev/null
+++ b/node_modules/sift/test/basic-test.js
@@ -0,0 +1,237 @@
+import * as assert from 'assert';
+import sift, {indexOf as siftIndexOf} from '..';
+
+describe(__filename + '#', function() {
+
+ it('doesn\'t sort arrays', function () {
+ var values = sift({
+ $or: [3, 2, 1]
+ }, [9,8,7,6,5,4,3,2,1]);
+
+
+ assert.equal(values.length, 3);
+ assert.equal(values[0], 3);
+ assert.equal(values[1], 2);
+ assert.equal(values[2], 1);
+ });
+
+ it('can create a custom selector, and use it', function () {
+ var sifter = sift({ age: { $gt: 5}}, function (item) {
+ return item.person;
+ });
+
+ var people = [{ person: { age: 6 }}],
+ filtered = people.filter(sifter);
+
+
+ assert.equal(filtered.length, 1);
+ assert.equal(filtered[0], people[0]);
+ });
+
+ it('throws an error if the operation is invalid', function () {
+
+ var err;
+ try {
+ sift({$aaa:1})('b');
+ } catch (e) {
+ err = e;
+ }
+
+ assert.equal(err.message, 'Unknown operation $aaa');
+
+ });
+
+ it('can use a custom selector as the 3rd param', function () {
+
+ var people = [{ person: { age: 6 }}];
+
+ var filtered = sift({ age: { $gt: 5}}, people, function (item) {
+ return item.person;
+ });
+
+ assert.equal(filtered.length, 1);
+ assert.equal(filtered[0], people[0]);
+ });
+
+ it('can get the first index of a matching element', function () {
+ var index = siftIndexOf({ val: { $gt: 5}}, [{val: 4}, {val: 3}, {val: 6}, {val: 7}]);
+
+ assert.equal(index, 2);
+ });
+
+ it('returns -1 as index if no matching element is found', function () {
+ var index = siftIndexOf({ val: { $gt: 7}}, [{val: 4}, {val: 3}, {val: 6}, {val: 7}]);
+
+ assert.equal(index, -1);
+ });
+
+ it('can match empty arrays', function () {
+ var statusQuery = {$or: [{status: {$exists: false}},
+ {status: []},
+ {status: {$in: ['urgent', 'completed', 'today']}}
+ ]};
+
+ var filtered = sift(statusQuery, [{ status: [] },
+ { status: ['urgent'] },
+ { status: ['nope'] }
+ ]);
+
+ assert.equal(filtered.length, 2);
+ });
+
+ it('$ne: null does not hit when field is present', function(){
+ var sifter = sift({age: {$ne: null}});
+
+ var people = [
+ {age: 'matched'},
+ {missed: 1}
+ ];
+ var filtered = people.filter(sifter);
+
+ assert.equal(filtered.length, 1);
+ assert.equal(filtered[0].age, 'matched');
+ });
+
+ it('$ne does not hit when field is different', function () {
+ var sifter = sift({ age: { $ne: 5 }});
+
+ var people = [{ age: 5 }],
+ filtered = people.filter(sifter);
+
+ assert.equal(filtered.length, 0);
+ });
+
+ it('$ne does hit when field exists with different value', function () {
+ var sifter = sift({ age: { $ne: 4 }});
+
+ var people = [{ age: 5 }],
+ filtered = people.filter(sifter);
+
+ assert.equal(filtered.length, 1);
+ });
+
+ it('$ne does hit when field does not exist', function(){
+ var sifter = sift({ age: { $ne: 5 }});
+
+ var people = [{}],
+ filtered = people.filter(sifter);
+
+ assert.equal(filtered.length, 1);
+ });
+
+ it('$eq matches objects that serialize to the same value', function() {
+ var counter = 0;
+ function Book(name) {
+ this.name = name;
+ this.copyNumber = counter;
+ this.toJSON = function() {
+ return this.name; // discard the copy when serializing.
+ };
+ counter += 1;
+ }
+
+ var warAndPeace = new Book('War and Peace');
+
+ var sifter = sift({ $eq: warAndPeace});
+
+ var books = [ new Book('War and Peace')];
+ var filtered = books.filter(sifter);
+
+ assert.equal(filtered.length, 1);
+ });
+
+ it('$neq does not match objects that serialize to the same value', function() {
+ var counter = 0;
+ function Book(name) {
+ this.name = name;
+ this.copyNumber = counter;
+ this.toJSON = function() {
+ return this.name; // discard the copy when serializing.
+ };
+ counter += 1;
+ }
+
+ var warAndPeace = new Book('War and Peace');
+
+ var sifter = sift({ $ne: warAndPeace});
+
+ var books = [ new Book('War and Peace')];
+ var filtered = books.filter(sifter);
+
+ assert.equal(filtered.length, 0);
+ });
+
+ // https://gist.github.com/jdnichollsc/00ea8cf1204b17d9fb9a991fbd1dfee6
+ it('returns a period between start and end dates', function() {
+
+ var product = {
+ 'productTypeCode': 'productTypeEnergy',
+ 'quantities': [
+ {
+ 'period': {
+ 'startDate': new Date('2017-01-13T05:00:00.000Z'),
+ 'endDate': new Date('2017-01-31T05:00:00.000Z'),
+ 'dayType': {
+ 'normal': true,
+ 'holiday': true
+ },
+ 'specificDays': [
+ 'monday',
+ 'wednesday',
+ 'friday'
+ ],
+ 'loadType': {
+ 'high': true,
+ 'medium': false,
+ 'low': false
+ }
+ },
+ 'type': 'DemandPercentage',
+ 'quantityValue': '44'
+ },
+ {
+ 'period': {
+ 'startDate': new Date('2017-01-13T05:00:00.000Z'),
+ 'endDate': new Date('2017-01-31T05:00:00.000Z'),
+ 'dayType': {
+ 'normal': true,
+ 'holiday': true
+ },
+ 'loadType': {
+ 'high': false,
+ 'medium': true,
+ 'low': false
+ }
+ },
+ 'type': 'Value',
+ 'quantityValue': '22'
+ }
+ ]
+ };
+
+ var period = {
+ 'startDate': new Date('2017-01-08T05:00:00.000Z'),
+ 'endDate': new Date('2017-01-29T05:00:00.000Z'),
+ 'dayType': {
+ 'normal': true,
+ 'holiday': true
+ },
+ 'loadType': {
+ 'high': true,
+ 'medium': false,
+ 'low': true
+ },
+ specificPeriods : ['3', '4', '5-10']
+ };
+
+
+ var results = sift({
+ $and: [
+ { 'period.startDate': { $lte : period.endDate } },
+ { 'period.endDate': { $gte : period.startDate } }
+ ]
+ }, product.quantities);
+
+ assert.equal(results.length, 2);
+ });
+});
diff --git a/node_modules/sift/test/immutable-test.js b/node_modules/sift/test/immutable-test.js
new file mode 100644
index 0000000..8685d30
--- /dev/null
+++ b/node_modules/sift/test/immutable-test.js
@@ -0,0 +1,20 @@
+import * as assert from 'assert';
+import * as Immutable from 'immutable';
+
+import sift from '..';
+const ObjectID = require('bson').ObjectID;
+
+describe(__filename + '#', function() {
+
+
+
+ var topic = Immutable.List([1, 2, 3, 4, 5, 6, 6, 4, 3]);
+
+
+ var persons = Immutable.fromJS([{ person: {age: 3} }, { person: {age: 5} }, { person: {age: 8} }]);
+
+ it('works with Immutable.Map in a Immutable.List', function() {
+ assert.equal(sift({ 'person.age' : { $gt: 4 } }, persons).size, 2);
+ assert.equal(persons.filter(sift({ 'person.age' : { $gt: 4 } })).size, 2);
+ });
+});
diff --git a/node_modules/sift/test/objects-test.js b/node_modules/sift/test/objects-test.js
new file mode 100755
index 0000000..951349b
--- /dev/null
+++ b/node_modules/sift/test/objects-test.js
@@ -0,0 +1,409 @@
+import assert from 'assert';
+import sift from '..';
+
+describe(__filename + '#', function () {
+
+
+ var topic = [
+ {
+ name: 'craig',
+ age: 90001,
+ tags: ['coder', 'programmer', 'traveler', 'photographer'],
+ address: {
+ city: 'Minneapolis',
+ state: 'MN',
+ phone: '9999999999'
+ },
+ tags: ['photos', 'cook'],
+ hobbies: [
+ {
+ name: 'programming',
+ description: 'some desc'
+ },
+ {
+ name: 'cooking'
+ },
+ {
+ name: 'photography',
+ places: ['haiti', 'brazil', 'costa rica']
+ },
+ {
+ name: 'backpacking'
+ }
+ ]
+ },
+ {
+ name: 'tim',
+ age: 90001,
+ tags: ['traveler', 'photographer'],
+ address: {
+ city: 'St. Paul',
+ state: 'MN',
+ phone: '765765756765'
+ },
+ tags: ['dj'],
+ hobbies: [
+ {
+ name: 'biking',
+ description: 'some desc'
+ },
+ {
+ name: 'DJ'
+ },
+ {
+ name: 'photography',
+ places: ['costa rica']
+ }
+ ]
+ }
+ ];
+ xit('throws error if $not is incorrect', function () {
+ assert.throws(function () {
+ sift({
+ $not: ['abc']
+ }, topic);
+ }, Error);
+ });
+ it('has sifted through photography in brazil count of 1', function () {
+ var sifted = sift({
+ hobbies: {
+ name: 'photography',
+ places: {
+ $in: ['brazil']
+ }
+ }
+ }, topic);
+ assert.equal(sifted.length, 1);
+ });
+ it('has sifted through photography in brazil, haiti, and costa rica count of 1', function () {
+ var sifted = sift({
+ hobbies: {
+ name: 'photography',
+ places: {
+ $all: ['brazil', 'haiti', 'costa rica']
+ }
+ }
+ }, topic);
+ assert.equal(sifted.length, 1);
+ assert.equal(sifted[0], topic[0]);
+ });
+ it('has a sifted hobbies of photography, cooking, or biking count of 2', function () {
+ var sifted = sift({
+ hobbies: {
+ name: {
+ $in: ['photography', 'cooking', 'biking']
+ }
+ }
+ }, topic);
+ assert.equal(sifted.length, 2);
+ });
+ it('has sifted to complex count of 2', function () {
+ var sifted = sift({
+ hobbies: {
+ name: 'photography',
+ places: {
+ $in: ['costa rica']
+ }
+ },
+ address: {
+ state: 'MN',
+ phone: {
+ $exists: true
+ }
+ }
+ }, topic);
+
+ assert.equal(sifted.length, 2);
+ });
+ it('has sifted to complex count of 0', function () {
+ var sifted = sift({
+ hobbies: {
+ name: 'photos',
+ places: {
+ $in: ['costa rica']
+ }
+ }
+ }, topic);
+ assert.equal(sifted.length, 0);
+ });
+ it('has sifted subobject hobbies count of 3', function () {
+ var sifted = sift({
+ 'hobbies.name': 'photography'
+ }, topic);
+ assert.equal(sifted.length, 2);
+ });
+ it('has sifted dot-notation hobbies of photography, cooking, and biking count of 3', function () {
+ var sifted = sift({
+ 'hobbies.name': {
+ $in: ['photography', 'cooking', 'biking']
+ }
+ }, topic);
+ assert.equal(sifted.length, 2);
+ });
+ it('has sifted to complex dot-search count of 2', function () {
+ var sifted = sift({
+ 'hobbies.name': 'photography',
+ 'hobbies.places': {
+ $in: ['costa rica']
+ },
+ 'address.state': 'MN',
+ 'address.phone': {
+ $exists: true
+ }
+ }, topic);
+ assert.equal(sifted.length, 2);
+ });
+ it('has sifted with selector function count of 2', function () {
+ var sifted = sift({
+ 'name': 'photography',
+ 'places': {
+ $in: ['costa rica']
+ }
+ }, topic, function (item) {
+ return item.hobbies;
+ });
+ assert.equal(sifted.length, 2);
+ });
+
+ describe('nesting', function () {
+ it('$eq for nested object', function () {
+ var sifted = sift({'sub.num': {'$eq': 10}}, loremArr);
+ assert(sifted.length > 0);
+ sifted.forEach(function (v) {
+ assert.equal(10, v.sub.num);
+ });
+ });
+
+ it('$ne for nested object', function () {
+ var sifted = sift({'sub.num': {'$ne': 10}}, loremArr);
+ assert(sifted.length > 0);
+ sifted.forEach(function (v) {
+ assert.notEqual(10, v.sub.num);
+ });
+ });
+
+ it('$regex for nested object (one missing key)', function () {
+ var persons = [{
+ id: 1,
+ prof: 'Mr. Moriarty'
+ }, {
+ id: 2,
+ prof: 'Mycroft Holmes'
+ }, {
+ id: 3,
+ name: 'Dr. Watson',
+ prof: 'Doctor'
+ }, {
+ id: 4,
+ name: 'Mr. Holmes',
+ prof: 'Detective'
+ }];
+ var q = { 'name': { '$regex': 'n' } };
+ var sifted = sift(q, persons);
+ assert.deepEqual(sifted, [{
+ id: 3,
+ name: 'Dr. Watson',
+ prof: 'Doctor'
+ }]);
+ });
+ });
+
+ describe('arrays of objects', function () {
+ var objects = [
+ {
+ things: [
+ {
+ id: 123
+ }, {
+ id: 456
+ }
+ ]
+ }, {
+ things: [
+ {
+ id: 123
+ },
+ {
+ id: 789
+ }
+ ]
+ }
+ ];
+ it('$eq for array of objects, matches if at least one exists', function () {
+ let q = {
+ 'things.id': 123
+ }
+ var sifted = sift(q, objects)
+ assert.deepEqual(sifted, objects)
+ let q2 = {
+ 'things.id': 789
+ }
+ var sifted2 = sift(q2, objects)
+ assert.deepEqual(sifted2, [objects[1]])
+ })
+ it('$ne for array of objects, returns if none of the array elements match the query', function () {
+ let q = {
+ 'things.id': {
+ $ne: 123
+ }
+ }
+ var sifted = sift(q, objects)
+ assert.deepEqual(sifted, [])
+ let q2 = {
+ 'things.id': {
+ $ne: 789
+ }
+ }
+ var sifted2 = sift(q2, objects)
+ assert.deepEqual(sifted2, [objects[0]])
+ })
+ })
+
+ describe('$where', function() {
+
+ var couples = [{
+ name: 'SMITH',
+ person: [{
+ firstName: 'craig',
+ gender: 'female',
+ age: 29
+ }, {
+ firstName: 'tim',
+ gender: 'male',
+ age: 32
+ }
+
+ ]
+ }, {
+ name: 'JOHNSON',
+ person: [{
+ firstName: 'emily',
+ gender: 'female',
+ age: 35
+ }, {
+ firstName: 'jacob',
+ gender: 'male',
+ age: 32
+ }
+
+ ]
+ }];
+
+ it('can filter people', function() {
+ var results = sift({'person': {$elemMatch: { 'gender': 'female', 'age': {'$lt': 30}}}}, couples);
+ assert.equal(results[0].name, 'SMITH');
+
+ var results = sift({'person': {$elemMatch: { 'gender': 'male', 'age': {'$lt': 30}}}}, [couples[0]]);
+ assert.equal(results.length, 0);
+ });
+ });
+
+ describe('keypath', function () {
+
+ var arr = [
+ {
+ a: {
+ b: {
+ c: 1,
+ c2: 1
+ }
+ }
+ }
+ ]
+ it('can be used', function () {
+ assert.equal(sift({'a.b.c':1})(arr[0]), true);
+ });
+ });
+});
+
+
+var loremArr = [
+ {
+ 'num': 1,
+ 'pum': 1,
+ 'sub': {
+ 'num': 1,
+ 'pum': 1
+ }
+ },
+ {
+ 'num': 2,
+ 'pum': 2,
+ 'sub': {
+ 'num': 2,
+ 'pum': 2
+ }
+ },
+ {
+ 'num': 3,
+ 'pum': 3,
+ 'sub': {
+ 'num': 3,
+ 'pum': 3
+ }
+ },
+ {
+ 'num': 4,
+ 'pum': 4,
+ 'sub': {
+ 'num': 4,
+ 'pum': 4
+ }
+ },
+ {
+ 'num': 5,
+ 'pum': 5,
+ 'sub': {
+ 'num': 5,
+ 'pum': 5
+ }
+ },
+ {
+ 'num': 6,
+ 'pum': 6,
+ 'sub': {
+ 'num': 6,
+ 'pum': 6
+ }
+ },
+ {
+ 'num': 7,
+ 'pum': 7,
+ 'sub': {
+ 'num': 7,
+ 'pum': 7
+ }
+ },
+ {
+ 'num': 8,
+ 'pum': 8,
+ 'sub': {
+ 'num': 8,
+ 'pum': 8
+ }
+ },
+ {
+ 'num': 9,
+ 'pum': 9,
+ 'sub': {
+ 'num': 9,
+ 'pum': 9
+ }
+ },
+ {
+ 'num': 10,
+ 'pum': 10,
+ 'sub': {
+ 'num': 10,
+ 'pum': 10
+ }
+ },
+ {
+ 'num': 11,
+ 'pum': 11,
+ 'sub': {
+ 'num': 10,
+ 'pum': 10
+ }
+ }
+];
diff --git a/node_modules/sift/test/operations-test.js b/node_modules/sift/test/operations-test.js
new file mode 100644
index 0000000..337600e
--- /dev/null
+++ b/node_modules/sift/test/operations-test.js
@@ -0,0 +1,203 @@
+import * as assert from 'assert';
+import sift from '..';
+var ObjectID = require('bson').ObjectID;
+
+describe(__filename + '#', function () {
+
+
+ [
+ // $eq
+ [{$eq:5}, [5,'5', 6], [5]],
+ ['5', [5,'5', 6], ['5']],
+ [false, [false,'false', true], [false]],
+ [true, [1, true], [true]],
+ [0, [0,'0'], [0]],
+ [null, [null], [null]],
+ [void 0, [void 0, null], [void 0]],
+ [1, [2,3,4,5], []],
+ [1, [[1]], [[1]]],
+ [new Date(1), [new Date(), new Date(1), new Date(2), new Date(3)], [new Date(1)]],
+ [/^a/, ['a','ab','abc','b','bc'], ['a','ab','abc']],
+
+ [function(b) { return b === 1; }, [1,2,3],[1]],
+
+ [ObjectID('54dd5546b1d296a54d152e84'),[ObjectID(),ObjectID('54dd5546b1d296a54d152e84')],[ObjectID('54dd5546b1d296a54d152e84')]],
+
+ // $ne
+ [{$ne:5}, [5, '5', 6], ['5', 6]],
+ [{$ne:'5'}, ['5', 6], [6]],
+ [{$ne:false}, [false], []],
+ [{$ne:void 0}, [false, 0, '0', void 0], [false, 0, '0']],
+ [{$ne:/^a/}, ['a','ab','abc','b','bc'], ['b','bc']],
+ [{$ne:1}, [[2],[1]], [[2]]],
+ [{groups:{$ne:111}}, [{groups:[111,222,333,444]},{groups:[222,333,444]}],[{groups:[222,333,444]}]],
+
+ // $lt
+ [{$lt:5}, [3,4,5,6],[3,4]],
+ [{$lt:'c'}, ['a','b','c'],['a','b']],
+ [{$lt:null}, [-3,-4], []],
+ [{$lt:new Date(3)}, [new Date(1), new Date(2), new Date(3)],[new Date(1), new Date(2)]],
+
+ // $lte
+ [{$lte:5}, [3,4,5,6],[3,4,5]],
+ [{groups:{$lt:5}}, [{groups:[1,2,3,4]}, {groups:[7,8]}], [{groups:[1,2,3,4]}]],
+
+ // $gt
+ [{$gt:5}, [3,4,5,6],[6]],
+ [{$gt:null}, [3,4], []],
+ [{groups:{$gt:5}}, [{groups:[1,2,3,4]}, {groups:[7,8]}], [{groups:[7,8]}]],
+
+ // $gte
+ [{$gte:5}, [3,4,5,6],[5, 6]],
+ [{groups:{$gte:5}}, [{groups:[1,2,3,4]}, {groups:[7,8]}], [{groups:[7,8]}]],
+
+ // $mod
+ [{$mod:[2,1]}, [1,2,3,4,5,6],[1,3,5]],
+ [{groups:{$mod:[2,0]}}, [{groups:[1,2,3,4]}, {groups:[7,9]}], [{groups:[1,2,3,4]}]],
+
+ // $exists
+ [{$exists:false}, [0,false,void 0, null],[]],
+ [{$exists:true}, [0,false,void 0, 1, {}],[0, false, void 0, 1, {}]],
+ [{'a.b': {$exists: true}}, [{a: {b: 'exists'}}, {a: {c: 'does not exist'}}], [{a: {b: 'exists'}}]],
+ [{field: { $exists: false }}, [{a: 1}, {a: 2, field: 5}, {a: 3, field: 0}, {a: 4, field: undefined}, {a: 5}],[{a: 1}, {a: 5}]],
+
+ // $in
+ // TODO - {$in:[Date]} doesn't work - make it work?
+ [{$in:[0,false,1,'1']},[0,1,2,3,4,false],[0,1,false]],
+ [{$in:[1,'1','2']},['1','2','3'],['1','2']],
+ [{$in:[new Date(1)]},[new Date(1), new Date(2)],[new Date(1)]],
+ [{'a.b.status':{'$in': [0]}}, [{'a':{'b':[{'status':0}]}},{'a':{'b':[{'status':2}]}}],[{'a':{'b':[{'status':0}]}}]],
+ [{'a.b.status':{'$in': [0, 2]}}, [{'a':{'b':[{'status':0}]}},{'a':{'b':[{'status':2}]}}], [{'a':{'b':[{'status':0}]}},{'a':{'b':[{'status':2}]}}]],
+ [{'x': {$in: [{$regex: '.*aaa.*'}, {$regex: '.*bbb.*'}]}}, [{'x': {'b': 'aaa'}}, {'x': 'bbb'}, {'x': 'ccc'}, {'x': 'aaa'}], [{'x': 'bbb'}, {'x': 'aaa'}]],
+ [{'x': {$in: [/.*aaa.*/, /.*bbb.*/]}}, [{'x': {'b': 'aaa'}}, {'x': 'bbb'}, {'x': 'ccc'}, {'x': 'aaa'}], [{'x': 'bbb'}, {'x': 'aaa'}]],
+
+ // $nin
+ [{$nin:[0,false,1,'1']},[0,1,2,3,4,false],[2,3,4]],
+ [{$nin:[1,'1','2']},['1','2','3'],['3']],
+ [{$nin:[new Date(1)]},[new Date(1), new Date(2)],[new Date(2)]],
+ [{'root.notDefined': {$nin: [1, 2, 3]}}, [{'root': {'defined': 1337}}], [{'root': {'defined': 1337}}]],
+ [{'root.notDefined': {$nin: [1, 2, 3, null]}}, [{'root': {'defined': 1337}}], []],
+ [{'x': {$nin: [{$regex: '.*aaa.*'}, {$regex: '.*bbb.*'}]}}, [{'x': {'b': 'aaa'}}, {'x': 'bbb'}, {'x': 'ccc'}, {'x': 'aaa'}], [{'x': {'b': 'aaa'}},{'x': 'ccc'}]],
+ [{'x': {$nin: [/.*aaa.*/, /.*bbb.*/]}}, [{'x': {'b': 'aaa'}}, {'x': 'bbb'}, {'x': 'ccc'}, {'x': 'aaa'}], [{'x': {'b': 'aaa'}},{'x': 'ccc'}]],
+
+ // $not
+ [{$not:false},[0,false],[0]],
+ [{$not:0},[0, false, 1, 2, 3],[false, 1, 2, 3]],
+ [{$not:{$in:[1,2,3]}},[1,2,3,4,5,6],[4,5,6]], // with expressions
+
+ // $type
+ [{$type:Date}, [0,new Date(1)],[new Date(1)]],
+ [{$type:Number}, [0,false,1],[0,1]],
+ [{$type:Boolean}, [0,false, void 0],[false]],
+ [{$type:String}, ['1',1,false],['1']],
+
+ // $all
+ [{$all:[1,2,3]},[[1,2,3,4],[1,2,4]],[[1,2,3,4]]],
+ [{$all:[0,false]},[[0,1,2],[0,false],['0','false'],void 0],[[0,false]]],
+ [{$all:['1']},[[1]],[]],
+ [{$all:[new Date(1),new Date(2)]},[[new Date(1), new Date(2)],[new Date(1)]],[[new Date(1), new Date(2)]]],
+
+ // $size
+ [{$size:3},['123',[1,2,3],'1'],['123',[1,2,3]]],
+ [{$size:1},['123',[1,2,3],'1', void 0],['1']],
+
+ // $or
+ [{$or:[1,2,3]},[1,2,3,4],[1,2,3]],
+ [{$or:[{$ne:1},2]},[1,2,3,4,5,6],[2,3,4,5,6]],
+
+ // $nor
+ [{$nor:[1,2,3]},[1,2,3,4],[4]],
+ [{$nor:[{$ne:1},2]},[1,2,3,4,5,6],[1]],
+
+ // $and
+ [{$and:[{$gt:1},{$lt:4}]},[1,2,3,4],[2,3]],
+ [{$and: [{field: {$not: {$type: String}}}, {field: {$ne: null}}]}, [{a: 1, field: 1}, {a: 2, field: '2'}], [{a: 1, field: 1}]],
+
+ // $regex
+ [{$regex:'^a'},['a','ab','abc','bc','bcd'],['a','ab','abc']],
+ [{a:{$regex:'b|c'}}, [{a:['b']},{a:['c']},{a:'c'},{a:'d'}], [{a:['b']},{a:['c']},{a:'c'}]],
+ [{ folder: { $regex:'^[0-9]{4}$' }}, [{ folder:['1234','3212'] }], [{ folder:['1234','3212'] }]],
+
+ // $options
+ [{$regex:'^a', $options: 'i'},['a','Ab','abc','bc','bcd'],['a','Ab','abc']],
+ [{'text':{'$regex':'.*lis.*','$options':'i'}}, [{text:['Bob','Melissa','Joe','Sherry']}], [{text:['Bob','Melissa','Joe','Sherry']}]],
+
+ // undefined
+ [{$regex:'a'},[undefined, null, true, false, 0, 'aa'],['aa']],
+ [/a/,[undefined, null, true, false, 0, 'aa'],['aa']],
+ [/.+/,[undefined, null, true, false, 0, 'aa', {}],['aa']],
+
+ // Multiple conditions on an undefined root
+ [{'a.b': {$exists: true, $nin: [null]}}, [{a: {b: 'exists'}}, {a: {c: 'does not exist'}}], [{a: {b: 'exists'}}]],
+
+ // $where
+ [{$where:function () { return this.v === 1 }}, [{v:1},{v:2}],[{v:1}]],
+ [{$where:'this.v === 1'}, [{v:1},{v:2}],[{v:1}]],
+ [{$where:'obj.v === 1'}, [{v:1},{v:2}],[{v:1}]],
+
+ // $elemMatch
+ //{'person': {'$elemMatch': {'gender': 'male', 'age': {'$lt': 30}}}}
+ [
+ {a:{$elemMatch:{b:1,c:2}}},
+ [{a:{b:1,c:2}},{a:[{b:1,c:2,d:3}]},{a:{b:2,c:3}}], [{a:{b:1,c:2}},{a:[{b:1,c:2,d:3}]}]
+ ],
+ [{a:{$elemMatch:{b:2,c:{$gt:2}}}}, [{a:{b:1,c:2}},{a:{b:1,c:2,d:3}},[{a:{b:2,c:3}}]], [[{a:{b:2,c:3}}]]],
+ [
+ {tags: {$all: [{$elemMatch: {a: 1}}]}},
+ [{tags: [{a: 1}]}, {tags: [{a: 1}, {b: 1}]}], [{tags: [{a: 1}]}, {tags: [{a: 1}, {b: 1}]}]
+ ],
+
+ // dot-notation
+ [
+ {'a.b': /c/ },
+ [{a:{b:'c'}}, {a:{b:'cd'}}, {'a.b':'c'},{a:{b:'e'}}],
+ [{a:{b:'c'}}, {a:{b:'cd'}}]
+ ],
+ [
+ {'foo.0': 'baz' },
+ [{foo:['bar', 'baz']}, {foo:['baz', 'bar']}],
+ [{foo:['baz', 'bar']}]
+ ],
+ [
+ {'foo.0.name': 'baz' },
+ [{foo:[{ name: 'bar' }, { name: 'baz' }]}, {foo:[{ name: 'baz' }, { name: 'bar' }]}],
+ [{foo:[{ name: 'baz' }, { name: 'bar' }]}]
+ ],
+
+ // object.toString() tests
+ [
+ { $in: [{ toString: function(){ return 'a'; }}]},
+ [{toString: function(){ return 'a'; }}, {toString: function(){ return 'b' }}],
+ [{toString: function(){ return 'a'; }}]
+ ],
+ [
+ { $in: [{}]},
+ [{}, {}],
+ []
+ ],
+
+ // various comparisons
+ [
+ { c: { d: 'd' }},
+ [{ a: 'b', b: 'c', c: { d: 'd', e: 'e' }}, { c: { d: 'e' }}],
+ [{ a: 'b', b: 'c', c: { d: 'd', e: 'e' }}]
+ ],
+
+ // based on https://gist.github.com/jdnichollsc/00ea8cf1204b17d9fb9a991fbd1dfee6
+ [
+ { $and: [{ 'a.s': { $lte: new Date('2017-01-29T05:00:00.000Z') }}, {'a.e': { $gte: new Date('2017-01-08T05:00:00.000Z') }}]},
+ [{ a: { s: new Date('2017-01-13T05:00:00.000Z'), e: new Date('2017-01-31T05:00:00.000Z') }}],
+ [{ a: { s: new Date('2017-01-13T05:00:00.000Z'), e: new Date('2017-01-31T05:00:00.000Z') }}]
+ ],
+
+ ].forEach(function (operation, i) {
+
+ var filter = operation[0];
+ var array = operation[1];
+ var matchArray = operation[2];
+
+ it(i + ': ' + JSON.stringify(filter), function() {
+ assert.equal(JSON.stringify(array.filter(sift(filter))), JSON.stringify(matchArray));
+ });
+ });
+});
diff --git a/node_modules/sift/tsconfig.json b/node_modules/sift/tsconfig.json
new file mode 100644
index 0000000..361020d
--- /dev/null
+++ b/node_modules/sift/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "moduleResolution": "node",
+ "module": "commonjs",
+ "allowSyntheticDefaultImports": true
+ }
+}
\ No newline at end of file
diff --git a/node_modules/sift/webpack.config.js b/node_modules/sift/webpack.config.js
new file mode 100644
index 0000000..4f08ab5
--- /dev/null
+++ b/node_modules/sift/webpack.config.js
@@ -0,0 +1,23 @@
+const {resolve} = require('path');
+const fs = require('fs');
+
+module.exports = {
+ devtool: 'none',
+ mode: 'production',
+ entry: {
+ index: [__dirname + '/lib/index.js']
+ },
+ output: {
+ path: __dirname,
+ library: 'sift',
+ libraryTarget: 'umd',
+ filename: 'sift.min.js'
+ },
+ resolve: {
+ extensions: ['.js']
+ },
+ module: {
+ rules: [
+ ]
+ }
+};
\ No newline at end of file
diff --git a/node_modules/sift/yarn.lock b/node_modules/sift/yarn.lock
new file mode 100644
index 0000000..09c676f
--- /dev/null
+++ b/node_modules/sift/yarn.lock
@@ -0,0 +1,4016 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@webassemblyjs/ast@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.8.tgz#f31f480debeef957f01b623f27eabc695fa4fe8f"
+ dependencies:
+ "@webassemblyjs/helper-module-context" "1.7.8"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.8"
+ "@webassemblyjs/wast-parser" "1.7.8"
+
+"@webassemblyjs/floating-point-hex-parser@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.8.tgz#1b3ed0e27e384032254e9322fc646dd3e70ef1b9"
+
+"@webassemblyjs/helper-api-error@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.8.tgz#a2b49c11f615e736f815ec927f035dcfa690d572"
+
+"@webassemblyjs/helper-buffer@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.8.tgz#3fc66bfa09c1c60e824cf3d5887826fac062877d"
+
+"@webassemblyjs/helper-code-frame@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.8.tgz#cc5a7e9522b70e7580df056dfd34020cf29645b0"
+ dependencies:
+ "@webassemblyjs/wast-printer" "1.7.8"
+
+"@webassemblyjs/helper-fsm@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.8.tgz#fe4607430af466912797c21acafd3046080182ea"
+
+"@webassemblyjs/helper-module-context@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.8.tgz#3c2e7ee93d14ff4768ba66fb1be42fdc9dc7160a"
+
+"@webassemblyjs/helper-wasm-bytecode@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.8.tgz#89bdb78cd6dd5209ae2ed2925de78d0f0e00b6f0"
+
+"@webassemblyjs/helper-wasm-section@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.8.tgz#c68ef7d26a6fc12421b2e6e56f9bc810dfb33e87"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-buffer" "1.7.8"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.8"
+ "@webassemblyjs/wasm-gen" "1.7.8"
+
+"@webassemblyjs/ieee754@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.8.tgz#1f37974b13cb486a9237e73ce04cac7a2f1265ed"
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.8.tgz#1bee83426819192db2ea1a234b84c7ebc6d34c1f"
+ dependencies:
+ "@xtuc/long" "4.2.1"
+
+"@webassemblyjs/utf8@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.8.tgz#2b489d5cf43e0aebb93d8e2d792aff9879c61f05"
+
+"@webassemblyjs/wasm-edit@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.8.tgz#f8bdbe7088718eca27b1c349bb7c06b8a457950c"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-buffer" "1.7.8"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.8"
+ "@webassemblyjs/helper-wasm-section" "1.7.8"
+ "@webassemblyjs/wasm-gen" "1.7.8"
+ "@webassemblyjs/wasm-opt" "1.7.8"
+ "@webassemblyjs/wasm-parser" "1.7.8"
+ "@webassemblyjs/wast-printer" "1.7.8"
+
+"@webassemblyjs/wasm-gen@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.8.tgz#7e8abf1545eae74ac6781d545c034af3cfd0c7d5"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.8"
+ "@webassemblyjs/ieee754" "1.7.8"
+ "@webassemblyjs/leb128" "1.7.8"
+ "@webassemblyjs/utf8" "1.7.8"
+
+"@webassemblyjs/wasm-opt@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.8.tgz#7ada6e211914728fce02ff0ff9c344edc6d41f26"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-buffer" "1.7.8"
+ "@webassemblyjs/wasm-gen" "1.7.8"
+ "@webassemblyjs/wasm-parser" "1.7.8"
+
+"@webassemblyjs/wasm-parser@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.8.tgz#dac47c291fb6a3e63529aecd647592cd34afbf94"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-api-error" "1.7.8"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.8"
+ "@webassemblyjs/ieee754" "1.7.8"
+ "@webassemblyjs/leb128" "1.7.8"
+ "@webassemblyjs/utf8" "1.7.8"
+
+"@webassemblyjs/wast-parser@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.8.tgz#f8aab9a450c048c1f9537695c89faeb92fabfba5"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/floating-point-hex-parser" "1.7.8"
+ "@webassemblyjs/helper-api-error" "1.7.8"
+ "@webassemblyjs/helper-code-frame" "1.7.8"
+ "@webassemblyjs/helper-fsm" "1.7.8"
+ "@xtuc/long" "4.2.1"
+
+"@webassemblyjs/wast-printer@1.7.8":
+ version "1.7.8"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.8.tgz#e7e965782c1912f6a965f14a53ff43d8ad0403a5"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/wast-parser" "1.7.8"
+ "@xtuc/long" "4.2.1"
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+
+"@xtuc/long@4.2.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8"
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+
+abbrev@1.0.x:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
+
+acorn-dynamic-import@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278"
+ dependencies:
+ acorn "^5.0.0"
+
+acorn@^5.0.0, acorn@^5.6.2:
+ version "5.7.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+
+ajv-keywords@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
+
+ajv@^5.3.0:
+ version "5.5.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
+ dependencies:
+ co "^4.6.0"
+ fast-deep-equal "^1.0.0"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.3.0"
+
+ajv@^6.1.0:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59"
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+amdefine@>=0.0.4:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ dependencies:
+ color-convert "^1.9.0"
+
+anymatch@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
+ dependencies:
+ micromatch "^2.1.5"
+ normalize-path "^2.0.0"
+
+anymatch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ dependencies:
+ micromatch "^3.1.4"
+ normalize-path "^2.1.1"
+
+aproba@^1.0.3, aproba@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+
+are-we-there-yet@~1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+ dependencies:
+ arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+
+array-unique@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+
+asn1.js@^4.0.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+ dependencies:
+ safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert@^1.1.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+ dependencies:
+ util "0.10.3"
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+
+async-each@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@1.x:
+ version "1.5.2"
+ resolved "http://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.5.0:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
+ dependencies:
+ lodash "^4.17.10"
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+atob@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+
+aws4@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
+
+babel-cli@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1"
+ dependencies:
+ babel-core "^6.26.0"
+ babel-polyfill "^6.26.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ commander "^2.11.0"
+ convert-source-map "^1.5.0"
+ fs-readdir-recursive "^1.0.0"
+ glob "^7.1.2"
+ lodash "^4.17.4"
+ output-file-sync "^1.1.2"
+ path-is-absolute "^1.0.1"
+ slash "^1.0.0"
+ source-map "^0.5.6"
+ v8flags "^2.1.1"
+ optionalDependencies:
+ chokidar "^1.6.1"
+
+babel-code-frame@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+ dependencies:
+ chalk "^1.1.3"
+ esutils "^2.0.2"
+ js-tokens "^3.0.2"
+
+babel-core@^6.26.0, babel-core@^6.26.3:
+ version "6.26.3"
+ resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-generator "^6.26.0"
+ babel-helpers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ convert-source-map "^1.5.1"
+ debug "^2.6.9"
+ json5 "^0.5.1"
+ lodash "^4.17.4"
+ minimatch "^3.0.4"
+ path-is-absolute "^1.0.1"
+ private "^0.1.8"
+ slash "^1.0.0"
+ source-map "^0.5.7"
+
+babel-generator@^6.26.0:
+ version "6.26.1"
+ resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
+ dependencies:
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ detect-indent "^4.0.0"
+ jsesc "^1.3.0"
+ lodash "^4.17.4"
+ source-map "^0.5.7"
+ trim-right "^1.0.1"
+
+babel-helper-call-delegate@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-define-map@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-helper-function-name@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
+ dependencies:
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-get-function-arity@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-hoist-variables@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-optimise-call-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-regex@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-helper-replace-supers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
+ dependencies:
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helpers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-messages@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-check-es2015-constants@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-arrow-functions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoping@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-plugin-transform-es2015-classes@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
+ dependencies:
+ babel-helper-define-map "^6.24.1"
+ babel-helper-function-name "^6.24.1"
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-helper-replace-supers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-computed-properties@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-destructuring@^6.22.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-for-of@^6.22.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-function-name@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-literals@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-modules-amd@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
+ dependencies:
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
+ version "6.26.2"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3"
+ dependencies:
+ babel-plugin-transform-strict-mode "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-types "^6.26.0"
+
+babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-modules-umd@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
+ dependencies:
+ babel-plugin-transform-es2015-modules-amd "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-object-super@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
+ dependencies:
+ babel-helper-replace-supers "^6.24.1"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-parameters@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
+ dependencies:
+ babel-helper-call-delegate "^6.24.1"
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-spread@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-sticky-regex@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
+ dependencies:
+ babel-helper-regex "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-template-literals@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-unicode-regex@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
+ dependencies:
+ babel-helper-regex "^6.24.1"
+ babel-runtime "^6.22.0"
+ regexpu-core "^2.0.0"
+
+babel-plugin-transform-regenerator@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
+ dependencies:
+ regenerator-transform "^0.10.0"
+
+babel-plugin-transform-strict-mode@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-polyfill@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
+ dependencies:
+ babel-runtime "^6.26.0"
+ core-js "^2.5.0"
+ regenerator-runtime "^0.10.5"
+
+babel-preset-es2015-loose@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-es2015-loose/-/babel-preset-es2015-loose-8.0.0.tgz#82ee293ab31329c7a94686b644b62adfbcdc3f57"
+ dependencies:
+ modify-babel-preset "^3.1.0"
+
+babel-preset-es2015@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
+ dependencies:
+ babel-plugin-check-es2015-constants "^6.22.0"
+ babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoping "^6.24.1"
+ babel-plugin-transform-es2015-classes "^6.24.1"
+ babel-plugin-transform-es2015-computed-properties "^6.24.1"
+ babel-plugin-transform-es2015-destructuring "^6.22.0"
+ babel-plugin-transform-es2015-duplicate-keys "^6.24.1"
+ babel-plugin-transform-es2015-for-of "^6.22.0"
+ babel-plugin-transform-es2015-function-name "^6.24.1"
+ babel-plugin-transform-es2015-literals "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.24.1"
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
+ babel-plugin-transform-es2015-modules-systemjs "^6.24.1"
+ babel-plugin-transform-es2015-modules-umd "^6.24.1"
+ babel-plugin-transform-es2015-object-super "^6.24.1"
+ babel-plugin-transform-es2015-parameters "^6.24.1"
+ babel-plugin-transform-es2015-shorthand-properties "^6.24.1"
+ babel-plugin-transform-es2015-spread "^6.22.0"
+ babel-plugin-transform-es2015-sticky-regex "^6.24.1"
+ babel-plugin-transform-es2015-template-literals "^6.22.0"
+ babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
+ babel-plugin-transform-es2015-unicode-regex "^6.24.1"
+ babel-plugin-transform-regenerator "^6.24.1"
+
+babel-register@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
+ dependencies:
+ babel-core "^6.26.0"
+ babel-runtime "^6.26.0"
+ core-js "^2.5.0"
+ home-or-tmp "^2.0.0"
+ lodash "^4.17.4"
+ mkdirp "^0.5.1"
+ source-map-support "^0.4.15"
+
+babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+ dependencies:
+ core-js "^2.4.0"
+ regenerator-runtime "^0.11.0"
+
+babel-template@^6.24.1, babel-template@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ lodash "^4.17.4"
+
+babel-traverse@^6.24.1, babel-traverse@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ debug "^2.6.8"
+ globals "^9.18.0"
+ invariant "^2.2.2"
+ lodash "^4.17.4"
+
+babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+ dependencies:
+ babel-runtime "^6.26.0"
+ esutils "^2.0.2"
+ lodash "^4.17.4"
+ to-fast-properties "^1.0.3"
+
+babel@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel/-/babel-6.23.0.tgz#d0d1e7d803e974765beea3232d4e153c0efb90f4"
+
+babylon@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
+base64-js@^1.0.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+ dependencies:
+ tweetnacl "^0.14.3"
+
+benchmark@^1.0.0:
+ version "1.0.0"
+ resolved "http://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz#2f1e2fa4c359f11122aa183082218e957e390c73"
+
+big.js@^3.1.3:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
+
+binary-extensions@^1.0.0:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
+
+bluebird@^3.5.1:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^1.8.2:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+ dependencies:
+ expand-range "^1.8.1"
+ preserve "^0.2.0"
+ repeat-element "^1.1.2"
+
+braces@^2.3.0, braces@^2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+brorand@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-stdout@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+ version "1.2.0"
+ resolved "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+ dependencies:
+ buffer-xor "^1.0.3"
+ cipher-base "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.3"
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+browserify-cipher@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
+ dependencies:
+ browserify-aes "^1.0.4"
+ browserify-des "^1.0.0"
+ evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+ dependencies:
+ cipher-base "^1.0.1"
+ des.js "^1.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
+browserify-rsa@^4.0.0:
+ version "4.0.1"
+ resolved "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+ dependencies:
+ bn.js "^4.1.0"
+ randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+ dependencies:
+ bn.js "^4.1.1"
+ browserify-rsa "^4.0.0"
+ create-hash "^1.1.0"
+ create-hmac "^1.1.2"
+ elliptic "^6.0.0"
+ inherits "^2.0.1"
+ parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
+ dependencies:
+ pako "~1.0.5"
+
+bson@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/bson/-/bson-3.0.2.tgz#2467a76507a98c63ce34072f9965f4024e753dfc"
+
+buffer-from@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+
+buffer-xor@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+ version "4.9.1"
+ resolved "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+ isarray "^1.0.0"
+
+builtin-status-codes@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+cacache@^10.0.4:
+ version "10.0.4"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460"
+ dependencies:
+ bluebird "^3.5.1"
+ chownr "^1.0.1"
+ glob "^7.1.2"
+ graceful-fs "^4.1.11"
+ lru-cache "^4.1.1"
+ mississippi "^2.0.0"
+ mkdirp "^0.5.1"
+ move-concurrently "^1.0.1"
+ promise-inflight "^1.0.1"
+ rimraf "^2.6.2"
+ ssri "^5.2.4"
+ unique-filename "^1.1.0"
+ y18n "^4.0.0"
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+camelcase@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+
+camelcase@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+chalk@^1.0.0, chalk@^1.1.3:
+ version "1.1.3"
+ resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chokidar@^1.6.1:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+ dependencies:
+ anymatch "^1.3.0"
+ async-each "^1.0.0"
+ glob-parent "^2.0.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^2.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ optionalDependencies:
+ fsevents "^1.0.0"
+
+chokidar@^2.0.2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.0"
+ braces "^2.3.0"
+ glob-parent "^3.1.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ lodash.debounce "^4.0.8"
+ normalize-path "^2.1.1"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ upath "^1.0.5"
+ optionalDependencies:
+ fsevents "^1.2.2"
+
+chownr@^1.0.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
+
+chrome-trace-event@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48"
+ dependencies:
+ tslib "^1.9.0"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+cliui@^3.0.3:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wrap-ansi "^2.0.0"
+
+cliui@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
+ dependencies:
+ string-width "^2.1.1"
+ strip-ansi "^4.0.0"
+ wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+
+combined-stream@1.0.6:
+ version "1.0.6"
+ resolved "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
+ dependencies:
+ delayed-stream "~1.0.0"
+
+combined-stream@~1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@2.15.1:
+ version "2.15.1"
+ resolved "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
+
+commander@^2.11.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+
+commander@~2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
+
+commander@~2.17.1:
+ version "2.17.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+
+commondir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+
+component-emitter@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+concat-stream@^1.5.0:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+configstore@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-0.3.2.tgz#25e4c16c3768abf75c5a65bc61761f495055b459"
+ dependencies:
+ graceful-fs "^3.0.1"
+ js-yaml "^3.1.0"
+ mkdirp "^0.5.0"
+ object-assign "^2.0.0"
+ osenv "^0.1.0"
+ user-home "^1.0.0"
+ uuid "^2.0.1"
+ xdg-basedir "^1.0.0"
+
+console-browserify@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+ dependencies:
+ date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+convert-source-map@^1.5.0, convert-source-map@^1.5.1:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
+ dependencies:
+ safe-buffer "~5.1.1"
+
+copy-concurrently@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
+ dependencies:
+ aproba "^1.1.1"
+ fs-write-stream-atomic "^1.0.8"
+ iferr "^0.1.5"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.0"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+
+core-js@^2.4.0, core-js@^2.5.0:
+ version "2.5.7"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+coveralls@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.2.tgz#f5a0bcd90ca4e64e088b710fa8dda640aea4884f"
+ dependencies:
+ growl "~> 1.10.0"
+ js-yaml "^3.11.0"
+ lcov-parse "^0.0.10"
+ log-driver "^1.2.7"
+ minimist "^1.2.0"
+ request "^2.85.0"
+
+create-ecdh@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
+ dependencies:
+ bn.js "^4.1.0"
+ elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.2:
+ version "1.2.0"
+ resolved "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ dependencies:
+ cipher-base "^1.0.1"
+ inherits "^2.0.1"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
+ sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+ version "1.1.7"
+ resolved "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ dependencies:
+ cipher-base "^1.0.3"
+ create-hash "^1.1.0"
+ inherits "^2.0.1"
+ ripemd160 "^2.0.0"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+ dependencies:
+ nice-try "^1.0.4"
+ path-key "^2.0.1"
+ semver "^5.5.0"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+crypto-browserify@^3.11.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
+ dependencies:
+ browserify-cipher "^1.0.0"
+ browserify-sign "^4.0.0"
+ create-ecdh "^4.0.0"
+ create-hash "^1.1.0"
+ create-hmac "^1.1.0"
+ diffie-hellman "^5.0.0"
+ inherits "^2.0.1"
+ pbkdf2 "^3.0.3"
+ public-encrypt "^4.0.0"
+ randombytes "^2.0.0"
+ randomfill "^1.0.3"
+
+cyclist@~0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
+
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ dependencies:
+ assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ dependencies:
+ ms "2.0.0"
+
+debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ dependencies:
+ ms "2.0.0"
+
+decamelize@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+decamelize@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
+ dependencies:
+ xregexp "4.0.0"
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+
+deep-is@~0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+ dependencies:
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+ dependencies:
+ repeating "^2.0.0"
+
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+
+diff@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+
+diffie-hellman@^5.0.0:
+ version "5.0.3"
+ resolved "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
+ dependencies:
+ bn.js "^4.1.0"
+ miller-rabin "^4.0.0"
+ randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
+
+duplexify@^3.2.0, duplexify@^3.4.2, duplexify@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410"
+ dependencies:
+ end-of-stream "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+ stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+ dependencies:
+ jsbn "~0.1.0"
+ safer-buffer "^2.1.0"
+
+elliptic@^6.0.0:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a"
+ dependencies:
+ bn.js "^4.4.0"
+ brorand "^1.0.1"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+ dependencies:
+ once "^1.4.0"
+
+enhanced-resolve@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
+ dependencies:
+ graceful-fs "^4.1.2"
+ memory-fs "^0.4.0"
+ tapable "^1.0.0"
+
+errno@^0.1.3, errno@~0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+ dependencies:
+ prr "~1.0.1"
+
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@1.8.x:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+ dependencies:
+ esprima "^2.7.1"
+ estraverse "^1.9.1"
+ esutils "^2.0.2"
+ optionator "^0.8.1"
+ optionalDependencies:
+ source-map "~0.2.0"
+
+eslint-scope@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+esprima@2.7.x, esprima@^2.7.1:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^1.9.1:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+estraverse@^4.1.0, estraverse@^4.1.1:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+
+esutils@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+event-stream@~0.5:
+ version "0.5.3"
+ resolved "http://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz#b77b9309f7107addfeab63f0c0eafd8db0bd8c1c"
+ dependencies:
+ optimist "0.2"
+
+events@^1.0.0:
+ version "1.1.1"
+ resolved "http://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
+ dependencies:
+ md5.js "^1.3.4"
+ safe-buffer "^5.1.1"
+
+execa@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
+ dependencies:
+ cross-spawn "^6.0.0"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+ dependencies:
+ is-posix-bracket "^0.1.0"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+expand-range@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+ dependencies:
+ fill-range "^2.1.0"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+
+extglob@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+ dependencies:
+ is-extglob "^1.0.0"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+extsprintf@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+
+extsprintf@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+
+fast-deep-equal@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
+
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+
+fast-levenshtein@~2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+filename-regex@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+
+fill-range@^2.1.0:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+ dependencies:
+ is-number "^2.1.0"
+ isobject "^2.0.0"
+ randomatic "^3.0.0"
+ repeat-element "^1.1.2"
+ repeat-string "^1.5.2"
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+find-cache-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
+ dependencies:
+ commondir "^1.0.1"
+ make-dir "^1.0.0"
+ pkg-dir "^2.0.0"
+
+find-up@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+ dependencies:
+ locate-path "^2.0.0"
+
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ dependencies:
+ locate-path "^3.0.0"
+
+flush-write-stream@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.4"
+
+for-in@^1.0.1, for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+ dependencies:
+ for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "1.0.6"
+ mime-types "^2.1.12"
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ dependencies:
+ map-cache "^0.2.2"
+
+from2@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+
+fs-minipass@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
+ dependencies:
+ minipass "^2.2.1"
+
+fs-readdir-recursive@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
+
+fs-write-stream-atomic@^1.0.8:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
+ dependencies:
+ graceful-fs "^4.1.2"
+ iferr "^0.1.5"
+ imurmurhash "^0.1.4"
+ readable-stream "1 || 2"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0, fsevents@^1.2.2:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
+ dependencies:
+ nan "^2.9.2"
+ node-pre-gyp "^0.10.0"
+
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+
+get-stream@^3.0.0:
+ version "3.0.0"
+ resolved "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+
+getpass@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+ dependencies:
+ assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+ dependencies:
+ glob-parent "^2.0.0"
+ is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+ dependencies:
+ is-glob "^2.0.0"
+
+glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob@7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^5.0.15:
+ version "5.0.15"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "2 || 3"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^7.0.5, glob@^7.1.2:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-modules-path@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc"
+
+globals@^9.18.0:
+ version "9.18.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+
+got@^3.2.0:
+ version "3.3.1"
+ resolved "http://registry.npmjs.org/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
+ dependencies:
+ duplexify "^3.2.0"
+ infinity-agent "^2.0.0"
+ is-redirect "^1.0.0"
+ is-stream "^1.0.0"
+ lowercase-keys "^1.0.0"
+ nested-error-stacks "^1.0.0"
+ object-assign "^3.0.0"
+ prepend-http "^1.0.0"
+ read-all-stream "^3.0.0"
+ timed-out "^2.0.0"
+
+graceful-fs@^3.0.1:
+ version "3.0.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
+ dependencies:
+ natives "^1.1.0"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growl@1.10.5, "growl@~> 1.10.0":
+ version "1.10.5"
+ resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
+
+handlebars@^4.0.1:
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
+ dependencies:
+ async "^2.5.0"
+ optimist "^0.6.1"
+ source-map "^0.6.1"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+
+har-validator@~5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29"
+ dependencies:
+ ajv "^5.3.0"
+ har-schema "^2.0.0"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+hash-base@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812"
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.1"
+
+he@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
+
+hmac-drbg@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
+home-or-tmp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.1"
+
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+https-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+
+iconv-lite@^0.4.4:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.1.4:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
+
+iferr@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
+
+ignore-walk@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+ dependencies:
+ minimatch "^3.0.4"
+
+immutable@^3.7.6:
+ version "3.8.2"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
+
+import-local@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
+ dependencies:
+ pkg-dir "^3.0.0"
+ resolve-cwd "^2.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+
+indexof@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+infinity-agent@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+
+interpret@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
+
+invariant@^2.2.2:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ dependencies:
+ loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+invert-kv@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
+
+is-accessor-descriptor@^0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-binary-path@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+ dependencies:
+ binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+
+is-data-descriptor@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-descriptor@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ dependencies:
+ is-accessor-descriptor "^0.1.6"
+ is-data-descriptor "^0.1.4"
+ kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ dependencies:
+ is-accessor-descriptor "^1.0.0"
+ is-data-descriptor "^1.0.0"
+ kind-of "^6.0.2"
+
+is-dotfile@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+
+is-equal-shallow@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+ dependencies:
+ is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
+is-finite@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+ dependencies:
+ is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-npm@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+
+is-number@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+
+is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ dependencies:
+ isobject "^3.0.1"
+
+is-posix-bracket@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-redirect@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+
+is-stream@^1.0.0, is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul@^0.4.5:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b"
+ dependencies:
+ abbrev "1.0.x"
+ async "1.x"
+ escodegen "1.8.x"
+ esprima "2.7.x"
+ glob "^5.0.15"
+ handlebars "^4.0.1"
+ js-yaml "3.x"
+ mkdirp "0.5.x"
+ nopt "3.x"
+ once "1.x"
+ resolve "1.1.x"
+ supports-color "^3.1.0"
+ which "^1.1.1"
+ wordwrap "^1.0.0"
+
+"js-tokens@^3.0.0 || ^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
+js-tokens@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+
+js-yaml@3.x, js-yaml@^3.1.0, js-yaml@^3.11.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+jsbn@~0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsesc@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+jsesc@~0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+
+json-parse-better-errors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+
+json-schema-traverse@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+
+json-schema@0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stringify-safe@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+ version "0.5.1"
+ resolved "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsprim@^1.2.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+ dependencies:
+ assert-plus "1.0.0"
+ extsprintf "1.3.0"
+ json-schema "0.2.3"
+ verror "1.10.0"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+
+latest-version@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb"
+ dependencies:
+ package-json "^1.0.0"
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ dependencies:
+ invert-kv "^1.0.0"
+
+lcid@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
+ dependencies:
+ invert-kv "^2.0.0"
+
+lcov-parse@^0.0.10:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3"
+
+levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+loader-runner@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979"
+
+loader-utils@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
+ dependencies:
+ big.js "^3.1.3"
+ emojis-list "^2.0.0"
+ json5 "^0.5.0"
+
+locate-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ dependencies:
+ p-locate "^2.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+
+lodash@^4.17.10, lodash@^4.17.4:
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+
+log-driver@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
+
+loose-envify@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lowercase-keys@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+
+lru-cache@2:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
+
+lru-cache@^4.1.1:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
+make-dir@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+ dependencies:
+ pify "^3.0.0"
+
+map-age-cleaner@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74"
+ dependencies:
+ p-defer "^1.0.0"
+
+map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ dependencies:
+ object-visit "^1.0.0"
+
+math-random@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac"
+
+md5.js@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
+mem@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf"
+ dependencies:
+ map-age-cleaner "^0.1.1"
+ mimic-fn "^1.0.0"
+ p-is-promise "^1.1.0"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+ dependencies:
+ errno "^0.1.3"
+ readable-stream "^2.0.1"
+
+micromatch@^2.1.5:
+ version "2.3.11"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+ dependencies:
+ arr-diff "^2.0.0"
+ array-unique "^0.2.1"
+ braces "^1.8.2"
+ expand-brackets "^0.1.4"
+ extglob "^0.3.1"
+ filename-regex "^2.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.1"
+ kind-of "^3.0.2"
+ normalize-path "^2.0.1"
+ object.omit "^2.0.0"
+ parse-glob "^3.0.4"
+ regex-cache "^0.4.2"
+
+micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+miller-rabin@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
+ dependencies:
+ bn.js "^4.0.0"
+ brorand "^1.0.1"
+
+mime-db@~1.36.0:
+ version "1.36.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
+
+mime-types@^2.1.12, mime-types@~2.1.19:
+ version "2.1.20"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19"
+ dependencies:
+ mime-db "~1.36.0"
+
+mimic-fn@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd"
+ dependencies:
+ lru-cache "2"
+ sigmund "~1.0.0"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.2.0:
+ version "1.2.0"
+ resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+minimist@~0.0.1:
+ version "0.0.10"
+ resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+
+minipass@^2.2.1, minipass@^2.3.3:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957"
+ dependencies:
+ safe-buffer "^5.1.2"
+ yallist "^3.0.0"
+
+minizlib@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.1.tgz#6734acc045a46e61d596a43bb9d9cd326e19cc42"
+ dependencies:
+ minipass "^2.2.1"
+
+mississippi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f"
+ dependencies:
+ concat-stream "^1.5.0"
+ duplexify "^3.4.2"
+ end-of-stream "^1.1.0"
+ flush-write-stream "^1.0.0"
+ from2 "^2.1.0"
+ parallel-transform "^1.1.0"
+ pump "^2.0.1"
+ pumpify "^1.3.3"
+ stream-each "^1.1.0"
+ through2 "^2.0.0"
+
+mixin-deep@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
+ version "0.5.1"
+ resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+mocha@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
+ dependencies:
+ browser-stdout "1.3.1"
+ commander "2.15.1"
+ debug "3.1.0"
+ diff "3.5.0"
+ escape-string-regexp "1.0.5"
+ glob "7.1.2"
+ growl "1.10.5"
+ he "1.1.1"
+ minimatch "3.0.4"
+ mkdirp "0.5.1"
+ supports-color "5.4.0"
+
+modify-babel-preset@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/modify-babel-preset/-/modify-babel-preset-3.2.1.tgz#d7172aa3c0822ed3fc08e308fd0971295136ab50"
+ dependencies:
+ require-relative "^0.8.7"
+
+move-concurrently@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
+ dependencies:
+ aproba "^1.1.1"
+ copy-concurrently "^1.0.0"
+ fs-write-stream-atomic "^1.0.8"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.3"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+
+nan@^2.9.2:
+ version "2.11.1"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766"
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+natives@^1.1.0:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb"
+
+needle@^2.2.1:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
+ dependencies:
+ debug "^2.1.2"
+ iconv-lite "^0.4.4"
+ sax "^1.2.4"
+
+neo-async@^2.5.0:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc"
+
+nested-error-stacks@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf"
+ dependencies:
+ inherits "~2.0.1"
+
+nice-try@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+
+nodangel@^1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/nodangel/-/nodangel-1.3.8.tgz#45627cb996679cef63d1e3f6f899d856d0df1956"
+ dependencies:
+ minimatch "~0.3.0"
+ ps-tree "~0.0.3"
+ touch "~0.0.3"
+ update-notifier "^0.3.0"
+
+node-libs-browser@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
+ dependencies:
+ assert "^1.1.1"
+ browserify-zlib "^0.2.0"
+ buffer "^4.3.0"
+ console-browserify "^1.1.0"
+ constants-browserify "^1.0.0"
+ crypto-browserify "^3.11.0"
+ domain-browser "^1.1.1"
+ events "^1.0.0"
+ https-browserify "^1.0.0"
+ os-browserify "^0.3.0"
+ path-browserify "0.0.0"
+ process "^0.11.10"
+ punycode "^1.2.4"
+ querystring-es3 "^0.2.0"
+ readable-stream "^2.3.3"
+ stream-browserify "^2.0.1"
+ stream-http "^2.7.2"
+ string_decoder "^1.0.0"
+ timers-browserify "^2.0.4"
+ tty-browserify "0.0.0"
+ url "^0.11.0"
+ util "^0.10.3"
+ vm-browserify "0.0.4"
+
+node-pre-gyp@^0.10.0:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
+ dependencies:
+ detect-libc "^1.0.2"
+ mkdirp "^0.5.1"
+ needle "^2.2.1"
+ nopt "^4.0.1"
+ npm-packlist "^1.1.6"
+ npmlog "^4.0.2"
+ rc "^1.2.7"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^4"
+
+nopt@3.x:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
+ dependencies:
+ abbrev "1"
+
+nopt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
+nopt@~1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
+ dependencies:
+ abbrev "1"
+
+normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+npm-bundled@^1.0.1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979"
+
+npm-packlist@^1.1.6:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a"
+ dependencies:
+ ignore-walk "^3.0.1"
+ npm-bundled "^1.0.1"
+
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ dependencies:
+ path-key "^2.0.0"
+
+npmlog@^4.0.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+
+object-assign@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa"
+
+object-assign@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+
+object-assign@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ dependencies:
+ isobject "^3.0.0"
+
+object.omit@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+ dependencies:
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
+object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ dependencies:
+ isobject "^3.0.1"
+
+once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ dependencies:
+ wrappy "1"
+
+optimist@0.2:
+ version "0.2.8"
+ resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31"
+ dependencies:
+ wordwrap ">=0.0.1 <0.1.0"
+
+optimist@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+ dependencies:
+ minimist "~0.0.1"
+ wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.4"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ wordwrap "~1.0.0"
+
+os-browserify@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
+
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+ version "1.4.0"
+ resolved "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+ dependencies:
+ lcid "^1.0.0"
+
+os-locale@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620"
+ dependencies:
+ execa "^0.10.0"
+ lcid "^2.0.0"
+ mem "^4.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.0, osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+output-file-sync@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76"
+ dependencies:
+ graceful-fs "^4.1.4"
+ mkdirp "^0.5.1"
+ object-assign "^4.1.0"
+
+p-defer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
+
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+
+p-is-promise@^1.1.0:
+ version "1.1.0"
+ resolved "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
+
+p-limit@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ dependencies:
+ p-try "^1.0.0"
+
+p-limit@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
+ dependencies:
+ p-try "^2.0.0"
+
+p-locate@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+ dependencies:
+ p-limit "^1.1.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ dependencies:
+ p-limit "^2.0.0"
+
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+
+p-try@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
+
+package-json@^1.0.0:
+ version "1.2.0"
+ resolved "http://registry.npmjs.org/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0"
+ dependencies:
+ got "^3.2.0"
+ registry-url "^3.0.0"
+
+pako@~1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
+
+parallel-transform@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
+ dependencies:
+ cyclist "~0.2.2"
+ inherits "^2.0.3"
+ readable-stream "^2.1.5"
+
+parse-asn1@^5.0.0:
+ version "5.1.1"
+ resolved "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8"
+ dependencies:
+ asn1.js "^4.0.0"
+ browserify-aes "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.0"
+ pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+ dependencies:
+ glob-base "^0.3.0"
+ is-dotfile "^1.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.0"
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+
+path-browserify@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-key@^2.0.0, path-key@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+
+pbkdf2@^3.0.3:
+ version "3.0.17"
+ resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
+ dependencies:
+ create-hash "^1.1.2"
+ create-hmac "^1.1.4"
+ ripemd160 "^2.0.1"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+
+pify@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+pkg-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ dependencies:
+ find-up "^2.1.0"
+
+pkg-dir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
+ dependencies:
+ find-up "^3.0.0"
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+prepend-http@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+
+preserve@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+private@^0.1.6, private@^0.1.8:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+
+process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+
+process@^0.11.10:
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise-inflight@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+
+prr@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
+
+ps-tree@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-0.0.3.tgz#dbf8d752a7fe22fa7d58635689499610e9276ddc"
+ dependencies:
+ event-stream "~0.5"
+
+pseudomap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+psl@^1.1.24:
+ version "1.1.29"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
+
+public-encrypt@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
+ dependencies:
+ bn.js "^4.1.0"
+ browserify-rsa "^4.0.0"
+ create-hash "^1.1.0"
+ parse-asn1 "^5.0.0"
+ randombytes "^2.0.1"
+ safe-buffer "^5.1.2"
+
+pump@^2.0.0, pump@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+pumpify@^1.3.3:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+ dependencies:
+ duplexify "^3.6.0"
+ inherits "^2.0.3"
+ pump "^2.0.0"
+
+punycode@1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+
+qs@~6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+
+querystring-es3@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.0.tgz#36f2ca708e9e567f5ed2ec01949026d50aa10116"
+ dependencies:
+ is-number "^4.0.0"
+ kind-of "^6.0.0"
+ math-random "^1.0.1"
+
+randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
+ dependencies:
+ safe-buffer "^5.1.0"
+
+randomfill@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
+ dependencies:
+ randombytes "^2.0.5"
+ safe-buffer "^5.1.0"
+
+rc@^1.0.1, rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+read-all-stream@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
+ dependencies:
+ pinkie-promise "^2.0.0"
+ readable-stream "^2.0.0"
+
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6:
+ version "2.3.6"
+ resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+ dependencies:
+ graceful-fs "^4.1.11"
+ micromatch "^3.1.10"
+ readable-stream "^2.0.2"
+
+regenerate@^1.2.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+
+regenerator-runtime@^0.10.5:
+ version "0.10.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
+
+regenerator-runtime@^0.11.0:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+
+regenerator-transform@^0.10.0:
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
+ dependencies:
+ babel-runtime "^6.18.0"
+ babel-types "^6.19.0"
+ private "^0.1.6"
+
+regex-cache@^0.4.2:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+ dependencies:
+ is-equal-shallow "^0.1.3"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+regexpu-core@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
+ dependencies:
+ regenerate "^1.2.1"
+ regjsgen "^0.2.0"
+ regjsparser "^0.1.4"
+
+registry-url@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+ dependencies:
+ rc "^1.0.1"
+
+regjsgen@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
+
+regjsparser@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
+ dependencies:
+ jsesc "~0.5.0"
+
+remove-trailing-separator@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+
+repeat-element@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+
+repeat-string@^1.5.2, repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+ dependencies:
+ is-finite "^1.0.0"
+
+request@^2.85.0:
+ version "2.88.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.0"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.4.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+require-relative@^0.8.7:
+ version "0.8.7"
+ resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de"
+
+resolve-cwd@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
+ dependencies:
+ resolve-from "^3.0.0"
+
+resolve-from@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+
+resolve@1.1.x:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+
+rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
+ dependencies:
+ glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+
+run-queue@^1.0.0, run-queue@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
+ dependencies:
+ aproba "^1.1.1"
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ dependencies:
+ ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+
+sax@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+
+schema-utils@^0.4.4, schema-utils@^0.4.5:
+ version "0.4.7"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
+ dependencies:
+ ajv "^6.1.0"
+ ajv-keywords "^3.1.0"
+
+semver-diff@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+ dependencies:
+ semver "^5.0.3"
+
+semver@^5.0.3, semver@^5.3.0, semver@^5.5.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+
+serialize-javascript@^1.4.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-value@^0.4.3:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.1"
+ to-object-path "^0.3.0"
+
+set-value@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setimmediate@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+ version "2.4.11"
+ resolved "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ dependencies:
+ shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+
+sigmund@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+
+signal-exit@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+source-list-map@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+
+source-map-resolve@^0.5.0:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+ dependencies:
+ atob "^2.1.1"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-support@^0.4.15:
+ version "0.4.18"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
+ dependencies:
+ source-map "^0.5.6"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+
+source-map@^0.5.6, source-map@^0.5.7:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+
+source-map@^0.6.1, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+
+source-map@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+ dependencies:
+ amdefine ">=0.0.4"
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ dependencies:
+ extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ dashdash "^1.12.0"
+ getpass "^0.1.1"
+ safer-buffer "^2.0.2"
+ optionalDependencies:
+ bcrypt-pbkdf "^1.0.0"
+ ecc-jsbn "~0.1.1"
+ jsbn "~0.1.0"
+ tweetnacl "~0.14.0"
+
+ssri@^5.2.4:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06"
+ dependencies:
+ safe-buffer "^5.1.1"
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+stream-browserify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+ dependencies:
+ inherits "~2.0.1"
+ readable-stream "^2.0.2"
+
+stream-each@^1.1.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
+ dependencies:
+ end-of-stream "^1.1.0"
+ stream-shift "^1.0.0"
+
+stream-http@^2.7.2:
+ version "2.8.3"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
+ dependencies:
+ builtin-status-codes "^3.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.3.6"
+ to-arraybuffer "^1.0.0"
+ xtend "^4.0.0"
+
+stream-shift@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
+
+string-length@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+ dependencies:
+ strip-ansi "^3.0.0"
+
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string_decoder@^1.0.0, string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ dependencies:
+ safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@5.4.0:
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+ dependencies:
+ has-flag "^1.0.0"
+
+supports-color@^5.3.0, supports-color@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ dependencies:
+ has-flag "^3.0.0"
+
+tapable@^1.0.0, tapable@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c"
+
+tar@^4:
+ version "4.4.6"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b"
+ dependencies:
+ chownr "^1.0.1"
+ fs-minipass "^1.2.5"
+ minipass "^2.3.3"
+ minizlib "^1.1.0"
+ mkdirp "^0.5.0"
+ safe-buffer "^5.1.2"
+ yallist "^3.0.2"
+
+through2@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
+timed-out@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
+
+timers-browserify@^2.0.4:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
+ dependencies:
+ setimmediate "^1.0.4"
+
+to-arraybuffer@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+touch@~0.0.3:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/touch/-/touch-0.0.4.tgz#fc1a7103cbe0ecee713d1384d775e2f9e21caae2"
+ dependencies:
+ nopt "~1.0.10"
+
+tough-cookie@~2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
+trim-right@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tslib@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
+
+tty-browserify@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ dependencies:
+ safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ dependencies:
+ prelude-ls "~1.1.2"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+
+uglify-es@^3.3.4:
+ version "3.3.9"
+ resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
+ dependencies:
+ commander "~2.13.0"
+ source-map "~0.6.1"
+
+uglify-js@^3.1.4:
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
+ dependencies:
+ commander "~2.17.1"
+ source-map "~0.6.1"
+
+uglifyjs-webpack-plugin@^1.2.4:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de"
+ dependencies:
+ cacache "^10.0.4"
+ find-cache-dir "^1.0.0"
+ schema-utils "^0.4.5"
+ serialize-javascript "^1.4.0"
+ source-map "^0.6.1"
+ uglify-es "^3.3.4"
+ webpack-sources "^1.1.0"
+ worker-farm "^1.5.2"
+
+union-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^0.4.3"
+
+unique-filename@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
+ dependencies:
+ unique-slug "^2.0.0"
+
+unique-slug@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6"
+ dependencies:
+ imurmurhash "^0.1.4"
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+upath@^1.0.5:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
+
+update-notifier@^0.3.0:
+ version "0.3.2"
+ resolved "http://registry.npmjs.org/update-notifier/-/update-notifier-0.3.2.tgz#22a8735baadef3320e2db928f693da898dc87777"
+ dependencies:
+ chalk "^1.0.0"
+ configstore "^0.3.1"
+ is-npm "^1.0.0"
+ latest-version "^1.0.0"
+ semver-diff "^2.0.0"
+ string-length "^1.0.0"
+
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ dependencies:
+ punycode "^2.1.0"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+
+url@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+ dependencies:
+ punycode "1.3.2"
+ querystring "0.2.0"
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+
+user-home@^1.0.0, user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+ dependencies:
+ inherits "2.0.1"
+
+util@^0.10.3:
+ version "0.10.4"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
+ dependencies:
+ inherits "2.0.3"
+
+uuid@^2.0.1:
+ version "2.0.3"
+ resolved "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
+
+uuid@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+
+v8-compile-cache@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c"
+
+v8flags@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+ dependencies:
+ user-home "^1.1.1"
+
+verror@1.10.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+ dependencies:
+ assert-plus "^1.0.0"
+ core-util-is "1.0.2"
+ extsprintf "^1.2.0"
+
+vm-browserify@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+ dependencies:
+ indexof "0.0.1"
+
+watchpack@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
+ dependencies:
+ chokidar "^2.0.2"
+ graceful-fs "^4.1.2"
+ neo-async "^2.5.0"
+
+webpack-cli@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.2.tgz#17d7e01b77f89f884a2bbf9db545f0f6a648e746"
+ dependencies:
+ chalk "^2.4.1"
+ cross-spawn "^6.0.5"
+ enhanced-resolve "^4.1.0"
+ global-modules-path "^2.3.0"
+ import-local "^2.0.0"
+ interpret "^1.1.0"
+ loader-utils "^1.1.0"
+ supports-color "^5.5.0"
+ v8-compile-cache "^2.0.2"
+ yargs "^12.0.2"
+
+webpack-sources@^1.1.0, webpack-sources@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack@^4.20.2:
+ version "4.20.2"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.20.2.tgz#89f6486b6bb276a91b0823453d377501fc625b5a"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.8"
+ "@webassemblyjs/helper-module-context" "1.7.8"
+ "@webassemblyjs/wasm-edit" "1.7.8"
+ "@webassemblyjs/wasm-parser" "1.7.8"
+ acorn "^5.6.2"
+ acorn-dynamic-import "^3.0.0"
+ ajv "^6.1.0"
+ ajv-keywords "^3.1.0"
+ chrome-trace-event "^1.0.0"
+ enhanced-resolve "^4.1.0"
+ eslint-scope "^4.0.0"
+ json-parse-better-errors "^1.0.2"
+ loader-runner "^2.3.0"
+ loader-utils "^1.1.0"
+ memory-fs "~0.4.1"
+ micromatch "^3.1.8"
+ mkdirp "~0.5.0"
+ neo-async "^2.5.0"
+ node-libs-browser "^2.0.0"
+ schema-utils "^0.4.4"
+ tapable "^1.1.0"
+ uglifyjs-webpack-plugin "^1.2.4"
+ watchpack "^1.5.0"
+ webpack-sources "^1.3.0"
+
+which-module@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+
+which@^1.1.1, which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ dependencies:
+ string-width "^1.0.2 || 2"
+
+window-size@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
+
+"wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wordwrap@^1.0.0, wordwrap@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.5.2:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
+ dependencies:
+ errno "~0.1.7"
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xdg-basedir@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-1.0.1.tgz#14ff8f63a4fdbcb05d5b6eea22b36f3033b9f04e"
+ dependencies:
+ user-home "^1.0.0"
+
+xregexp@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
+
+xtend@^4.0.0, xtend@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+
+yallist@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+
+yallist@^3.0.0, yallist@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
+
+yargs-parser@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
+ dependencies:
+ camelcase "^4.1.0"
+
+yargs@^12.0.2:
+ version "12.0.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc"
+ dependencies:
+ cliui "^4.0.0"
+ decamelize "^2.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^1.0.1"
+ os-locale "^3.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1 || ^4.0.0"
+ yargs-parser "^10.1.0"
+
+yargs@^3.15.0:
+ version "3.32.0"
+ resolved "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
+ dependencies:
+ camelcase "^2.0.1"
+ cliui "^3.0.3"
+ decamelize "^1.1.1"
+ os-locale "^1.4.0"
+ string-width "^1.0.1"
+ window-size "^0.1.4"
+ y18n "^3.2.0"
diff --git a/node_modules/sliced/History.md b/node_modules/sliced/History.md
new file mode 100644
index 0000000..e45cefe
--- /dev/null
+++ b/node_modules/sliced/History.md
@@ -0,0 +1,41 @@
+
+1.0.1 / 2015-07-14
+==================
+
+ * fixed; missing file introduced in 4f5cea1
+
+1.0.0 / 2015-07-12
+==================
+
+ * Remove unnecessary files from npm package - #6 via joaquimserafim
+ * updated readme stats
+
+0.0.5 / 2013-02-05
+==================
+
+ * optimization: remove use of arguments [jkroso](https://github.com/jkroso)
+ * add scripts to component.json [jkroso](https://github.com/jkroso)
+ * tests; remove time for travis
+
+0.0.4 / 2013-01-07
+==================
+
+ * added component.json #1 [jkroso](https://github.com/jkroso)
+ * reversed array loop #1 [jkroso](https://github.com/jkroso)
+ * remove fn params
+
+0.0.3 / 2012-09-29
+==================
+
+ * faster with negative start args
+
+0.0.2 / 2012-09-29
+==================
+
+ * support full [].slice semantics
+
+0.0.1 / 2012-09-29
+===================
+
+ * initial release
+
diff --git a/node_modules/sliced/LICENSE b/node_modules/sliced/LICENSE
new file mode 100644
index 0000000..38c529d
--- /dev/null
+++ b/node_modules/sliced/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/sliced/README.md b/node_modules/sliced/README.md
new file mode 100644
index 0000000..b6ff85e
--- /dev/null
+++ b/node_modules/sliced/README.md
@@ -0,0 +1,62 @@
+#sliced
+==========
+
+A faster alternative to `[].slice.call(arguments)`.
+
+[](http://travis-ci.org/aheckmann/sliced)
+
+Example output from [benchmark.js](https://github.com/bestiejs/benchmark.js)
+
+ Array.prototype.slice.call x 1,401,820 ops/sec ±2.16% (90 runs sampled)
+ [].slice.call x 1,313,116 ops/sec ±2.04% (96 runs sampled)
+ cached slice.call x 10,297,910 ops/sec ±1.81% (96 runs sampled)
+ sliced x 19,906,019 ops/sec ±1.23% (89 runs sampled)
+ fastest is sliced
+
+ Array.prototype.slice.call(arguments, 1) x 1,373,238 ops/sec ±1.84% (95 runs sampled)
+ [].slice.call(arguments, 1) x 1,395,336 ops/sec ±1.36% (93 runs sampled)
+ cached slice.call(arguments, 1) x 9,926,018 ops/sec ±1.67% (92 runs sampled)
+ sliced(arguments, 1) x 20,747,990 ops/sec ±1.16% (93 runs sampled)
+ fastest is sliced(arguments, 1)
+
+ Array.prototype.slice.call(arguments, -1) x 1,319,908 ops/sec ±2.12% (91 runs sampled)
+ [].slice.call(arguments, -1) x 1,336,170 ops/sec ±1.33% (97 runs sampled)
+ cached slice.call(arguments, -1) x 10,078,718 ops/sec ±1.21% (98 runs sampled)
+ sliced(arguments, -1) x 20,471,474 ops/sec ±1.81% (92 runs sampled)
+ fastest is sliced(arguments, -1)
+
+ Array.prototype.slice.call(arguments, -2, -10) x 1,369,246 ops/sec ±1.68% (97 runs sampled)
+ [].slice.call(arguments, -2, -10) x 1,387,935 ops/sec ±1.70% (95 runs sampled)
+ cached slice.call(arguments, -2, -10) x 9,593,428 ops/sec ±1.23% (97 runs sampled)
+ sliced(arguments, -2, -10) x 23,178,931 ops/sec ±1.70% (92 runs sampled)
+ fastest is sliced(arguments, -2, -10)
+
+ Array.prototype.slice.call(arguments, -2, -1) x 1,441,300 ops/sec ±1.26% (98 runs sampled)
+ [].slice.call(arguments, -2, -1) x 1,410,326 ops/sec ±1.96% (93 runs sampled)
+ cached slice.call(arguments, -2, -1) x 9,854,419 ops/sec ±1.02% (97 runs sampled)
+ sliced(arguments, -2, -1) x 22,550,801 ops/sec ±1.86% (91 runs sampled)
+ fastest is sliced(arguments, -2, -1)
+
+_Benchmark [source](https://github.com/aheckmann/sliced/blob/master/bench.js)._
+
+##Usage
+
+`sliced` accepts the same arguments as `Array#slice` so you can easily swap it out.
+
+```js
+function zing () {
+ var slow = [].slice.call(arguments, 1, 8);
+ var args = slice(arguments, 1, 8);
+
+ var slow = Array.prototype.slice.call(arguments);
+ var args = slice(arguments);
+ // etc
+}
+```
+
+## install
+
+ npm install sliced
+
+
+[LICENSE](https://github.com/aheckmann/sliced/blob/master/LICENSE)
diff --git a/node_modules/sliced/index.js b/node_modules/sliced/index.js
new file mode 100644
index 0000000..d88c85b
--- /dev/null
+++ b/node_modules/sliced/index.js
@@ -0,0 +1,33 @@
+
+/**
+ * An Array.prototype.slice.call(arguments) alternative
+ *
+ * @param {Object} args something with a length
+ * @param {Number} slice
+ * @param {Number} sliceEnd
+ * @api public
+ */
+
+module.exports = function (args, slice, sliceEnd) {
+ var ret = [];
+ var len = args.length;
+
+ if (0 === len) return ret;
+
+ var start = slice < 0
+ ? Math.max(0, slice + len)
+ : slice || 0;
+
+ if (sliceEnd !== undefined) {
+ len = sliceEnd < 0
+ ? sliceEnd + len
+ : sliceEnd
+ }
+
+ while (len-- > start) {
+ ret[len - start] = args[len];
+ }
+
+ return ret;
+}
+
diff --git a/node_modules/sliced/package.json b/node_modules/sliced/package.json
new file mode 100644
index 0000000..d57fc18
--- /dev/null
+++ b/node_modules/sliced/package.json
@@ -0,0 +1,86 @@
+{
+ "_args": [
+ [
+ "sliced@1.0.1",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose"
+ ]
+ ],
+ "_from": "sliced@1.0.1",
+ "_id": "sliced@1.0.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/sliced",
+ "_nodeVersion": "1.8.1",
+ "_npmUser": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "aaron"
+ },
+ "_npmVersion": "2.8.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "sliced",
+ "raw": "sliced@1.0.1",
+ "rawSpec": "1.0.1",
+ "scope": null,
+ "spec": "1.0.1",
+ "type": "version"
+ },
+ "_requiredBy": [
+ "/mongoose",
+ "/mquery"
+ ],
+ "_resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
+ "_shasum": "0b3a662b5d04c3177b1926bea82b03f837a2ef41",
+ "_shrinkwrap": null,
+ "_spec": "sliced@1.0.1",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/mongoose",
+ "author": {
+ "email": "aaron.heckmann+github@gmail.com",
+ "name": "Aaron Heckmann"
+ },
+ "bugs": {
+ "url": "https://github.com/aheckmann/sliced/issues"
+ },
+ "dependencies": {},
+ "description": "A faster Node.js alternative to Array.prototype.slice.call(arguments)",
+ "devDependencies": {
+ "benchmark": "~1.0.0",
+ "mocha": "1.5.0"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "0b3a662b5d04c3177b1926bea82b03f837a2ef41",
+ "tarball": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz"
+ },
+ "files": [
+ "LICENSE",
+ "README.md",
+ "index.js"
+ ],
+ "gitHead": "e7c989016d2062995cd102322b65784ba8977ee3",
+ "homepage": "https://github.com/aheckmann/sliced",
+ "keywords": [
+ "arguments",
+ "array",
+ "slice"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "aaron",
+ "email": "aaron.heckmann+github@gmail.com"
+ }
+ ],
+ "name": "sliced",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aheckmann/sliced.git"
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "version": "1.0.1"
+}
diff --git a/node_modules/sparse-bitfield/.npmignore b/node_modules/sparse-bitfield/.npmignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/node_modules/sparse-bitfield/.npmignore
@@ -0,0 +1 @@
+node_modules
diff --git a/node_modules/sparse-bitfield/.travis.yml b/node_modules/sparse-bitfield/.travis.yml
new file mode 100644
index 0000000..c042821
--- /dev/null
+++ b/node_modules/sparse-bitfield/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - '0.10'
+ - '0.12'
+ - '4.0'
+ - '5.0'
diff --git a/node_modules/sparse-bitfield/LICENSE b/node_modules/sparse-bitfield/LICENSE
new file mode 100644
index 0000000..bae9da7
--- /dev/null
+++ b/node_modules/sparse-bitfield/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Mathias Buus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/sparse-bitfield/README.md b/node_modules/sparse-bitfield/README.md
new file mode 100644
index 0000000..7b6b8f9
--- /dev/null
+++ b/node_modules/sparse-bitfield/README.md
@@ -0,0 +1,62 @@
+# sparse-bitfield
+
+Bitfield implementation that allocates a series of 1kb buffers to support sparse bitfields
+without allocating a massive buffer. If you want to simple implementation of a flat bitfield
+see the [bitfield](https://github.com/fb55/bitfield) module.
+
+This module is mostly useful if you need a big bitfield where you won't nessecarily set every bit.
+
+```
+npm install sparse-bitfield
+```
+
+[](http://travis-ci.org/mafintosh/sparse-bitfield)
+
+## Usage
+
+``` js
+var bitfield = require('sparse-bitfield')
+var bits = bitfield()
+
+bits.set(0, true) // set first bit
+bits.set(1, true) // set second bit
+bits.set(1000000000000, true) // set the 1.000.000.000.000th bit
+```
+
+Running the above example will allocate two 1kb buffers internally.
+Each 1kb buffer can hold information about 8192 bits so the first one will be used to store information about the first two bits and the second will be used to store the 1.000.000.000.000th bit.
+
+## API
+
+#### `var bits = bitfield([options])`
+
+Create a new bitfield. Options include
+
+``` js
+{
+ pageSize: 1024, // how big should the partial buffers be
+ buffer: anExistingBitfield,
+ trackUpdates: false // track when pages are being updated in the pager
+}
+```
+
+#### `bits.set(index, value)`
+
+Set a bit to true or false.
+
+#### `bits.get(index)`
+
+Get the value of a bit.
+
+#### `bits.pages`
+
+A [memory-pager](https://github.com/mafintosh/memory-pager) instance that is managing the underlying memory.
+If you set `trackUpdates` to true in the constructor you can use `.lastUpdate()` on this instance to get the last updated memory page.
+
+#### `var buffer = bits.toBuffer()`
+
+Get a single buffer representing the entire bitfield.
+
+## License
+
+MIT
diff --git a/node_modules/sparse-bitfield/index.js b/node_modules/sparse-bitfield/index.js
new file mode 100644
index 0000000..ff458c9
--- /dev/null
+++ b/node_modules/sparse-bitfield/index.js
@@ -0,0 +1,95 @@
+var pager = require('memory-pager')
+
+module.exports = Bitfield
+
+function Bitfield (opts) {
+ if (!(this instanceof Bitfield)) return new Bitfield(opts)
+ if (!opts) opts = {}
+ if (Buffer.isBuffer(opts)) opts = {buffer: opts}
+
+ this.pageOffset = opts.pageOffset || 0
+ this.pageSize = opts.pageSize || 1024
+ this.pages = opts.pages || pager(this.pageSize)
+
+ this.byteLength = this.pages.length * this.pageSize
+ this.length = 8 * this.byteLength
+
+ if (!powerOfTwo(this.pageSize)) throw new Error('The page size should be a power of two')
+
+ this._trackUpdates = !!opts.trackUpdates
+ this._pageMask = this.pageSize - 1
+
+ if (opts.buffer) {
+ for (var i = 0; i < opts.buffer.length; i += this.pageSize) {
+ this.pages.set(i / this.pageSize, opts.buffer.slice(i, i + this.pageSize))
+ }
+ this.byteLength = opts.buffer.length
+ this.length = 8 * this.byteLength
+ }
+}
+
+Bitfield.prototype.get = function (i) {
+ var o = i & 7
+ var j = (i - o) / 8
+
+ return !!(this.getByte(j) & (128 >> o))
+}
+
+Bitfield.prototype.getByte = function (i) {
+ var o = i & this._pageMask
+ var j = (i - o) / this.pageSize
+ var page = this.pages.get(j, true)
+
+ return page ? page.buffer[o + this.pageOffset] : 0
+}
+
+Bitfield.prototype.set = function (i, v) {
+ var o = i & 7
+ var j = (i - o) / 8
+ var b = this.getByte(j)
+
+ return this.setByte(j, v ? b | (128 >> o) : b & (255 ^ (128 >> o)))
+}
+
+Bitfield.prototype.toBuffer = function () {
+ var all = alloc(this.pages.length * this.pageSize)
+
+ for (var i = 0; i < this.pages.length; i++) {
+ var next = this.pages.get(i, true)
+ var allOffset = i * this.pageSize
+ if (next) next.buffer.copy(all, allOffset, this.pageOffset, this.pageOffset + this.pageSize)
+ }
+
+ return all
+}
+
+Bitfield.prototype.setByte = function (i, b) {
+ var o = i & this._pageMask
+ var j = (i - o) / this.pageSize
+ var page = this.pages.get(j, false)
+
+ o += this.pageOffset
+
+ if (page.buffer[o] === b) return false
+ page.buffer[o] = b
+
+ if (i >= this.byteLength) {
+ this.byteLength = i + 1
+ this.length = this.byteLength * 8
+ }
+
+ if (this._trackUpdates) this.pages.updated(page)
+
+ return true
+}
+
+function alloc (n) {
+ if (Buffer.alloc) return Buffer.alloc(n)
+ var b = new Buffer(n)
+ b.fill(0)
+ return b
+}
+
+function powerOfTwo (x) {
+ return !(x & (x - 1))
+}
diff --git a/node_modules/sparse-bitfield/package.json b/node_modules/sparse-bitfield/package.json
new file mode 100644
index 0000000..f809e7b
--- /dev/null
+++ b/node_modules/sparse-bitfield/package.json
@@ -0,0 +1,82 @@
+{
+ "_args": [
+ [
+ "sparse-bitfield@^3.0.3",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/saslprep"
+ ]
+ ],
+ "_from": "sparse-bitfield@>=3.0.3 <4.0.0",
+ "_id": "sparse-bitfield@3.0.3",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/sparse-bitfield",
+ "_nodeVersion": "6.9.5",
+ "_npmOperationalInternal": {
+ "host": "packages-12-west.internal.npmjs.com",
+ "tmp": "tmp/sparse-bitfield-3.0.3.tgz_1488673063925_0.47190379025414586"
+ },
+ "_npmUser": {
+ "email": "mathiasbuus@gmail.com",
+ "name": "mafintosh"
+ },
+ "_npmVersion": "3.10.10",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "sparse-bitfield",
+ "raw": "sparse-bitfield@^3.0.3",
+ "rawSpec": "^3.0.3",
+ "scope": null,
+ "spec": ">=3.0.3 <4.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/saslprep"
+ ],
+ "_resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+ "_shasum": "ff4ae6e68656056ba4b3e792ab3334d38273ca11",
+ "_shrinkwrap": null,
+ "_spec": "sparse-bitfield@^3.0.3",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/saslprep",
+ "author": {
+ "name": "Mathias Buus",
+ "url": "@mafintosh"
+ },
+ "bugs": {
+ "url": "https://github.com/mafintosh/sparse-bitfield/issues"
+ },
+ "dependencies": {
+ "memory-pager": "^1.0.2"
+ },
+ "description": "Bitfield that allocates a series of small buffers to support sparse bits without allocating a massive buffer",
+ "devDependencies": {
+ "buffer-alloc": "^1.1.0",
+ "standard": "^9.0.0",
+ "tape": "^4.6.3"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "ff4ae6e68656056ba4b3e792ab3334d38273ca11",
+ "tarball": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz"
+ },
+ "gitHead": "922ad0e94c4134fa1de17ae456551f950eef528f",
+ "homepage": "https://github.com/mafintosh/sparse-bitfield",
+ "license": "MIT",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "mafintosh",
+ "email": "mathiasbuus@gmail.com"
+ }
+ ],
+ "name": "sparse-bitfield",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/mafintosh/sparse-bitfield.git"
+ },
+ "scripts": {
+ "test": "standard && tape test.js"
+ },
+ "version": "3.0.3"
+}
diff --git a/node_modules/sparse-bitfield/test.js b/node_modules/sparse-bitfield/test.js
new file mode 100644
index 0000000..ae42ef4
--- /dev/null
+++ b/node_modules/sparse-bitfield/test.js
@@ -0,0 +1,79 @@
+var alloc = require('buffer-alloc')
+var tape = require('tape')
+var bitfield = require('./')
+
+tape('set and get', function (t) {
+ var bits = bitfield()
+
+ t.same(bits.get(0), false, 'first bit is false')
+ bits.set(0, true)
+ t.same(bits.get(0), true, 'first bit is true')
+ t.same(bits.get(1), false, 'second bit is false')
+ bits.set(0, false)
+ t.same(bits.get(0), false, 'first bit is reset')
+ t.end()
+})
+
+tape('set large and get', function (t) {
+ var bits = bitfield()
+
+ t.same(bits.get(9999999999999), false, 'large bit is false')
+ bits.set(9999999999999, true)
+ t.same(bits.get(9999999999999), true, 'large bit is true')
+ t.same(bits.get(9999999999999 + 1), false, 'large bit + 1 is false')
+ bits.set(9999999999999, false)
+ t.same(bits.get(9999999999999), false, 'large bit is reset')
+ t.end()
+})
+
+tape('get and set buffer', function (t) {
+ var bits = bitfield({trackUpdates: true})
+
+ t.same(bits.pages.get(0, true), undefined)
+ t.same(bits.pages.get(Math.floor(9999999999999 / 8 / 1024), true), undefined)
+ bits.set(9999999999999, true)
+
+ var bits2 = bitfield()
+ var upd = bits.pages.lastUpdate()
+ bits2.pages.set(Math.floor(upd.offset / 1024), upd.buffer)
+ t.same(bits2.get(9999999999999), true, 'bit is set')
+ t.end()
+})
+
+tape('toBuffer', function (t) {
+ var bits = bitfield()
+
+ t.same(bits.toBuffer(), alloc(0))
+
+ bits.set(0, true)
+
+ t.same(bits.toBuffer(), bits.pages.get(0).buffer)
+
+ bits.set(9000, true)
+
+ t.same(bits.toBuffer(), Buffer.concat([bits.pages.get(0).buffer, bits.pages.get(1).buffer]))
+ t.end()
+})
+
+tape('pass in buffer', function (t) {
+ var bits = bitfield()
+
+ bits.set(0, true)
+ bits.set(9000, true)
+
+ var clone = bitfield(bits.toBuffer())
+
+ t.same(clone.get(0), true)
+ t.same(clone.get(9000), true)
+ t.end()
+})
+
+tape('set small buffer', function (t) {
+ var buf = alloc(1)
+ buf[0] = 255
+ var bits = bitfield(buf)
+
+ t.same(bits.get(0), true)
+ t.same(bits.pages.get(0).buffer.length, bits.pageSize)
+ t.end()
+})
diff --git a/node_modules/string_decoder/.travis.yml b/node_modules/string_decoder/.travis.yml
new file mode 100644
index 0000000..3347a72
--- /dev/null
+++ b/node_modules/string_decoder/.travis.yml
@@ -0,0 +1,50 @@
+sudo: false
+language: node_js
+before_install:
+ - npm install -g npm@2
+ - test $NPM_LEGACY && npm install -g npm@latest-3 || npm install npm -g
+notifications:
+ email: false
+matrix:
+ fast_finish: true
+ include:
+ - node_js: '0.8'
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: '0.10'
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: '0.11'
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: '0.12'
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: 1
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: 2
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: 3
+ env:
+ - TASK=test
+ - NPM_LEGACY=true
+ - node_js: 4
+ env: TASK=test
+ - node_js: 5
+ env: TASK=test
+ - node_js: 6
+ env: TASK=test
+ - node_js: 7
+ env: TASK=test
+ - node_js: 8
+ env: TASK=test
+ - node_js: 9
+ env: TASK=test
diff --git a/node_modules/string_decoder/LICENSE b/node_modules/string_decoder/LICENSE
new file mode 100644
index 0000000..778edb2
--- /dev/null
+++ b/node_modules/string_decoder/LICENSE
@@ -0,0 +1,48 @@
+Node.js is licensed for use as follows:
+
+"""
+Copyright Node.js contributors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
+This license applies to parts of Node.js originating from the
+https://github.com/joyent/node repository:
+
+"""
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
diff --git a/node_modules/string_decoder/README.md b/node_modules/string_decoder/README.md
new file mode 100644
index 0000000..5fd5831
--- /dev/null
+++ b/node_modules/string_decoder/README.md
@@ -0,0 +1,47 @@
+# string_decoder
+
+***Node-core v8.9.4 string_decoder for userland***
+
+
+[](https://nodei.co/npm/string_decoder/)
+[](https://nodei.co/npm/string_decoder/)
+
+
+```bash
+npm install --save string_decoder
+```
+
+***Node-core string_decoder for userland***
+
+This package is a mirror of the string_decoder implementation in Node-core.
+
+Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v8.9.4/docs/api/).
+
+As of version 1.0.0 **string_decoder** uses semantic versioning.
+
+## Previous versions
+
+Previous version numbers match the versions found in Node core, e.g. 0.10.24 matches Node 0.10.24, likewise 0.11.10 matches Node 0.11.10.
+
+## Update
+
+The *build/* directory contains a build script that will scrape the source from the [nodejs/node](https://github.com/nodejs/node) repo given a specific Node version.
+
+## Streams Working Group
+
+`string_decoder` is maintained by the Streams Working Group, which
+oversees the development and maintenance of the Streams API within
+Node.js. The responsibilities of the Streams Working Group include:
+
+* Addressing stream issues on the Node.js issue tracker.
+* Authoring and editing stream documentation within the Node.js project.
+* Reviewing changes to stream subclasses within the Node.js project.
+* Redirecting changes to streams from the Node.js project to this
+ project.
+* Assisting in the implementation of stream providers within Node.js.
+* Recommending versions of `readable-stream` to be included in Node.js.
+* Messaging about the future of streams to give the community advance
+ notice of changes.
+
+See [readable-stream](https://github.com/nodejs/readable-stream) for
+more details.
diff --git a/node_modules/string_decoder/lib/string_decoder.js b/node_modules/string_decoder/lib/string_decoder.js
new file mode 100644
index 0000000..2e89e63
--- /dev/null
+++ b/node_modules/string_decoder/lib/string_decoder.js
@@ -0,0 +1,296 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+/**/
+
+var Buffer = require('safe-buffer').Buffer;
+/**/
+
+var isEncoding = Buffer.isEncoding || function (encoding) {
+ encoding = '' + encoding;
+ switch (encoding && encoding.toLowerCase()) {
+ case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':
+ return true;
+ default:
+ return false;
+ }
+};
+
+function _normalizeEncoding(enc) {
+ if (!enc) return 'utf8';
+ var retried;
+ while (true) {
+ switch (enc) {
+ case 'utf8':
+ case 'utf-8':
+ return 'utf8';
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return 'utf16le';
+ case 'latin1':
+ case 'binary':
+ return 'latin1';
+ case 'base64':
+ case 'ascii':
+ case 'hex':
+ return enc;
+ default:
+ if (retried) return; // undefined
+ enc = ('' + enc).toLowerCase();
+ retried = true;
+ }
+ }
+};
+
+// Do not cache `Buffer.isEncoding` when checking encoding names as some
+// modules monkey-patch it to support additional encodings
+function normalizeEncoding(enc) {
+ var nenc = _normalizeEncoding(enc);
+ if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
+ return nenc || enc;
+}
+
+// StringDecoder provides an interface for efficiently splitting a series of
+// buffers into a series of JS strings without breaking apart multi-byte
+// characters.
+exports.StringDecoder = StringDecoder;
+function StringDecoder(encoding) {
+ this.encoding = normalizeEncoding(encoding);
+ var nb;
+ switch (this.encoding) {
+ case 'utf16le':
+ this.text = utf16Text;
+ this.end = utf16End;
+ nb = 4;
+ break;
+ case 'utf8':
+ this.fillLast = utf8FillLast;
+ nb = 4;
+ break;
+ case 'base64':
+ this.text = base64Text;
+ this.end = base64End;
+ nb = 3;
+ break;
+ default:
+ this.write = simpleWrite;
+ this.end = simpleEnd;
+ return;
+ }
+ this.lastNeed = 0;
+ this.lastTotal = 0;
+ this.lastChar = Buffer.allocUnsafe(nb);
+}
+
+StringDecoder.prototype.write = function (buf) {
+ if (buf.length === 0) return '';
+ var r;
+ var i;
+ if (this.lastNeed) {
+ r = this.fillLast(buf);
+ if (r === undefined) return '';
+ i = this.lastNeed;
+ this.lastNeed = 0;
+ } else {
+ i = 0;
+ }
+ if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
+ return r || '';
+};
+
+StringDecoder.prototype.end = utf8End;
+
+// Returns only complete characters in a Buffer
+StringDecoder.prototype.text = utf8Text;
+
+// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
+StringDecoder.prototype.fillLast = function (buf) {
+ if (this.lastNeed <= buf.length) {
+ buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
+ return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+ }
+ buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
+ this.lastNeed -= buf.length;
+};
+
+// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
+// continuation byte. If an invalid byte is detected, -2 is returned.
+function utf8CheckByte(byte) {
+ if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;
+ return byte >> 6 === 0x02 ? -1 : -2;
+}
+
+// Checks at most 3 bytes at the end of a Buffer in order to detect an
+// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
+// needed to complete the UTF-8 character (if applicable) are returned.
+function utf8CheckIncomplete(self, buf, i) {
+ var j = buf.length - 1;
+ if (j < i) return 0;
+ var nb = utf8CheckByte(buf[j]);
+ if (nb >= 0) {
+ if (nb > 0) self.lastNeed = nb - 1;
+ return nb;
+ }
+ if (--j < i || nb === -2) return 0;
+ nb = utf8CheckByte(buf[j]);
+ if (nb >= 0) {
+ if (nb > 0) self.lastNeed = nb - 2;
+ return nb;
+ }
+ if (--j < i || nb === -2) return 0;
+ nb = utf8CheckByte(buf[j]);
+ if (nb >= 0) {
+ if (nb > 0) {
+ if (nb === 2) nb = 0;else self.lastNeed = nb - 3;
+ }
+ return nb;
+ }
+ return 0;
+}
+
+// Validates as many continuation bytes for a multi-byte UTF-8 character as
+// needed or are available. If we see a non-continuation byte where we expect
+// one, we "replace" the validated continuation bytes we've seen so far with
+// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
+// behavior. The continuation byte check is included three times in the case
+// where all of the continuation bytes for a character exist in the same buffer.
+// It is also done this way as a slight performance increase instead of using a
+// loop.
+function utf8CheckExtraBytes(self, buf, p) {
+ if ((buf[0] & 0xC0) !== 0x80) {
+ self.lastNeed = 0;
+ return '\ufffd';
+ }
+ if (self.lastNeed > 1 && buf.length > 1) {
+ if ((buf[1] & 0xC0) !== 0x80) {
+ self.lastNeed = 1;
+ return '\ufffd';
+ }
+ if (self.lastNeed > 2 && buf.length > 2) {
+ if ((buf[2] & 0xC0) !== 0x80) {
+ self.lastNeed = 2;
+ return '\ufffd';
+ }
+ }
+ }
+}
+
+// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
+function utf8FillLast(buf) {
+ var p = this.lastTotal - this.lastNeed;
+ var r = utf8CheckExtraBytes(this, buf, p);
+ if (r !== undefined) return r;
+ if (this.lastNeed <= buf.length) {
+ buf.copy(this.lastChar, p, 0, this.lastNeed);
+ return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+ }
+ buf.copy(this.lastChar, p, 0, buf.length);
+ this.lastNeed -= buf.length;
+}
+
+// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
+// partial character, the character's bytes are buffered until the required
+// number of bytes are available.
+function utf8Text(buf, i) {
+ var total = utf8CheckIncomplete(this, buf, i);
+ if (!this.lastNeed) return buf.toString('utf8', i);
+ this.lastTotal = total;
+ var end = buf.length - (total - this.lastNeed);
+ buf.copy(this.lastChar, 0, end);
+ return buf.toString('utf8', i, end);
+}
+
+// For UTF-8, a replacement character is added when ending on a partial
+// character.
+function utf8End(buf) {
+ var r = buf && buf.length ? this.write(buf) : '';
+ if (this.lastNeed) return r + '\ufffd';
+ return r;
+}
+
+// UTF-16LE typically needs two bytes per character, but even if we have an even
+// number of bytes available, we need to check if we end on a leading/high
+// surrogate. In that case, we need to wait for the next two bytes in order to
+// decode the last character properly.
+function utf16Text(buf, i) {
+ if ((buf.length - i) % 2 === 0) {
+ var r = buf.toString('utf16le', i);
+ if (r) {
+ var c = r.charCodeAt(r.length - 1);
+ if (c >= 0xD800 && c <= 0xDBFF) {
+ this.lastNeed = 2;
+ this.lastTotal = 4;
+ this.lastChar[0] = buf[buf.length - 2];
+ this.lastChar[1] = buf[buf.length - 1];
+ return r.slice(0, -1);
+ }
+ }
+ return r;
+ }
+ this.lastNeed = 1;
+ this.lastTotal = 2;
+ this.lastChar[0] = buf[buf.length - 1];
+ return buf.toString('utf16le', i, buf.length - 1);
+}
+
+// For UTF-16LE we do not explicitly append special replacement characters if we
+// end on a partial character, we simply let v8 handle that.
+function utf16End(buf) {
+ var r = buf && buf.length ? this.write(buf) : '';
+ if (this.lastNeed) {
+ var end = this.lastTotal - this.lastNeed;
+ return r + this.lastChar.toString('utf16le', 0, end);
+ }
+ return r;
+}
+
+function base64Text(buf, i) {
+ var n = (buf.length - i) % 3;
+ if (n === 0) return buf.toString('base64', i);
+ this.lastNeed = 3 - n;
+ this.lastTotal = 3;
+ if (n === 1) {
+ this.lastChar[0] = buf[buf.length - 1];
+ } else {
+ this.lastChar[0] = buf[buf.length - 2];
+ this.lastChar[1] = buf[buf.length - 1];
+ }
+ return buf.toString('base64', i, buf.length - n);
+}
+
+function base64End(buf) {
+ var r = buf && buf.length ? this.write(buf) : '';
+ if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
+ return r;
+}
+
+// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
+function simpleWrite(buf) {
+ return buf.toString(this.encoding);
+}
+
+function simpleEnd(buf) {
+ return buf && buf.length ? this.write(buf) : '';
+}
\ No newline at end of file
diff --git a/node_modules/string_decoder/package.json b/node_modules/string_decoder/package.json
new file mode 100644
index 0000000..d4f5c98
--- /dev/null
+++ b/node_modules/string_decoder/package.json
@@ -0,0 +1,106 @@
+{
+ "_args": [
+ [
+ "string_decoder@~1.1.1",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream"
+ ]
+ ],
+ "_from": "string_decoder@>=1.1.1 <1.2.0",
+ "_hasShrinkwrap": false,
+ "_id": "string_decoder@1.1.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/string_decoder",
+ "_nodeVersion": "8.10.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/string_decoder_1.1.1_1522397654739_0.2722524344416213"
+ },
+ "_npmUser": {
+ "email": "hello@matteocollina.com",
+ "name": "matteo.collina"
+ },
+ "_npmVersion": "5.8.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "string_decoder",
+ "raw": "string_decoder@~1.1.1",
+ "rawSpec": "~1.1.1",
+ "scope": null,
+ "spec": ">=1.1.1 <1.2.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/readable-stream"
+ ],
+ "_resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "_shasum": "9cf1611ba62685d7030ae9e4ba34149c3af03fc8",
+ "_shrinkwrap": null,
+ "_spec": "string_decoder@~1.1.1",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream",
+ "bugs": {
+ "url": "https://github.com/nodejs/string_decoder/issues"
+ },
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ },
+ "description": "The string_decoder module from Node core",
+ "devDependencies": {
+ "babel-polyfill": "^6.23.0",
+ "core-util-is": "^1.0.2",
+ "inherits": "^2.0.3",
+ "tap": "~0.4.8"
+ },
+ "directories": {},
+ "dist": {
+ "fileCount": 5,
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "shasum": "9cf1611ba62685d7030ae9e4ba34149c3af03fc8",
+ "tarball": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "unpackedSize": 15298
+ },
+ "gitHead": "18c7f89c894ced5f610505bb006dfde9a3d1ac5e",
+ "homepage": "https://github.com/nodejs/string_decoder",
+ "keywords": [
+ "browser",
+ "browserify",
+ "decoder",
+ "string"
+ ],
+ "license": "MIT",
+ "main": "lib/string_decoder.js",
+ "maintainers": [
+ {
+ "name": "cwmma",
+ "email": "calvin.metcalf@gmail.com"
+ },
+ {
+ "name": "matteo.collina",
+ "email": "hello@matteocollina.com"
+ },
+ {
+ "name": "nodejs-foundation",
+ "email": "build@iojs.org"
+ },
+ {
+ "name": "rvagg",
+ "email": "rod@vagg.org"
+ },
+ {
+ "name": "substack",
+ "email": "substack@gmail.com"
+ }
+ ],
+ "name": "string_decoder",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/string_decoder.git"
+ },
+ "scripts": {
+ "ci": "tap test/parallel/*.js test/ours/*.js --tap | tee test.tap && node test/verify-dependencies.js",
+ "test": "tap test/parallel/*.js && node test/verify-dependencies"
+ },
+ "version": "1.1.1"
+}
diff --git a/node_modules/util-deprecate/History.md b/node_modules/util-deprecate/History.md
new file mode 100644
index 0000000..acc8675
--- /dev/null
+++ b/node_modules/util-deprecate/History.md
@@ -0,0 +1,16 @@
+
+1.0.2 / 2015-10-07
+==================
+
+ * use try/catch when checking `localStorage` (#3, @kumavis)
+
+1.0.1 / 2014-11-25
+==================
+
+ * browser: use `console.warn()` for deprecation calls
+ * browser: more jsdocs
+
+1.0.0 / 2014-04-30
+==================
+
+ * initial commit
diff --git a/node_modules/util-deprecate/LICENSE b/node_modules/util-deprecate/LICENSE
new file mode 100644
index 0000000..6a60e8c
--- /dev/null
+++ b/node_modules/util-deprecate/LICENSE
@@ -0,0 +1,24 @@
+(The MIT License)
+
+Copyright (c) 2014 Nathan Rajlich
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/util-deprecate/README.md b/node_modules/util-deprecate/README.md
new file mode 100644
index 0000000..75622fa
--- /dev/null
+++ b/node_modules/util-deprecate/README.md
@@ -0,0 +1,53 @@
+util-deprecate
+==============
+### The Node.js `util.deprecate()` function with browser support
+
+In Node.js, this module simply re-exports the `util.deprecate()` function.
+
+In the web browser (i.e. via browserify), a browser-specific implementation
+of the `util.deprecate()` function is used.
+
+
+## API
+
+A `deprecate()` function is the only thing exposed by this module.
+
+``` javascript
+// setup:
+exports.foo = deprecate(foo, 'foo() is deprecated, use bar() instead');
+
+
+// users see:
+foo();
+// foo() is deprecated, use bar() instead
+foo();
+foo();
+```
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2014 Nathan Rajlich
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/util-deprecate/browser.js b/node_modules/util-deprecate/browser.js
new file mode 100644
index 0000000..549ae2f
--- /dev/null
+++ b/node_modules/util-deprecate/browser.js
@@ -0,0 +1,67 @@
+
+/**
+ * Module exports.
+ */
+
+module.exports = deprecate;
+
+/**
+ * Mark that a method should not be used.
+ * Returns a modified function which warns once by default.
+ *
+ * If `localStorage.noDeprecation = true` is set, then it is a no-op.
+ *
+ * If `localStorage.throwDeprecation = true` is set, then deprecated functions
+ * will throw an Error when invoked.
+ *
+ * If `localStorage.traceDeprecation = true` is set, then deprecated functions
+ * will invoke `console.trace()` instead of `console.error()`.
+ *
+ * @param {Function} fn - the function to deprecate
+ * @param {String} msg - the string to print to the console when `fn` is invoked
+ * @returns {Function} a new "deprecated" version of `fn`
+ * @api public
+ */
+
+function deprecate (fn, msg) {
+ if (config('noDeprecation')) {
+ return fn;
+ }
+
+ var warned = false;
+ function deprecated() {
+ if (!warned) {
+ if (config('throwDeprecation')) {
+ throw new Error(msg);
+ } else if (config('traceDeprecation')) {
+ console.trace(msg);
+ } else {
+ console.warn(msg);
+ }
+ warned = true;
+ }
+ return fn.apply(this, arguments);
+ }
+
+ return deprecated;
+}
+
+/**
+ * Checks `localStorage` for boolean values for the given `name`.
+ *
+ * @param {String} name
+ * @returns {Boolean}
+ * @api private
+ */
+
+function config (name) {
+ // accessing global.localStorage can trigger a DOMException in sandboxed iframes
+ try {
+ if (!global.localStorage) return false;
+ } catch (_) {
+ return false;
+ }
+ var val = global.localStorage[name];
+ if (null == val) return false;
+ return String(val).toLowerCase() === 'true';
+}
diff --git a/node_modules/util-deprecate/node.js b/node_modules/util-deprecate/node.js
new file mode 100644
index 0000000..5e6fcff
--- /dev/null
+++ b/node_modules/util-deprecate/node.js
@@ -0,0 +1,6 @@
+
+/**
+ * For Node.js, simply re-export the core `util.deprecate` function.
+ */
+
+module.exports = require('util').deprecate;
diff --git a/node_modules/util-deprecate/package.json b/node_modules/util-deprecate/package.json
new file mode 100644
index 0000000..f21b337
--- /dev/null
+++ b/node_modules/util-deprecate/package.json
@@ -0,0 +1,81 @@
+{
+ "_args": [
+ [
+ "util-deprecate@~1.0.1",
+ "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream"
+ ]
+ ],
+ "_from": "util-deprecate@>=1.0.1 <1.1.0",
+ "_id": "util-deprecate@1.0.2",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/util-deprecate",
+ "_nodeVersion": "4.1.2",
+ "_npmUser": {
+ "email": "nathan@tootallnate.net",
+ "name": "tootallnate"
+ },
+ "_npmVersion": "2.14.4",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "util-deprecate",
+ "raw": "util-deprecate@~1.0.1",
+ "rawSpec": "~1.0.1",
+ "scope": null,
+ "spec": ">=1.0.1 <1.1.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/readable-stream"
+ ],
+ "_resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "_shasum": "450d4dc9fa70de732762fbd2d4a28981419a0ccf",
+ "_shrinkwrap": null,
+ "_spec": "util-deprecate@~1.0.1",
+ "_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/readable-stream",
+ "author": {
+ "email": "nathan@tootallnate.net",
+ "name": "Nathan Rajlich",
+ "url": "http://n8.io/"
+ },
+ "browser": "browser.js",
+ "bugs": {
+ "url": "https://github.com/TooTallNate/util-deprecate/issues"
+ },
+ "dependencies": {},
+ "description": "The Node.js `util.deprecate()` function with browser support",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "shasum": "450d4dc9fa70de732762fbd2d4a28981419a0ccf",
+ "tarball": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ },
+ "gitHead": "475fb6857cd23fafff20c1be846c1350abf8e6d4",
+ "homepage": "https://github.com/TooTallNate/util-deprecate",
+ "keywords": [
+ "browser",
+ "browserify",
+ "deprecate",
+ "node",
+ "util"
+ ],
+ "license": "MIT",
+ "main": "node.js",
+ "maintainers": [
+ {
+ "name": "tootallnate",
+ "email": "nathan@tootallnate.net"
+ }
+ ],
+ "name": "util-deprecate",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/TooTallNate/util-deprecate.git"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "version": "1.0.2"
+}
diff --git a/package.json b/package.json
index 0483ea2..8aa99e0 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
"description": "Node.js REST API alongside MongoDB",
"main": "index.js",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "nodemon index.js"
},
"author": "Arthur Dambrine",
"license": "ISC",
diff --git a/routes.js b/routes.js
new file mode 100755
index 0000000..731dbe4
--- /dev/null
+++ b/routes.js
@@ -0,0 +1,19 @@
+const express = require("express")
+const router = express.Router()
+
+// Set default API response
+router.get('/', function (req, res) {
+ res.json({
+ status: "L'API fonctionne",
+ message: "Bienvenu sur l'API Etudiants"
+ });
+});
+
+// Import etudiant controller
+var etudiantController = require('./etudiantController');
+
+// GET All etudiants
+router.route('/etudiants').get(etudiantController.index);
+
+
+module.exports = router //module.exports en fin de fichier pour export API routes
\ No newline at end of file
diff --git a/server.js b/server.js
deleted file mode 100755
index ed6d5b4..0000000
--- a/server.js
+++ /dev/null
@@ -1,8 +0,0 @@
-const http = require('http');
-const app = require('./app');
-
-const port = process.env.PORT || 3000;
-
-const server = http.createServer(app);
-
-server.listen(port);
\ No newline at end of file