<commit_before>var InsertCommand = require('./commands/insert_command').InsertCommand,
  QueryCommand = require('./commands/query_command').QueryCommand,
  DeleteCommand = require('./commands/delete_command').DeleteCommand,
  UpdateCommand = require('./commands/update_command').UpdateCommand,
  DbCommand = require('./commands/db_command').DbCommand,
  BinaryParser = require('./bson/binary_parser').BinaryParser,
  OrderedHash = require('./bson/collections').OrderedHash,
  BSON = require('./bson/bson'),
  ObjectID = BSON.ObjectID,
  Code = BSON.Code,
  Cursor = require('./cursor').Cursor;

/**
  Handles all the operations on objects in collections
**/
var Collection = exports.Collection = function(db, collectionName, pkFactory) {
    this.db = db;
  this.collectionName = collectionName;
  this.internalHint;
  this.pkFactory = pkFactory == null ? ObjectID : pkFactory;
  this.className = "Collection";
  // Add getter and setters
  this.__defineGetter__("hint", function() { return this.internalHint; });
  this.__defineSetter__("hint", function(value) { this.internalHint = this.normalizeHintField(value); });
  // Ensure the collection name is not illegal
  this.checkCollectionName(collectionName);
};

Collection.prototype.insert = function(docs, callback) {
  docs.constructor == Array ? this.insertAll(docs, callback) : this.insertAll([docs], callback);
  return this;
};

Collection.prototype.checkCollectionName = function(collectionName) {
  if(collectionName != null && collectionName.constructor != String) {
    throw Error("collection name must be a String");
  } else if(collectionName == null || collectionName == "" || collectionName.indexOf('..') != -1) {
    throw Error("collection names cannot be empty");
  } else if(collectionName.indexOf('$') != -1 && collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) {
    throw Error("collection names must not contain '$'");
  } else if(collectionName.match(/^\./) != null || collectionName.match(/\.$/) != null) {
    throw Error("collection names must not start or end with '.'");
  }
};

Collection.prototype.remove = function(selector, callback) {
  if(callback == null) { callback = selector; selector = null; }

  // Generate selector for remove all if not available
  var removeSelector = selector == null ? {} : selector;
  var deleteCommand = new DeleteCommand(this.db.databaseName + "." + this.collectionName, removeSelector);
  // Execute the command
  this.db.executeCommand(deleteCommand, callback);
  // Callback with no commands
  if(callback != null) callback(null, this);
};

Collection.prototype.rename = function(collectionName, callback) {
  var self = this;

  try {
    this.checkCollectionName(collectionName);
    this.db.renameCollection(this.collectionName, collectionName, function(err, results) {
      if(results[0].documents[0].ok == 0) {
        callback(new Error(results[0].documents[0].errmsg));
      } else {
        // Set collectionname to new one and return the collection
        self.db.collection(collectionName, callback);
      }
    });
  } catch(err) {
    callback(new Error(err.toString()));
  }
};

Collection.prototype.insertAll = function(docs, callback) {
  try {
    // List of all id's inserted
    var objects = [];
    // Create an insert command
    var insertCommand = new InsertCommand(this.db.databaseName + "." + this.collectionName);
    // Add id to each document if it's not already defined
    for(var index = 0; index < docs.length; index++) {
      var doc = docs[index];

      if(!(doc.className == "OrderedHash")) {
        doc._id = doc._id == null ? this.pkFactory.createPk() : doc._id;
      } else {
        // Add the id to the document
        var id = doc.get("_id") == null ? this.pkFactory.createPk() : doc.get("_id");
        doc.add('_id', id);
      }

      // Insert the document
      insertCommand.add(doc);
      objects.push(doc);
    }
    // Execute the command
    this.db.executeCommand(insertCommand);
    // Return the id's inserted calling the callback (mongo does not callback on inserts)
    if(callback != null) callback(null, objects);
  } catch(err) {
    if(callback != null) callback(new Error(err.toString()), null);
  }
};

Collection.prototype.save = function(doc, options, callback) {
  var args = Array.prototype.slice.call(arguments, 1);
  callback = args.pop();
  options = args.length ? args.shift() : null;

  var id = (doc.className == "OrderedHash") ? doc.get('_id') : doc['_id'];

  if(id != null) {
    this.update({'_id':id}, doc, {'upsert':true, 'safe':options != null ? options['safe'] : false}, callback);
  } else {
    this.insert(doc, function(err, docs) { Array.isArray(docs) ? callback(err, docs[0]) : callback(err, docs); });
  }
};

/**
  Update a single document in this collection.
    spec - a associcated array containing the fields that need to be present in
      the document for the update to succeed

    document - an associated array with the fields to be updated or in the case of
      a upsert operation the fields to be inserted.

  Options:
    upsert - true/false (perform upsert operation)
    safe - true/false (perform check if the operation failed, required extra call to db)
**/
Collection.prototype.update = function(spec, document, options, callback) {
  if(callback == null) { callback = options; options = null; }
  try {
    var safe = options == null || options['safe'] == null || options['safe'] == false ? false : true;
    // Create update command
    var updateCommand = new UpdateCommand(this.db.databaseName + "." + this.collectionName, spec, document, options);
    // Execute command
    this.db.executeCommand(updateCommand);
    // If safe, we need to check for successful execution
    if(safe) {
      this.db.error(function(documents) {
        if(documents[0].updatedExisting == false) {
          if(callback != null) callback(new Error("Failed to update document"), null);
        } else {
          if(callback != null) callback(null, document);
        }
      });
    } else {
      // Call back with ok if no error found
      if(callback != null) callback(null, document);
    }
  } catch(err) {
    if(callback != null) callback(new Error(err.toString()), null);
  }
};

