<commit_before>/**
 * @fileoverview A job item.
 */
var util = require('util');
var _ = require('underscore');
var when = require('when');
var log = require('logg').getLogger('kickq.model.JobItem');

var kconfig = require('../utility/config');
var states = require('./states');
var kError = require('../utility/kerror');
var Model = require('./model');

/**
 * The Job object
 *
 * @param {Object=} optJobItem optionally define a job item object
 *                             as returned by the database to fill up
 *                             this instance values.
 * @constructor
 * @extends {Kickq.Model}
 */
var JobItem = module.exports = function(optJobItem) {
  log.finer('Ctor() :: Init');
  Model.apply(this, arguments);

  /** @type {?string} the job id. */
  this.id = null;

  /** @type {string} the job name. */
  this.name = '';

  /** @type {boolean} irrespective of success / fail. */
  this.complete = false;

  /** @type {boolean} turns true when complete and executed with success. */
  this.success = false;

  /** @type {number} JS timestamp. */
  this.createTime = Date.now();

  /** @type {number} JS timestamp. */
  this.updateTime = this.createTime;

  /** @type {?number} JS timestamp or null. */
  this.finishTime = null;

  /** @type {?number} total process time in ms or null. */
  this.totalProcessTime = null;

  /** @type {?number} If this job will get delayed before it's queued. */
  this.delay = null;

  /** @type {number} ms, 10 seconds to wait for a worker to complete processing. */
  this.processTimeout = 10000;

  /** @type {boolean} If this job will retry. */
  this.retry = false;

  /** @type {number} How many times to retry. */
  this.retryTimes = 3;

  /** @type {number} ms, 30minutes of interval between retrying. */
  this.retryInterval = 1800000;

  /** @type {boolean} */
  this.hotjob = false;

  /** @type {number} ms, 10 seconds. */
  this.hotjobTimeout = 10000;

  /** @type {boolean} Enable retrying ghost jobs */
  this.ghostRetry = true;

  /** @type {number} How many times to retry a ghost job */
  this.ghostTimes = 1;

  /** @type {number} milliseconds of interval between retrying */
  this.ghostInterval = 1800000;

  /** @type {*} Any type, passed data on job creation. */
  this.data = null;

  /** @type {?string} Last processing error as defined by consumer  */
  this.lastError = null;

  /** @type {?number} JS timestamp of when this job has been scheduled for */
  this.scheduledFor = null;

  /**
   *
   * the state can be one of:
   *   - new
   *   - queued :: A job has been queued for re-processing
   *   - delayed
   *   - processing
   *   - retry
   *   - ghost   :: A re-process state when callback does not report.
   *   - success :: 'complete' flag is true
   *   - fail    :: 'complete' flag is true
   *
   * @type {Kickq.states.Job}
   */
  this.state = states.Job.NEW;

  /**
   * Processing runs performed for this job. Can be 1 up to n retries.
   *
   * When the job is new this is an empty array.
   *
   * @type {Array.<JobItem.ProcessItem>} An array of process items.
   */
  this.runs = [];

  //
  //
  // Private variables
  //
  //

  /** @type {boolean} If item has initialized */
  this._hasInitialized = false;

  /** @type {?when.Promise} The hotjob's promise object is referenced here */
  this._hotjobPromise = null;

  // Check if a jobItem has been passed as argument and use it
  if (_.isObject(optJobItem)) {
    this._useItem(optJobItem);
  }
};
util.inherits(JobItem, Model);

/**
 * Initialize values for a new job item using options provided or
 * falling back to config.
 *
 * @param  {Object=} options Job Options object as passed by the consumer.
 */
JobItem.prototype.initialize = function( options ) {
  if (this._hasInitialized) {
    return;
  }
  this._hasInitialized = true;

  // Define all the options that needs to be examined
  var optsExamine = [
    'delay',
    'retry',
    'retryTimes',
    'retryInterval',
    'ghostRetry',
    'ghostTimes',
    'ghostInterval',
    'hotjob',
    'hotjobTimeout',
    'processTimeout'
  ];

  // Get "per job" specific config options
  var configOpts = kconfig.getJob(this.name);

  // examine existence and assign to job.
  optsExamine.forEach(function(prop){
    // defense
    if (!this.hasOwnProperty(prop)) {
      return;
    }

    // check consumer options
    if ( options.hasOwnProperty(prop) ) {
      this[prop] = options[prop];
      return; //next
    }

    // check per job config options
    if ( configOpts.hasOwnProperty(prop) ) {
      this[prop] = configOpts[prop];
      return; // next
    }

    // Finally get global config options
    this[prop] = kconfig.get(prop);
  }, this);

  // determine original state
  if (_.isNumber(this.delay)) {
    this.state = states.Job.DELAYED;
  }
};

/**
 * A processing item, contains information for each processing of a job.
 *
 * @param {Kickq.JobItem} job A job item instance.
 * @constructor
 */
JobItem.ProcessItem = function(job) {

  if (!(job instanceof JobItem)) {
    throw new TypeError('argument not instance of Kickq.JotItem');
  }

  /** @type {number} the process count of this process item. */
  this.count = 1 + job.runs.length;

  /** @type {number} JS timestamp. */
  this.startTime = Date.now();

  /** @type {?number} Processing time in ms or null. */
  this.processTime = null;

  /** @type {?number} Processing timeout in ms for this item */
  this.processTimeout = null;

  /**
   * One of these states:
   *   - processing
   *   - ghost   :: A re-process state when callback does not report.
   *   - success :: 'complete' flag is true
   *   - fail    :: 'complete' flag is true
   *
   * @type {Kickq.states.Process}
   */
  this.state = states.Process.PROCESSING;

  /** @type {?string} if failed the consumer provided error message */
  this.errorMessage = null;

  /** @type {?number} setTimeout index */
  this.timeout = null;
};

/**
 * Return a public job item for API consumption.
 *
 * @return {Object}
 */
JobItem.prototype.getPublic = function() {
  var publicItem = Object.create(null);
  _.forEach(this, function(item, key){
    if (_.isFunction(item)) {
      return;
    }

    // check for private
    if ('_' === key.substr(0,1)) {
      return;
    }

    // check for special symbols that should not be exposed
    if (0 <= [
        'client',
        'clientSub',
        'NS'
      ].indexOf(key)) {
        return;
      }

    publicItem[key] = item;
  });

  // expose hotjob Promise
  publicItem.hotjobPromise = this._hotjobPromise;
  return publicItem;
};

/**
 * Serialize the public object. This method will guarantee a returned JSON
 * value, if standard JSON stringify fails a custom minimum object
 * will be serialized instead.
 *
 * @return {!string} Always string no errors thrown.
 */
JobItem.prototype.getPublicJSON = function() {
  var serialized;
  try {
    serialized = JSON.stringify(this.getPublic());
  } catch(ex) {
    // create minimum viable object
    serialized = '{"id":"' + this.id + '"}';
  }
  return serialized;
};

/**
 * Add a process item to the current job.
 *
 * @param {Kickq.JobItem.ProcessItem} processItem The process item to add.
 */
JobItem.prototype.addProcessItem = function( processItem ) {
  if ( !(processItem instanceof JobItem.ProcessItem) ) {
    throw new TypeError('argument not of type Kickq.JobItem.ProcessItem');
  }

  this.runs.push(processItem);
};

/**
 * A job item object has been passed to the constructor, use it.
 *
 * @param  {Object} jobItem The job item as was saved in the db.
 * @private
 */
JobItem.prototype._useItem = function(jobItem) {
  _.keys(jobItem).forEach(function(key){
    this[key] = jobItem[key];
  }.bind(this));
};

/**
 * Set a hotjob promise object to this instance.
 *
 * @param {when.Promise} promise The hotjob promise.
 */
JobItem.prototype.setHotjobPromise = function(promise) {
  this._hotjobPromise = promise;
};

/**
 * Save the job item.
 *
 * @return {when.Promise} A promise.
 */