/**
  Fetch a distinct collection
**/
Collection.prototype.distinct = function(key, query, callback) {
  var args = Array.prototype.slice.call(arguments, 1);
  callback = args.pop();
  query = args.length ? args.shift() : {};

  var mapCommandHash = new OrderedHash();
  mapCommandHash.add('distinct', this.collectionName)
        .add('key', key).add('query', query);

  this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, mapCommandHash), function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, results[0].documents[0].values);
    } else {
      callback(new Error(results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.count = function(query, callback) {
  if(typeof query === "function") { callback = query; query = null; }
  var query_object = query == null ? new OrderedHash() : query;
  var final_query = {'count':this.collectionName, 'query':query_object, 'fields':null};
  var queryCommand = new QueryCommand(this.db.databaseName + ".$cmd", QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, final_query, null);
  // Execute the command
  this.db.executeCommand(queryCommand, function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, results[0].documents[0].n);
    } else {
      callback(new Error(results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.drop = function(callback) {
  this.db.dropCollection(this.collectionName, callback);
};

Collection.prototype.find = function(selector, options, callback) {
  if(typeof selector === "function") { callback = selector; selector = null; options = null; }
  if(typeof options === "function") { callback = options; options = null; }

  if (options == null) options = {};
  // Unpack options
  var fields = options['fields'] != null && options['fields'].length == 0 ? ["_id"] : options['fields'];
  var finalSelector = selector == null ? new OrderedHash() : selector;
  var skip = options['skip'] == null ? 0 : options['skip'];
  var limit = options['limit'] == null ? 0 : options['limit'];
  var sort = options['sort'];
  var explain = options['explain'];
  var snapshot = options['snapshot'];
  var timeout = options['timeout'];
  var finalFields = {};

  var finalHint = options['hint'] != null ? this.normalizeHintField(options['hint']) : this.internalHint;

  // Build the list off options into a object if it's an array (need to encode as BSON object)
  if(fields != null && fields.constructor == Array) {
    fields.forEach(function(field) {
      finalFields[field] = 1;
    });
  } else {
    finalFields = fields;
  }
  // Create cursor
  callback(null, new Cursor(this.db, this, finalSelector, finalFields, skip, limit, sort, finalHint, explain, snapshot, timeout));
};

Collection.prototype.normalizeHintField = function(hint) {
  var finalHint = null;
  // Normalize the hint parameter
  if(hint != null && hint.constructor == String) {
    finalHint = new OrderedHash().add(hint, 1);
  } else if(hint != null && hint.constructor == Object) {
    finalHint = new OrderedHash();
    for(var name in hint) { finalHint.add(name, hint[name]); }
  } else if(hint != null && hint.constructor == Array) {
    finalHint = new OrderedHash();
    hint.forEach(function(param) { finalHint.add(param, 1); });
  }
  return finalHint;
};

Collection.prototype.findOne = function(queryObject, callback) {
  if(callback == null) { callback = queryObject; queryObject = {}; }
  var finalQueryObject = queryObject == null ? {} : queryObject;
  // Validate the type of query
  finalQueryObject = finalQueryObject.className == "ObjectID" ? {'_id':finalQueryObject} : finalQueryObject;
  // Execute the command
  var queryCommand = new QueryCommand(this.db.databaseName + "." + this.collectionName, {}, 0, -1, finalQueryObject, null);
  this.db.executeCommand(queryCommand, function(results) {
    callback(null, results[0].documents[0]);
  });
};

Collection.prototype.createIndex = function(fieldOrSpec, unique, callback) {
  this.db.createIndex(this.collectionName, fieldOrSpec, unique, callback);
};

Collection.prototype.indexInformation = function(callback) {
  this.db.indexInformation(this.collectionName, callback);
};

Collection.prototype.dropIndex = function(indexName, callback) {
  this.db.dropIndex(this.collectionName, indexName, callback);
};

Collection.prototype.dropIndexes = function(callback) {
  this.db.dropIndex(this.collectionName, "*", function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, true);
    } else {
      callback(new Error("map-reduce failed: " + results[0].documents[0].errmsg), false);
    }
  });
};

Collection.prototype.mapReduce = function(map, reduce, options, callback) {
  var args = Array.prototype.slice.call(arguments, 2);
  callback = args.pop();
  options = args.length ? args.shift() : {};

  var self = this;

  if(typeof map === "function") { map = map.toString(); }
  if(typeof reduce == "function") { reduce = reduce.toString(); }

  // Build command object for execution
  var mapCommandHash = new OrderedHash();
  mapCommandHash.add('mapreduce', this.collectionName)
    .add('map', map)
    .add('reduce', reduce);
  // Add any other options passed in
  for(var name in options) {
    mapCommandHash.add(name, options[name]);
  }
  // Execute command against server
  this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, mapCommandHash), function(results) {
    if(results[0].documents[0].ok == 1) {
      // Create a collection object that wraps the result collection
      self.db.collection(results[0].documents[0].result, function(err, collection) {
        callback(null, collection);
      });
    } else {
      callback(new Error("map-reduce failed: " + results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.group = function(keys, condition, initial, reduce, command, callback) {
  var args = Array.prototype.slice.call(arguments, 3);
  callback = args.pop();
  reduce = args.length ? args.shift() : null;
  command = args.length ? args.shift() : null;

  if(command) {
    var hash = new OrderedHash();
    keys.forEach(function(key) {
      hash.add(key, 1);
    });

    var reduceFunction = reduce != null && reduce.className == "Code" ? reduce : new Code(reduce);
    var selector = {'group': {
                      'ns':this.collectionName,
                      '$reduce': reduce,
                      'key':hash,
                      'cond':condition,
                      'initial': initial}};

    this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, selector), function(results) {
      var document = results[0].documents[0];
      if(document.retval != null) {
        callback(null, document.retval);
      } else {
        callback(new Error("group command failed: " + document.errmsg), null);
      }
    });
  } else {
    // Create execution scope
    var scope = reduce != null && reduce.className == "Code" ? reduce.scope : new OrderedHash();
    // Create scope for execution
    scope.add('ns', this.collectionName)
      .add('keys', keys)
      .add('condition', condition)
      .add('initial', initial);

    // Define group function
    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; i < keys.length; 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()};
      };

    // Turn function into text and replace the "result" function of the grouping function
    var groupFunctionString = groupFunction.toString().replace(/ reduce;/, reduce.toString() + ';');
    // Execute group
    this.db.eval(new Code(groupFunctionString, scope), function(err, results) {
      if(err instanceof Error) {
        callback(err, null);
      } else {
        if(results.constructor == Object) {
          callback(err, results.result);
        } else {
          callback(err, results);
        }
      }
    });
  }
};

Collection.prototype.options = function(callback) {
  this.db.collectionsInfo(this.collectionName, function(err, cursor) {
    // Fetch the object from the cursor
    cursor.nextObject(function(err, document) {
      callback(null, (document != null ? document.options : document));
    });
  });
};
<commit_msg>* Some minor code changes<commit_after>var InsertCommand = require('./commands/insert_command').InsertCommand,
  QueryCommand = require('./commands/query_command').QueryCommand,
  DeleteCommand = require('./commands/delete_command').DeleteCommand,
  UpdateCommand = require('./commands/update_command').UpdateCommand,
  DbCommand = require('./commands/db_command').DbCommand,
  BinaryParser = require('./bson/binary_parser').BinaryParser,
  OrderedHash = require('./bson/collections').OrderedHash,
  BSON = require('./bson/bson'),
  ObjectID = BSON.ObjectID,
  Code = BSON.Code,
  Cursor = require('./cursor').Cursor;

/**
  Handles all the operations on objects in collections
**/
var Collection = exports.Collection = function(db, collectionName, pkFactory) {
    this.db = db;
  this.collectionName = collectionName;
  this.internalHint;
  this.pkFactory = pkFactory == null ? ObjectID : pkFactory;
  this.className = "Collection";
  // Add getter and setters
  this.__defineGetter__("hint", function() { return this.internalHint; });
  this.__defineSetter__("hint", function(value) { this.internalHint = this.normalizeHintField(value); });
  // Ensure the collection name is not illegal
  this.checkCollectionName(collectionName);
};

Collection.prototype.insert = function(docs, callback) {
  this.insertAll(Array.isArray(docs) ? docs : [docs], callback);
  return this;
};

Collection.prototype.checkCollectionName = function(collectionName) {
  if (typeof collectionName != 'string')
    throw Error("collection name must be a String");

  if (!collectionName || collectionName.indexOf('..') != -1)
    throw Error("collection names cannot be empty");

  if (collectionName.indexOf('$') != -1 && collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null)
    throw Error("collection names must not contain '$'");

  if (collectionName.match(/^\.|\.$/) != null)
    throw Error("collection names must not start or end with '.'");
};

Collection.prototype.remove = function(selector, callback) {
  if(callback == null) { callback = selector; selector = null; }

  // Generate selector for remove all if not available
  var removeSelector = selector == null ? {} : selector;
  var deleteCommand = new DeleteCommand(this.db.databaseName + "." + this.collectionName, removeSelector);
  // Execute the command
  this.db.executeCommand(deleteCommand, callback);
  // Callback with no commands
  if(callback != null) callback(null, this);
};

Collection.prototype.rename = function(collectionName, callback) {
  var self = this;

  try {
    this.checkCollectionName(collectionName);
    this.db.renameCollection(this.collectionName, collectionName, function(err, results) {
      if(results[0].documents[0].ok == 0) {
        callback(new Error(results[0].documents[0].errmsg));
      } else {
        // Set collectionname to new one and return the collection
        self.db.collection(collectionName, callback);
      }
    });
  } catch(err) {
    callback(err);
  }
};

Collection.prototype.insertAll = function(docs, callback) {
  try {
    // List of all id's inserted
    var objects = [];
    // Create an insert command
    var insertCommand = new InsertCommand(this.db.databaseName + "." + this.collectionName);
    // Add id to each document if it's not already defined
    for(var index = 0; index < docs.length; index++) {
      var doc = docs[index];

      if(!(doc.className == "OrderedHash")) {
        doc._id = doc._id == null ? this.pkFactory.createPk() : doc._id;
      } else {
        // Add the id to the document
        var id = doc.get("_id") == null ? this.pkFactory.createPk() : doc.get("_id");
        doc.add('_id', id);
      }

      // Insert the document
      insertCommand.add(doc);
      objects.push(doc);
    }
    // Execute the command
    this.db.executeCommand(insertCommand);
    // Return the id's inserted calling the callback (mongo does not callback on inserts)
    if(callback != null) callback(null, objects);
  } catch(err) {
    if(callback != null) callback(err, null);
  }
};

Collection.prototype.save = function(doc, options, callback) {
  var args = Array.prototype.slice.call(arguments, 1);
  callback = args.pop();
  options = args.length ? args.shift() : null;

  var id = (doc.className == "OrderedHash") ? doc.get('_id') : doc['_id'];

  if(id != null) {
    this.update({'_id':id}, doc, {upsert: true, safe: options != null ? options.safe : false}, callback);
  } else {
    this.insert(doc, function(err, docs) { Array.isArray(docs) ? callback(err, docs[0]) : callback(err, docs); });
  }
};

/**
  Update a single document in this collection.
    spec - a associcated array containing the fields that need to be present in
      the document for the update to succeed

    document - an associated array with the fields to be updated or in the case of
      a upsert operation the fields to be inserted.

  Options:
    upsert - true/false (perform upsert operation)
    safe - true/false (perform check if the operation failed, required extra call to db)
**/
Collection.prototype.update = function(spec, document, options, callback) {
  if(callback == null) { callback = options; options = null; }
  try {
    var safe = options == null || options.safe == null || options.safe == false ? false : true;
    // Create update command
    var updateCommand = new UpdateCommand(this.db.databaseName + "." + this.collectionName, spec, document, options);
    // Execute command
    this.db.executeCommand(updateCommand);
    // If safe, we need to check for successful execution
    if(safe) {
      this.db.error(function(documents) {
        if(documents[0].updatedExisting == false) {
          if(callback != null) callback(new Error("Failed to update document"), null);
        } else {
          if(callback != null) callback(null, document);
        }
      });
    } else {
      // Call back with ok if no error found
      if(callback != null) callback(null, document);
    }
  } catch(err) {
    if(callback != null) callback(err, null);
  }
};

/**
  Fetch a distinct collection
**/
Collection.prototype.distinct = function(key, query, callback) {
  var args = Array.prototype.slice.call(arguments, 1);
  callback = args.pop();
  query = args.length ? args.shift() : {};

  var mapCommandHash = new OrderedHash();
  mapCommandHash.add('distinct', this.collectionName).add('key', key).add('query', query);

  this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, mapCommandHash), function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, results[0].documents[0].values);
    } else {
      callback(new Error(results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.count = function(query, callback) {
  if(typeof query === "function") { callback = query; query = null; }
  var query_object = query == null ? new OrderedHash() : query;
  var final_query = {count: this.collectionName, query: query_object, fields: null};
  var queryCommand = new QueryCommand(this.db.databaseName + ".$cmd", QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, final_query, null);
  // Execute the command
  this.db.executeCommand(queryCommand, function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, results[0].documents[0].n);
    } else {
      callback(new Error(results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.drop = function(callback) {
  this.db.dropCollection(this.collectionName, callback);
};

Collection.prototype.find = function(selector, options, callback) {
  if(typeof selector === "function") { callback = selector; selector = null; options = null; }
  if(typeof options === "function") { callback = options; options = null; }

  if (options == null) options = {};
  // Unpack options
  var fields = options.fields != null && options.fields.length == 0 ? ["_id"] : options.fields;
  var finalSelector = selector == null ? new OrderedHash() : selector;
  var skip = options.skip == null ? 0 : options.skip;
  var limit = options.limit == null ? 0 : options.limit;
  var sort = options.sort;
  var explain = options.explain;
  var snapshot = options.snapshot;
  var timeout = options.timeout;
  var finalFields = {};

  var finalHint = options.hint != null ? this.normalizeHintField(options.hint) : this.internalHint;

  // Build the list off options into a object if it's an array (need to encode as BSON object)
  if(fields != null && fields.constructor == Array) {
    fields.forEach(function(field) {
      finalFields[field] = 1;
    });
  } else {
    finalFields = fields;
  }
  // Create cursor
  callback(null, new Cursor(this.db, this, finalSelector, finalFields, skip, limit, sort, finalHint, explain, snapshot, timeout));
};

Collection.prototype.normalizeHintField = function(hint) {
  var finalHint = null;
  // Normalize the hint parameter
  if(hint != null && hint.constructor == String) {
    finalHint = new OrderedHash().add(hint, 1);
  } else if(hint != null && hint.constructor == Object) {
    finalHint = new OrderedHash();
    for(var name in hint) { finalHint.add(name, hint[name]); }
  } else if(hint != null && hint.constructor == Array) {
    finalHint = new OrderedHash();
    hint.forEach(function(param) { finalHint.add(param, 1); });
  }
  return finalHint;
};

Collection.prototype.findOne = function(queryObject, callback) {
  if(callback == null) { callback = queryObject; queryObject = {}; }
  var finalQueryObject = queryObject == null ? {} : queryObject;
  // Validate the type of query
  finalQueryObject = finalQueryObject.className == "ObjectID" ? {'_id':finalQueryObject} : finalQueryObject;
  // Execute the command
  var queryCommand = new QueryCommand(this.db.databaseName + "." + this.collectionName, {}, 0, -1, finalQueryObject, null);
  this.db.executeCommand(queryCommand, function(results) {
    callback(null, results[0].documents[0]);
  });
};

Collection.prototype.createIndex = function(fieldOrSpec, unique, callback) {
  this.db.createIndex(this.collectionName, fieldOrSpec, unique, callback);
};

Collection.prototype.indexInformation = function(callback) {
  this.db.indexInformation(this.collectionName, callback);
};

Collection.prototype.dropIndex = function(indexName, callback) {
  this.db.dropIndex(this.collectionName, indexName, callback);
};

Collection.prototype.dropIndexes = function(callback) {
  this.db.dropIndex(this.collectionName, "*", function(results) {
    if(results[0].documents[0].ok == 1) {
      callback(null, true);
    } else {
      callback(new Error("map-reduce failed: " + results[0].documents[0].errmsg), false);
    }
  });
};

Collection.prototype.mapReduce = function(map, reduce, options, callback) {
  var args = Array.prototype.slice.call(arguments, 2);
  callback = args.pop();
  options = args.length ? args.shift() : {};

  var self = this;

  if(typeof map === "function") { map = map.toString(); }
  if(typeof reduce == "function") { reduce = reduce.toString(); }

  // Build command object for execution
  var mapCommandHash = new OrderedHash();
  mapCommandHash.add('mapreduce', this.collectionName)
    .add('map', map)
    .add('reduce', reduce);
  // Add any other options passed in
  for(var name in options) {
    mapCommandHash.add(name, options[name]);
  }
  // Execute command against server
  this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, mapCommandHash), function(results) {
    if(results[0].documents[0].ok == 1) {
      // Create a collection object that wraps the result collection
      self.db.collection(results[0].documents[0].result, function(err, collection) {
        callback(null, collection);
      });
    } else {
      callback(new Error("map-reduce failed: " + results[0].documents[0].errmsg), null);
    }
  });
};

Collection.prototype.group = function(keys, condition, initial, reduce, command, callback) {
  var args = Array.prototype.slice.call(arguments, 3);
  callback = args.pop();
  reduce = args.length ? args.shift() : null;
  command = args.length ? args.shift() : null;

  if(command) {
    var hash = new OrderedHash();
    keys.forEach(function(key) {
      hash.add(key, 1);
    });

    var reduceFunction = reduce != null && reduce.className == "Code" ? reduce : new Code(reduce);
    var selector = {'group': {
                      'ns':this.collectionName,
                      '$reduce': reduce,
                      'key':hash,
                      'cond':condition,
                      'initial': initial}};

    this.db.executeCommand(DbCommand.createDbCommand(this.db.databaseName, selector), function(results) {
      var document = results[0].documents[0];
      if(document.retval != null) {
        callback(null, document.retval);
      } else {
        callback(new Error("group command failed: " + document.errmsg), null);
      }
    });
  } else {
    // Create execution scope
    var scope = reduce != null && reduce.className == "Code" ? reduce.scope : new OrderedHash();
    // Create scope for execution
    scope.add('ns', this.collectionName)
      .add('keys', keys)
      .add('condition', condition)
      .add('initial', initial);

    // Define group function
    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; i < keys.length; 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()};
      };

    // Turn function into text and replace the "result" function of the grouping function
    var groupFunctionString = groupFunction.toString().replace(/ reduce;/, reduce.toString() + ';');
    // Execute group
    this.db.eval(new Code(groupFunctionString, scope), function(err, results) {
      if(err instanceof Error) {
        callback(err, null);
      } else {
        if(results.constructor == Object) {
          callback(err, results.result);
        } else {
          callback(err, results);
        }
      }
    });
  }
};

Collection.prototype.options = function(callback) {
  this.db.collectionsInfo(this.collectionName, function(err, cursor) {
    // Fetch the object from the cursor
    cursor.nextObject(function(err, document) {
      callback(null, (document != null ? document.options : document));
    });
  });
};
<|endoftext|>


<commit_before>;(function(){'use strict';function u(a,c,b){if(null==a)throw Error("Undefined or null cannot be stringified.");if(F(a))throw Error("Converting circular structure to TOML.");c="function"===typeof c?c:null;b=B(b);if(!n(a))return C(a,c,b);var d=[];w({path:[],table:{"":a},c:!1,replace:c,a:0,b:b,d:d},"",a,function(a,b,c){var g=null;if(n(c))""!==b&&(0<d.length&&d.push(""),g=a.c?"[["+x(a.path,!0)+"]]":"["+x(a.path,!0)+"]",d.push(r(g,a.a,a.b)));else if(p(c))if(k(b))v(c)||(g=A(a,b,c),k(g)&&d.push(r(g,a.a,a.b)));
else return!0;else return k(b)&&(g=A(a,b,c),k(g)&&d.push(r(g,a.a,a.b))),!0});return d.join("\n")}function B(a){return k(a)?a:"number"===typeof a&&0<=a&&isFinite(a)&&Math.floor(a)===a?D(" ",a):""}function r(a,c,b){c=D(b,c);return a.replace(/^/mg,c)}function D(a,c){if(a.repeat)return a.repeat(c);for(var b="",d="";0<c;)d+=d||a,c&1&&(b+=d),c>>>=1;return b}function w(a,c,b,d){var e;if(a.replace&&0===a.path.length&&(e=y(a,c,b),k(e)&&a.d.push(e),!1!==e))return;if(!d(a,c,b)){c=a.table;a.table=b;if(p(b)){var g=
a.c;a.c=v(b);for(var f=0,l=b.length;f<l;f++)a.path.push(f),w(a,f,b[f],d),a.path.pop();a.c=g}else if(n(b)){g=a.c;a.c=!1;var q=[],m=[],h;for(h in b)Object.prototype.hasOwnProperty.call(b,h)&&(e=b[h],f=0<a.path.length&&(p(e)?v(e):n(e)),p(e)&&v(e)?m.push(h,e,f):n(e)?q.push(h,e,f):(a.path.push(h),w(a,h,e,d),a.path.pop()));if(a.replace){f=0;for(l=q.length;f<l;f+=3)a.path.push(q[f]),e=y(a,q[f],q[f+1]),k(e)?(a.d.push(r(e,a.a,a.b)),q[f+1]=null):null==e&&(q[f+1]=null),a.path.pop();f=0;for(l=m.length;f<l;f+=
3){a.path.push(m[f]);e=y(a,m[f],m[f+1]);if(k(e))e=t(m[f])+" = "+e,a.d.push(r(e,a.a,a.b));else if(null==e){m[f+1]=null;a.path.pop();continue}b=0;for(h=m[f+1].length;b<h;b++)if(a.path.push(b),e=y(a,f,m[f+1][b]),a.path.pop(),!1!==e){e=A(a,m[f],m[f+1]);k(e)&&a.d.push(r(e,a.a,a.b));m[f+1]=null;break}a.path.pop()}}h=q.concat(m);f=0;for(l=h.length;f<l;f+=3)null!=h[f+1]&&(a.path.push(h[f]),h[f+2]&&a.a++,w(a,h[f],h[f+1],d),h[f+2]&&a.a--,a.path.pop());a.c=g}a.table=c}}function y(a,c,b){if(a.replace){b=a.replace.call({path:a.path.slice(0),
table:a.table},c,b);if(k(b))return t(c)+" = "+b;if(null==b)return null;if(!1!==b)throw Error(l(a.path,"Replacer must return a string, false, null or undefined."));}return!1}function A(a,c,b){var d=t(c);if(!d)throw Error(l(a.path,"Key cannot be an empty string."));a=z(a,c,b);return k(a)?d+" = "+a:null}function t(a){return a?/^[a-zA-Z0-9\-_]+$/.test(a)?a:E(a):!1}function C(a,c,b){if(null==a)throw Error("Undefined or null cannot be stringified.");return z({path:[],table:{"":a},c:!1,replace:"function"===
typeof c?c:null,a:0,b:B(b)},"",a)}function z(a,c,b){if(a.replace){c=a.replace.call({path:a.path.slice(0),table:a.table},c,b);if(k(c))return c;if(null==c)return null;if(!1!==c)throw Error(l(a.path,"Replacer must return a string, false, null or undefined."));}switch(g(b)){case g.Boolean:return b?"true":"false";case g.String:return E(b);case g.Number:if(!isFinite(b))throw Error(l(a.path,"Number must be finite."));a=(Number.e?Number.e(b):Math.floor(b)===b)?b.toFixed(1):String(b);a=a.replace(/([eE])(\d)/,
"$1+$2");return/[.eE]/.test(a)?a:a+".0";case g.Array:var d;a:{if(!(2>b.length)){d=g(b[0]);c=1;for(var e=b.length;c<e;c++)if(null!=b[c]&&g(b[c])!==d){d=!0;break a}}d=!1}if(d)throw Error(l(a.path,"Array cannot contain values of different types."));c=a.table;a.table=b;d=[];for(var e=0,n=b.length;e<n;e++){a.path.push(e);var f=z(a,e,b[e]);k(f)&&d.push(f);a.path.pop()}a.table=c;if(c=0<d.length&&a.b){a:{if(!(1>b.length))for(c=0,e=b.length;c<e;c++)if(p(b[c])){c=!0;break a}c=!1}c=c||v(b)}return c?"[\n"+r(d.join(",\n"),
1,a.b)+"\n]":"["+d.join(", ")+"]";case g.Date:if(!isFinite(b.getTime()))throw Error(l(a.path,"Invalid Date"));return b.toISOString();default:if(null==b)a=null;else{c=a.table;a.table=b;e=[];for(d in b)if(Object.prototype.hasOwnProperty.call(b,d)&&null!=b[d]){if(!d)throw Error(l(a.path,"Key cannot be an empty string."));a.path.push(d);n=z(a,d,b[d]);k(n)&&e.push(t(d)+" = "+n);a.path.pop()}a.table=c;a="{"+e.join(", ")+"}"}return a}}function E(a){return"object"===typeof JSON&&JSON?JSON.stringify(a):'"'+
String(a).replace(/[\x00-\x1F"\\]/g,function(a){switch(a){case '"':case "\\":return"\\"+a;case "\t":return"\\t";case "\n":return"\\n";case "\r":return"\\r";case "\b":return"\\b";case "\f":return"\\f";default:return a=a.charCodeAt(0).toString(16),"\\u"+"0000".substr(a.length)+a}})+'"'}function F(a){function c(a,d){if(!p(a)&&!n(a))return!1;if(-1!==d.indexOf(a))return!0;d.push(a);for(var e in a)if(Object.prototype.hasOwnProperty.call(a,e)){var g=d.length;if(c(a[e],d))return!0;d.splice(g)}return!1}return c(a,
[])}function v(a){if(1>a.length)return!1;for(var c=0,b=a.length;c<b;c++)if(n(a[c]))return!0;return!1}function n(a){return null!==a&&"object"===typeof a&&!(p(a)||g(a)===g.Date)}function k(a){return"string"===typeof a}function g(a){return Object.prototype.toString.call(a)}function l(a,c){return(x(a)||"<root>")+": "+c}function x(a,c){if(0===a.length)return"";for(var b="",d=0,e=a.length;d<e;d++)if(k(a[d])&&a[d])b+=(b?".":"")+t(a[d]);else if("number"===typeof a[d])c||(b+=(b?".":"")+"["+a[d]+"]");else return!1;
return b?b:!1}g.Boolean=g(!1);g.String=g("");g.Number=g(0);g.Array=g([]);g.Date=g(new Date(0));var p=Array.isArray||function(a){return g(a)===g.Array};u.toKey=function(a,c){if(k(a)){var b=t(a);if(!b)throw Error("Key cannot be an empty string.");return b}if(p(a)){b=x(a,c);if(!1===b)throw Error("Key path must consist of non-empty string(s).");return b}throw Error("Invalid Arguments for tomlify.toKey({String | Array})");};u.toValue=C;null!=("undefined"!==typeof module&&null!==module?module.exports:void 0)?
module.exports=u:"function"===typeof define&&define.amd?define([],function(){return u}):this.tomlify=u}).call(this);
<commit_msg>Update minified script<commit_after>;(function(){'use strict';function u(a,c,b){if(null==a)throw Error("Undefined or null cannot be stringified.");if(F(a))throw Error("Converting circular structure to TOML.");c="function"===typeof c?c:null;b=B(b);if(!n(a))return C(a,c,b);var d=[];w({path:[],table:{"":a},b:!1,replace:c,level:0,a:b,c:d},"",a,function(a,b,c){if(n(c))""!==b&&(0<d.length&&d.push(""),b=a.b?"[["+x(a.path,!0)+"]]":"["+x(a.path,!0)+"]",d.push(r(b,a.level,a.a)));else if(p(c))if(k(b))v(c)||(b=A(a,b,c),k(b)&&d.push(r(b,a.level,a.a)));else return!0;
else return k(b)&&(b=A(a,b,c),k(b)&&d.push(r(b,a.level,a.a))),!0});return d.join("\n")}function B(a){return k(a)?a:"number"===typeof a&&0<=a&&isFinite(a)&&Math.floor(a)===a?D(" ",a):""}function r(a,c,b){c=D(b,c);return a.replace(/^(?!$)/mg,c)}function D(a,c){if(a.repeat)return a.repeat(c);for(var b="",d="";0<c;)d+=d||a,c&1&&(b+=d),c>>>=1;return b}function w(a,c,b,d){var e;if(a.replace&&0===a.path.length&&(e=y(a,c,b),k(e)&&a.c.push(e),!1!==e))return;if(!d(a,c,b)){c=a.table;a.table=b;if(p(b)){var g=
a.b;a.b=v(b);for(var f=0,l=b.length;f<l;f++)a.path.push(f),w(a,f,b[f],d),a.path.pop();a.b=g}else if(n(b)){g=a.b;a.b=!1;var q=[],m=[],h;for(h in b)Object.prototype.hasOwnProperty.call(b,h)&&(e=b[h],f=0<a.path.length&&(p(e)?v(e):n(e)),p(e)&&v(e)?m.push(h,e,f):n(e)?q.push(h,e,f):(a.path.push(h),w(a,h,e,d),a.path.pop()));if(a.replace){f=0;for(l=q.length;f<l;f+=3)a.path.push(q[f]),e=y(a,q[f],q[f+1]),k(e)?(a.c.push(r(e,a.level,a.a)),q[f+1]=null):null==e&&(q[f+1]=null),a.path.pop();f=0;for(l=m.length;f<
l;f+=3){a.path.push(m[f]);e=y(a,m[f],m[f+1]);if(k(e))e=t(m[f])+" = "+e,a.c.push(r(e,a.level,a.a));else if(null==e){m[f+1]=null;a.path.pop();continue}b=0;for(h=m[f+1].length;b<h;b++)if(a.path.push(b),e=y(a,b,m[f+1][b]),a.path.pop(),null==e)m[f+1][b]=null;else if(!1!==e){e=A(a,m[f],m[f+1]);k(e)&&a.c.push(r(e,a.level,a.a));m[f+1]=null;break}a.path.pop()}}h=q.concat(m);f=0;for(l=h.length;f<l;f+=3)null!=h[f+1]&&(a.path.push(h[f]),h[f+2]&&a.level++,w(a,h[f],h[f+1],d),h[f+2]&&a.level--,a.path.pop());a.b=
g}a.table=c}}function y(a,c,b){if(a.replace){b=a.replace.call({path:a.path.slice(0),table:a.table},c,b);if(k(b))return t(c)+" = "+b;if(null==b)return null;if(!1!==b)throw Error(l(a.path,"Replacer must return a string, false, null or undefined."));}return!1}function A(a,c,b){var d=t(c);if(!d)throw Error(l(a.path,"Key cannot be an empty string."));a=z(a,c,b);return k(a)?d+" = "+a:null}function t(a){return a?/^[a-zA-Z0-9\-_]+$/.test(a)?a:E(a):!1}function C(a,c,b){if(null==a)throw Error("Undefined or null cannot be stringified.");
return z({path:[],table:{"":a},b:!1,replace:"function"===typeof c?c:null,level:0,a:B(b)},"",a)}function z(a,c,b){if(a.replace){c=a.replace.call({path:a.path.slice(0),table:a.table},c,b);if(k(c))return c;if(null==c)return null;if(!1!==c)throw Error(l(a.path,"Replacer must return a string, false, null or undefined."));}switch(g(b)){case g.Boolean:return b?"true":"false";case g.String:return E(b);case g.Number:if(!isFinite(b))throw Error(l(a.path,"Number must be finite."));a=(Number.isInteger?Number.isInteger(b):
Math.floor(b)===b)?b.toFixed(1):String(b);a=a.replace(/([eE])(\d)/,"$1+$2");return/[.eE]/.test(a)?a:a+".0";case g.Array:var d;a:{if(!(2>b.length)){d=g(b[0]);c=1;for(var e=b.length;c<e;c++)if(null!=b[c]&&g(b[c])!==d){d=!0;break a}}d=!1}if(d)throw Error(l(a.path,"Array cannot contain values of different types."));c=a.table;a.table=b;d=[];for(var e=0,n=b.length;e<n;e++){a.path.push(e);var f=z(a,e,b[e]);k(f)&&d.push(f);a.path.pop()}a.table=c;if(c=0<d.length&&a.a){a:{if(!(1>b.length))for(c=0,e=b.length;c<
e;c++)if(p(b[c])){c=!0;break a}c=!1}c=c||v(b)}return c?"[\n"+r(d.join(",\n"),1,a.a)+"\n]":"["+d.join(", ")+"]";case g.Date:if(!isFinite(b.getTime()))throw Error(l(a.path,"Invalid Date"));return b.toISOString();default:if(null==b)a=null;else{c=a.table;a.table=b;e=[];for(d in b)if(Object.prototype.hasOwnProperty.call(b,d)&&null!=b[d]){if(!d)throw Error(l(a.path,"Key cannot be an empty string."));a.path.push(d);n=z(a,d,b[d]);k(n)&&e.push(t(d)+" = "+n);a.path.pop()}a.table=c;a="{"+e.join(", ")+"}"}return a}}
function E(a){return"object"===typeof JSON&&JSON?JSON.stringify(a):'"'+String(a).replace(/[\x00-\x1F"\\]/g,function(a){switch(a){case '"':case "\\":return"\\"+a;case "\t":return"\\t";case "\n":return"\\n";case "\r":return"\\r";case "\b":return"\\b";case "\f":return"\\f";default:return a=a.charCodeAt(0).toString(16),"\\u"+"0000".substr(a.length)+a}})+'"'}function F(a){function c(a,d){if(!p(a)&&!n(a))return!1;if(-1!==d.indexOf(a))return!0;d.push(a);for(var b in a)if(Object.prototype.hasOwnProperty.call(a,
b)){var g=d.length;if(c(a[b],d))return!0;d.splice(g)}return!1}return c(a,[])}function v(a){if(1>a.length)return!1;for(var c=0,b=a.length;c<b;c++)if(n(a[c]))return!0;return!1}function n(a){return null!==a&&"object"===typeof a&&!(p(a)||g(a)===g.Date)}function k(a){return"string"===typeof a}function g(a){return Object.prototype.toString.call(a)}function l(a,c){return(x(a)||"<root>")+": "+c}function x(a,c){if(0===a.length)return"";for(var b="",d=0,e=a.length;d<e;d++)if(k(a[d])&&a[d])b+=(b?".":"")+t(a[d]);
else if("number"===typeof a[d])c||(b+=(b?".":"")+"["+a[d]+"]");else return!1;return b?b:!1}g.Boolean=g(!1);g.String=g("");g.Number=g(0);g.Array=g([]);g.Date=g(new Date(0));var p=Array.isArray||function(a){return g(a)===g.Array};u.toKey=function(a,c){if(k(a)){var b=t(a);if(!b)throw Error("Key cannot be an empty string.");return b}if(p(a)){b=x(a,c);if(!1===b)throw Error("Key path must consist of non-empty string(s).");return b}throw Error("Invalid Arguments for tomlify.toKey({String | Array})");};u.toValue=
C;null!=("undefined"!==typeof module&&null!==module?module.exports:void 0)?module.exports=u:"function"===typeof define&&define.amd?define([],function(){return u}):this.tomlify=u}).call(this);
<|endoftext|>


<commit_before>// https://github.com/wizard04wsu/Class

/** @module Class */

export { BaseClass as default };

//for a Class instance property, an object with the instance's protected members
const protectedMembersSymbol = Symbol("protected members");

//state: when true, indicates that an instance of a class is being constructed and that there are still super class constructors that need to be invoked using $super
let _invokingSuperConstructor = false;

/**
 * @alias module:Class-Class
 * @abstract
 * @class
 */
const BaseClass = function Class(){

	if(!new.target && !_invokingSuperConstructor){
		//the 'new' keyword was not used

		throw new TypeError(`class constructor 'Class' cannot be invoked without 'new'`);
	}

	_invokingSuperConstructor = false;
	defineNonEnumerableProperty(this, protectedMembersSymbol, {}, true);

}

//*** for the prototype ***

//rename it so Object.prototype.toString() will use the base class's name
defineNonEnumerableProperty(BaseClass.prototype, Symbol.toStringTag, "Class", true);

//*** for the constructor ***

//make extend() a static member of the base class
defineNonEnumerableProperty(BaseClass, "extend", extend);

/**
 * Creates a child class.
 * @static
 * @param {initializer} init - Handler to initialize a new instance of the child class. The name of the function is used as the name of the class.
 * @param {function} [call] - Handler for when the class is called without using the `new` keyword. Default behavior is to throw a TypeError.
 * @return {Class} - The new child class.
 * @throws {TypeError} - 'extend' method requires that 'this' be a Class constructor
 * @throws {TypeError} - 'init' is not a function
 * @throws {TypeError} - 'init' must be a named function
 * @throws {TypeError} - 'call' is not a function
 */
function extend(init, call){
	/**
	 * @typedef {function} initializer
	 * @param {function} $super - The parent class's constructor, bound as the first argument. It is to be used like the `super` keyword. It *must* be called exactly once during the execution of the initializer, before any use of the `this` keyword.
	 * @param {...*} args
	 * @returns {object} - An object providing access to protected members.
	 */

	if(typeof this !== "function" || !(this === BaseClass || this.prototype instanceof BaseClass))
		throw new TypeError("'extend' method requires that 'this' be a Class constructor");
	if(typeof init !== "function")
		throw new TypeError("'init' is not a function");
	if(!init.name)
		throw new TypeError("'init' must be a named function");
	if(arguments.length > 1 && typeof call !== "function")
		throw new TypeError("'call' is not a function");

	const ParentClass = this;
	const className = init.name;

	/**
	 * The constructor for the new class.
	 * @class
	 * @augments ParentClass
	 * @private
	 * @throws {ReferenceError} - unexpected use of 'new' keyword
	 * @throws {ReferenceError} - super constructor may be called only once during execution of derived constructor
	 * @throws {ReferenceError} - invalid delete involving super constructor
	 * @throws {ReferenceError} - must call super constructor before accessing 'this'
	 * @throws {ReferenceError} - must call super constructor before returning from derived constructor
	 * @throws {ReferenceError} - class constructor cannot be invoked without 'new'
	 */
	function ChildClass(...argumentsList){

		if(!new.target && !_invokingSuperConstructor){
			//the 'new' keyword was not used

			//if a 'call' function was passed to 'extend', return its result
			if(call)
				return call(...argumentsList);

			throw new TypeError(`class constructor '${className}' cannot be invoked without 'new'`);
		}

		const newInstance = this;

		_invokingSuperConstructor = false;
		let _$superCalled = false;
		const $super = new Proxy(ParentClass, {
			construct(target, argumentsList, newTarget){
				//target = ParentClass
				//newTarget = $super

				//disallow use of the 'new' keyword when calling '$super'
				throw new ReferenceError("unexpected use of 'new' keyword");
			},
			apply(target, thisArg, argumentsList){
				//target = ParentClass

				if(_$superCalled)
					throw new ReferenceError("super constructor may be called only once during execution of derived constructor");
				_$superCalled = true;

				_invokingSuperConstructor = true;
				target.apply(newInstance, argumentsList);

				return newInstance[protectedMembersSymbol];
			},
			deleteProperty(target, property){
				//target = ParentClass

				//disallow deletion of static members of a parent class
				throw new ReferenceError("invalid delete involving super constructor");
			}
		});

		//I don't believe there's a way to trap access to `this` itself, but we can at least trap access to its properties:
		function proxyThisMethod(methodName, argumentsList){
			if(!_$superCalled)
				throw new ReferenceError("must call super constructor before accessing 'this'");
			return Reflect[methodName](...argumentsList);
		}
		let proxyForKeywordThis = new Proxy(newInstance, {
			defineProperty(){           return proxyThisMethod("defineProperty", arguments); },
			deleteProperty(){           return proxyThisMethod("deleteProperty", arguments); },
			get(){                      return proxyThisMethod("get", arguments); },
			getOwnPropertyDescriptor(){ return proxyThisMethod("getOwnPropertyDescriptor", arguments); },
			getPrototypeOf(){           return proxyThisMethod("getPrototypeOf", arguments); },
			has(){                      return proxyThisMethod("has", arguments); },
			isExtensible(){             return proxyThisMethod("isExtensible", arguments); },
			ownKeys(){                  return proxyThisMethod("ownKeys", arguments); },
			preventExtensions(){        return proxyThisMethod("preventExtensions", arguments); },
			set(){                      return proxyThisMethod("set", arguments); },
			setPrototypeOf(){           return proxyThisMethod("setPrototypeOf", arguments); }
		});

		init.apply(proxyForKeywordThis, [$super, ...argumentsList]);

		if(!_$superCalled) throw new ReferenceError("must call super constructor before returning from derived constructor");

		return newInstance;
	}

	//*** for the prototype ***

	//create the prototype (an instance of the parent class)
	ChildClass.prototype = Object.create(ParentClass.prototype);
	//rename it so Object.prototype.toString() will use the new class's name
	defineNonEnumerableProperty(ChildClass.prototype, Symbol.toStringTag, className, true);
	//set its constructor to be that of the new class
	defineNonEnumerableProperty(ChildClass.prototype, "constructor", ChildClass);

	//*** for the constructor ***

	//rename it to be that of the initializer
	defineNonEnumerableProperty(ChildClass, "name", className, true);
	//override .toString() to only output the initializer function
	defineNonEnumerableProperty(ChildClass, "toString", function toString(){ return init.toString(); });

	//make extend() a static method of the new class
	defineNonEnumerableProperty(ChildClass, "extend", extend);

	return ChildClass;
}

/* helper functions */

function defineNonEnumerableProperty(object, property, value, readonly){
	Object.defineProperty(object, property, {
		writable: !readonly, enumerable: false, configurable: true,
		value: value
	});
}
<commit_msg>- delete stray file<commit_after><|endoftext|>


<commit_before>
// get the information of the hacker on the current page
// this session variable 'hacker' is setted in the router
var hackerId = function () { return Session.get('hackerId'); }
var hackerProp = function(field) { return OtherUserProp(hackerId(), field); }
var hackerProps = function (fields) { return OtherUserProps(hackerId(), fields); }

// state
var state = new State('hacker', {
  activePanel: null,  /* mail, edit, null */
});

Template.hackerToolbar.events({
  'click [panel]': function(evt) {
    state.toggle('activePanel', $(evt.currentTarget).attr('panel'));
    Deps.flush();
    fillTemplate();
  },
  "click [action='invite']": function(evt) {
    var by = $(evt.currentTarget).attr('by');
    var userId = hackerId();

    // invite user
    Meteor.call('inviteUserAnonymous', userId, function(err,res) {
      var err = false;
      if (err) {
        console.log(err);
        new PNotify({
          title: 'Failed',
          text: "Something went wrong",
          type: 'error',
          icon: false
        });
      } else {
        openMailTemplate('personalWelcome');
        new PNotify({
          title: 'Activated',
          text: "User is now activated and has access to the site. Send a welcome message.",
          icon: false
        });
      }
    });
  },
  "click [action='verifyEmail']": function(evt) {
    Meteor.call('forceEmailVerification', hackerId(), function(err, res) {
      if (err) {
        console.log(err);
        new PNotify({
          title: 'Failed',
          text: "Something went wrong",
          type: 'error',
          icon: false
        });
      } else {
        openMailTemplate('personalWelcome');
        new PNotify({
          title: 'Email verified',
          text: "You have forced the verification of user's email address. Send a welcome message.",
          icon: false
        });
      }
    });
  },
  "click [action='sendVerificationEmail']": function() {
    Meteor.call('sendVerificationEmail', hackerId(), function(err) {
      if (err) console.log(err);
    });
  },
  'keyup #invitationsNumber, change #invitationsNumber': function(evt) {
    var $target = $(evt.currentTarget);
    var invitations = $target.val();
    var userId = hackerId();

    // update invitations count
    exec(function() {
      Users.update(userId, {$set: {invitations: invitations}});
    });

    openMailTemplate('personalInviteSlots');
  },
  "change #citySelect select": function(evt) {
    var city = $(evt.currentTarget).val();
    var cityName = CITYMAP[city].name;
    var userId = hackerId();
    var userName = hackerProp('profile.name');

    if (confirm("Are you sure you want move this user to '"+cityName+"'?")) {

      // move
      Meteor.call('moveUserToCity', userId, city, function(err) {
        if (err) return;

        new PNotify({
          title: 'Moved to ' + cityName,
          text: 'Moved \'' + userName + '\' to ' + cityName,
          icon: false
        });

        // redirect to hackers page
        Router.go('hackers');
      });

    } else {

      // cancel, reset <select>
      $(evt.currentTarget).val(Session.get('currentCity'));
    }

  },
  'click [flag]': function(evt) {
    var $flag = $(evt.currentTarget);
    var flag = $flag.attr('flag');
    var activate = !$flag.hasClass('active');
    Users.update(hackerId(), _.object([activate ? '$set' : '$unset'], [_.object([flag], [true])]));
  }
});

Template.hackerToolbarPanelMail.events({
  'change select[name="group"]': function(evt) {
    fillTemplate();
  },
  'click [action="submit"]': function(evt) {
    evt.preventDefault();

    var $button = $(evt.currentTarget);
    var $form = $("#hackerMailForm");
    var formData = $form.serializeObject();

    // validate email
    if (!AutoForm.validateForm("hackerMailForm"))
      return;

    // disable button for a few seconds
    var text = $button.text();
    $button.attr('disabled', 'disabled').addClass('disabled').text('Sending...');
    var cb = function() {
      $button.removeAttr('disabled').removeClass('disabled').text(text);
    }

    // send mail
    sendMailing(formData, cb);
  }
})

Template.hackerToolbar.helpers({
  'owner': function() {
    return hackerProp('_id') === Meteor.userId();
  },
  'unverifiedEmail': function() {
    return _.findWhere(hackerProp('emails'), {address: hackerProp('profile.email'), verified: false});
  },
  'statusLabels': function() {
    return userStatusLabel(hackerId());
  },
  'active': function(panel) {
    return state.equals('activePanel', panel) ? 'active' : '';
  },
  'flag': function(flag) {
    return hackerProp(flag) ? 'active' : '';
  },
  'staff': function() {
    return hasAmbassadorPermission(hackerId());
  }
});

Template.hackerToolbarPanelMail.helpers({
  'mailSchema': function() {
    return new SimpleSchema({
      "group": { type: String },
      "subject": { type: String },
      "message": { type: String }
    });
  }
});

Template.hackerToolbar.rendered = function() {
  $('[data-toggle="tooltip"]').tooltip();
}

/* mailing */

// after doing some actions, we directly open a mail template
// so that the ambassador can notify the user about the changes.
var openMailTemplate = function(requestTmpl) {
  setTimeout(function() {
    // if 'welcome' message requested, but user still haven't access
    // because of missing info, we should open the 'missingInfo' template.
    if (requestTmpl === 'personalWelcome' && hackerProp('isIncompleteProfile'))
      requestTmpl = 'personalMissingInfo';

    state.set('activePanel', 'mail');
    Deps.flush();
    setTemplate(requestTmpl);
  }, 800);
}

var setTemplate = function(tmpl) {
  var $mailing = $("#hackerMailForm"),
      $select = $mailing.find('[name="group"]'),
      $option = $select.find('option[template="'+tmpl+'"]');
  $select.val(''); // reset current selected template
  $option.attr('selected', 'selected'); // select correct template
  fillTemplate();
}

var fillTemplate = function() {
  var $mailing = $("#hackerMailForm"),
      $subject = $mailing.find('[name="subject"]'),
      $message = $mailing.find('[name="message"]'),
      $option = $mailing.find('[name="group"] option:selected'),
      templateName = $option.attr('template'),
      template = loadEmailTemplate(templateName);
  $subject.val(template.subject);
  $message.val(template.message);
}

var loadEmailTemplate = function(templateName) {
  var tmpl_subject = Template['emailSubject_' + templateName],
      tmpl_message = Template['emailContent_' + templateName],
      subject = Blaze.toHTML(tmpl_subject),
      message = Blaze.toHTML(tmpl_message);

  return { subject: subject, message: message };
}

var sendMailing = function(mail, cb) {

  // preserve line breaks in message
  mail.message = mail.message.replace(/\n/g, '
');

  // selector (recipient)
  mail.selector = {userId: hackerId()};

  // send mail from server
  Meteor.call('ambassadorMail', mail, function(err, res) {

    // error handling
    if (err) {
      console.log('Mail failed')
      new PNotify({
        title: 'Mail failed',
        text: "Mailing isn't sent correctly.",
        type: 'error',
        icon: false
      });
    } else {
      console.log('Mail send');
      new PNotify({
        title: 'Mail sent',
        text: 'E-mail sent to user ' + hackerProp('profile.name'),
        icon: false
      });
      state.set('activePanel', null);
    }

    cb(err);
  });
}

<commit_msg>Bugfix: allow changing staff fields<commit_after>
// get the information of the hacker on the current page
// this session variable 'hacker' is setted in the router
var hackerId = function () { return Session.get('hackerId'); }
var hackerProp = function(field) { return OtherUserProp(hackerId(), field); }
var hackerProps = function (fields) { return OtherUserProps(hackerId(), fields); }

// state
var state = new State('hacker', {
  activePanel: null,  /* mail, edit, null */
});

Template.hackerToolbar.events({
  'click [panel]': function(evt) {
    state.toggle('activePanel', $(evt.currentTarget).attr('panel'));
    Deps.flush();
    fillTemplate();
  },
  "click [action='invite']": function(evt) {
    var by = $(evt.currentTarget).attr('by');
    var userId = hackerId();

    // invite user
    Meteor.call('inviteUserAnonymous', userId, function(err,res) {
      var err = false;
      if (err) {
        console.log(err);
        new PNotify({
          title: 'Failed',
          text: "Something went wrong",
          type: 'error',
          icon: false
        });
      } else {
        openMailTemplate('personalWelcome');
        new PNotify({
          title: 'Activated',
          text: "User is now activated and has access to the site. Send a welcome message.",
          icon: false
        });
      }
    });
  },
  "click [action='verifyEmail']": function(evt) {
    Meteor.call('forceEmailVerification', hackerId(), function(err, res) {
      if (err) {
        console.log(err);
        new PNotify({
          title: 'Failed',
          text: "Something went wrong",
          type: 'error',
          icon: false
        });
      } else {
        openMailTemplate('personalWelcome');
        new PNotify({
          title: 'Email verified',
          text: "You have forced the verification of user's email address. Send a welcome message.",
          icon: false
        });
      }
    });
  },
  "click [action='sendVerificationEmail']": function() {
    Meteor.call('sendVerificationEmail', hackerId(), function(err) {
      if (err) console.log(err);
    });
  },
  'keyup #invitationsNumber, change #invitationsNumber': function(evt) {
    var $target = $(evt.currentTarget);
    var invitations = $target.val();
    var userId = hackerId();

    // update invitations count
    exec(function() {
      Users.update(userId, {$set: {invitations: invitations}});
    });

    openMailTemplate('personalInviteSlots');
  },
  "change #citySelect select": function(evt) {
    var city = $(evt.currentTarget).val();
    var cityName = CITYMAP[city].name;
    var userId = hackerId();
    var userName = hackerProp('profile.name');

    if (confirm("Are you sure you want move this user to '"+cityName+"'?")) {

      // move
      Meteor.call('moveUserToCity', userId, city, function(err) {
        if (err) return;

        new PNotify({
          title: 'Moved to ' + cityName,
          text: 'Moved \'' + userName + '\' to ' + cityName,
          icon: false
        });

        // redirect to hackers page
        Router.go('hackers');
      });

    } else {

      // cancel, reset <select>
      $(evt.currentTarget).val(Session.get('currentCity'));
    }

  },
  'click [flag]': function(evt) {
    var $flag = $(evt.currentTarget);
    var flag = $flag.attr('flag');
    var activate = !$flag.hasClass('active');

    // make property staff in doc if not already exists
    if (!hackerProp('staff'))
      Users.update(hackerId(), {$set: {staff: {}}});

    Users.update(hackerId(), _.object([activate ? '$set' : '$unset'], [_.object([flag], [true])]));
  }
});

Template.hackerToolbarPanelMail.events({
  'change select[name="group"]': function(evt) {
    fillTemplate();
  },
  'click [action="submit"]': function(evt) {
    evt.preventDefault();

    var $button = $(evt.currentTarget);
    var $form = $("#hackerMailForm");
    var formData = $form.serializeObject();

    // validate email
    if (!AutoForm.validateForm("hackerMailForm"))
      return;

    // disable button for a few seconds
    var text = $button.text();
    $button.attr('disabled', 'disabled').addClass('disabled').text('Sending...');
    var cb = function() {
      $button.removeAttr('disabled').removeClass('disabled').text(text);
    }

    // send mail
    sendMailing(formData, cb);
  }
})

Template.hackerToolbar.helpers({
  'owner': function() {
    return hackerProp('_id') === Meteor.userId();
  },
  'unverifiedEmail': function() {
    return _.findWhere(hackerProp('emails'), {address: hackerProp('profile.email'), verified: false});
  },
  'statusLabels': function() {
    return userStatusLabel(hackerId());
  },
  'active': function(panel) {
    return state.equals('activePanel', panel) ? 'active' : '';
  },
  'flag': function(flag) {
    return hackerProp(flag) ? 'active' : '';
  },
  'staff': function() {
    return hasAmbassadorPermission(hackerId());
  }
});

Template.hackerToolbarPanelMail.helpers({
  'mailSchema': function() {
    return new SimpleSchema({
      "group": { type: String },
      "subject": { type: String },
      "message": { type: String }
    });
  }
});

Template.hackerToolbar.rendered = function() {
  $('[data-toggle="tooltip"]').tooltip();
}

/* mailing */

// after doing some actions, we directly open a mail template
// so that the ambassador can notify the user about the changes.
var openMailTemplate = function(requestTmpl) {
  setTimeout(function() {
    // if 'welcome' message requested, but user still haven't access
    // because of missing info, we should open the 'missingInfo' template.
    if (requestTmpl === 'personalWelcome' && hackerProp('isIncompleteProfile'))
      requestTmpl = 'personalMissingInfo';

    state.set('activePanel', 'mail');
    Deps.flush();
    setTemplate(requestTmpl);
  }, 800);
}

var setTemplate = function(tmpl) {
  var $mailing = $("#hackerMailForm"),
      $select = $mailing.find('[name="group"]'),
      $option = $select.find('option[template="'+tmpl+'"]');
  $select.val(''); // reset current selected template
  $option.attr('selected', 'selected'); // select correct template
  fillTemplate();
}

var fillTemplate = function() {
  var $mailing = $("#hackerMailForm"),
      $subject = $mailing.find('[name="subject"]'),
      $message = $mailing.find('[name="message"]'),
      $option = $mailing.find('[name="group"] option:selected'),
      templateName = $option.attr('template'),
      template = loadEmailTemplate(templateName);
  $subject.val(template.subject);
  $message.val(template.message);
}

var loadEmailTemplate = function(templateName) {
  var tmpl_subject = Template['emailSubject_' + templateName],
      tmpl_message = Template['emailContent_' + templateName],
      subject = Blaze.toHTML(tmpl_subject),
      message = Blaze.toHTML(tmpl_message);

  return { subject: subject, message: message };
}

var sendMailing = function(mail, cb) {

  // preserve line breaks in message
  mail.message = mail.message.replace(/\n/g, '
');

  // selector (recipient)
  mail.selector = {userId: hackerId()};

  // send mail from server
  Meteor.call('ambassadorMail', mail, function(err, res) {

    // error handling
    if (err) {
      console.log('Mail failed')
      new PNotify({
        title: 'Mail failed',
        text: "Mailing isn't sent correctly.",
        type: 'error',
        icon: false
      });
    } else {
      console.log('Mail send');
      new PNotify({
        title: 'Mail sent',
        text: 'E-mail sent to user ' + hackerProp('profile.name'),
        icon: false
      });
      state.set('activePanel', null);
    }

    cb(err);
  });
}

<|endoftext|>


<commit_before><commit_msg>提交代码<commit_after><|endoftext|>


<commit_before>const path = require('path');
require('dotenv').load({path: path.join(__dirname, '.env.test')});
//start db, store connection
const connection = require('../lib/mongoose-setup');

//drop db before starting
before( done => {
  console.log('before all tests');
  const drop = () => connection.db.dropDatabase(done);
  if (connection.readyState === 1) drop();
  else connection.on('open', drop);
});

//close connection after all tests run
after(() => {
  console.log('after all tests');
  connection.close();
});
<commit_msg>path change<commit_after>const path = require('path');
require('dotenv').load({path: path.join(__dirname, '../.env.test')});
//start db, store connection
const connection = require('../lib/mongoose-setup');

//drop db before starting
before( done => {
  console.log('before all tests');
  const drop = () => connection.db.dropDatabase(done);
  if (connection.readyState === 1) drop();
  else connection.on('open', drop);
});

//close connection after all tests run
after(() => {
  console.log('after all tests');
  connection.close();
});
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import Card from '../Card';
import ButtonIconText from '../ButtonIconText';
import Pin from './Pin';
import { adminCloseIssue } from '../../actionCreators/adminButtons';
import { getIssueText, activeIssueExists, getIssue } from '../../selectors/issues';
import css from './Issue.css';

const Issue = ({ closeIssue, allowClosing, issueText }) => (
  <Card classes={css.issue}>

        <Pin code="DEADBEEF" />

Aktiv sak

        <ButtonIconText text="Rediger" iconClass={css.edit} />
        <ButtonIconText text="Resett" iconClass={css.reset} />
        <ButtonIconText
          onClick={closeIssue} hidden={!allowClosing}
          text="Avslutt" iconClass={css.end}
        />
        <ButtonIconText text="Slett" iconClass={css.delete} />

{issueText}

  </Card>
);

Issue.propTypes = {
  closeIssue: React.PropTypes.func.isRequired,
  allowClosing: React.PropTypes.bool.isRequired,
  issueText: React.PropTypes.string.isRequired,
};

const mapStateToProps = state => ({
  allowClosing: activeIssueExists(state),
  issueText: getIssueText(state),
  issue: getIssue(state),
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<commit_msg>Fixes issue description not being on its own row<commit_after>import React from 'react';
import { connect } from 'react-redux';
import Card from '../Card';
import ButtonIconText from '../ButtonIconText';
import Pin from './Pin';
import { adminCloseIssue } from '../../actionCreators/adminButtons';
import { getIssueText, activeIssueExists, getIssue } from '../../selectors/issues';
import css from './Issue.css';

const Issue = ({ closeIssue, allowClosing, issueText }) => (
  <Card classes={css.issue}>

        <Pin code="DEADBEEF" />

Aktiv sak

        <ButtonIconText text="Rediger" iconClass={css.edit} />
        <ButtonIconText text="Resett" iconClass={css.reset} />
        <ButtonIconText
          onClick={closeIssue} hidden={!allowClosing}
          text="Avslutt" iconClass={css.end}
        />
        <ButtonIconText text="Slett" iconClass={css.delete} />

{issueText}

  </Card>
);

Issue.propTypes = {
  closeIssue: React.PropTypes.func.isRequired,
  allowClosing: React.PropTypes.bool.isRequired,
  issueText: React.PropTypes.string.isRequired,
};

const mapStateToProps = state => ({
  allowClosing: activeIssueExists(state),
  issueText: getIssueText(state),
  issue: getIssue(state),
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<|endoftext|>


<commit_before>// Load in our dependencies
const assert = require('assert');

const _ = require('underscore');
const sinon = require('sinon');
const graphqlParser = require('graphql-parser').default;

// Define `xhrUtils.mock`
exports.mock = function (responses) {
  before(function callMockXHR () {
    // Create our server
    // http://sinonjs.org/docs/#fakeServer
    // DEV: `this.sinonServer.respond()` must be called to trigger responses
    //   This allows us to test loading states
    assert(!this.sinonServer, 'Expected no Sinon server to be running but one is. ' +
      'Please only use `testUtils.mockXHR` once per test');
    this.sinonServer = sinon.fakeServer.create();

    // Resolve GraphQL specific fixtures
    responses = responses.map(function resolveGraphQLFixtures (response) {
      if (response.graphql) {
        // graphqlFixtures(['posts-and-comments-empty-200.json'])
        return graphqlFixtures(response.graphql);
      } else {
        return response;
      }
    });

    // Bind our responses
    this.requests = [];
    const that = this;
    responses.forEach(function bindResponse (response) {
      that.sinonServer.respondWith(response.method, response.url, function handleRequest (req) {
        // Save our request
        that.requests.push(req);
        if (that.onRequest) {
          that.onRequest(req);
        }

        // Call our fixture
        return response.fn.apply(that, arguments);
      });
    });
  });
  after(function cleanup () {
    this.sinonServer.restore();
    delete this.sinonServer;
  });
};

// Define our GraphQL fixtures
exports.GRAPHQL_LOADING_ONLY = {
  method: 'POST',
  url: '/graphql',
  fn: function (req) {
    throw new Error('GRAPHQL_LOADING_ONLY was run when it should never be run. ' +
      'Please remove any `this.sinonServer.respond()`');
  }
};
/* eslint-disable global-require */
function loadGraphqlContract(graphqlContract) {
  // Parse our query lines into a query
  graphqlContract.request.query = graphqlContract.request.queryLines.join('\n');
  console.log(graphqlParser(graphqlContract.request.query));
  return graphqlContract;
}
const graphqlContractsByFilepath = {
  'posts-and-comments-empty-200.json': loadGraphqlContract(require(__dirname + '/../../test-files/graphql-contracts' +
    '/posts-and-comments-empty-200.json')),
  'posts-and-comments-full-200.json': loadGraphqlContract(require(__dirname + '/../../test-files/graphql-contracts' +
    '/posts-and-comments-full-200.json'))
};
/* eslint-enable global-require */
exports.graphql = function (filepaths) {
  // Load our matching filepaths
  assert(Array.isArray(filepaths), `Expected ${filepaths} to be an array but it wasn't`);
  const graphqlContracts = filepaths.map(function resolveGraphqlContract (filepath) {
    const graphqlContract = graphqlContractsByFilepath[filepath];
    assert(graphqlContract,
      `Unable to find GraphQL contract for "${filepath}". Please verify it's loaded via \`require\``);
    return graphqlContract;
  });

  // Return a mock XHR response for our GraphQL endpoint
  return {
    method: 'POST',
    url: '/graphql',
    fn: function (req) {
      // Load our request body
      const reqBody = JSON.parse(req.requestBody);
      const reqQuery = reqBody.query;
      assert(reqQuery, `No \`query\` was specified for "${req.requestBody}"`);
      const variables = reqBody.variables || {};

      // Find the first matching contract
      const graphqlContract = _.find(graphqlContracts, function isMatchingContract (graphqlContract) {
        // TODO: Perform parsing and subsetting
        // TODO: Add variables matching
        return true;
        // return graphqlContract.request.query === stripIndent(reqQuery).trim();
      });
      assert(graphqlContract, `Unable to find matching GraphQL contract for query "${reqQuery}" ' +
        'and variables "${JSON.stringify(variables)}"`);

      // http://sinonjs.org/releases/v2.3.4/fake-xhr-and-server/#simulating-server-responses
      req.respond(graphqlContract.response.statusCode, {},
        JSON.stringify(graphqlContract.response.body));
    }
  };
};
<commit_msg>Broke down our content into tokens<commit_after>// Load in our dependencies
const assert = require('assert');

const _ = require('underscore');
const sinon = require('sinon');
const graphqlLanguage = require('graphql/language');

// Define `xhrUtils.mock`
exports.mock = function (responses) {
  before(function callMockXHR () {
    // Create our server
    // http://sinonjs.org/docs/#fakeServer
    // DEV: `this.sinonServer.respond()` must be called to trigger responses
    //   This allows us to test loading states
    assert(!this.sinonServer, 'Expected no Sinon server to be running but one is. ' +
      'Please only use `testUtils.mockXHR` once per test');
    this.sinonServer = sinon.fakeServer.create();

    // Resolve GraphQL specific fixtures
    responses = responses.map(function resolveGraphQLFixtures (response) {
      if (response.graphql) {
        // graphqlFixtures(['posts-and-comments-empty-200.json'])
        return graphqlFixtures(response.graphql);
      } else {
        return response;
      }
    });

    // Bind our responses
    this.requests = [];
    const that = this;
    responses.forEach(function bindResponse (response) {
      that.sinonServer.respondWith(response.method, response.url, function handleRequest (req) {
        // Save our request
        that.requests.push(req);
        if (that.onRequest) {
          that.onRequest(req);
        }

        // Call our fixture
        return response.fn.apply(that, arguments);
      });
    });
  });
  after(function cleanup () {
    this.sinonServer.restore();
    delete this.sinonServer;
  });
};

// Define our GraphQL fixtures
exports.GRAPHQL_LOADING_ONLY = {
  method: 'POST',
  url: '/graphql',
  fn: function (req) {
    throw new Error('GRAPHQL_LOADING_ONLY was run when it should never be run. ' +
      'Please remove any `this.sinonServer.respond()`');
  }
};
/* eslint-disable global-require */
function loadGraphqlContract(graphqlContract) {
  // Parse our query lines into a query
  graphqlContract.request.query = graphqlContract.request.queryLines.join('\n');
  var x = new graphqlLanguage.Source(graphqlContract.request.query);
  // console.log(graphqlLanguage.Source);
  var y = graphqlLanguage.createLexer(x);
  console.log(y.token);
  console.log(y.advance());
  console.log(y.token);
  console.log(y.advance());
  console.log(y.token);
  return graphqlContract;
}
const graphqlContractsByFilepath = {
  'posts-and-comments-empty-200.json': loadGraphqlContract(require(__dirname + '/../../test-files/graphql-contracts' +
    '/posts-and-comments-empty-200.json')),
  'posts-and-comments-full-200.json': loadGraphqlContract(require(__dirname + '/../../test-files/graphql-contracts' +
    '/posts-and-comments-full-200.json'))
};
/* eslint-enable global-require */
exports.graphql = function (filepaths) {
  // Load our matching filepaths
  assert(Array.isArray(filepaths), `Expected ${filepaths} to be an array but it wasn't`);
  const graphqlContracts = filepaths.map(function resolveGraphqlContract (filepath) {
    const graphqlContract = graphqlContractsByFilepath[filepath];
    assert(graphqlContract,
      `Unable to find GraphQL contract for "${filepath}". Please verify it's loaded via \`require\``);
    return graphqlContract;
  });

  // Return a mock XHR response for our GraphQL endpoint
  return {
    method: 'POST',
    url: '/graphql',
    fn: function (req) {
      // Load our request body
      const reqBody = JSON.parse(req.requestBody);
      const reqQuery = reqBody.query;
      assert(reqQuery, `No \`query\` was specified for "${req.requestBody}"`);
      const variables = reqBody.variables || {};

      // Find the first matching contract
      const graphqlContract = _.find(graphqlContracts, function isMatchingContract (graphqlContract) {
        // TODO: Perform parsing and subsetting
        // TODO: Add variables matching
        return true;
        // return graphqlContract.request.query === stripIndent(reqQuery).trim();
      });
      assert(graphqlContract, `Unable to find matching GraphQL contract for query "${reqQuery}" ' +
        'and variables "${JSON.stringify(variables)}"`);

      // http://sinonjs.org/releases/v2.3.4/fake-xhr-and-server/#simulating-server-responses
      req.respond(graphqlContract.response.statusCode, {},
        JSON.stringify(graphqlContract.response.body));
    }
  };
};
<|endoftext|>


<commit_before>const ServiceBroker = require("../../src/service-broker");
const Cacher = require("../../src/cachers/base");
const Context = require("../../src/context");
const utils = require("../../src/utils");

describe("Test BaseCacher", () => {

	it("check constructor", () => {
		let cacher = new Cacher();
		expect(cacher).toBeDefined();
		expect(cacher.opts).toBeDefined();
		expect(cacher.prefix).toBe("");
		expect(cacher.opts.ttl).toBeNull();
		expect(cacher.init).toBeDefined();
		expect(cacher.get).toBeDefined();
		expect(cacher.set).toBeDefined();
		expect(cacher.del).toBeDefined();
		expect(cacher.clean).toBeDefined();
	});

	it("check constructor with empty opts", () => {
		let opts = {};
		let cacher = new Cacher(opts);
		expect(cacher.opts).toBeDefined();
		expect(cacher.prefix).toBe("");
		expect(cacher.opts.ttl).toBeNull();
	});

	it("check constructor with options", () => {
		let opts = { prefix: "TEST", ttl: 500 };
		let cacher = new Cacher(opts);
		expect(cacher).toBeDefined();
		expect(cacher.opts).toEqual(opts);
		expect(cacher.prefix).toBe("TEST");
		expect(cacher.opts.ttl).toBe(500);
	});

	it("check init", () => {
		let broker = new ServiceBroker();
		let cacher = new Cacher();

		cacher.init(broker);
		expect(cacher.broker).toBe(broker);
		expect(cacher.logger).toBeDefined();
	});

	it("check getCacheKey", () => {
		let broker = new ServiceBroker();
		let cacher = new Cacher();

		cacher.init(broker);
		// Check result
		let res = cacher.getCacheKey("posts.find.model", { id: 1, name: "Bob" });
		expect(res).toBe("posts.find.model:bab3f6e5c7672d1d642523157711b8b745b1bc9b");

		// Same result, with same params
		let res2 = cacher.getCacheKey("posts.find.model", { id: 1, name: "Bob" });
		expect(res2).toEqual(res);

		// Different result, with different params
		let res3 = cacher.getCacheKey("posts.find.model", { id: 2, name: "Bob" });
		expect(res3).not.toEqual(res);
		expect(res3).toBe("posts.find.model:01738894945c7c885d275a0ec2ced133e2d9d6ed");

		res = cacher.getCacheKey();
		expect(res).toBe("");

		res = cacher.getCacheKey("posts.find");
		expect(res).toBe("posts.find:");

		res = cacher.getCacheKey(null, {});
		expect(res).toBe("323217f643c3e3f1fe7532e72ac01bb0748c97be");

		res = cacher.getCacheKey(null, {a: 5});
		expect(res).toBe("4a811383176bf8c7bf15a2cec8f91d4e9636383f");

	});
});

describe("Test utils.wrapHandler", () => {
	let cachedData = { num: 5 };

	let cacher = new Cacher();
	let broker = new ServiceBroker({
		cacher
	});

	cacher.get = jest.fn(() => Promise.resolve(cachedData)),
	cacher.set = jest.fn();

	let mockAction = {
		name: "posts.find",
		handler: jest.fn()
	};
	let params = { id: 3, name: "Antsa" };

	it("should give back the cached data and not called the handler", () => {
		let cachedHandler = cacher.wrapHandler(mockAction);
		expect(typeof cachedHandler).toBe("function");

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith("posts.find:e263ebd5ec9c63793ee3316efb8bfbe9f761f7ba");
			expect(mockAction.handler).toHaveBeenCalledTimes(0);
			expect(response).toBe(cachedData);
		});
	});

	it("should not give back cached data and should call the handler and call the 'cache.put' action with promise", () => {
		let resData = [1,3,5];
		let cacheKey = cacher.getCacheKey(mockAction.name, params);
		broker.cacher.get = jest.fn(() => Promise.resolve(null));
		mockAction.handler = jest.fn(() => Promise.resolve(resData));

		let cachedHandler = cacher.wrapHandler(mockAction);

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(response).toBe(resData);
			expect(mockAction.handler).toHaveBeenCalledTimes(1);

			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith(cacheKey);

			expect(broker.cacher.set).toHaveBeenCalledTimes(1);
			expect(broker.cacher.set).toHaveBeenCalledWith(cacheKey, resData);
		});
	});

	it("should not give back cached data and should call the handler and call the 'cache.put' action with sync res", () => {
		let resData = [1,3,5];
		let cacheKey = cacher.getCacheKey(mockAction.name, params);
		broker.cacher.get = jest.fn(() => Promise.resolve(null));
		broker.cacher.set.mockClear();
		mockAction.handler = jest.fn(() => resData); // no Promise

		let cachedHandler = cacher.wrapHandler(mockAction);

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(response).toBe(resData);
			expect(mockAction.handler).toHaveBeenCalledTimes(1);

			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith(cacheKey);

			expect(broker.cacher.set).toHaveBeenCalledTimes(1);
			expect(broker.cacher.set).toHaveBeenCalledWith(cacheKey, resData);
		});
	});

});
<commit_msg>cover cacher<commit_after>const ServiceBroker = require("../../src/service-broker");
const Cacher = require("../../src/cachers/base");
const Context = require("../../src/context");
const utils = require("../../src/utils");

describe("Test BaseCacher", () => {

	it("check constructor", () => {
		let cacher = new Cacher();
		expect(cacher).toBeDefined();
		expect(cacher.opts).toBeDefined();
		expect(cacher.prefix).toBe("");
		expect(cacher.opts.ttl).toBeNull();
		expect(cacher.init).toBeDefined();
		expect(cacher.get).toBeDefined();
		expect(cacher.set).toBeDefined();
		expect(cacher.del).toBeDefined();
		expect(cacher.clean).toBeDefined();
	});

	it("check constructor with empty opts", () => {
		let opts = {};
		let cacher = new Cacher(opts);
		expect(cacher.opts).toBeDefined();
		expect(cacher.prefix).toBe("");
		expect(cacher.opts.ttl).toBeNull();
	});

	it("check constructor with options", () => {
		let opts = { prefix: "TEST", ttl: 500 };
		let cacher = new Cacher(opts);
		expect(cacher).toBeDefined();
		expect(cacher.opts).toEqual(opts);
		expect(cacher.prefix).toBe("TEST");
		expect(cacher.opts.ttl).toBe(500);
	});

	it("check init", () => {
		let broker = new ServiceBroker();
		let cacher = new Cacher();

		cacher.init(broker);
		expect(cacher.broker).toBe(broker);
		expect(cacher.logger).toBeDefined();
	});

	it("check getCacheKey", () => {
		let broker = new ServiceBroker();
		let cacher = new Cacher();

		cacher.init(broker);
		// Check result
		let res = cacher.getCacheKey("posts.find.model", { id: 1, name: "Bob" });
		expect(res).toBe("posts.find.model:bab3f6e5c7672d1d642523157711b8b745b1bc9b");

		// Same result, with same params
		let res2 = cacher.getCacheKey("posts.find.model", { id: 1, name: "Bob" });
		expect(res2).toEqual(res);

		// Different result, with different params
		let res3 = cacher.getCacheKey("posts.find.model", { id: 2, name: "Bob" });
		expect(res3).not.toEqual(res);
		expect(res3).toBe("posts.find.model:01738894945c7c885d275a0ec2ced133e2d9d6ed");

		res = cacher.getCacheKey();
		expect(res).toBe("");

		res = cacher.getCacheKey("posts.find");
		expect(res).toBe("posts.find:");

		res = cacher.getCacheKey(null, {});
		expect(res).toBe("323217f643c3e3f1fe7532e72ac01bb0748c97be");

		res = cacher.getCacheKey(null, {a: 5});
		expect(res).toBe("4a811383176bf8c7bf15a2cec8f91d4e9636383f");

	});
});

describe("Test utils.wrapHandler", () => {
	let cachedData = { num: 5 };

	let cacher = new Cacher();
	let broker = new ServiceBroker({
		cacher
	});

	cacher.get = jest.fn(() => Promise.resolve(cachedData)),
	cacher.set = jest.fn();

	let mockAction = {
		name: "posts.find",
		handler: jest.fn()
	};
	let params = { id: 3, name: "Antsa" };

	it("should give back the cached data and not called the handler", () => {
		let cachedHandler = cacher.wrapHandler(mockAction);
		expect(typeof cachedHandler).toBe("function");

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith("posts.find:e263ebd5ec9c63793ee3316efb8bfbe9f761f7ba");
			expect(mockAction.handler).toHaveBeenCalledTimes(0);
			expect(response).toBe(cachedData);
		});
	});

	it("should not give back cached data and should call the handler and call the 'cache.put' action with promise", () => {
		let resData = [1,3,5];
		let cacheKey = cacher.getCacheKey(mockAction.name, params);
		broker.cacher.get = jest.fn(() => Promise.resolve(null));
		mockAction.handler = jest.fn(() => Promise.resolve(resData));

		let cachedHandler = cacher.wrapHandler(mockAction);

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(response).toBe(resData);
			expect(mockAction.handler).toHaveBeenCalledTimes(1);

			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith(cacheKey);

			expect(broker.cacher.set).toHaveBeenCalledTimes(1);
			expect(broker.cacher.set).toHaveBeenCalledWith(cacheKey, resData);
		});
	});

	it("should not give back cached data and should call the handler and call the 'cache.put' action with sync res", () => {
		let resData = [1,3,5];
		let cacheKey = cacher.getCacheKey(mockAction.name, params);
		broker.cacher.get = jest.fn(() => Promise.resolve(null));
		broker.cacher.set.mockClear();
		mockAction.handler = jest.fn(() => resData); // no Promise

		let cachedHandler = cacher.wrapHandler(mockAction);

		let ctx = new Context({ params, service: { broker } });
		let p = cachedHandler(ctx);

		expect(utils.isPromise(p)).toBeTruthy();
		return p.then((response) => {
			expect(response).toBe(resData);
			expect(mockAction.handler).toHaveBeenCalledTimes(1);

			expect(broker.cacher.get).toHaveBeenCalledTimes(1);
			expect(broker.cacher.get).toHaveBeenCalledWith(cacheKey);

			expect(broker.cacher.set).toHaveBeenCalledTimes(1);
			expect(broker.cacher.set).toHaveBeenCalledWith(cacheKey, resData);
		});
	});

});

describe("Test utils.wrapHandler", () => {
	let cacher = new Cacher();
	let broker = new ServiceBroker({
		cacher
	});

	cacher.clean = jest.fn(),
	cacher.del = jest.fn();

	it("should call clean method", () => {
		broker.emit("cache.clean", { match: "users.*" });
		expect(cacher.clean).toHaveBeenCalledTimes(1);
		expect(cacher.clean).toHaveBeenCalledWith("users.*");
	});

	it("should call del method", () => {
		broker.emit("cache.del", { key: "users.model.123" });
		expect(cacher.del).toHaveBeenCalledTimes(1);
		expect(cacher.del).toHaveBeenCalledWith("users.model.123");
	});
});<|endoftext|>


<commit_before>import angular from 'angular';
// components used by this module

// imports for this component
import template from './feed.html';
import './feed.css';

class FeedController {
  constructor() {
  }
}

FeedController.$inject = [];

const FeedComponent = {
  restrict: 'E',
  bindings: {
    plan: '<'
  },
  template: template,
  controller: FeedController
};

const FeedModule = angular.module('app.plan.feed', [])
  .component('feed', FeedComponent);

export default FeedModule.name;
<commit_msg>Remove inject<commit_after>import angular from 'angular';
// components used by this module

// imports for this component
import template from './feed.html';
import './feed.css';