JobItem.prototype.save = function() {
  log.fine('save() :: Init. jobId, state, Queue:', this.id, this.state, this.name);
  var def = when.defer();

  var key = this._getKey();

  // prep job item for save
  this.updateTime = Date.now();

  var itemDataJson;
  try {
    itemDataJson = this.getPublicJSON();
  } catch(ex) {
    return def.reject(new kError.JSON(ex));
  }

  var redisJobItem = {
    id: this.id,
    name: this.name,
    createTime: this.createTime,
    updateTime: this.updateTime,
    state: this.state,
    itemData: itemDataJson
  };

  this.client.hmset( key, redisJobItem, function(err) {
    if (err) {
      log.db('save() :: "hmset" failed. err: ', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Purge the job.
 *
 * @return {when.Promise} a promise.
 */
JobItem.prototype.delete = function() {
  log.fine('delete() :: Init. jobId:', this.id);
  var def = when.defer();

  this.client.del( this._getKey(), function(err) {
    if (err) {
      log.db('delete() :: "del" failed. err: ', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Change the state of the job item.
 *
 * @param {kickq.states.Job=} newState State.
 * @return {when.Promise} A promise
 */
JobItem.prototype.setState = function(newState) {
  var def = when.defer();

  if (this.state === newState) {
    return;
  }

  var jobKey = this._getKey();
  var oldSetKey = states.getKey(this.state);
  var newSetKey = states.getKey(newState);

  log.info('setState() :: jobId, oldState, newState, Queue: ', this.id,
    this.state, newState, this.name);

  // perform the move
  this.state = newState;
  this.client.multi()
    .hset(jobKey, 'state', this.state)
    .smove(oldSetKey, newSetKey, this.id)
    .exec(function(err, response){
      if (err) {
        log.db('setState() :: "hmset/smove/exec" failed. err: ', err);
        return def.reject(new kError.Database(err));
      }

      if (0 === response[1]) {
        log.warn('setState() :: State Set Move failed. Will attempt to create' +
          ' a new record. jobId, oldState, ' +
          'newState, Queue :: ', this.id, this.state, newState, this.name);

        this.createState(this.state).then(def.resolve, def.reject);
      } else {
        def.resolve();
      }
    }.bind(this));

  return def.promise;
};

/**
 * Create the state record in redis for a new job.
 *
 * @param {kickq.states.Job=} optState Optionally override state.
 * @return {when.Promise} a promise.
 */
JobItem.prototype.createState = function(optState) {
  var def = when.defer();

  var setKey = states.getKey( optState || this.state );
  this.client.sadd(setKey, this.id, function(err) {
    if (err) {
      log.db('createState() :: "sadd" failed. err:', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Create the time-index record for this job item.
 *
 * @return {when.Promise} a promise.
 */
JobItem.prototype.createTimeIndex = function() {
  var def = when.defer();
  var setKey = this.NS + ':time-index';
  this.client.zadd(setKey, this.createTime, this.id, function(err) {
    if (err) {
      log.db('createTimeIndex() :: "zadd" failed. err:', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });
  return def.promise;
};

/**
 * Get the db key for the current item for job hash.
 *
 * @return {string} the key.
 * @private
 */
JobItem.prototype._getKey = function() {
  return this.NS + ':job:' + this.id;
};
<commit_msg>remove all traces of job items<commit_after>/**
 * @fileoverview A job item.
 */
var util = require('util');
var _ = require('underscore');
var when = require('when');
var log = require('logg').getLogger('kickq.model.JobItem');

var kconfig = require('../utility/config');
var states = require('./states');
var kError = require('../utility/kerror');
var Model = require('./model');

/**
 * The Job object
 *
 * @param {Object=} optJobItem optionally define a job item object
 *                             as returned by the database to fill up
 *                             this instance values.
 * @constructor
 * @extends {Kickq.Model}
 */
var JobItem = module.exports = function(optJobItem) {
  log.finer('Ctor() :: Init');
  Model.apply(this, arguments);

  /** @type {?string} the job id. */
  this.id = null;

  /** @type {string} the job name. */
  this.name = '';

  /** @type {boolean} irrespective of success / fail. */
  this.complete = false;

  /** @type {boolean} turns true when complete and executed with success. */
  this.success = false;

  /** @type {number} JS timestamp. */
  this.createTime = Date.now();

  /** @type {number} JS timestamp. */
  this.updateTime = this.createTime;

  /** @type {?number} JS timestamp or null. */
  this.finishTime = null;

  /** @type {?number} total process time in ms or null. */
  this.totalProcessTime = null;

  /** @type {?number} If this job will get delayed before it's queued. */
  this.delay = null;

  /** @type {number} ms, 10 seconds to wait for a worker to complete processing. */
  this.processTimeout = 10000;

  /** @type {boolean} If this job will retry. */
  this.retry = false;

  /** @type {number} How many times to retry. */
  this.retryTimes = 3;

  /** @type {number} ms, 30minutes of interval between retrying. */
  this.retryInterval = 1800000;

  /** @type {boolean} */
  this.hotjob = false;

  /** @type {number} ms, 10 seconds. */
  this.hotjobTimeout = 10000;

  /** @type {boolean} Enable retrying ghost jobs */
  this.ghostRetry = true;

  /** @type {number} How many times to retry a ghost job */
  this.ghostTimes = 1;

  /** @type {number} milliseconds of interval between retrying */
  this.ghostInterval = 1800000;

  /** @type {*} Any type, passed data on job creation. */
  this.data = null;

  /** @type {?string} Last processing error as defined by consumer  */
  this.lastError = null;

  /** @type {?number} JS timestamp of when this job has been scheduled for */
  this.scheduledFor = null;

  /**
   *
   * the state can be one of:
   *   - new
   *   - queued :: A job has been queued for re-processing
   *   - delayed
   *   - processing
   *   - retry
   *   - ghost   :: A re-process state when callback does not report.
   *   - success :: 'complete' flag is true
   *   - fail    :: 'complete' flag is true
   *
   * @type {Kickq.states.Job}
   */
  this.state = states.Job.NEW;

  /**
   * Processing runs performed for this job. Can be 1 up to n retries.
   *
   * When the job is new this is an empty array.
   *
   * @type {Array.<JobItem.ProcessItem>} An array of process items.
   */
  this.runs = [];

  //
  //
  // Private variables
  //
  //

  /** @type {boolean} If item has initialized */
  this._hasInitialized = false;

  /** @type {?when.Promise} The hotjob's promise object is referenced here */
  this._hotjobPromise = null;

  // Check if a jobItem has been passed as argument and use it
  if (_.isObject(optJobItem)) {
    this._useItem(optJobItem);
  }
};
util.inherits(JobItem, Model);

/**
 * Initialize values for a new job item using options provided or
 * falling back to config.
 *
 * @param  {Object=} options Job Options object as passed by the consumer.
 */
JobItem.prototype.initialize = function( options ) {
  if (this._hasInitialized) {
    return;
  }
  this._hasInitialized = true;

  // Define all the options that needs to be examined
  var optsExamine = [
    'delay',
    'retry',
    'retryTimes',
    'retryInterval',
    'ghostRetry',
    'ghostTimes',
    'ghostInterval',
    'hotjob',
    'hotjobTimeout',
    'processTimeout'
  ];

  // Get "per job" specific config options
  var configOpts = kconfig.getJob(this.name);

  // examine existence and assign to job.
  optsExamine.forEach(function(prop){
    // defense
    if (!this.hasOwnProperty(prop)) {
      return;
    }

    // check consumer options
    if ( options.hasOwnProperty(prop) ) {
      this[prop] = options[prop];
      return; //next
    }

    // check per job config options
    if ( configOpts.hasOwnProperty(prop) ) {
      this[prop] = configOpts[prop];
      return; // next
    }

    // Finally get global config options
    this[prop] = kconfig.get(prop);
  }, this);

  // determine original state
  if (_.isNumber(this.delay)) {
    this.state = states.Job.DELAYED;
  }
};

/**
 * A processing item, contains information for each processing of a job.
 *
 * @param {Kickq.JobItem} job A job item instance.
 * @constructor
 */
JobItem.ProcessItem = function(job) {

  if (!(job instanceof JobItem)) {
    throw new TypeError('argument not instance of Kickq.JotItem');
  }

  /** @type {number} the process count of this process item. */
  this.count = 1 + job.runs.length;

  /** @type {number} JS timestamp. */
  this.startTime = Date.now();

  /** @type {?number} Processing time in ms or null. */
  this.processTime = null;

  /** @type {?number} Processing timeout in ms for this item */
  this.processTimeout = null;

  /**
   * One of these states:
   *   - processing
   *   - ghost   :: A re-process state when callback does not report.
   *   - success :: 'complete' flag is true
   *   - fail    :: 'complete' flag is true
   *
   * @type {Kickq.states.Process}
   */
  this.state = states.Process.PROCESSING;

  /** @type {?string} if failed the consumer provided error message */
  this.errorMessage = null;

  /** @type {?number} setTimeout index */
  this.timeout = null;
};

/**
 * Return a public job item for API consumption.
 *
 * @return {Object}
 */
JobItem.prototype.getPublic = function() {
  var publicItem = Object.create(null);
  _.forEach(this, function(item, key){
    if (_.isFunction(item)) {
      return;
    }

    // check for private
    if ('_' === key.substr(0,1)) {
      return;
    }

    // check for special symbols that should not be exposed
    if (0 <= [
        'client',
        'clientSub',
        'NS'
      ].indexOf(key)) {
        return;
      }

    publicItem[key] = item;
  });

  // expose hotjob Promise
  publicItem.hotjobPromise = this._hotjobPromise;
  return publicItem;
};

/**
 * Serialize the public object. This method will guarantee a returned JSON
 * value, if standard JSON stringify fails a custom minimum object
 * will be serialized instead.
 *
 * @return {!string} Always string no errors thrown.
 */
JobItem.prototype.getPublicJSON = function() {
  var serialized;
  try {
    serialized = JSON.stringify(this.getPublic());
  } catch(ex) {
    // create minimum viable object
    serialized = '{"id":"' + this.id + '"}';
  }
  return serialized;
};

/**
 * Add a process item to the current job.
 *
 * @param {Kickq.JobItem.ProcessItem} processItem The process item to add.
 */
JobItem.prototype.addProcessItem = function( processItem ) {
  if ( !(processItem instanceof JobItem.ProcessItem) ) {
    throw new TypeError('argument not of type Kickq.JobItem.ProcessItem');
  }

  this.runs.push(processItem);
};

/**
 * A job item object has been passed to the constructor, use it.
 *
 * @param  {Object} jobItem The job item as was saved in the db.
 * @private
 */
JobItem.prototype._useItem = function(jobItem) {
  _.keys(jobItem).forEach(function(key){
    this[key] = jobItem[key];
  }.bind(this));
};

/**
 * Set a hotjob promise object to this instance.
 *
 * @param {when.Promise} promise The hotjob promise.
 */
JobItem.prototype.setHotjobPromise = function(promise) {
  this._hotjobPromise = promise;
};

/**
 * Save the job item.
 *
 * @return {when.Promise} A promise.
 */
JobItem.prototype.save = function() {
  log.fine('save() :: Init. jobId, state, Queue:', this.id, this.state, this.name);
  var def = when.defer();

  var key = this._getKey();

  // prep job item for save
  this.updateTime = Date.now();

  var itemDataJson;
  try {
    itemDataJson = this.getPublicJSON();
  } catch(ex) {
    return def.reject(new kError.JSON(ex));
  }

  var redisJobItem = {
    id: this.id,
    name: this.name,
    createTime: this.createTime,
    updateTime: this.updateTime,
    state: this.state,
    itemData: itemDataJson
  };

  this.client.hmset( key, redisJobItem, function(err) {
    if (err) {
      log.db('save() :: "hmset" failed. err: ', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Purge the job.
 *
 * @return {when.Promise} a promise.
 */
JobItem.prototype.delete = function() {
  log.fine('delete() :: Init. jobId:', this.id);
  var def = when.defer();

  this.client.multi()
    .del( this._getKey())
    .zrem( this.NS + ':time-index', this.id)
    .srem( states.getKey(this.state), this.id)
    .exec(function(err) {
    if (err) {
      log.db('delete() :: "exec" failed. err: ', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Change the state of the job item.
 *
 * @param {kickq.states.Job=} newState State.
 * @return {when.Promise} A promise
 */
JobItem.prototype.setState = function(newState) {
  var def = when.defer();

  if (this.state === newState) {
    return;
  }

  var jobKey = this._getKey();
  var oldSetKey = states.getKey(this.state);
  var newSetKey = states.getKey(newState);

  log.info('setState() :: jobId, oldState, newState, Queue: ', this.id,
    this.state, newState, this.name);

  // perform the move
  this.state = newState;
  this.client.multi()
    .hset(jobKey, 'state', this.state)
    .smove(oldSetKey, newSetKey, this.id)
    .exec(function(err, response){
      if (err) {
        log.db('setState() :: "hmset/smove/exec" failed. err: ', err);
        return def.reject(new kError.Database(err));
      }

      if (0 === response[1]) {
        log.warn('setState() :: State Set Move failed. Will attempt to create' +
          ' a new record. jobId, oldState, ' +
          'newState, Queue :: ', this.id, this.state, newState, this.name);

        this.createState(this.state).then(def.resolve, def.reject);
      } else {
        def.resolve();
      }
    }.bind(this));

  return def.promise;
};

/**
 * Create the state record in redis for a new job.
 *
 * @param {kickq.states.Job=} optState Optionally override state.
 * @return {when.Promise} a promise.
 */
JobItem.prototype.createState = function(optState) {
  var def = when.defer();

  var setKey = states.getKey( optState || this.state );
  this.client.sadd(setKey, this.id, function(err) {
    if (err) {
      log.db('createState() :: "sadd" failed. err:', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });

  return def.promise;
};

/**
 * Create the time-index record for this job item.
 *
 * @return {when.Promise} a promise.
 */
JobItem.prototype.createTimeIndex = function() {
  var def = when.defer();
  var setKey = this.NS + ':time-index';
  this.client.zadd(setKey, this.createTime, this.id, function(err) {
    if (err) {
      log.db('createTimeIndex() :: "zadd" failed. err:', err);
      return def.reject(new kError.Database(err));
    }
    def.resolve();
  });
  return def.promise;
};

/**
 * Get the db key for the current item for job hash.
 *
 * @return {string} the key.
 * @private
 */
JobItem.prototype._getKey = function() {
  return this.NS + ':job:' + this.id;
};
<|endoftext|>


<commit_before>"use strict";
var webdav = require('../../lib/index.js').v2,
    request = require('request'),
    path = require('path'),
    fs = require('fs'),
    xmljs = require('xml-js-builder')

module.exports = (callback, options) => {
    var successes = [];
    var errors = [];

    function success(text)
    {
        successes.push(' \x1b[42m\x1b[37m\x1b[1m o \x1b[0m ' + text + '\x1b[0m');
    }
    function error(text)
    {
        errors.push(' \x1b[41m\x1b[37m\x1b[1m x \x1b[0m ' + text + '\x1b[0m');
    }

    var nb = 0;

    function callCallback()
    {
        --nb;
        if(nb <= 0)
            callback(successes, errors);
    }

    var root = path.join(__dirname, 'tests');
    fs.readdir(root, (e, files) => {
        if(e)
            throw e;

        files = files.filter((f) => f.indexOf('.js') === -1);
        nb += files.length;
        let gindex = 0;
        files.forEach((f1) => {
            const f1x = path.join(root, f1);
            fs.readdir(f1x, (e, files) => {
                if(e)
                    throw e;

                files = files.filter((f) => f.indexOf('.js') === f.length - 3 && f.indexOf('.') !== 0);
                nb += files.length;
                files.forEach((f) => {
                    const fx = path.join(f1x, f);

                    const info = {
                        name: undefined,
                        options,
                        port: options.port + gindex * options.nbReservedSocketPerTest,
                        easyError: (e, cb) => (e, arg1, arg2, arg3) => {
                            if(e)
                                info.isValid(false, e);
                            else
                                cb(arg1, arg2, arg3);
                        },
                        startServer: (options, autoStart) => {
                            options = options ? options : {};
                            options.port = info.port + info.servers.length;
                            const startServer = new webdav.WebDAVServer(options);
                            if(autoStart || autoStart === undefined || autoStart === null)
                                startServer.start();
                            info.servers.push(startServer);
                            return startServer;
                        },
                        reqStream: (config, callback) => {
                            const stream = request(config);
                            stream.on('error', (e) => {
                                info.isValid(false, 'HTTP error.', e);
                            })
                            stream.on('complete', (res, body) => {
                                if(res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);

                                callback();
                            })
                            return stream;
                        },
                        req: (config, _codeStatusExpected, _callback) => {
                            const codeStatusExpected = _callback ? _codeStatusExpected : -1;
                            const callback = _callback ? _callback : _codeStatusExpected;

                            request(config, (e, res, body) => {
                                if(e)
                                    return info.isValid(false, 'HTTP error.', e);
                                if(codeStatusExpected === -1 && res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);
                                if(codeStatusExpected !== -1 && res.statusCode != codeStatusExpected)
                                    return info.isValid(false, 'Expected ' + codeStatusExpected + ' but got : ' + res.statusCode + ' - ' + res.statusMessage);

                                if(body)
                                    body = body.toString();

                                callback(res, body);
                            })
                        },
                        reqXML: (config, _codeStatusExpected, _callback) => {
                            const codeStatusExpected = _callback ? _codeStatusExpected : -1;
                            const callback = _callback ? _callback : _codeStatusExpected;

                            request(config, (e, res, body) => {
                                if(e)
                                    return info.isValid(false, 'HTTP error.', e);
                                if(codeStatusExpected === -1 && res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);
                                if(codeStatusExpected !== -1 && res.statusCode != codeStatusExpected)
                                    return info.isValid(false, 'Expected ' + codeStatusExpected + ' but got : ' + res.statusCode + ' - ' + res.statusMessage);

                                if(body)
                                {
                                    try
                                    {
                                        body = xmljs.XML.parse(body);
                                    }
                                    catch(ex)
                                    {
                                        return info.isValid(false, 'Invlid XML in the response body.', body.toString());
                                    }
                                }

                                callback(res, body);
                            })
                        },
                        init: (nbExpected, name) => {
                            if(name !== undefined)
                            {
                                if(name.constructor === String)
                                {
                                    info.name = name;
                                    info.startServer();
                                }
                                else
                                {
                                    name.port = info.port;
                                    info.startServer(name);
                                }
                            }
                            else
                                info.startServer();
                            info.ctx = webdav.ExternalRequestContext.create(info.servers[0]);
                            info.expect(nbExpected);
                            return info.servers[0];
                        },
                        servers: [],
                        expect: (nb) => {
                            let callback = (valid, details) => {
                                callback = (valid, details) => { }

                                details = details ? ' :: ' + details : '';
                                const prefix = '[' + f1.replace(/([A-Z-])/g, ' $1').trim().toLowerCase() + ' :: ' + f.replace('.js', '').replace(/([A-Z-])/g, ' $1').trim().toLowerCase() + (info.name ? ' : ' + info.name : '') + ']';
                                if(valid)
                                    success(prefix + details)
                                else
                                    error(prefix + details)
                                callCallback();
                            }

                            info.exit = (msg) => {
                                callback(false, msg);
                            }

                            var allGood = true;
                            var allMsg;
                            info.isValid = function(good, msg, error)
                            {
                                if(error)
                                {
                                    msg += ' :: ' + error;
                                    if(options.showExceptions)
                                        console.error(error);
                                }

                                --nb;
                                if(msg && allGood && !good)
                                    allMsg = msg;
                                allGood = allGood && good;
                                if(nb === 0)
                                {
                                    info.servers.forEach((s) => s.stop());
                                    callback(allGood, allMsg);
                                }
                            }
                        }
                    };

                    try
                    {
                        setTimeout(() => info.exit('Timeout'), options.timeout);
                        process.nextTick(() => require(fx).default(info, (good, msg, e) => info.isValid(good, msg, e)));
                    }
                    catch(ex)
                    {
                        if(options.showExceptions)
                            console.error(ex);

                        error(info.name + '\r\n' + ex)
                        callCallback();
                    }
                    ++gindex;
                })

                --nb;
            })
        })
    })
};

if(!module.parent)
    module.exports((successes, errors) => {
        console.log('=====================================');
        console.log('==== webdav-server === Version 2 ====');
        console.log('=====================================');
        console.log();
        console.log(' ' + successes.length + ' successe(s).');
        console.log(' ' + errors.length + ' error(s).');

        if(successes.length)
        {
            console.log();
            console.log(' Successe(s) :');
            successes.sort().forEach(v => console.log(v));
        }
        if(errors.length)
        {
            console.log();
            console.log(' Error(s) :');
            errors.sort().forEach(v => console.log(v));
        }

        console.log();
        console.log(' ' + successes.length + ' successe(s).');
        console.log(' ' + errors.length + ' error(s).');

        process.exit(errors.length > 0 ? 1 : 0);
    }, {
        port: 1900,
        showExceptions : true,
        timeout: 6000,
        nbReservedSocketPerTest: 20
    })
<commit_msg>Added more server ports to the tests of the v2<commit_after>"use strict";
var webdav = require('../../lib/index.js').v2,
    request = require('request'),
    path = require('path'),
    fs = require('fs'),
    xmljs = require('xml-js-builder')

module.exports = (callback, options) => {
    var successes = [];
    var errors = [];

    function success(text)
    {
        successes.push(' \x1b[42m\x1b[37m\x1b[1m o \x1b[0m ' + text + '\x1b[0m');
    }
    function error(text)
    {
        errors.push(' \x1b[41m\x1b[37m\x1b[1m x \x1b[0m ' + text + '\x1b[0m');
    }

    var nb = 0;

    function callCallback()
    {
        --nb;
        if(nb <= 0)
            callback(successes, errors);
    }

    var root = path.join(__dirname, 'tests');
    fs.readdir(root, (e, files) => {
        if(e)
            throw e;

        files = files.filter((f) => f.indexOf('.js') === -1);
        nb += files.length;
        let gindex = 0;
        files.forEach((f1) => {
            const f1x = path.join(root, f1);
            fs.readdir(f1x, (e, files) => {
                if(e)
                    throw e;

                files = files.filter((f) => f.indexOf('.js') === f.length - 3 && f.indexOf('.') !== 0);
                nb += files.length;
                files.forEach((f) => {
                    const fx = path.join(f1x, f);

                    const info = {
                        name: undefined,
                        options,
                        port: options.port + gindex * options.nbReservedSocketPerTest,
                        easyError: (e, cb) => (e, arg1, arg2, arg3) => {
                            if(e)
                                info.isValid(false, e);
                            else
                                cb(arg1, arg2, arg3);
                        },
                        startServer: (options, autoStart) => {
                            options = options ? options : {};
                            options.port = info.port + info.servers.length;
                            const startServer = new webdav.WebDAVServer(options);
                            if(autoStart || autoStart === undefined || autoStart === null)
                                startServer.start();
                            info.servers.push(startServer);
                            return startServer;
                        },
                        reqStream: (config, callback) => {
                            const stream = request(config);
                            stream.on('error', (e) => {
                                info.isValid(false, 'HTTP error.', e);
                            })
                            stream.on('complete', (res, body) => {
                                if(res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);

                                callback();
                            })
                            return stream;
                        },
                        req: (config, _codeStatusExpected, _callback) => {
                            const codeStatusExpected = _callback ? _codeStatusExpected : -1;
                            const callback = _callback ? _callback : _codeStatusExpected;

                            request(config, (e, res, body) => {
                                if(e)
                                    return info.isValid(false, 'HTTP error.', e);
                                if(codeStatusExpected === -1 && res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);
                                if(codeStatusExpected !== -1 && res.statusCode != codeStatusExpected)
                                    return info.isValid(false, 'Expected ' + codeStatusExpected + ' but got : ' + res.statusCode + ' - ' + res.statusMessage);

                                if(body)
                                    body = body.toString();

                                callback(res, body);
                            })
                        },
                        reqXML: (config, _codeStatusExpected, _callback) => {
                            const codeStatusExpected = _callback ? _codeStatusExpected : -1;
                            const callback = _callback ? _callback : _codeStatusExpected;

                            request(config, (e, res, body) => {
                                if(e)
                                    return info.isValid(false, 'HTTP error.', e);
                                if(codeStatusExpected === -1 && res.statusCode >= 300)
                                    return info.isValid(false, res.statusCode + ' - ' + res.statusMessage);
                                if(codeStatusExpected !== -1 && res.statusCode != codeStatusExpected)
                                    return info.isValid(false, 'Expected ' + codeStatusExpected + ' but got : ' + res.statusCode + ' - ' + res.statusMessage);

                                if(body)
                                {
                                    try
                                    {
                                        body = xmljs.XML.parse(body);
                                    }
                                    catch(ex)
                                    {
                                        return info.isValid(false, 'Invlid XML in the response body.', body.toString());
                                    }
                                }

                                callback(res, body);
                            })
                        },
                        init: (nbExpected, name) => {
                            if(name !== undefined)
                            {
                                if(name.constructor === String)
                                {
                                    info.name = name;
                                    info.startServer();
                                }
                                else
                                {
                                    name.port = info.port;
                                    info.startServer(name);
                                }
                            }
                            else
                                info.startServer();
                            info.ctx = webdav.ExternalRequestContext.create(info.servers[0]);
                            info.expect(nbExpected);
                            return info.servers[0];
                        },
                        servers: [],
                        expect: (nb) => {
                            let callback = (valid, details) => {
                                callback = (valid, details) => { }

                                details = details ? ' :: ' + details : '';
                                const prefix = '[' + f1.replace(/([A-Z-])/g, ' $1').trim().toLowerCase() + ' :: ' + f.replace('.js', '').replace(/([A-Z-])/g, ' $1').trim().toLowerCase() + (info.name ? ' : ' + info.name : '') + ']';
                                if(valid)
                                    success(prefix + details)
                                else
                                    error(prefix + details)
                                callCallback();
                            }

                            info.exit = (msg) => {
                                callback(false, msg);
                            }

                            var allGood = true;
                            var allMsg;
                            info.isValid = function(good, msg, error)
                            {
                                if(error)
                                {
                                    msg += ' :: ' + error;
                                    if(options.showExceptions)
                                        console.error(error);
                                }

                                --nb;
                                if(msg && allGood && !good)
                                    allMsg = msg;
                                allGood = allGood && good;
                                if(nb === 0)
                                {
                                    info.servers.forEach((s) => s.stop());
                                    callback(allGood, allMsg);
                                }
                            }
                        }
                    };

                    try
                    {
                        setTimeout(() => info.exit('Timeout'), options.timeout);
                        process.nextTick(() => require(fx).default(info, (good, msg, e) => info.isValid(good, msg, e)));
                    }
                    catch(ex)
                    {
                        if(options.showExceptions)
                            console.error(ex);

                        error(info.name + '\r\n' + ex)
                        callCallback();
                    }
                    ++gindex;
                })

                --nb;
            })
        })
    })
};

if(!module.parent)
    module.exports((successes, errors) => {
        console.log('=====================================');
        console.log('==== webdav-server === Version 2 ====');
        console.log('=====================================');
        console.log();
        console.log(' ' + successes.length + ' successe(s).');
        console.log(' ' + errors.length + ' error(s).');

        if(successes.length)
        {
            console.log();
            console.log(' Successe(s) :');
            successes.sort().forEach(v => console.log(v));
        }
        if(errors.length)
        {
            console.log();
            console.log(' Error(s) :');
            errors.sort().forEach(v => console.log(v));
        }

        console.log();
        console.log(' ' + successes.length + ' successe(s).');
        console.log(' ' + errors.length + ' error(s).');

        process.exit(errors.length > 0 ? 1 : 0);
    }, {
        port: 1900,
        showExceptions : true,
        timeout: 6000,
        nbReservedSocketPerTest: 30
    })
<|endoftext|>


<commit_before>const co = require('co')
const pify = require('pify')
const fs = pify(require('fs'), { include: ['readFile'] })
const cloneDeep = require('lodash.clonedeep')
const hookUtils = require('./hook-utils')
const combineErrors = require('combine-errors')
const Nightwatch = {
  Runner: require('nightwatch/lib/runner/run'),
  ClientManager: require('nightwatch/lib/runner/clientmanager'),
  ClientRunner: require('nightwatch/lib/runner/cli/clirunner'),
  ChildProcess: require('nightwatch/lib/runner/cli/child-process'),
  Utils: require('nightwatch/lib/util/utils'),
  Logger: require('nightwatch/lib/util/logger'),
  Protocol: require('nightwatch/lib/api/protocol'),
  ErrorHandler: require('nightwatch/lib/runner/cli/errorhandler'),
  Assertion: require('nightwatch/lib/core/assertion'),
  Expect: require('nightwatch/lib/api/expect'),
  queue: require('nightwatch/lib/core/queue.js')
}

process.on('unhandledRejection', (reason, p) => {
  console.error('Unhandled Rejection at: Promise', p, 'reason:', reason)
})

module.exports = class NightwatchApi {
  constructor (options) {
    this.options = options
  }

  _startSession (options) {
    this.client = new Nightwatch.ClientManager()
    this.client.init(options)
    const api = this.client.api('currentEnv', options.currentEnv)
    this.promisifyApi(api)
    this.promisifyAssertions()
    this.promisifyExpect(api)
    this.promisifyPageObjects(api)
    if (this.options.nightwatchOutput) {
      this.addAssertionLogger()
    }
    this.protocol = Nightwatch.Protocol(this.client.get())
  }

  promisifyApi (api) {
    let _successCb, _catchCb
    api.catch = (catchCb) => {
      if (catchCb) _catchCb = catchCb
    }
    api.then = (successCb, catchCb) => {
      if (successCb) _successCb = successCb
      if (catchCb) _catchCb = catchCb
      return this.start()
        .then(_successCb)
        .catch(_catchCb)
    }
  }

  promisifyAssertions () {
    const promise = {}
    this.promisifyApi(promise)
    const originalAssert = Nightwatch.Assertion.assert

    Nightwatch.Assertion.assert = function () {
      originalAssert.apply(this, arguments)
      return promise
    }
  }

  promisifyExpect (api) {
    const self = this
    if (!api.expect) return
    const originalExpectElement = api.expect.element

    api.expect.element = function () {
      const result = originalExpectElement.apply(this, arguments)
      self.promisifyApi(result)
      return result
    }
  }

  promisifySection (section) {
    this.promisifyApi(section)
    this.promisifyExpect(section)
    if (section.section) {
      Object.keys(section.section).forEach((key) => {
        this.promisifySection(section.section[key])
      })
    }
  }

  promisifyChildPageObjects (page) {
    const self = this
    Object.keys(page).forEach((key) => {
      if (typeof page[key] !== 'function') {
        this.promisifyChildPageObjects(page[key])
      } else {
        const originalPageCreator = page[key]
        page[key] = function () {
          const page = originalPageCreator.call(this)
          self.promisifySection(page)
          return page
        }
      }
    })
  }

  promisifyPageObjects (api) {
    if (api.page) {
      return this.promisifyChildPageObjects(api.page)
    }
  }

  getClientApi () {
    return this.client.api()
  }

  * _closeSession () {
    yield new Promise((resolve, reject) => {
      this.client.get().once('nightwatch:finished', function () {
        resolve()
      })
      this.client.terminate()
    })
  }

  * takeScreenshot (moduleName, testName) {
    if (!this.takeScreenshotOnFailure || Nightwatch.queue.instance().rootNode.started) return

    const forbiddenCharacters = /[*|\\:"<>?/+]/g

    const filePath = Nightwatch.Utils.getScreenshotFileName(
      {module: moduleName, name: testName.replace(forbiddenCharacters, '')},
      true,
      this.client.options.screenshots.path
    )

    yield new Promise((resolve, reject) => {
      this.protocol.screenshot(false, (response) => {
        if (response.state !== 'success' && response.status !== 0) {
          reject(new Error('Creating screenshot was not successful. Response was:\n' + require('util').inspect(response)))
        }

        this.client.get().saveScreenshotToFile(filePath, response.value, (err) => {
          if (err) reject(err)
          resolve()
        })
      })
    })

    return {
      data: yield fs.readFile(filePath, 'base64'),
      mimeType: 'image/png'
    }
  }

  addTestModulePaths (modulePaths) {
    this.modulePaths = modulePaths
  }

  isSingleFeatureFile (featureFile) {
    let stat
    try {
      stat = fs.statSync(featureFile)
    } catch (err) {
      featureFile = featureFile.replace(/:\d+$/, '')
      if (!featureFile.match(/\.feature$/)) featureFile += '.feature'
      try {
        stat = fs.statSync(featureFile)
      } catch (err) {
        throw new Error(`Feature file or folder ${featureFile} was not found!`)
      }
    }

    return stat.isFile()
  }

  overrideOriginalSourceGetter (convert) {
    const self = this
    const originalClientRunnerGetTestSource = Nightwatch.ClientRunner.prototype.getTestSource

    Nightwatch.ClientRunner.prototype.getTestSource = function () {
      Nightwatch.ClientRunner.prototype.getTestSource = originalClientRunnerGetTestSource
      const originalArgv = cloneDeep(this.argv)
      const originalSettings = cloneDeep(this.settings)

      if (this.argv._source && this.argv._source.length) {
        this.argv._source = this.argv._source.map(convert)
      } else if (this.argv.test) {
        this.argv.test = convert(this.argv.test)
      } else {
        this.settings.src_folders = self.modulePaths
      }
      self.nightwatchArgv = this.argv
      self.testSource = Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)

      if (this.parallelMode) {
        return self.testSource
      }

      this.argv = originalArgv
      this.settings = originalSettings
      this.settings.src_folders = this.settings.src_folders || []
      return Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)
    }

    Nightwatch.ClientRunner.prototype.singleSourceFile = function () {
      if (this.singleTestRun()) {
        return self.isSingleFeatureFile(this.argv.test)
      }

      return (Array.isArray(this.argv._source) && this.argv._source.length === 1) && self.isSingleFeatureFile(this.argv._source[0])
    }
  }

  addHookTests (revert) {
    hookUtils.addHookBefore(Nightwatch.ChildProcess.prototype, 'getArgs', function () {
      if (this.args.indexOf('--test') === -1) return

      const cliArgs = this.args
      const testIndex = cliArgs.indexOf('--test') + 1
      cliArgs[testIndex] = revert(cliArgs[testIndex])
    })
  }

  addPathConverter (convert, revert) {
    this.overrideOriginalSourceGetter(convert)
    this.addHookTests(revert)
  }

  addAssertionLogger () {
    const originalAssertion = this.client.get().assertion
    this.__originalAssertion = originalAssertion
    this.client.get().assertion = function (passed, receivedValue, expectedValue, message, abortOnFailure, originalStackTrace) {
      if (passed) {
        console.log(`\n ${Nightwatch.Logger.colors.green(Nightwatch.Utils.symbols.ok)} ${message}`)
      }
      return originalAssertion.apply(this, arguments)
    }
  }

  removeAssertionLogger () {
    this.client.get().assertion = this.__originalAssertion
  }

  overrideOriginalStartTestWorkers () {
    const originalStartTestWorkers = Nightwatch.ClientRunner.prototype.startTestWorkers

    Nightwatch.ClientRunner.prototype.startTestWorkers = function () {
      this.test_settings.tag_filter = undefined
      return originalStartTestWorkers.apply(this, arguments)
    }
  }

  addHookAfterChildProcesses (hook) {
    hookUtils.addCallbackedHookAfter(Nightwatch.ClientRunner.prototype, 'startChildProcesses', 1, hook)
  }

  isRunningInParallel () {
    return process.env.__NIGHTWATCH_PARALLEL_MODE === '1'
  }

  getWorkerIndex () {
    return process.env.__NIGHTWATCH_ENV_KEY.split('_').pop()
  }

  clearResult () {
    this.client.get().clearResult()
    this.client.get().results.lastError = null
  }

  start () {
    return new Promise((resolve, reject) => {
      this.client.get().once('nightwatch:finished', (results, errors) => {
        const errorList = results.tests.filter(test => test.failure).map(test => {
          const error = new Error(`${test.message} - ${test.failure}`)
          error.stack = `\n${test.stackTrace}`
          return error
        }).concat(errors.map(errorString => {
          const cutPos = errorString.indexOf(':')
          const error = new Error(errorString.substring(0, cutPos))
          error.stack = errorString
          return error
        }))
        this.clearResult()
        if (errorList.length) {
          reject(combineErrors(errorList))
          return
        }
        resolve()
      })
      this.client.start()
    })
  }

  addTestRunner (testRunner) {
    const self = this
    const originalRunnerRun = Nightwatch.Runner.prototype.run

    Nightwatch.Runner.prototype.run = co.wrap(function * () {
      const that = this
      let error
      let executionSuccess
      const originalOptions = cloneDeep(this.options)
      const originalAdditionalOpts = cloneDeep(this.additionalOpts)
      this.additionalOpts.output_folder = false
      this.options.output = false
      this.options.tag_filter = undefined
      this.options.end_session_on_fail = false
      self.takeScreenshotOnFailure = this.options.screenshots &&
        this.options.screenshots.enabled &&
        this.options.screenshots.path &&
        this.options.screenshots.on_failure

      if (this.options.screenshots) this.options.screenshots.enabled = false

      try {
        const modules = yield new Promise((resolve, reject) => {
          Nightwatch.Runner
            .readPaths(self.testSource, that.options)
            .spread(function (modulePaths, fullPaths) {
              resolve(modulePaths)
            }).then(resolve, reject)
        })
        self._startSession(this.options)
        executionSuccess = yield * testRunner(modules)
      } catch (err) {
        error = err
      }

      try {
        if (self.client) {
          self.client.endSessionOnFail(typeof originalOptions.end_session_on_fail === 'undefined' || originalOptions.end_session_on_fail)
          yield * self._closeSession()
        }
      } catch (err) {
        error = err
      }

      if (typeof process.send === 'function') {
        process.send(JSON.stringify({
          type: 'testsuite_finished',
          itemKey: process.env.__NIGHTWATCH_ENV_LABEL,
          moduleKey: 'moduleKey',
          results: {
            completed: {
              ok: 1
            }
          },
          errmessages: []
        }))
      }

      this.options = originalOptions
      this.additionalOpts = originalAdditionalOpts
      self.removeAssertionLogger()

      if (!originalAdditionalOpts.src_folders || !originalAdditionalOpts.src_folders.length || error || !executionSuccess) {
        return this.doneCb(error || !executionSuccess, {})
      }

      return originalRunnerRun.apply(this, arguments)
    })
  }
}
<commit_msg>Improve assertion logger<commit_after>const co = require('co')
const pify = require('pify')
const fs = pify(require('fs'), { include: ['readFile'] })
const cloneDeep = require('lodash.clonedeep')
const hookUtils = require('./hook-utils')
const combineErrors = require('combine-errors')
const Nightwatch = {
  Runner: require('nightwatch/lib/runner/run'),
  ClientManager: require('nightwatch/lib/runner/clientmanager'),
  ClientRunner: require('nightwatch/lib/runner/cli/clirunner'),
  ChildProcess: require('nightwatch/lib/runner/cli/child-process'),
  Utils: require('nightwatch/lib/util/utils'),
  Logger: require('nightwatch/lib/util/logger'),
  Protocol: require('nightwatch/lib/api/protocol'),
  ErrorHandler: require('nightwatch/lib/runner/cli/errorhandler'),
  Assertion: require('nightwatch/lib/core/assertion'),
  Expect: require('nightwatch/lib/api/expect'),
  queue: require('nightwatch/lib/core/queue.js')
}

process.on('unhandledRejection', (reason, p) => {
  console.error('Unhandled Rejection at: Promise', p, 'reason:', reason)
})

module.exports = class NightwatchApi {
  constructor (options) {
    this.options = options
  }

  _startSession (options) {
    this.client = new Nightwatch.ClientManager()
    this.client.init(options)
    const api = this.client.api('currentEnv', options.currentEnv)
    this.promisifyApi(api)
    this.promisifyAssertions()
    this.promisifyExpect(api)
    this.promisifyPageObjects(api)
    if (this.options.nightwatchOutput) {
      this.addAssertionLogger()
    }
    this.protocol = Nightwatch.Protocol(this.client.get())
  }

  promisifyApi (api) {
    let _successCb, _catchCb
    api.catch = (catchCb) => {
      if (catchCb) _catchCb = catchCb
    }
    api.then = (successCb, catchCb) => {
      if (successCb) _successCb = successCb
      if (catchCb) _catchCb = catchCb
      return this.start()
        .then(_successCb)
        .catch(_catchCb)
    }
  }

  promisifyAssertions () {
    const promise = {}
    this.promisifyApi(promise)
    const originalAssert = Nightwatch.Assertion.assert

    Nightwatch.Assertion.assert = function () {
      originalAssert.apply(this, arguments)
      return promise
    }
  }

  promisifyExpect (api) {
    const self = this
    if (!api.expect) return
    const originalExpectElement = api.expect.element

    api.expect.element = function () {
      const result = originalExpectElement.apply(this, arguments)
      self.promisifyApi(result)
      return result
    }
  }

  promisifySection (section) {
    this.promisifyApi(section)
    this.promisifyExpect(section)
    if (section.section) {
      Object.keys(section.section).forEach((key) => {
        this.promisifySection(section.section[key])
      })
    }
  }

  promisifyChildPageObjects (page) {
    const self = this
    Object.keys(page).forEach((key) => {
      if (typeof page[key] !== 'function') {
        this.promisifyChildPageObjects(page[key])
      } else {
        const originalPageCreator = page[key]
        page[key] = function () {
          const page = originalPageCreator.call(this)
          self.promisifySection(page)
          return page
        }
      }
    })
  }

  promisifyPageObjects (api) {
    if (api.page) {
      return this.promisifyChildPageObjects(api.page)
    }
  }

  getClientApi () {
    return this.client.api()
  }

  * _closeSession () {
    yield new Promise((resolve, reject) => {
      this.client.get().once('nightwatch:finished', function () {
        resolve()
      })
      this.client.terminate()
    })
  }

  * takeScreenshot (moduleName, testName) {
    if (!this.takeScreenshotOnFailure || Nightwatch.queue.instance().rootNode.started) return

    const forbiddenCharacters = /[*|\\:"<>?/+]/g

    const filePath = Nightwatch.Utils.getScreenshotFileName(
      {module: moduleName, name: testName.replace(forbiddenCharacters, '')},
      true,
      this.client.options.screenshots.path
    )

    yield new Promise((resolve, reject) => {
      this.protocol.screenshot(false, (response) => {
        if (response.state !== 'success' && response.status !== 0) {
          reject(new Error('Creating screenshot was not successful. Response was:\n' + require('util').inspect(response)))
        }

        this.client.get().saveScreenshotToFile(filePath, response.value, (err) => {
          if (err) reject(err)
          resolve()
        })
      })
    })

    return {
      data: yield fs.readFile(filePath, 'base64'),
      mimeType: 'image/png'
    }
  }

  addTestModulePaths (modulePaths) {
    this.modulePaths = modulePaths
  }

  isSingleFeatureFile (featureFile) {
    let stat
    try {
      stat = fs.statSync(featureFile)
    } catch (err) {
      featureFile = featureFile.replace(/:\d+$/, '')
      if (!featureFile.match(/\.feature$/)) featureFile += '.feature'
      try {
        stat = fs.statSync(featureFile)
      } catch (err) {
        throw new Error(`Feature file or folder ${featureFile} was not found!`)
      }
    }

    return stat.isFile()
  }

  overrideOriginalSourceGetter (convert) {
    const self = this
    const originalClientRunnerGetTestSource = Nightwatch.ClientRunner.prototype.getTestSource

    Nightwatch.ClientRunner.prototype.getTestSource = function () {
      Nightwatch.ClientRunner.prototype.getTestSource = originalClientRunnerGetTestSource
      const originalArgv = cloneDeep(this.argv)
      const originalSettings = cloneDeep(this.settings)

      if (this.argv._source && this.argv._source.length) {
        this.argv._source = this.argv._source.map(convert)
      } else if (this.argv.test) {
        this.argv.test = convert(this.argv.test)
      } else {
        this.settings.src_folders = self.modulePaths
      }
      self.nightwatchArgv = this.argv
      self.testSource = Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)

      if (this.parallelMode) {
        return self.testSource
      }

      this.argv = originalArgv
      this.settings = originalSettings
      this.settings.src_folders = this.settings.src_folders || []
      return Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)
    }

    Nightwatch.ClientRunner.prototype.singleSourceFile = function () {
      if (this.singleTestRun()) {
        return self.isSingleFeatureFile(this.argv.test)
      }

      return (Array.isArray(this.argv._source) && this.argv._source.length === 1) && self.isSingleFeatureFile(this.argv._source[0])
    }
  }

  addHookTests (revert) {
    hookUtils.addHookBefore(Nightwatch.ChildProcess.prototype, 'getArgs', function () {
      if (this.args.indexOf('--test') === -1) return

      const cliArgs = this.args
      const testIndex = cliArgs.indexOf('--test') + 1
      cliArgs[testIndex] = revert(cliArgs[testIndex])
    })
  }

  addPathConverter (convert, revert) {
    this.overrideOriginalSourceGetter(convert)
    this.addHookTests(revert)
  }

  addAssertionLogger () {
    if (!this.client) return
    const originalAssertion = this.client.get().assertion
    this.__originalAssertion = originalAssertion
    this.client.get().assertion = function (passed, receivedValue, expectedValue, message, abortOnFailure, originalStackTrace) {
      if (passed) {
        console.log(`\n ${Nightwatch.Logger.colors.green(Nightwatch.Utils.symbols.ok)} ${message}`)
      }
      return originalAssertion.apply(this, arguments)
    }
  }

  removeAssertionLogger () {
    if (!this.client) return
    this.client.get().assertion = this.__originalAssertion
  }

  overrideOriginalStartTestWorkers () {
    const originalStartTestWorkers = Nightwatch.ClientRunner.prototype.startTestWorkers

    Nightwatch.ClientRunner.prototype.startTestWorkers = function () {
      this.test_settings.tag_filter = undefined
      return originalStartTestWorkers.apply(this, arguments)
    }
  }

  addHookAfterChildProcesses (hook) {
    hookUtils.addCallbackedHookAfter(Nightwatch.ClientRunner.prototype, 'startChildProcesses', 1, hook)
  }

  isRunningInParallel () {
    return process.env.__NIGHTWATCH_PARALLEL_MODE === '1'
  }

  getWorkerIndex () {
    return process.env.__NIGHTWATCH_ENV_KEY.split('_').pop()
  }

  clearResult () {
    this.client.get().clearResult()
    this.client.get().results.lastError = null
  }

  start () {
    return new Promise((resolve, reject) => {
      this.client.get().once('nightwatch:finished', (results, errors) => {
        const errorList = results.tests.filter(test => test.failure).map(test => {
          const error = new Error(`${test.message} - ${test.failure}`)
          error.stack = `\n${test.stackTrace}`
          return error
        }).concat(errors.map(errorString => {
          const cutPos = errorString.indexOf(':')
          const error = new Error(errorString.substring(0, cutPos))
          error.stack = errorString
          return error
        }))
        this.clearResult()
        if (errorList.length) {
          reject(combineErrors(errorList))
          return
        }
        resolve()
      })
      this.client.start()
    })
  }

  addTestRunner (testRunner) {
    const self = this
    const originalRunnerRun = Nightwatch.Runner.prototype.run

    Nightwatch.Runner.prototype.run = co.wrap(function * () {
      const that = this
      let error
      let executionSuccess
      const originalOptions = cloneDeep(this.options)
      const originalAdditionalOpts = cloneDeep(this.additionalOpts)
      this.additionalOpts.output_folder = false
      this.options.output = false
      this.options.tag_filter = undefined
      this.options.end_session_on_fail = false
      self.takeScreenshotOnFailure = this.options.screenshots &&
        this.options.screenshots.enabled &&
        this.options.screenshots.path &&
        this.options.screenshots.on_failure

      if (this.options.screenshots) this.options.screenshots.enabled = false

      try {
        const modules = yield new Promise((resolve, reject) => {
          Nightwatch.Runner
            .readPaths(self.testSource, that.options)
            .spread(function (modulePaths, fullPaths) {
              resolve(modulePaths)
            }).then(resolve, reject)
        })
        self._startSession(this.options)
        executionSuccess = yield * testRunner(modules)
      } catch (err) {
        error = err
      }

      try {
        if (self.client) {
          self.client.endSessionOnFail(typeof originalOptions.end_session_on_fail === 'undefined' || originalOptions.end_session_on_fail)
          yield * self._closeSession()
        }
      } catch (err) {
        error = err
      }

      if (typeof process.send === 'function') {
        process.send(JSON.stringify({
          type: 'testsuite_finished',
          itemKey: process.env.__NIGHTWATCH_ENV_LABEL,
          moduleKey: 'moduleKey',
          results: {
            completed: {
              ok: 1
            }
          },
          errmessages: []
        }))
      }

      this.options = originalOptions
      this.additionalOpts = originalAdditionalOpts
      self.removeAssertionLogger()

      if (!originalAdditionalOpts.src_folders || !originalAdditionalOpts.src_folders.length || error || !executionSuccess) {
        return this.doneCb(error || !executionSuccess, {})
      }

      return originalRunnerRun.apply(this, arguments)
    })
  }
}
<|endoftext|>


<commit_before>'use strict';

var chalk   = require('chalk');
var Task    = require('./task');
var debug   = require('debug')('ember-cli:watcher');
var Promise = require('../ext/promise');
var exec    = Promise.denodeify(require('child_process').exec);

var Watcher = Task.extend({
  verbose: true,

  init: function() {
    var options = this.buildOptions();

    debug('initialize %o', options);

    this.watcher = this.watcher || new (require('broccoli-sane-watcher'))(this.builder, options);

    this.watcher.on('error', this.didError.bind(this));
    this.watcher.on('change', this.didChange.bind(this));
  },

  didError: function(error) {
    debug('didError %o', error);
    this.ui.writeError(error);
    this.analytics.trackError({
      description: error && error.message
    });
  },

  then: function() {
    return this.watcher.then.apply(this.watcher, arguments);
  },

  didChange: function(results) {
    debug('didChange %o', results);
    var totalTime = results.totalTime / 1e6;

    this.ui.writeLine('');
    this.ui.writeLine(chalk.green('Build successful - ' + Math.round(totalTime) + 'ms.'));

    this.analytics.track({
      name:    'ember rebuild',
      message: 'broccoli rebuild time: ' + totalTime + 'ms'
    });

    this.analytics.trackTiming({
      category: 'rebuild',
      variable: 'rebuild time',
      label:    'broccoli rebuild time',
      value:    parseInt(totalTime, 10)
    });
  },

  on: function() {
    this.watcher.on.apply(this.watcher, arguments);
  },

  off: function() {
    this.watcher.off.apply(this.watcher, arguments);
  },
  buildOptions: function() {
    var watcher = this.options && this.options.watcher;

    if (watcher && ['polling', 'watchman', 'node', 'events'].indexOf(watcher) === -1) {
      throw new Error('Unknown watcher type --watcher=[polling|watchman|node] but was: ' + watcher);
    }

    return {
      verbose:  this.verbose,
      poll:     watcher === 'polling',
      watchman: watcher === 'watchman' || watcher === 'events',
      node:     watcher === 'node'
    };
  }
});

Watcher.detectWatcher = function(ui, _options) {
  var options = _options || {};

  if (options.watcher === 'polling') {
    debug('skip detecting watchman, poll instead');
    return Promise.resolve(options);
  } else if (options.watcher === 'node') {
    debug('skip detecting watchman, node instead');
    return Promise.resolve(options);
  } else {
    debug('detecting watchman');
    return exec('watchman version').then(function(output) {
      var version;
      try {
        version = JSON.parse(output).version;
      } catch(e) {
        options.watcher = 'node';
        debug('looks like you have a different program called watchman, falling back to NodeWatcher');
        return options;
      }
      debug('detected watchman: %s', version);

      if (require('semver').satisfies(version, '^3.0.0')) {
        debug('watchman %s does satisfy: %s', version, '^3.0.0');
        options.watcher = 'watchman';
        ui.writeLine('valid watchman found, version: [' + version + ']');
      } else {
        debug('watchman %s does NOT satisfy: %s', version, '^3.0.0');
        ui.writeLine('invalid watchman found, version: [' + version + '] did not satisfy [^3.0.0], falling back to NodeWatcher');
        options.watcher = 'node';
      }

      return options;
    }, function(reason) {
      debug('detecting watchman failed %o', reason);
      ui.writeLine('Could not find watchman, falling back to NodeWatcher for file system events');
      options.watcher = 'node';
      return options;
    });
  }
};

module.exports = Watcher;
<commit_msg>switch debug to ui.writeLine<commit_after>'use strict';

var chalk   = require('chalk');
var Task    = require('./task');
var debug   = require('debug')('ember-cli:watcher');
var Promise = require('../ext/promise');
var exec    = Promise.denodeify(require('child_process').exec);

var Watcher = Task.extend({
  verbose: true,

  init: function() {
    var options = this.buildOptions();

    debug('initialize %o', options);

    this.watcher = this.watcher || new (require('broccoli-sane-watcher'))(this.builder, options);

    this.watcher.on('error', this.didError.bind(this));
    this.watcher.on('change', this.didChange.bind(this));
  },

  didError: function(error) {
    debug('didError %o', error);
    this.ui.writeError(error);
    this.analytics.trackError({
      description: error && error.message
    });
  },

  then: function() {
    return this.watcher.then.apply(this.watcher, arguments);
  },

  didChange: function(results) {
    debug('didChange %o', results);
    var totalTime = results.totalTime / 1e6;

    this.ui.writeLine('');
    this.ui.writeLine(chalk.green('Build successful - ' + Math.round(totalTime) + 'ms.'));

    this.analytics.track({
      name:    'ember rebuild',
      message: 'broccoli rebuild time: ' + totalTime + 'ms'
    });

    this.analytics.trackTiming({
      category: 'rebuild',
      variable: 'rebuild time',
      label:    'broccoli rebuild time',
      value:    parseInt(totalTime, 10)
    });
  },

  on: function() {
    this.watcher.on.apply(this.watcher, arguments);
  },

  off: function() {
    this.watcher.off.apply(this.watcher, arguments);
  },
  buildOptions: function() {
    var watcher = this.options && this.options.watcher;

    if (watcher && ['polling', 'watchman', 'node', 'events'].indexOf(watcher) === -1) {
      throw new Error('Unknown watcher type --watcher=[polling|watchman|node] but was: ' + watcher);
    }

    return {
      verbose:  this.verbose,
      poll:     watcher === 'polling',
      watchman: watcher === 'watchman' || watcher === 'events',
      node:     watcher === 'node'
    };
  }
});

Watcher.detectWatcher = function(ui, _options) {
  var options = _options || {};

  if (options.watcher === 'polling') {
    debug('skip detecting watchman, poll instead');
    return Promise.resolve(options);
  } else if (options.watcher === 'node') {
    debug('skip detecting watchman, node instead');
    return Promise.resolve(options);
  } else {
    debug('detecting watchman');
    return exec('watchman version').then(function(output) {
      var version;
      try {
        version = JSON.parse(output).version;
      } catch(e) {
        options.watcher = 'node';
        ui.writeLine('Looks like you have a different program called watchman, falling back to NodeWatcher');
        return options;
      }
      debug('detected watchman: %s', version);

      if (require('semver').satisfies(version, '^3.0.0')) {
        debug('watchman %s does satisfy: %s', version, '^3.0.0');
        options.watcher = 'watchman';
        ui.writeLine('valid watchman found, version: [' + version + ']');
      } else {
        debug('watchman %s does NOT satisfy: %s', version, '^3.0.0');
        ui.writeLine('invalid watchman found, version: [' + version + '] did not satisfy [^3.0.0], falling back to NodeWatcher');
        options.watcher = 'node';
      }

      return options;
    }, function(reason) {
      debug('detecting watchman failed %o', reason);
      ui.writeLine('Could not find watchman, falling back to NodeWatcher for file system events');
      options.watcher = 'node';
      return options;
    });
  }
};

module.exports = Watcher;
<|endoftext|>


<commit_before>'use strict';

const debug     = require('debug')('mongo-observer'),
      Oplog     = require('./oplog'),
      Emitter   = require('create-emitter');

module.exports = require('tofactory')(MongoObserver);

function MongoObserver(spec) {
    const emitter   = Emitter.create(),
          INSERT    = 'isert',
          UPDATE    = 'update',
          REMOVE    = 'remove';

    let db, oplog, colOpts;

    init();

    return {
        on: emitter.on,
        off: emitter.off,
        observe: oplog.listen
    };

    function init() {
        db = spec.db;
        colOpts = spec.collections || [];
        Array.isArray(colOpts) && (colOpts = colOpts.join('|'));
        oplog = Oplog.create(Object.assign(spec, {
            onInsert: insertOp,
            onUpdate: updateOp,
            onRemove: removeOp
        }));
    }

    function insertOp(collection, data) {
        emitter.emit(`${collection}:${INSERT}:${data._id}`, data);
    }

    function removeOp(collection, data) {
        emitter.emit(`${collection}:${REMOVE}:${data._id}`);
    }

    function updateOp(collection, data, _id) {
        if (data) {
            emitter.emit(`${collection}:${UPDATE}:${_id}`, data);
        } else {
            getDataFromDb(collection, _id);
        }
    }

    function getDataFromDb(collection, _id) {
        findOneById(collection, _id, function (err, doc) {
            if (err) return debug(err);
            emitter.emit(`${collection}:${UPDATE}`, doc);
        });
    }

    function findOneById(colName, _id, next) {
        db.collection(colName, function (err, col) {
            if (err) return next(err);
            col.find({_id: _id}).limit(1).next(function (err, doc) {
                if (err) return next(err);
                return next(undefined, doc);
            });
        });
    }
}<commit_msg>added db connections options<commit_after>'use strict';

const MongoClient   = require('mongodb').MongoClient,
      debug         = require('debug')('mongo-observer'),
      Oplog         = require('./oplog'),
      Emitter       = require('create-emitter'),
      connOptions   = {
        server: {
            poolSize: 10,
            socketOptions: {
                autoReconnect: true,
                noDelay: true,
                keepAlive: 1000,
                connectTimeoutMS: 30000
            }
        }
      };

module.exports = require('tofactory')(MongoObserver);

function MongoObserver(spec) {
    const emitter   = Emitter.create(),
          INSERT    = 'isert',
          UPDATE    = 'update',
          REMOVE    = 'remove';

    let db, oplog, colOpts;

    init();

    return {
        on: emitter.on,
        off: emitter.off,
        observe: oplog.listen
    };

    function init() {
        getDbConn(function (err) {
            if (err) throw err;
            defineObserver();
        });
    }

    function insertOp(collection, data) {
        emitter.emit(`${collection}:${INSERT}:${data._id}`, data);
    }

    function removeOp(collection, data) {
        emitter.emit(`${collection}:${REMOVE}:${data._id}`);
    }

    function updateOp(collection, data, _id) {
        if (data) {
            emitter.emit(`${collection}:${UPDATE}:${_id}`, data);
        } else {
            getDataFromDb(collection, _id);
        }
    }

    function getDataFromDb(collection, _id) {
        findOneById(collection, _id, function (err, doc) {
            if (err) return debug(err);
            emitter.emit(`${collection}:${UPDATE}`, doc);
        });
    }

    function findOneById(colName, _id, next) {
        db.collection(colName, function (err, col) {
            if (err) return next(err);
            col.find({_id: _id}).limit(1).next(function (err, doc) {
                if (err) return next(err);
                return next(undefined, doc);
            });
        });
    }

    function getDbConn(next) {
        db = spec.db;
        if (!db) {
            let host    = spec.host,
                port    = spec.port,
                dbName  = spec.dbName,
                dbURL   = spec.dbURL || `mongodb://${host}:${port}/${dbName}`,
                options = spec.connOptions || connOptions;

            MongoClient.connect(dbURL, options, function (err, dbConn) {
                if (err) return next(err);
                db = dbConn;
                spec.db = dbConn;
                next();
            });
        } else {
            next();
        }
    }

    function defineObserver() {
        colOpts = spec.collections || [];
        Array.isArray(colOpts) && (colOpts = colOpts.join('|'));
        oplog = Oplog.create(Object.assign(spec, {
            onInsert: insertOp,
            onUpdate: updateOp,
            onRemove: removeOp
        }));
    }
}<|endoftext|>


<commit_before>var game = new Phaser.Game(800, 600, Phaser.AUTO, 'game', {
    preload: preload, create: create, update: update });

// Declare the sprites globally so we can modify them later
var background;
var plots;
var flowers;
var weeds;
var weapons;

// Declare the text fields
var flowerText;
var weedText;

// Declare our score trackers
var flowerCount = 0;
var weedCount = 0;

// Set our default weapon
var currentWeapon = 0;

// Declare the game timers
var time;
var weaponLastFired;

function preload() {
    // Load the background image and game sprites
    // TODO: Combine sprites into an atlas
    game.load.image('background', 'assets/background.png');
    game.load.image('acid_icon', 'assets/acid_icon.png');
    game.load.image('fireball_icon', 'assets/fireball_icon.png');
    game.load.image('sawblade_icon', 'assets/sawblade_icon.png');
    game.load.image('uav_icon', 'assets/uav_icon.png');
    game.load.image('plot', 'assets/plot.png');
    game.load.image('flower_1', 'assets/flower_1.png');
    game.load.image('flower_2', 'assets/flower_2.png');
    game.load.image('weed_1', 'assets/weed_1.png');
    game.load.image('acid_weapon', 'assets/acid_weapon.png');
    game.load.image('fireball_weapon', 'assets/fireball_weapon.png');
    game.load.image('sawblade_weapon', 'assets/sawblade_weapon.png');
    game.load.image('uav_weapon', 'assets/uav_weapon.png');
}

function create() {
    // Enable the physics engine
    game.physics.startSystem(Phaser.Physics.ARCADE);

    // Apply the background sprite and set the initial background color
    background = game.add.sprite(0,0, 'background');
    background.tint = 0x0EE68;

    // Add the weapon selection buttons
    game.add.sprite(25, 479, 'acid_icon');
    game.add.sprite(146, 479, 'fireball_icon');
    game.add.sprite(558, 479, 'sawblade_icon');
    game.add.sprite(679, 479, 'uav_icon');

    // Add and configure the score text fields
    flowerText = game.add.text(5, 0, 'Flowers: 0');
    weedText = game.add.text(5, 25, 'Weeds: 0');

    // Generate the flower/weed plots
    // TODO: Prevent overlapping plots during generation
    plots = game.add.group();
    for (var i = 0; i < 10; i++) {
        // Determine valid X/Y coordinates in the game area
        var x = Math.floor(Math.random() * (800 - (i * 8)) + 1);
        var y = Math.floor(Math.random() * (600 - (i * 6)) + 1);

        // Prevent sprite from extending off of the right or bottom
        if (x > 736) {
            x = 736;
        }
        if (y > 400) {
            // Leave room for bottom text and interaction area
            y = 400;
        } else if (y < 110) {
            // Leave enough room for flower to prevent clipping
            y = 110;
        }

        plot = plots.create(x, y, 'plot');
        plot.occupied = false;
    }

    // Define the flowers group and add physics properties
    flowers = game.add.group();
    flowers.enableBody = true;
    flowers.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random flowers outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichFlower = Math.floor(Math.random() * 2 + 1);
        flower = flowers.create(-100, -100, 'flower_' + whichFlower);
    }

    // Define the weeds group and add physics properties
    weeds = game.add.group();
    weeds.enableBody = true;
    weeds.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random weeds outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichWeed = Math.floor(Math.random() * 1 + 1);
        weed = weeds.create(-100, -100, 'weed_' + whichWeed);
    }

    // Define the weaopns group and add physics properties
    weapons = game.add.group();
    weapons.enableBody = true;
    weapons.physicsBodyType = Phaser.Physics.ARCADE;
    weapons.create(-100, -100, 'acid_weapon');
    weapons.create(-100, -100, 'fireball_weapon');
    weapons.create(-100, -100, 'sawblade_weapon');
    weapons.create(-100, -100, 'uav_weapon');

    // Set up inital clock for update();
    time = game.time.now;
    // Set up initial clock for weapon firing
    weaponLastFired = game.time.now;
}

function update() {
    // Every two seconds, spawn a flower or weed
    if (game.time.now > time + 2000) {
        // Modify a random plot
        // TODO: Refactor to generate an index between 0 and 9
        var currentPlot = Math.floor(Math.random() * 10 + 1);
        if (currentPlot > 9) {
            currentPlot = 0;
        }

        // Save the plot's position and modify y for flower/weed placement
        var x = plots.children[currentPlot].x;
        var y = plots.children[currentPlot].y - 110;

        // If the plot isn't occupied, add a flower or weed
        if (plots.children[currentPlot].occupied === false) {
            var determineOccupant = Math.floor(Math.random() * 2);
            if (determineOccupant === 0) {
                // Spawn a flower
                flowers.children[currentPlot].x = x;
                flowers.children[currentPlot].y = y;

                flowerCount++;
                flowerText.text = 'Flowers: ' + flowerCount;
            } else {
                // Spawn a weed
                weeds.children[currentPlot].x = x;
                weeds.children[currentPlot].y = y;

                weedCount++;
                weedText.text = 'Weeds: ' + weedCount;
            }

            plots.children[currentPlot].occupied = true;
        }

        time = game.time.now;
    }

    // Tint the background based on how many flowers vs. weeds
    var ratioFlowersToWeeds = flowerCount / weedCount;
    if (ratioFlowersToWeeds < 1.0) {
        background.tint = 0x869E82;
    } else if (ratioFlowersToWeeds < 0.43) {
        background.tint = 0xA6AB79;
    } else if (ratioFlowersToWeeds < 0.12) {
        background.tint = 0x917B56;
    } else {
        background.tint = 0x0EE68;
    }

    // Detect input
    if (game.input.activePointer.isDown) {
        // Get tap/click position
        var xInput = game.input.activePointer.x;
        var yInput = game.input.activePointer.y;

        // If y < 470, shoot the current weapon
        if (yInput < 470 && game.time.now > (weaponLastFired + 1000)) {
            // Shoot selected weapon in direction of tap/click
            var weapon = weapons.children[currentWeapon];
            weapon.x = 400;
            weapon.y = 500;
            game.physics.arcade.moveToPointer(weapon, 300);

            weaponLastFired = game.time.now;
        } else {
            // Detect weapon selection
            if (xInput > 25 && xInput < 121) {
                currentWeapon = 0;
            } else if (xInput > 146 && xInput < 242) {
                currentWeapon = 1;
            } else if (xInput > 558 && xInput < 654) {
                currentWeapon = 2;
            } else if (xInput > 679 && xInput < 775) {
                currentWeapon = 3;
            }
        }
    }
}<commit_msg>Add y check for weapon selection buttons<commit_after>var game = new Phaser.Game(800, 600, Phaser.AUTO, 'game', {
    preload: preload, create: create, update: update });

// Declare the sprites globally so we can modify them later
var background;
var plots;
var flowers;
var weeds;
var weapons;

// Declare the text fields
var flowerText;
var weedText;

// Declare our score trackers
var flowerCount = 0;
var weedCount = 0;

// Set our default weapon
var currentWeapon = 0;

// Declare the game timers
var time;
var weaponLastFired;

function preload() {
    // Load the background image and game sprites
    // TODO: Combine sprites into an atlas
    game.load.image('background', 'assets/background.png');
    game.load.image('acid_icon', 'assets/acid_icon.png');
    game.load.image('fireball_icon', 'assets/fireball_icon.png');
    game.load.image('sawblade_icon', 'assets/sawblade_icon.png');
    game.load.image('uav_icon', 'assets/uav_icon.png');
    game.load.image('plot', 'assets/plot.png');
    game.load.image('flower_1', 'assets/flower_1.png');
    game.load.image('flower_2', 'assets/flower_2.png');
    game.load.image('weed_1', 'assets/weed_1.png');
    game.load.image('acid_weapon', 'assets/acid_weapon.png');
    game.load.image('fireball_weapon', 'assets/fireball_weapon.png');
    game.load.image('sawblade_weapon', 'assets/sawblade_weapon.png');
    game.load.image('uav_weapon', 'assets/uav_weapon.png');
}

function create() {
    // Enable the physics engine
    game.physics.startSystem(Phaser.Physics.ARCADE);

    // Apply the background sprite and set the initial background color
    background = game.add.sprite(0,0, 'background');
    background.tint = 0x0EE68;

    // Add the weapon selection buttons
    game.add.sprite(25, 479, 'acid_icon');
    game.add.sprite(146, 479, 'fireball_icon');
    game.add.sprite(558, 479, 'sawblade_icon');
    game.add.sprite(679, 479, 'uav_icon');

    // Add and configure the score text fields
    flowerText = game.add.text(5, 0, 'Flowers: 0');
    weedText = game.add.text(5, 25, 'Weeds: 0');

    // Generate the flower/weed plots
    // TODO: Prevent overlapping plots during generation
    plots = game.add.group();
    for (var i = 0; i < 10; i++) {
        // Determine valid X/Y coordinates in the game area
        var x = Math.floor(Math.random() * (800 - (i * 8)) + 1);
        var y = Math.floor(Math.random() * (600 - (i * 6)) + 1);

        // Prevent sprite from extending off of the right or bottom
        if (x > 736) {
            x = 736;
        }
        if (y > 400) {
            // Leave room for bottom text and interaction area
            y = 400;
        } else if (y < 110) {
            // Leave enough room for flower to prevent clipping
            y = 110;
        }

        plot = plots.create(x, y, 'plot');
        plot.occupied = false;
    }

    // Define the flowers group and add physics properties
    flowers = game.add.group();
    flowers.enableBody = true;
    flowers.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random flowers outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichFlower = Math.floor(Math.random() * 2 + 1);
        flower = flowers.create(-100, -100, 'flower_' + whichFlower);
    }

    // Define the weeds group and add physics properties
    weeds = game.add.group();
    weeds.enableBody = true;
    weeds.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random weeds outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichWeed = Math.floor(Math.random() * 1 + 1);
        weed = weeds.create(-100, -100, 'weed_' + whichWeed);
    }

    // Define the weaopns group and add physics properties
    weapons = game.add.group();
    weapons.enableBody = true;
    weapons.physicsBodyType = Phaser.Physics.ARCADE;
    weapons.create(-100, -100, 'acid_weapon');
    weapons.create(-100, -100, 'fireball_weapon');
    weapons.create(-100, -100, 'sawblade_weapon');
    weapons.create(-100, -100, 'uav_weapon');

    // Set up inital clock for update();
    time = game.time.now;
    // Set up initial clock for weapon firing
    weaponLastFired = game.time.now;
}

function update() {
    // Every two seconds, spawn a flower or weed
    if (game.time.now > time + 2000) {
        // Modify a random plot
        // TODO: Refactor to generate an index between 0 and 9
        var currentPlot = Math.floor(Math.random() * 10 + 1);
        if (currentPlot > 9) {
            currentPlot = 0;
        }

        // Save the plot's position and modify y for flower/weed placement
        var x = plots.children[currentPlot].x;
        var y = plots.children[currentPlot].y - 110;

        // If the plot isn't occupied, add a flower or weed
        if (plots.children[currentPlot].occupied === false) {
            var determineOccupant = Math.floor(Math.random() * 2);
            if (determineOccupant === 0) {
                // Spawn a flower
                flowers.children[currentPlot].x = x;
                flowers.children[currentPlot].y = y;

                flowerCount++;
                flowerText.text = 'Flowers: ' + flowerCount;
            } else {
                // Spawn a weed
                weeds.children[currentPlot].x = x;
                weeds.children[currentPlot].y = y;

                weedCount++;
                weedText.text = 'Weeds: ' + weedCount;
            }

            plots.children[currentPlot].occupied = true;
        }

        time = game.time.now;
    }

    // Tint the background based on how many flowers vs. weeds
    var ratioFlowersToWeeds = flowerCount / weedCount;
    if (ratioFlowersToWeeds < 1.0) {
        background.tint = 0x869E82;
    } else if (ratioFlowersToWeeds < 0.43) {
        background.tint = 0xA6AB79;
    } else if (ratioFlowersToWeeds < 0.12) {
        background.tint = 0x917B56;
    } else {
        background.tint = 0x0EE68;
    }

    // Detect input
    if (game.input.activePointer.isDown) {
        // Get tap/click position
        var xInput = game.input.activePointer.x;
        var yInput = game.input.activePointer.y;

        // If y < 470, shoot the current weapon
        if (yInput < 470 && game.time.now > (weaponLastFired + 1000)) {
            // Shoot selected weapon in direction of tap/click
            var weapon = weapons.children[currentWeapon];
            weapon.x = 400;
            weapon.y = 500;
            game.physics.arcade.moveToPointer(weapon, 300);

            weaponLastFired = game.time.now;
        } else if (yInput > 470) {
            // Detect weapon selection
            if (xInput > 25 && xInput < 121) {
                currentWeapon = 0;
            } else if (xInput > 146 && xInput < 242) {
                currentWeapon = 1;
            } else if (xInput > 558 && xInput < 654) {
                currentWeapon = 2;
            } else if (xInput > 679 && xInput < 775) {
                currentWeapon = 3;
            }
        }
    }
}<|endoftext|>


<commit_before>var _ = require('underscore')._;
var util = require("util");

function literalizeArray(arr) {
  if (!_.isArray(arr)) { return arr; }

  return util.format('{%s}', arr.map(function (v) {
    if (v.search(/[,{}]/) !== -1) { return util.format('"%s"', v); }

    return v;
  }).join(','));
}

exports = module.exports = {
  // basic comparison
  '=': {operator: '='},
  '!': {operator: '<>'},
  '>': {operator: '>'},
  '<': {operator: '<'},
  '>=': {operator: '>='},
  '<=': {operator: '<='},
  '!=': {operator: '<>'},
  '<>': {operator: '<>'},
  // array
  '@>': {operator: '@>', mutator: literalizeArray},
  '<@': {operator: '<@', mutator: literalizeArray},
  '&&': {operator: '&&', mutator: literalizeArray},
  // pattern matching
  '~~': {operator: 'LIKE'},
  'like': {operator: 'LIKE'},
  '!~~': {operator: 'NOT LIKE'},
  'not like': {operator: 'NOT LIKE'},
  '~~*': {operator: 'ILIKE'},
  'ilike': {operator: 'ILIKE'},
  '!~~*': {operator: 'NOT ILIKE'},
  'not ilike': {operator: 'NOT ILIKE'},
  'similar to': {operator: 'SIMILAR TO'},
  'not similar to': {operator: 'NOT SIMILAR TO'},
  // regex
  '~': {operator: '~'},
  '!~': {operator: '!~'},
  '~*': {operator: '~*'},
  '!~*': {operator: '!~*'},
  // distinct
  'is distinct from': {operator: 'IS DISTINCT FROM'},
  'is not distinct from': {operator: 'IS NOT DISTINCT FROM'}
};
<commit_msg>Jsonb text array operators.<commit_after>var _ = require('underscore')._;
var util = require("util");

function literalizeArray(arr) {
  if (!_.isArray(arr)) { return arr; }

  return util.format('{%s}', arr.map(function (v) {
    if (v.search(/[,{}]/) !== -1) { return util.format('"%s"', v); }

    return v;
  }).join(','));
}

exports = module.exports = {
  // basic comparison
  '=': {operator: '='},
  '!': {operator: '<>'},
  '>': {operator: '>'},
  '<': {operator: '<'},
  '>=': {operator: '>='},
  '<=': {operator: '<='},
  '!=': {operator: '<>'},
  '<>': {operator: '<>'},
  // array
  '@>': {operator: '@>', mutator: literalizeArray},
  '<@': {operator: '<@', mutator: literalizeArray},
  '&&': {operator: '&&', mutator: literalizeArray},
  '?|': {operator: '?|', mutator: literalizeArray},
  '?&': {operator: '?&', mutator: literalizeArray},
  // pattern matching
  '~~': {operator: 'LIKE'},
  'like': {operator: 'LIKE'},
  '!~~': {operator: 'NOT LIKE'},
  'not like': {operator: 'NOT LIKE'},
  '~~*': {operator: 'ILIKE'},
  'ilike': {operator: 'ILIKE'},
  '!~~*': {operator: 'NOT ILIKE'},
  'not ilike': {operator: 'NOT ILIKE'},
  'similar to': {operator: 'SIMILAR TO'},
  'not similar to': {operator: 'NOT SIMILAR TO'},
  // regex
  '~': {operator: '~'},
  '!~': {operator: '!~'},
  '~*': {operator: '~*'},
  '!~*': {operator: '!~*'},
  // distinct
  'is distinct from': {operator: 'IS DISTINCT FROM'},
  'is not distinct from': {operator: 'IS NOT DISTINCT FROM'}
};
<|endoftext|>