class FeedController {
  constructor() {
  }
}

const FeedComponent = {
  restrict: 'E',
  bindings: {
    plan: '<'
  },
  template: template,
  controller: FeedController
};

const FeedModule = angular.module('app.plan.feed', [])
  .component('feed', FeedComponent);

export default FeedModule.name;
<|endoftext|>


<commit_before>'use strict';

const http = require('http');
const https = require('https');

const {HttpClient, HttpClientResponse} = require('./HttpClient');

const defaultHttpAgent = new http.Agent({keepAlive: true});
const defaultHttpsAgent = new https.Agent({keepAlive: true});

/**
 * HTTP client which uses the Node `http` and `https` packages to issue
 * requests.`
 */
class NodeHttpClient extends HttpClient {
  constructor(agent) {
    super();
    this._agent = agent;
  }

  /** @override. */
  getClientName() {
    return 'node';
  }

  makeRequest(
    host,
    port,
    path,
    method,
    headers,
    requestData,
    protocol,
    timeout
  ) {
    const isInsecureConnection = protocol === 'http';

    let agent = this._agent;
    if (!agent) {
      agent = isInsecureConnection ? defaultHttpAgent : defaultHttpsAgent;
    }

    const requestPromise = new Promise((resolve, reject) => {
      const req = (isInsecureConnection ? http : https).request({
        host: host,
        port: port,
        path,
        method,
        agent,
        headers,
        ciphers: 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!MD5',
      });

      req.setTimeout(timeout, () => {
        req.destroy(HttpClient.makeTimeoutError());
      });

      req.on('response', (res) => {
        resolve(new NodeHttpClientResponse(res));
      });

      req.on('error', (error) => {
        reject(error);
      });

      req.once('socket', (socket) => {
        if (socket.connecting) {
          socket.once(
            isInsecureConnection ? 'connect' : 'secureConnect',
            () => {
              // Send payload; we're safe:
              req.write(requestData);
              req.end();
            }
          );
        } else {
          // we're already connected
          req.write(requestData);
          req.end();
        }
      });
    });

    return requestPromise;
  }
}

class NodeHttpClientResponse extends HttpClientResponse {
  constructor(res) {
    super(res.statusCode, res.headers || {});
    this._res = res;
  }

  getRawResponse() {
    return this._res;
  }

  toStream(streamCompleteCallback) {
    // The raw response is itself the stream, so we just return that. To be
    // backwards comaptible, we should invoke the streamCompleteCallback only
    // once the stream has been fully consumed.
    this._res.once('end', () => streamCompleteCallback());
    return this._res;
  }

  toJSON() {
    return new Promise((resolve, reject) => {
      let response = '';

      this._res.setEncoding('utf8');
      this._res.on('data', (chunk) => {
        response += chunk;
      });
      this._res.once('end', () => {
        try {
          resolve(JSON.parse(response));
        } catch (e) {
          reject(e);
        }
      });
    });
  }
}

module.exports = {NodeHttpClient, NodeHttpClientResponse};
<commit_msg>Typo in NodeHttpClient comment (#1287)<commit_after>'use strict';

const http = require('http');
const https = require('https');

const {HttpClient, HttpClientResponse} = require('./HttpClient');

const defaultHttpAgent = new http.Agent({keepAlive: true});
const defaultHttpsAgent = new https.Agent({keepAlive: true});

/**
 * HTTP client which uses the Node `http` and `https` packages to issue
 * requests.`
 */
class NodeHttpClient extends HttpClient {
  constructor(agent) {
    super();
    this._agent = agent;
  }

  /** @override. */
  getClientName() {
    return 'node';
  }

  makeRequest(
    host,
    port,
    path,
    method,
    headers,
    requestData,
    protocol,
    timeout
  ) {
    const isInsecureConnection = protocol === 'http';

    let agent = this._agent;
    if (!agent) {
      agent = isInsecureConnection ? defaultHttpAgent : defaultHttpsAgent;
    }

    const requestPromise = new Promise((resolve, reject) => {
      const req = (isInsecureConnection ? http : https).request({
        host: host,
        port: port,
        path,
        method,
        agent,
        headers,
        ciphers: 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!MD5',
      });

      req.setTimeout(timeout, () => {
        req.destroy(HttpClient.makeTimeoutError());
      });

      req.on('response', (res) => {
        resolve(new NodeHttpClientResponse(res));
      });

      req.on('error', (error) => {
        reject(error);
      });

      req.once('socket', (socket) => {
        if (socket.connecting) {
          socket.once(
            isInsecureConnection ? 'connect' : 'secureConnect',
            () => {
              // Send payload; we're safe:
              req.write(requestData);
              req.end();
            }
          );
        } else {
          // we're already connected
          req.write(requestData);
          req.end();
        }
      });
    });

    return requestPromise;
  }
}

class NodeHttpClientResponse extends HttpClientResponse {
  constructor(res) {
    super(res.statusCode, res.headers || {});
    this._res = res;
  }

  getRawResponse() {
    return this._res;
  }

  toStream(streamCompleteCallback) {
    // The raw response is itself the stream, so we just return that. To be
    // backwards compatible, we should invoke the streamCompleteCallback only
    // once the stream has been fully consumed.
    this._res.once('end', () => streamCompleteCallback());
    return this._res;
  }

  toJSON() {
    return new Promise((resolve, reject) => {
      let response = '';

      this._res.setEncoding('utf8');
      this._res.on('data', (chunk) => {
        response += chunk;
      });
      this._res.once('end', () => {
        try {
          resolve(JSON.parse(response));
        } catch (e) {
          reject(e);
        }
      });
    });
  }
}

module.exports = {NodeHttpClient, NodeHttpClientResponse};
<|endoftext|>