<commit_before>var events = require('events');
var util = require('util');

module.exports = Worker;

function Worker(queues, options) {
  options = options || {};

  this.queues = queues || {};
  this.additionalQuery = options.additionalQuery || null;
  this.interval = options.interval || 3000;
  this.maxPerQueue = options.maxPerQueue || 1;

  this.callbacks = options.callbacks || {};
  this.strategies = options.strategies || {};
  this.validation = options.validation || ((queueName, job, cb) => cb());

  // Default retry strategies
  this.strategies.linear = this.strategies.linear || linear;
  this.strategies.exponential = this.strategies.exponential || exponential;

  // This worker will only process jobs of this priority or higher
  this.minPriority = options.minPriority;
  this.timers = {};
  this.counter = {};
}

util.inherits(Worker, events.EventEmitter);

Worker.prototype.register = function (callbacks) {
  for (var name in callbacks) {
    if (callbacks.hasOwnProperty(name)) {
      this.callbacks[name] = callbacks[name];
    }
  }
};

Worker.prototype.strategies = function (strategies) {
  for (var name in strategies) {
    if (strategies.hasOwnProperty(name)) {
      this.strategies[name] = strategies[name];
    }
  }
};

Worker.prototype.start = function () {
  this.working = true;
  if (Object.keys(this.queues).length !== 0) {
    for (var queueName in this.queues) {
      if (this.queues.hasOwnProperty(queueName)) {
        this.startPolling(queueName);
      }
    }
  }
};

Worker.prototype.startPolling = function (queueName) {
  this.timers[queueName] = setInterval(() => {
    if (!this.counter[queueName]) {
      this.counter[queueName] = 0;
    }
    if (this.counter[queueName] < this.maxPerQueue) {
      this.poll(queueName);
    }
  }, this.interval);
};

Worker.prototype.incCounter = function (queueName, amt) {
  if (!amt) {
    amt = 1;
  }
  if (!this.counter[queueName]) {
    this.counter[queueName] = 0;
  }
  this.counter[queueName] += amt;
};

Worker.prototype.stop = function (callback) {
  function done() {
    if (callback) {
      callback();
    }
  }

  if (!this.working) {
    done();
  }
  this.working = false;

  var tCnt = Object.keys(this.timers).length;
  if (tCnt > 0) {
    for (var name in this.timers) {
      if (this.timers.hasOwnProperty(name)) {
        clearInterval(this.timers[name]);
      }
    }
    var qCnt = Object.keys(this.queues).length;
    if (tCnt === qCnt) {
      return done();
    }
  }

  this.once('stopped', done);
};

Worker.prototype.poll = function (queueName) {
  if (!this.working) {
    return this.emit('stopped');
  }
  var self = this;
  var query = null;
  if (this.additionalQuery) {
    query = this.additionalQuery();
  }

  this.queues[queueName].dequeue({
    minPriority: this.minPriority,
    query: query,
    callbacks: this.callbacks
  }, function (err, job) {
    if (err) {
      return self.emit('error', {
        queue: queueName,
        job: job.data,
        error: err
      });
    }

    if (job) {
      self.validation(queueName, job, function (err) {
        if (err) {
          job.delay(30000);
          return;
        }
        self.incCounter(queueName);
        self.emit('dequeued', {queue: queueName, job: job.data});
        self.work(queueName, job);
      });
    } else {
      self.emit('empty', {queue: queueName});
    }
  });
};

Worker.prototype.addQueue = function (name, queue) {
  if (typeof name !== 'string' || typeof queue !== 'object') {
    throw new Error('Wrong params');
  }
  this.queues[name] = queue;
  this.startPolling(name);
};

Worker.prototype.getQueue = function (name) {
  return this.queues[name];
};

Worker.prototype.dropQueue = function (name) {
  if (this.timers[name]) {
    clearInterval(this.timers[name]);
    delete this.timers[name];
  }
  if (this.queues[name]) {
    delete this.queues[name];
  }
};

Worker.prototype.work = function (queueName, job) {
  var self = this;
  var finished = false;
  var timer;

  if (job.data.timeout) {
    timer = setTimeout(function () {
      done(new Error('timeout'));
    }, job.data.timeout);
  }

  function done(err, result) {
    // It's possible that this could be called twice in the case that a job times out,
    // but the handler ends up finishing later on
    if (finished) {
      console.log(queueName, 'twice');
      return;
    }
    finished = true;
    self.incCounter(queueName, -1);

    clearTimeout(timer);
    self.emit('done', {queue: queueName, job: job.data});
    result = result || '';

    if (err) {
      self.error(job, err, function (err) {
        if (err) {
          return self.emit('error', {
            queue: queueName,
            job: job.data,
            error: err
          });
        }

        self.emit('failed', {queue: queueName, job: job.data});
      });
    } else {
      job.complete(result, function (err) {
        if (err) {
          return self.emit('error', {
            queue: queueName,
            job: job.data,
            error: err
          });
        }

        self.emit('complete', {queue: queueName, job: job.data});
      });
    }
  }

  this.process(job.data, done);
};

Worker.prototype.process = function (data, callback) {
  var func = this.callbacks[data.name];

  if (func) {
    func(data).then(res => {
      callback(null, res);
    }).catch(callback);
  } else {
    callback(new Error('No callback registered for `' + data.name + '`'));
  }
};

Worker.prototype.error = function (job, err, callback) {
  var attempts = job.data.attempts;
  var remaining = 0;
  var wait;

  if (attempts) {
    remaining = attempts.remaining = (attempts.remaining || attempts.count) - 1;
  }

  if (remaining > 0) {
    var strategy = this.strategies[attempts.strategy || 'linear'];
    if (!strategy) {
      strategy = linear;

      console.error('No such retry strategy: `' + attempts.strategy + '`');
      console.error('Using linear strategy');
    }

    if (attempts.delay === undefined) {
      wait = 0;
    } else {
      wait = strategy(attempts);
    }

    job.delay(wait, callback);
  } else {
    job.fail(err, callback);
  }
};

// Strategies
// ---------------

function linear(attempts) {
  return attempts.delay;
}

function exponential(attempts) {
  return attempts.delay * (attempts.count - attempts.remaining);
}
<commit_msg>delay with zero<commit_after>var events = require('events');
var util = require('util');

module.exports = Worker;

function Worker(queues, options) {
  options = options || {};

  this.queues = queues || {};
  this.additionalQuery = options.additionalQuery || null;
  this.interval = options.interval || 3000;
  this.maxPerQueue = options.maxPerQueue || 1;

  this.callbacks = options.callbacks || {};
  this.strategies = options.strategies || {};
  this.validation = options.validation || ((queueName, job, cb) => cb());

  // Default retry strategies
  this.strategies.linear = this.strategies.linear || linear;
  this.strategies.exponential = this.strategies.exponential || exponential;

  // This worker will only process jobs of this priority or higher
  this.minPriority = options.minPriority;
  this.timers = {};
  this.counter = {};
}

util.inherits(Worker, events.EventEmitter);

Worker.prototype.register = function (callbacks) {
  for (var name in callbacks) {
    if (callbacks.hasOwnProperty(name)) {
      this.callbacks[name] = callbacks[name];
    }
  }
};

Worker.prototype.strategies = function (strategies) {
  for (var name in strategies) {
    if (strategies.hasOwnProperty(name)) {
      this.strategies[name] = strategies[name];
    }
  }
};

Worker.prototype.start = function () {
  this.working = true;
  if (Object.keys(this.queues).length !== 0) {
    for (var queueName in this.queues) {
      if (this.queues.hasOwnProperty(queueName)) {
        this.startPolling(queueName);
      }
    }
  }
};

Worker.prototype.startPolling = function (queueName) {
  this.timers[queueName] = setInterval(() => {
    if (!this.counter[queueName]) {
      this.counter[queueName] = 0;
    }
    if (this.counter[queueName] < this.maxPerQueue) {
      this.poll(queueName);
    }
  }, this.interval);
};

Worker.prototype.incCounter = function (queueName, amt) {
  if (!amt) {
    amt = 1;
  }
  if (!this.counter[queueName]) {
    this.counter[queueName] = 0;
  }
  this.counter[queueName] += amt;
};

Worker.prototype.stop = function (callback) {
  function done() {
    if (callback) {
      callback();
    }
  }

  if (!this.working) {
    done();
  }
  this.working = false;

  var tCnt = Object.keys(this.timers).length;
  if (tCnt > 0) {
    for (var name in this.timers) {
      if (this.timers.hasOwnProperty(name)) {
        clearInterval(this.timers[name]);
      }
    }
    var qCnt = Object.keys(this.queues).length;
    if (tCnt === qCnt) {
      return done();
    }
  }

  this.once('stopped', done);
};

Worker.prototype.poll = function (queueName) {
  if (!this.working) {
    return this.emit('stopped');
  }
  var self = this;
  var query = null;
  if (this.additionalQuery) {
    query = this.additionalQuery();
  }

  this.queues[queueName].dequeue({
    minPriority: this.minPriority,
    query: query,
    callbacks: this.callbacks
  }, function (err, job) {
    if (err) {
      return self.emit('error', {
        queue: queueName,
        job: job.data,
        error: err
      });
    }

    if (job) {
      self.validation(queueName, job, function (err) {
        if (err) {
          job.delay(0);
          return;
        }
        self.incCounter(queueName);
        self.emit('dequeued', {queue: queueName, job: job.data});
        self.work(queueName, job);
      });
    } else {
      self.emit('empty', {queue: queueName});
    }
  });
};

Worker.prototype.addQueue = function (name, queue) {
  if (typeof name !== 'string' || typeof queue !== 'object') {
    throw new Error('Wrong params');
  }
  this.queues[name] = queue;
  this.startPolling(name);
};

Worker.prototype.getQueue = function (name) {
  return this.queues[name];
};

Worker.prototype.dropQueue = function (name) {
  if (this.timers[name]) {
    clearInterval(this.timers[name]);
    delete this.timers[name];
  }
  if (this.queues[name]) {
    delete this.queues[name];
  }
};

Worker.prototype.work = function (queueName, job) {
  var self = this;
  var finished = false;
  var timer;

  if (job.data.timeout) {
    timer = setTimeout(function () {
      done(new Error('timeout'));
    }, job.data.timeout);
  }

  function done(err, result) {
    // It's possible that this could be called twice in the case that a job times out,
    // but the handler ends up finishing later on
    if (finished) {
      console.log(queueName, 'twice');
      return;
    }
    finished = true;
    self.incCounter(queueName, -1);

    clearTimeout(timer);
    self.emit('done', {queue: queueName, job: job.data});
    result = result || '';

    if (err) {
      self.error(job, err, function (err) {
        if (err) {
          return self.emit('error', {
            queue: queueName,
            job: job.data,
            error: err
          });
        }

        self.emit('failed', {queue: queueName, job: job.data});
      });
    } else {
      job.complete(result, function (err) {
        if (err) {
          return self.emit('error', {
            queue: queueName,
            job: job.data,
            error: err
          });
        }

        self.emit('complete', {queue: queueName, job: job.data});
      });
    }
  }

  this.process(job.data, done);
};

Worker.prototype.process = function (data, callback) {
  var func = this.callbacks[data.name];

  if (func) {
    func(data).then(res => {
      callback(null, res);
    }).catch(callback);
  } else {
    callback(new Error('No callback registered for `' + data.name + '`'));
  }
};

Worker.prototype.error = function (job, err, callback) {
  var attempts = job.data.attempts;
  var remaining = 0;
  var wait;

  if (attempts) {
    remaining = attempts.remaining = (attempts.remaining || attempts.count) - 1;
  }

  if (remaining > 0) {
    var strategy = this.strategies[attempts.strategy || 'linear'];
    if (!strategy) {
      strategy = linear;

      console.error('No such retry strategy: `' + attempts.strategy + '`');
      console.error('Using linear strategy');
    }

    if (attempts.delay === undefined) {
      wait = 0;
    } else {
      wait = strategy(attempts);
    }

    job.delay(wait, callback);
  } else {
    job.fail(err, callback);
  }
};

// Strategies
// ---------------

function linear(attempts) {
  return attempts.delay;
}

function exponential(attempts) {
  return attempts.delay * (attempts.count - attempts.remaining);
}
<|endoftext|>


<commit_before>/* This is a variant of the suggestion in the jQuery FAQ:
     https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
   We need this since election IDs now have dots in them.
 */
function escapeID(originalID) {
  return originalID.replace( /(:|\.|\[|\]|,)/g, "\\$1" );
}

/* Get the element that should have its visibility changed to hide or show
   a Select2. */

function getSelect2Enclosure(selectElement) {
  /* This assumes that there's a label that's a sibling of the
   * Select2, and that they're the only elements in a containing
   * element (the one that will be returned by this function) */
  return selectElement.select2('container').parent();
}

/* Change the visibility of a Select2 widget; select2Element should be a
   jQuery-wrapped element */

function setSelect2Visibility(select2Element, visibility) {
  /* If visibility is false, this both disables the Select2 boxes and
   * hides them by hiding their enclosing element. Otherwise it
   * enables it and makes the enclosure visible. */
  var enclosure = getSelect2Enclosure(select2Element);
  select2Element.prop(
    'disabled',
    !visibility
  );
  if (visibility) {
    enclosure.show()
  } else {
    enclosure.hide();
  }
}

/* Make all the party drop-downs into Select2 widgets */

function setUpPartySelect2s() {
  $('.party-select').not('.select2-offscreen').not('.select2-container')
    .select2({width: '100%'});
}

/* Make all the post drop-downs into Select2 widgets */

function setUpPostSelect2s() {
  $('.post-select').each(function(i) {
    var postSelect = $(this),
      hidden = postSelect.prop('tagName') == 'INPUT' &&
         postSelect.attr('type') == 'hidden';
    /* If it's a real select box (not a hidden input) make it into a
     * Select2 box */
    if (!hidden) {
      postSelect.select2({
        placeholder: 'Post',
        allowClear: true,
        width: '100%'
      });
    }
    postSelect.on('change', function (e) {
      updateFields();
    });
    updateFields();
  });
}

/* Set the visibility of an input element and any label for it */

function setVisibility(plainInputElement, newVisiblity) {
  var inputElement = $(plainInputElement),
      inputElementID = escapeID(plainInputElement.id),
      labelElement = $('label[for=' + inputElementID + ']');
  inputElement.toggle(newVisiblity);
  labelElement.toggle(newVisiblity);
}

/* Update the visibility of the party and post drop-downs for a particular
   election */

function updateSelectsForElection(show, election) {
  /* Whether we should show the party and post selects is
     determined by the boolean 'show'. */
  var partySelectToShowID,
      partyPositionToShowID,
      postID = $('#id_constituency_' + escapeID(election)).val(),
      partySet;
  if (postID) {
    partySet = postIDToPartySet[postID];
  }
  if (show) {
    if (postID) {
      partySelectToShowID = 'id_party_' + partySet + '_' + election;
      partyPositionToShowID = 'id_party_list_position_' + partySet + '_' + election;
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility(
          $(this),
          $(this).attr('id') == partySelectToShowID
        );
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, $(this).attr('id') == partyPositionToShowID);
      });
    } else {
      /* Then just show the first party select and hide the others: */
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility($(this), i == 0);
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, i == 0);
      });
    }
  } else {
    $('.party-select-' + escapeID(election)).each(function(i) {
      setSelect2Visibility($(this), false);
    });
    $('.party-position-' + escapeID(election)).each(function() {
      setVisibility(this, false);
    });
  }
  setSelect2Visibility($('#id_constituency_' + escapeID(election)), show);
}

/* Make sure that the party and constituency select boxes are updated
   when you choose whether the candidate is standing in that election
   or not. */

function setUpStandingCheckbox() {
  $('#person-details select.standing-select').on('change', function() {
    updateFields();
  });
}

/* This should be called whenever the select drop-downs for party
   and post that have to be shown might have to be shown.  */

function updateFields() {
  $('#person-details select.standing-select').each(function(i) {
    var standing = $(this).val() == 'standing',
        match = /^id_standing_(.*)/.exec($(this).attr('id')),
        election = match[1];
    updateSelectsForElection(standing, election); });
}

$(document).ready(function() {
  $.getJSON('/post-id-to-party-set.json', function(data) {
      window.postIDToPartySet = data;
      setUpPartySelect2s();
      setUpPostSelect2s();
      setUpStandingCheckbox();
      updateFields();
  });
});
<commit_msg>Don't try to initialize a select as a select2 twice<commit_after>/* This is a variant of the suggestion in the jQuery FAQ:
     https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
   We need this since election IDs now have dots in them.
 */
function escapeID(originalID) {
  return originalID.replace( /(:|\.|\[|\]|,)/g, "\\$1" );
}

/* Get the element that should have its visibility changed to hide or show
   a Select2. */

function getSelect2Enclosure(selectElement) {
  /* This assumes that there's a label that's a sibling of the
   * Select2, and that they're the only elements in a containing
   * element (the one that will be returned by this function) */
  return selectElement.select2('container').parent();
}

/* Change the visibility of a Select2 widget; select2Element should be a
   jQuery-wrapped element */

function setSelect2Visibility(select2Element, visibility) {
  /* If visibility is false, this both disables the Select2 boxes and
   * hides them by hiding their enclosing element. Otherwise it
   * enables it and makes the enclosure visible. */
  var enclosure = getSelect2Enclosure(select2Element);
  select2Element.prop(
    'disabled',
    !visibility
  );
  if (visibility) {
    enclosure.show()
  } else {
    enclosure.hide();
  }
}

/* Make all the party drop-downs into Select2 widgets */

function setUpPartySelect2s() {
  $('.party-select').not('.select2-offscreen').not('.select2-container')
    .select2({width: '100%'});
}

/* Make all the post drop-downs into Select2 widgets */

function setUpPostSelect2s() {
  $('.post-select').each(function(i) {
    var postSelect = $(this),
      hidden = postSelect.prop('tagName') == 'INPUT' &&
         postSelect.attr('type') == 'hidden';
    /* If it's a real select box (not a hidden input) make it into a
     * Select2 box; also, don't try to reinitialize a select that's
     * already a Select2 */
    if (!(hidden || $(postSelect).data('select2'))) {
      postSelect.select2({
        placeholder: 'Post',
        allowClear: true,
        width: '100%'
      });
    }
    postSelect.on('change', function (e) {
      updateFields();
    });
    updateFields();
  });
}

/* Set the visibility of an input element and any label for it */

function setVisibility(plainInputElement, newVisiblity) {
  var inputElement = $(plainInputElement),
      inputElementID = escapeID(plainInputElement.id),
      labelElement = $('label[for=' + inputElementID + ']');
  inputElement.toggle(newVisiblity);
  labelElement.toggle(newVisiblity);
}

/* Update the visibility of the party and post drop-downs for a particular
   election */

function updateSelectsForElection(show, election) {
  /* Whether we should show the party and post selects is
     determined by the boolean 'show'. */
  var partySelectToShowID,
      partyPositionToShowID,
      postID = $('#id_constituency_' + escapeID(election)).val(),
      partySet;
  if (postID) {
    partySet = postIDToPartySet[postID];
  }
  if (show) {
    if (postID) {
      partySelectToShowID = 'id_party_' + partySet + '_' + election;
      partyPositionToShowID = 'id_party_list_position_' + partySet + '_' + election;
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility(
          $(this),
          $(this).attr('id') == partySelectToShowID
        );
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, $(this).attr('id') == partyPositionToShowID);
      });
    } else {
      /* Then just show the first party select and hide the others: */
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility($(this), i == 0);
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, i == 0);
      });
    }
  } else {
    $('.party-select-' + escapeID(election)).each(function(i) {
      setSelect2Visibility($(this), false);
    });
    $('.party-position-' + escapeID(election)).each(function() {
      setVisibility(this, false);
    });
  }
  setSelect2Visibility($('#id_constituency_' + escapeID(election)), show);
}

/* Make sure that the party and constituency select boxes are updated
   when you choose whether the candidate is standing in that election
   or not. */

function setUpStandingCheckbox() {
  $('#person-details select.standing-select').on('change', function() {
    updateFields();
  });
}

/* This should be called whenever the select drop-downs for party
   and post that have to be shown might have to be shown.  */

function updateFields() {
  $('#person-details select.standing-select').each(function(i) {
    var standing = $(this).val() == 'standing',
        match = /^id_standing_(.*)/.exec($(this).attr('id')),
        election = match[1];
    updateSelectsForElection(standing, election); });
}

$(document).ready(function() {
  $.getJSON('/post-id-to-party-set.json', function(data) {
      window.postIDToPartySet = data;
      setUpPartySelect2s();
      setUpPostSelect2s();
      setUpStandingCheckbox();
      updateFields();
  });
});
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var debug = require('debug')('wpcom:commentlike');

/**
 * CommentLike methods
 *
 * @param {String} cid comment id
 * @param {String} sid site id
 * @param {WPCOM} wpcom
 * @api public
 */

function CommentLike(cid, sid, wpcom){
  if (!sid) {
    throw new Error('`side id` is not correctly defined');
  }

  if (!cid) {
    throw new Error('`comment id` is not correctly defined');
  }

  if (!(this instanceof CommentLike)) return new CommentLike(cid, sid, wpcom);

  this.wpcom = wpcom;
  this._cid = cid;
  this._sid = sid;
}

/**
 * Get your Like status for a Comment
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype.state =
CommentLike.prototype.mine = function(query, fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/mine';
  return this.wpcom.sendRequest(path, query, null, fn);
};

/**
 * Like a comment
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype.add = function(query, fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/new';
  return this.wpcom.sendRequest({ path: path, method: 'post' }, query, null, fn);
};

/**
 * Remove your Like from a Comment
 *
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype['delete'] =
CommentLike.prototype.del = function(fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/mine/delete';
  return this.wpcom.sendRequest({ path: path, method: 'post' }, null, null, fn);
};

/**
 * Expose `CommentLike` module
 */

module.exports = CommentLike;
<commit_msg>commentlike: use request module<commit_after>
/**
 * Module dependencies.
 */

var request = require('./util/request');
var debug = require('debug')('wpcom:commentlike');

/**
 * CommentLike methods
 *
 * @param {String} cid comment id
 * @param {String} sid site id
 * @param {WPCOM} wpcom
 * @api public
 */

function CommentLike(cid, sid, wpcom){
  if (!sid) {
    throw new Error('`side id` is not correctly defined');
  }

  if (!cid) {
    throw new Error('`comment id` is not correctly defined');
  }

  if (!(this instanceof CommentLike)) return new CommentLike(cid, sid, wpcom);

  this.wpcom = wpcom;
  this._cid = cid;
  this._sid = sid;
}

/**
 * Get your Like status for a Comment
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype.state =
CommentLike.prototype.mine = function(query, fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/mine';
  return request.get(this.wpcom, null, path, query, fn);
};

/**
 * Like a comment
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype.add = function(query, body, fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/new';
  return request.post(this.wpcom, null, path, query, body, fn);
};

/**
 * Remove your Like from a Comment
 *
 * @param {Function} fn
 * @api public
 */

CommentLike.prototype['delete'] =
CommentLike.prototype.del = function(query, fn){
  var path = '/sites/' + this._sid + '/comments/' + this._cid + '/likes/mine/delete';
  return request.del(this.wpcom, null, path, query, fn);
};

/**
 * Expose `CommentLike` module
 */

module.exports = CommentLike;
<|endoftext|>


<commit_before>var Monitor = require('./monitor');
var Job = require('./job');
var defaults = require('../config/defaults');
var _ = require('lodash');

module.exports = function (config) {
    var self = this;
    self.config = _.merge(defaults, config);
    self.monitor = new Monitor(self.config);
    self.queues = {};
    self.active = true;

    self.createJob = function (type, data) {
        return new Job(type, data, self.monitor);
    };

    self.pause = function () {
        self.active = false;
    };

    self.start = function () {
        self.active = true;
    };

    self.getWork = function () {
        if (self.active) {
            self.monitor.getWork(self.getFreeSlots(), function (newJobs) {
                _(newJobs).forEach(function (newJob) {
                    self.executeJob(new Job(null, null, self.monitor).fromData(newJob), self.queues[newJob.type].jobLogic);
                });
            });
        }
    };

    self.executeJob = function (job, jobLogic) {
        self.queues[job.type].jobs.push(job);
        console.log(job.type, self.queues[job.type].jobs.length);
        jobLogic(job, self.createDoneMethod(job));
    };

    self.createDoneMethod = function (job) {
        return function (err, result) {
            if (err) {
                self.monitor.finishJob(job, 'failed');
            } else {
                self.monitor.finishJob(job, 'completed');
                if (result !== null) {
                    self.monitor.saveResult(job, result);
                }
            }

            _.remove(self.queues[job.type].jobs, function (activeJob) {
                return activeJob.id === job.id;
            });
        }
    };

    self.getFreeSlots = function () {
        var freeSlots = [];
        _(self.queues).forEach(function (queue, type) {
            if (queue.jobs.length < queue.concurrency && typeof queue.jobLogic === 'function') {
                freeSlots.push({type: type, available: queue.concurrency - queue.jobs.length})
            }
        });
        return freeSlots;
    };

    self.process = function (type, concurrency, jobLogic) {
        if (typeof concurrency === 'function') {
            self.monitor.registerQueue(type, 1);
            self.queues[type] = {concurrency: 1, jobLogic: concurrency, jobs: []};
        } else {
            self.monitor.registerQueue(type, concurrency);
            self.queues[type] = {concurrency: concurrency, jobLogic: jobLogic, jobs: []};
        }
    };

    self.getJob = function (type, jobId, cb) {
        return self.monitor.getJob(type, jobId, cb);
    };

    self.getJobResult = function (type, id, cb) {
        return self.monitor.getJobResult(type, id, cb);
    };

    self.updateInterval = setInterval(self.getWork, self.config.refreshRate);

    return self;
};<commit_msg>fixing processing without concurrency provided<commit_after>var Monitor = require('./monitor');
var Job = require('./job');
var defaults = require('../config/defaults');
var _ = require('lodash');

module.exports = function (config) {
    var self = this;
    self.config = _.merge(defaults, config);
    self.monitor = new Monitor(self.config);
    self.queues = {};
    self.active = true;

    self.createJob = function (type, data) {
        return new Job(type, data, self.monitor);
    };

    self.pause = function () {
        self.active = false;
    };

    self.start = function () {
        self.active = true;
    };

    self.getWork = function () {
        if (self.active) {
            self.monitor.getWork(self.getFreeSlots(), function (newJobs) {
                _(newJobs).forEach(function (newJob) {
                    self.executeJob(new Job(null, null, self.monitor).fromData(newJob), self.queues[newJob.type].jobLogic);
                });
            });
        }
    };

    self.executeJob = function (job, jobLogic) {
        self.queues[job.type].jobs.push(job);
        jobLogic(job, self.createDoneMethod(job));
    };

    self.createDoneMethod = function (job) {
        return function (err, result) {
            if (err) {
                self.monitor.finishJob(job, 'failed');
            } else {
                self.monitor.finishJob(job, 'completed');
                if (result !== null) {
                    self.monitor.saveResult(job, result);
                }
            }

            _.remove(self.queues[job.type].jobs, function (activeJob) {
                return activeJob.id === job.id;
            });
        }
    };

    self.getFreeSlots = function () {
        var freeSlots = [];
        _(self.queues).forEach(function (queue, type) {
            if (queue.jobs.length < queue.concurrency && typeof queue.jobLogic === 'function') {
                freeSlots.push({type: type, available: queue.concurrency - queue.jobs.length})
            }
        });

        console.log('free', freeSlots);

        return freeSlots;
    };

    self.process = function (type, concurrency, jobLogic) {
        if (typeof concurrency === 'function') {
            self.monitor.registerQueue(type, 1);
            self.queues[type] = {concurrency: 1, jobLogic: concurrency, jobs: []};
        } else {
            self.monitor.registerQueue(type, concurrency);
            self.queues[type] = {concurrency: concurrency, jobLogic: jobLogic, jobs: []};
        }
    };

    self.getJob = function (type, jobId, cb) {
        return self.monitor.getJob(type, jobId, cb);
    };

    self.getJobResult = function (type, id, cb) {
        return self.monitor.getJobResult(type, id, cb);
    };

    self.updateInterval = setInterval(self.getWork, self.config.refreshRate);

    return self;
};<|endoftext|>


<commit_before>import .SAT;

var min = Math.min;
var max = Math.max;
var abs = Math.abs;
var sqrt = Math.sqrt;

// this value helps resolve colliding state between entities
var COLLISION_OFFSET = 0.001;

/**
 * IMPORTANT NOTES:
 * ~ all required functions to interface with Entity are labeled
 * ~ by default, collisions support circles and axis-aligned rectangles only
 * ~ these are NOT continuous collision detection algorithms, meaning a large
 * value of dt could cause entities to pass through each other - it's up to the
 * developer to manage the time step of his/her game to prevent this behavior
 */
exports = {
  name: "SATPhysics",

    // anchor (pivot) point, offset from the primary point
    this.anchorX = 0;
    this.anchorY = 0;

    this.rotate = function (dr) {
      this.view.style.r += dr;
      if (this.rigidBody && this.rigidBody.rotate) {
        this.rigidBody.rotate(dr);
      }
    };

    this.setAnchor = function (x, y) {
      this.anchorX = x || 0;
      this.anchorY = y || 0;
      if (this.view) {
        this.view.style.anchorX = this.anchorX;
        this.view.style.anchorY = this.anchorY;
      }
      if (this.rigidBody && this.rigidBody.setPivot) {
        this.rigidBody.setPivot(new SAT.Vector(this.x + x, this.y + y));
      }
    }

  /**
   * ~ REQUIRED for Entity
   * ~ stepPosition updates an entity's position based on dt (delta time)
   * ~ velocity is added half before update and half after, which helps
   * mitigate lag spikes, for smoother, more frame independent animations
   */
  stepPosition: function (entity, dt) {
    entity.x += dt * entity.vx / 2;
    entity.vx += dt * entity.ax;
    entity.x += dt * entity.vx / 2;

    entity.y += dt * entity.vy / 2;
    entity.vy += dt * entity.ay;
    entity.y += dt * entity.vy / 2;
  },

  updatePosition: function (entity, dx, dy){
    if(dx == 0 && dy == 0){
      return;
    }
    entity.rigidbody2d.pos.x += dx;
    entity.rigidbody2d.pos.y += dy;
  },
  /**
   * ~ REQUIRED for Entity
   * ~ collide defines how collisions behave and what data is returned
   * ~ by default, returns a bool, and only works with circles and rects
   */
  collide: function (entity1, entity2, response) {
    if (entity1.isCircle) {
      if (entity2.isCircle) {
        return this.circleCollidesWithCircle(entity1, entity2, response);
      } else {
        return this.circleCollidesWithRect(entity1, entity2, response);
      }
    } else {
      if (entity2.isCircle) {
        return this.circleCollidesWithRect(entity2, entity1, response);
      } else {
        return this.rectCollidesWithRect(entity1, entity2, response);
      }
    }
  },
  circleCollidesWithCircle: function (circ1, circ2, response) {
    return SAT.testCircleCircle(circ1.rigidbody2d, circ2.rigidbody2d, response);
  },
  circleCollidesWithRect: function (circ, rect, response) {
    return SAT.testCirclePolygon(circ.rigidbody2d, rect.rigidbody2d, response);
  },
  rectCollidesWithRect: function (rect1, rect2, response) {
    return SAT.testPolygonPolygon(rect1.rigidbody2d, rect2.rigidbody2d, response);
  },
  /**
   * ~ REQUIRED for Entity
   * ~ resolveCollidingState uses hit bounds to guarantee that two entities
   * are no longer colliding by pushing them apart
   * ~ entities with isAnchored true are never moved
   * ~ returns total distance moved to separate the objects
   */
  resolveCollidingState: function (entity1, entity2) {
    if (entity1.isCircle) {
      if (entity2.isCircle) {
        return this.resolveCollidingCircles(entity1, entity2);
      } else {
        return this.resolveCollidingCircleRect(entity1, entity2);
      }
    } else {
      if (entity2.isCircle) {
        return this.resolveCollidingCircleRect(entity2, entity1);
      } else {
        return this.resolveCollidingRects(entity1, entity2);
      }
    }
  },
  /**
   * ~ resolveCollidingCircles forces two circles apart based on their centers
   */
  resolveCollidingCircles: function (circ1, circ2) {
    var x1 = circ1.getHitX();
    var y1 = circ1.getHitY();
    var r1 = circ1.getHitRadius();
    var mult1 = 0.5;
    var x2 = circ2.getHitX();
    var y2 = circ2.getHitY();
    var r2 = circ2.getHitRadius();
    var mult2 = 0.5;

    var dx = x2 - x1;
    var dy = y2 - y1;
    var dist = sqrt(dx * dx + dy * dy);
    var distColl = r1 + r2 + COLLISION_OFFSET;

    // if concentric, force a very small distance
    if (dist === 0) {
      dx = COLLISION_OFFSET;
      dist = COLLISION_OFFSET;
    }

    var dd = distColl - dist;

    // anchored entities cannot be moved by physics
    if (circ1.isAnchored && circ2.isAnchored) {
      dd = 0;
    } else if (circ1.isAnchored) {
      mult1 = 0;
      mult2 = 1;
    } else if (circ2.isAnchored) {
      mult1 = 1;
      mult2 = 0;
    }

    circ1.x += mult1 * dd * -(dx / dist);
    circ1.y += mult1 * dd * -(dy / dist);
    circ2.x += mult2 * dd * (dx / dist);
    circ2.y += mult2 * dd * (dy / dist);

    return dd;
  },
  /**
   * ~ resolveCollidingCircleRect forces apart a circle and rect
   * ~ good default collision behavior for landing on a platforms vs.
   * hitting the side (missing the platform)
   */
  resolveCollidingCircleRect: function (circ, rect) {
    var cx = circ.getHitX();
    var cy = circ.getHitY();
    var cr = circ.getHitRadius();
    var rwHalf = rect.getHitWidth() / 2;
    var rhHalf = rect.getHitHeight() / 2;
    var rx = rect.getMinHitX() + rwHalf;
    var ry = rect.getMinHitY() + rhHalf;
    var dx = abs(cx - rx);
    var dy = abs(cy - ry);
    if (dx > rwHalf + cr || dy > rhHalf + cr
      || (circ.isAnchored && rect.isAnchored))
    {
      // far case: circle's center too far or both entities are anchored
      return 0;
    } else if (dx <= rwHalf || dy <= rhHalf) {
      // close case: treat the circle like another rect, then resolve
      var origHitBounds = circ.hitBounds;
      circ.hitBounds = {
        x: cx - circ.x - cr,
        y: cy - circ.y - cr,
        w: 2 * cr,
        h: 2 * cr
      };

      var dd = this.resolveCollidingRects(rect, circ);
      circ.hitBounds = origHitBounds;
      return dd;
    } else {
      // corner case: the two meet at a rect corner, push them away
      var mult1 = 0.5;
      var mult2 = 0.5;
      // get the right corner point
      var nx = cx < rx ? rx - rwHalf : rx + rwHalf;
      var ny = cy < ry ? ry - rhHalf : ry + rhHalf;
      dx = nx - cx;
      dy = ny - cy;
      var dist = sqrt(dx * dx + dy * dy);
      var distColl = cr + COLLISION_OFFSET;
      var dd = distColl - dist;

      // anchored entities cannot be moved by physics
      if (circ.isAnchored) {
        mult1 = 0;
        mult2 = 1;
      } else if (rect.isAnchored) {
        mult1 = 1;
        mult2 = 0;
      }

      circ.x += mult1 * dd * -(dx / dist);
      circ.y += mult1 * dd * -(dy / dist);
      rect.x += mult2 * dd * (dx / dist);
      rect.y += mult2 * dd * (dy / dist);

      return dd;
    }
  },
  /**
   * ~ resolveCollidingRects forces two rects apart, but only in one direction
   * ~ good default collision behavior for landing on a platforms vs.
   * hitting the side (missing the platform)
   */
  resolveCollidingRects: function (rect1, rect2) {
    var x1 = rect1.getMinHitX();
    var y1 = rect1.getMinHitY();
    var w1 = rect1.getHitWidth();
    var h1 = rect1.getHitHeight();
    var xf1 = rect1.getMaxHitX();
    var yf1 = rect1.getMaxHitY();
    var mult1 = 0.5;
    var x2 = rect2.getMinHitX();
    var y2 = rect2.getMinHitY();
    var w2 = rect2.getHitWidth();
    var h2 = rect2.getHitHeight();
    var xf2 = rect2.getMaxHitX();
    var yf2 = rect2.getMaxHitY();
    var mult2 = 0.5;

    // find shallowest collision overlap, positive value means no overlap
    var dx = 1;
    var dx1 = x1 - xf2;
    var dx2 = x2 - xf1;
    if (dx1 <= 0 && dx2 <= 0) {
      dx = max(dx1, dx2) - COLLISION_OFFSET;
    } else if (dx1 <= 0) {
      dx = dx1 - COLLISION_OFFSET;
    } else if (dx2 <= 0) {
      dx = dx2 - COLLISION_OFFSET;
    }

    var dy = 1;
    var dy1 = y1 - yf2;
    var dy2 = y2 - yf1;
    if (dy1 <= 0 && dy2 <= 0) {
      dy = max(dy1, dy2) - COLLISION_OFFSET;
    } else if (dy1 <= 0) {
      dy = dy1 - COLLISION_OFFSET;
    } else if (dy2 <= 0) {
      dy = dy2 - COLLISION_OFFSET;
    }

    // step out in only one direction, pick the smallest overlap
    if (dx <= 0 && dy <= 0) {
      if (dx > dy) {
        dy = 0;
      } else {
        dx = 0;
      }
    } else if (dx <= 0) {
      dy = 0;
    } else if (dy <= 0) {
      dx = 0;
    } else {
      // there was no collision to begin with
      dx = 0;
      dy = 0;
    }

    // anchored entities cannot be moved by physics
    if (rect1.isAnchored && rect2.isAnchored) {
      dx = 0;
      dy = 0;
    } else if (rect1.isAnchored) {
      mult1 = 0;
      mult2 = 1;
    } else if (rect2.isAnchored) {
      mult1 = 1;
      mult2 = 0;
    }

    // dx and dy are never positive; so fix signs here based on rect centers
    var cx1 = x1 + w1 / 2;
    var cx2 = x2 + w2 / 2;
    var cy1 = y1 + h1 / 2;
    var cy2 = y2 + h2 / 2;
    var sign = (dx && cx1 > cx2) || (dy && cy1 > cy2) ? -1 : 1;
    rect1.x += mult1 * sign * dx;
    rect1.y += mult1 * sign * dy;
    rect2.x += mult2 * sign * -dx;
    rect2.y += mult2 * sign * -dy;

    // one of these will always be 0, so this is also the delta distance
    return dx + dy;
  },
  /**
   * ~ REQUIRED for Entity
   * ~ used by advanced physics implementations, like SATPhysics
   */
  getRigidBody: function (entity) {
    var vec = new SAT.Vector(entity.getHitX(), entity.getHitY());
    if (entity.isCircle) {
      return new SAT.Circle(vec, entity.getHitRadius());
    } else {
      var box = new SAT.Box(vec, entity.getHitWidth(), entity.getHitHeight());
      return box.toPolygon();
    }
  }
};
<commit_msg>SAT/physics whitespace<commit_after>import .SAT;

var min = Math.min;
var max = Math.max;
var abs = Math.abs;
var sqrt = Math.sqrt;

// this value helps resolve colliding state between entities
var COLLISION_OFFSET = 0.001;

/**
 * IMPORTANT NOTES:
 * ~ all required functions to interface with Entity are labeled
 * ~ by default, collisions support circles and axis-aligned rectangles only
 * ~ these are NOT continuous collision detection algorithms, meaning a large
 * value of dt could cause entities to pass through each other - it's up to the
 * developer to manage the time step of his/her game to prevent this behavior
 */
exports = {
  name: "SATPhysics",

  // anchor (pivot) point, offset from the primary point
  this.anchorX = 0;
  this.anchorY = 0;

  this.rotate = function (dr) {
    this.view.style.r += dr;
    if (this.rigidBody && this.rigidBody.rotate) {
      this.rigidBody.rotate(dr);
    }
  };

  this.setAnchor = function (x, y) {
    this.anchorX = x || 0;
    this.anchorY = y || 0;
    if (this.view) {
      this.view.style.anchorX = this.anchorX;
      this.view.style.anchorY = this.anchorY;
    }
    if (this.rigidBody && this.rigidBody.setPivot) {
      this.rigidBody.setPivot(new SAT.Vector(this.x + x, this.y + y));
    }
  }

  /**
   * ~ REQUIRED for Entity
   * ~ stepPosition updates an entity's position based on dt (delta time)
   * ~ velocity is added half before update and half after, which helps
   * mitigate lag spikes, for smoother, more frame independent animations
   */
  stepPosition: function (entity, dt) {
    entity.x += dt * entity.vx / 2;
    entity.vx += dt * entity.ax;
    entity.x += dt * entity.vx / 2;

    entity.y += dt * entity.vy / 2;
    entity.vy += dt * entity.ay;
    entity.y += dt * entity.vy / 2;
  },

  updatePosition: function (entity, dx, dy){
    if(dx == 0 && dy == 0){
      return;
    }
    entity.rigidbody2d.pos.x += dx;
    entity.rigidbody2d.pos.y += dy;
  },

  /**
   * ~ REQUIRED for Entity
   * ~ collide defines how collisions behave and what data is returned
   * ~ by default, returns a bool, and only works with circles and rects
   */
  collide: function (entity1, entity2, response) {
    if (entity1.isCircle) {
      if (entity2.isCircle) {
        return this.circleCollidesWithCircle(entity1, entity2, response);
      } else {
        return this.circleCollidesWithRect(entity1, entity2, response);
      }
    } else {
      if (entity2.isCircle) {
        return this.circleCollidesWithRect(entity2, entity1, response);
      } else {
        return this.rectCollidesWithRect(entity1, entity2, response);
      }
    }
  },

  circleCollidesWithCircle: function (circ1, circ2, response) {
    return SAT.testCircleCircle(circ1.rigidbody2d, circ2.rigidbody2d, response);
  },

  circleCollidesWithRect: function (circ, rect, response) {
    return SAT.testCirclePolygon(circ.rigidbody2d, rect.rigidbody2d, response);
  },

  rectCollidesWithRect: function (rect1, rect2, response) {
    return SAT.testPolygonPolygon(rect1.rigidbody2d, rect2.rigidbody2d, response);
  },

  /**
   * ~ REQUIRED for Entity
   * ~ resolveCollidingState uses hit bounds to guarantee that two entities
   * are no longer colliding by pushing them apart
   * ~ entities with isAnchored true are never moved
   * ~ returns total distance moved to separate the objects
   */
  resolveCollidingState: function (entity1, entity2) {
    if (entity1.isCircle) {
      if (entity2.isCircle) {
        return this.resolveCollidingCircles(entity1, entity2);
      } else {
        return this.resolveCollidingCircleRect(entity1, entity2);
      }
    } else {
      if (entity2.isCircle) {
        return this.resolveCollidingCircleRect(entity2, entity1);
      } else {
        return this.resolveCollidingRects(entity1, entity2);
      }
    }
  },

  /**
   * ~ resolveCollidingCircles forces two circles apart based on their centers
   */
  resolveCollidingCircles: function (circ1, circ2) {
    var x1 = circ1.getHitX();
    var y1 = circ1.getHitY();
    var r1 = circ1.getHitRadius();
    var mult1 = 0.5;
    var x2 = circ2.getHitX();
    var y2 = circ2.getHitY();
    var r2 = circ2.getHitRadius();
    var mult2 = 0.5;

    var dx = x2 - x1;
    var dy = y2 - y1;
    var dist = sqrt(dx * dx + dy * dy);
    var distColl = r1 + r2 + COLLISION_OFFSET;

    // if concentric, force a very small distance
    if (dist === 0) {
      dx = COLLISION_OFFSET;
      dist = COLLISION_OFFSET;
    }

    var dd = distColl - dist;

    // anchored entities cannot be moved by physics
    if (circ1.isAnchored && circ2.isAnchored) {
      dd = 0;
    } else if (circ1.isAnchored) {
      mult1 = 0;
      mult2 = 1;
    } else if (circ2.isAnchored) {
      mult1 = 1;
      mult2 = 0;
    }

    circ1.x += mult1 * dd * -(dx / dist);
    circ1.y += mult1 * dd * -(dy / dist);
    circ2.x += mult2 * dd * (dx / dist);
    circ2.y += mult2 * dd * (dy / dist);

    return dd;
  },

  /**
   * ~ resolveCollidingCircleRect forces apart a circle and rect
   * ~ good default collision behavior for landing on a platforms vs.
   * hitting the side (missing the platform)
   */
  resolveCollidingCircleRect: function (circ, rect) {
    var cx = circ.getHitX();
    var cy = circ.getHitY();
    var cr = circ.getHitRadius();
    var rwHalf = rect.getHitWidth() / 2;
    var rhHalf = rect.getHitHeight() / 2;
    var rx = rect.getMinHitX() + rwHalf;
    var ry = rect.getMinHitY() + rhHalf;
    var dx = abs(cx - rx);
    var dy = abs(cy - ry);
    if (dx > rwHalf + cr || dy > rhHalf + cr
      || (circ.isAnchored && rect.isAnchored))
    {
      // far case: circle's center too far or both entities are anchored
      return 0;
    } else if (dx <= rwHalf || dy <= rhHalf) {
      // close case: treat the circle like another rect, then resolve
      var origHitBounds = circ.hitBounds;
      circ.hitBounds = {
        x: cx - circ.x - cr,
        y: cy - circ.y - cr,
        w: 2 * cr,
        h: 2 * cr
      };

      var dd = this.resolveCollidingRects(rect, circ);
      circ.hitBounds = origHitBounds;
      return dd;
    } else {
      // corner case: the two meet at a rect corner, push them away
      var mult1 = 0.5;
      var mult2 = 0.5;
      // get the right corner point
      var nx = cx < rx ? rx - rwHalf : rx + rwHalf;
      var ny = cy < ry ? ry - rhHalf : ry + rhHalf;
      dx = nx - cx;
      dy = ny - cy;
      var dist = sqrt(dx * dx + dy * dy);
      var distColl = cr + COLLISION_OFFSET;
      var dd = distColl - dist;

      // anchored entities cannot be moved by physics
      if (circ.isAnchored) {
        mult1 = 0;
        mult2 = 1;
      } else if (rect.isAnchored) {
        mult1 = 1;
        mult2 = 0;
      }

      circ.x += mult1 * dd * -(dx / dist);
      circ.y += mult1 * dd * -(dy / dist);
      rect.x += mult2 * dd * (dx / dist);
      rect.y += mult2 * dd * (dy / dist);

      return dd;
    }
  },

  /**
   * ~ resolveCollidingRects forces two rects apart, but only in one direction
   * ~ good default collision behavior for landing on a platforms vs.
   * hitting the side (missing the platform)
   */
  resolveCollidingRects: function (rect1, rect2) {
    var x1 = rect1.getMinHitX();
    var y1 = rect1.getMinHitY();
    var w1 = rect1.getHitWidth();
    var h1 = rect1.getHitHeight();
    var xf1 = rect1.getMaxHitX();
    var yf1 = rect1.getMaxHitY();
    var mult1 = 0.5;
    var x2 = rect2.getMinHitX();
    var y2 = rect2.getMinHitY();
    var w2 = rect2.getHitWidth();
    var h2 = rect2.getHitHeight();
    var xf2 = rect2.getMaxHitX();
    var yf2 = rect2.getMaxHitY();
    var mult2 = 0.5;

    // find shallowest collision overlap, positive value means no overlap
    var dx = 1;
    var dx1 = x1 - xf2;
    var dx2 = x2 - xf1;
    if (dx1 <= 0 && dx2 <= 0) {
      dx = max(dx1, dx2) - COLLISION_OFFSET;
    } else if (dx1 <= 0) {
      dx = dx1 - COLLISION_OFFSET;
    } else if (dx2 <= 0) {
      dx = dx2 - COLLISION_OFFSET;
    }

    var dy = 1;
    var dy1 = y1 - yf2;
    var dy2 = y2 - yf1;
    if (dy1 <= 0 && dy2 <= 0) {
      dy = max(dy1, dy2) - COLLISION_OFFSET;
    } else if (dy1 <= 0) {
      dy = dy1 - COLLISION_OFFSET;
    } else if (dy2 <= 0) {
      dy = dy2 - COLLISION_OFFSET;
    }

    // step out in only one direction, pick the smallest overlap
    if (dx <= 0 && dy <= 0) {
      if (dx > dy) {
        dy = 0;
      } else {
        dx = 0;
      }
    } else if (dx <= 0) {
      dy = 0;
    } else if (dy <= 0) {
      dx = 0;
    } else {
      // there was no collision to begin with
      dx = 0;
      dy = 0;
    }

    // anchored entities cannot be moved by physics
    if (rect1.isAnchored && rect2.isAnchored) {
      dx = 0;
      dy = 0;
    } else if (rect1.isAnchored) {
      mult1 = 0;
      mult2 = 1;
    } else if (rect2.isAnchored) {
      mult1 = 1;
      mult2 = 0;
    }

    // dx and dy are never positive; so fix signs here based on rect centers
    var cx1 = x1 + w1 / 2;
    var cx2 = x2 + w2 / 2;
    var cy1 = y1 + h1 / 2;
    var cy2 = y2 + h2 / 2;
    var sign = (dx && cx1 > cx2) || (dy && cy1 > cy2) ? -1 : 1;
    rect1.x += mult1 * sign * dx;
    rect1.y += mult1 * sign * dy;
    rect2.x += mult2 * sign * -dx;
    rect2.y += mult2 * sign * -dy;

    // one of these will always be 0, so this is also the delta distance
    return dx + dy;
  },

  /**
   * ~ REQUIRED for Entity
   * ~ used by advanced physics implementations, like SATPhysics
   */
  getRigidBody: function (entity) {
    var vec = new SAT.Vector(entity.getHitX(), entity.getHitY());
    if (entity.isCircle) {
      return new SAT.Circle(vec, entity.getHitRadius());
    } else {
      var box = new SAT.Box(vec, entity.getHitWidth(), entity.getHitHeight());
      return box.toPolygon();
    }
  }
};
<|endoftext|>


<commit_before>var path         = require('path');

var express      = require('express');
var favicon      = require('serve-favicon');
var logger       = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser   = require('body-parser');

var passport     = require('passport');
var OpenStreetMapStrategy
                 = require('passport-openstreetmap').Strategy;

var session      = require('express-session');
var FileStore    = require('session-file-store')(session);

var debug        = require('debug')('OSMBC:app');

var config     = require('./config.js');

var index      = require('./routes/index').router;
var users      = require('./routes/users').router;
var article    = require('./routes/article').router;
var changes    = require('./routes/changes').router;
var blog       = require('./routes/blog');
var layout     = require('./routes/layout').router;

var userModule = require('./model/user.js');

// Initialise config Module
config.initialise();
var htmlRoot = config.getValue("htmlroot");
console.log("Express Routes set to: SERVER"+htmlRoot);

// taken from: https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
// Passport session setup.
//   To support persistent login sessions, Passport needs to be able to
//   serialize users into and deserialize users out of the session.  Typically,
//   this will be as simple as storing the user ID when serializing, and finding
//   the user by ID when deserializing.  However, since this example does not
//   have a database of user records, the complete OpenStreetMap profile is
//   serialized and deserialized.
// in OSMBC only the displayName is relevant (as long as there is no user database)
// so this is enough for serialising.
// if there will be a user database, this has to be integrated here
passport.serializeUser(function(user, done) {
  debug("passport.serializeUser CB");
  done(null, user.displayName);
});

passport.deserializeUser(function(name, done) {
  debug("passport.deserializeUser CB");
  var user = {}
  user.displayName = name;
  done(null, user);
});

// taken from https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
// Use the OpenStreetMapStrategy within Passport.
//   Strategies in passport require a `verify` function, which accept
//   credentials (in this case, a token, tokenSecret, and OpenStreetMap profile), and
//   invoke a callback with a user object.

passport.use(new OpenStreetMapStrategy({
    consumerKey: config.getConfiguration().OPENSTREETMAP_CONSUMER_KEY,
    consumerSecret: config.getConfiguration().OPENSTREETMAP_CONSUMER_SECRET,
    callbackURL: config.getCallbackUrl()
  },
  function(token, tokenSecret, profile, done) {
    debug('passport.use Token Function');
    // asynchronous verification, for effect...
    process.nextTick(function () {

      // To keep the example simple, the user's OpenStreetMap profile is returned to
      // represent the logged-in user.  In a typical application, you would want
      // to associate the OpenStreetMap account with a user record in your database,
      // and return that user instead.
      return done(null, profile);
    });
  }
));

/*passport.use(new Strategy(
  function(username, password, cb) {
    debug('Strategy')
    var user = {};
     user.displayName = "TheFive"
      console.log(username," ",password);
      if (username =="TheFive") {
        console.log("User OK");
        return cb(null,user);
      }

      return cb(null, false);
    })
  );*/

function ensureAuthenticated(req, res, next) {
  debug("ensureAuthenticated");

  if (req.isAuthenticated()) {
    // check User
    userModule.find({OSMUser:req.user.displayName},function(err,result){
      if (err) return next(err);
      if (result.length==1) {
        for (var k in result[0]) {
          req.user[k] = result[0][k];
        }
        if (result[0].access == "full") {
          // save last access, ignore save callback
          var date = new Date();
          var lastStore = new Date(result[0].lastAccess);
          if (!result[0].lastAccess || (date.getTime()-lastStore.getTime()) > 1000*60*2) {
            result[0].lastAccess = new Date();
            result[0].save(function(err) {});
          }
          return next();
        }
      }

      var err = new Error('OSM User >'+req.user.displayName+'< has no access rights');
      return next(err);
    })
    return;
  }
  req.session.returnTo = req.originalUrl;
  res.redirect(htmlRoot+'/auth/openstreetmap')

}

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(favicon(path.join(__dirname , 'public','images','favicon.ico')));

// take from https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
app.use(session({ store: new FileStore(),
                  secret: 'LvwnH}uHhDLxvAu3X6' ,
                  resave:true,
                  saveUninitialized:true,
                  cookie:{_expires : 1000*60*60*24*365}}));
// Initialize Passport!  Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());

// uncomment after placing your favicon in /public
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(htmlRoot,express.static(path.join(__dirname, 'public')));

// GET /auth/openstreetmap
//   Use passport.authenticate() as route middleware to authenticate the
//   request.  The first step in OpenStreetMap authentication will involve redirecting
//   the user to openstreetmap.org.  After authorization, OpenStreetMap will redirect the user
//   back to this application at /auth/openstreetmap/callback
app.get(htmlRoot + '/auth/openstreetmap',
  //passport.authenticate('openstreetmap'),
  passport.authenticate('openstreetmap'),
  function(req, res){
    // The request will be redirected to OpenStreetMap for authentication, so this
    // function will not be called.
  });

// GET /auth/openstreetmap/callback
//   Use passport.authenticate() as route middleware to authenticate the
//   request.  If authentication fails, the user will be redirected back to the
//   login page.  Otherwise, the primary route function function will be called,
//   which, in this example, will redirect the user to the home page.
app.get(htmlRoot + '/auth/openstreetmap/callback',
  passport.authenticate('openstreetmap', { failureRedirect: '/login'  }),
  function(req, res) {
    debug('passport.authenticate Function');
    res.redirect(req.session.returnTo || '/');
    //res.redirect('/');
  });

app.get(htmlRoot + '/logout', function(req, res){
  debug('logoutFunction')
  req.logout();
  res.redirect('/');
});

// layout does not render, but prepares the res.rendervar variable fro
// dynamic contend in layout.jade
app.use(htmlRoot + '/',ensureAuthenticated,layout);
app.use(htmlRoot + '/',ensureAuthenticated,index);
app.use(htmlRoot + '/usert',ensureAuthenticated, users);
app.use(htmlRoot + '/article',ensureAuthenticated, article);
app.use(htmlRoot + '/changes',ensureAuthenticated, changes);
app.use(htmlRoot + '/blog',ensureAuthenticated, blog);

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.

// error handlers

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  debug('app.use Error Handler');
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    debug('app.use Error Handler for Debug');
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err,
      layout:{htmlroot:htmlRoot}
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  debug('app.use status function');
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

module.exports = app;
<commit_msg>Quickfix Error Handler.<commit_after>var path         = require('path');

var express      = require('express');
var favicon      = require('serve-favicon');
var logger       = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser   = require('body-parser');

var passport     = require('passport');
var OpenStreetMapStrategy
                 = require('passport-openstreetmap').Strategy;

var session      = require('express-session');
var FileStore    = require('session-file-store')(session);

var debug        = require('debug')('OSMBC:app');

var config     = require('./config.js');

var index      = require('./routes/index').router;
var users      = require('./routes/users').router;
var article    = require('./routes/article').router;
var changes    = require('./routes/changes').router;
var blog       = require('./routes/blog');
var layout     = require('./routes/layout').router;

var userModule = require('./model/user.js');

// Initialise config Module
config.initialise();
var htmlRoot = config.getValue("htmlroot");
console.log("Express Routes set to: SERVER"+htmlRoot);

// taken from: https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
// Passport session setup.
//   To support persistent login sessions, Passport needs to be able to
//   serialize users into and deserialize users out of the session.  Typically,
//   this will be as simple as storing the user ID when serializing, and finding
//   the user by ID when deserializing.  However, since this example does not
//   have a database of user records, the complete OpenStreetMap profile is
//   serialized and deserialized.
// in OSMBC only the displayName is relevant (as long as there is no user database)
// so this is enough for serialising.
// if there will be a user database, this has to be integrated here
passport.serializeUser(function(user, done) {
  debug("passport.serializeUser CB");
  done(null, user.displayName);
});

passport.deserializeUser(function(name, done) {
  debug("passport.deserializeUser CB");
  var user = {}
  user.displayName = name;
  done(null, user);
});

// taken from https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
// Use the OpenStreetMapStrategy within Passport.
//   Strategies in passport require a `verify` function, which accept
//   credentials (in this case, a token, tokenSecret, and OpenStreetMap profile), and
//   invoke a callback with a user object.

passport.use(new OpenStreetMapStrategy({
    consumerKey: config.getConfiguration().OPENSTREETMAP_CONSUMER_KEY,
    consumerSecret: config.getConfiguration().OPENSTREETMAP_CONSUMER_SECRET,
    callbackURL: config.getCallbackUrl()
  },
  function(token, tokenSecret, profile, done) {
    debug('passport.use Token Function');
    // asynchronous verification, for effect...
    process.nextTick(function () {

      // To keep the example simple, the user's OpenStreetMap profile is returned to
      // represent the logged-in user.  In a typical application, you would want
      // to associate the OpenStreetMap account with a user record in your database,
      // and return that user instead.
      return done(null, profile);
    });
  }
));

/*passport.use(new Strategy(
  function(username, password, cb) {
    debug('Strategy')
    var user = {};
     user.displayName = "TheFive"
      console.log(username," ",password);
      if (username =="TheFive") {
        console.log("User OK");
        return cb(null,user);
      }

      return cb(null, false);
    })
  );*/

function ensureAuthenticated(req, res, next) {
  debug("ensureAuthenticated");

  if (req.isAuthenticated()) {
    // check User
    userModule.find({OSMUser:req.user.displayName},function(err,result){
      if (err) return next(err);
      if (result.length==1) {
        for (var k in result[0]) {
          req.user[k] = result[0][k];
        }
        if (result[0].access == "full") {
          // save last access, ignore save callback
          var date = new Date();
          var lastStore = new Date(result[0].lastAccess);
          if (!result[0].lastAccess || (date.getTime()-lastStore.getTime()) > 1000*60*2) {
            result[0].lastAccess = new Date();
            result[0].save(function(err) {});
          }
          return next();
        }
      }

      var err = new Error('OSM User >'+req.user.displayName+'< has no access rights');
      return next(err);
    })
    return;
  }
  req.session.returnTo = req.originalUrl;
  res.redirect(htmlRoot+'/auth/openstreetmap')

}

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(favicon(path.join(__dirname , 'public','images','favicon.ico')));

// take from https://github.com/jaredhanson/passport-openstreetmap/blob/master/examples/login/app.js
app.use(session({ store: new FileStore(),
                  secret: 'LvwnH}uHhDLxvAu3X6' ,
                  resave:true,
                  saveUninitialized:true,
                  cookie:{_expires : 1000*60*60*24*365}}));
// Initialize Passport!  Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());

// uncomment after placing your favicon in /public
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(htmlRoot,express.static(path.join(__dirname, 'public')));

// GET /auth/openstreetmap
//   Use passport.authenticate() as route middleware to authenticate the
//   request.  The first step in OpenStreetMap authentication will involve redirecting
//   the user to openstreetmap.org.  After authorization, OpenStreetMap will redirect the user
//   back to this application at /auth/openstreetmap/callback
app.get(htmlRoot + '/auth/openstreetmap',
  //passport.authenticate('openstreetmap'),
  passport.authenticate('openstreetmap'),
  function(req, res){
    // The request will be redirected to OpenStreetMap for authentication, so this
    // function will not be called.
  });

// GET /auth/openstreetmap/callback
//   Use passport.authenticate() as route middleware to authenticate the
//   request.  If authentication fails, the user will be redirected back to the
//   login page.  Otherwise, the primary route function function will be called,
//   which, in this example, will redirect the user to the home page.
app.get(htmlRoot + '/auth/openstreetmap/callback',
  passport.authenticate('openstreetmap', { failureRedirect: '/login'  }),
  function(req, res) {
    debug('passport.authenticate Function');
    res.redirect(req.session.returnTo || '/');
    //res.redirect('/');
  });

app.get(htmlRoot + '/logout', function(req, res){
  debug('logoutFunction')
  req.logout();
  res.redirect('/');
});

// layout does not render, but prepares the res.rendervar variable fro
// dynamic contend in layout.jade
app.use(htmlRoot + '/',ensureAuthenticated,layout);
app.use(htmlRoot + '/',ensureAuthenticated,index);
app.use(htmlRoot + '/usert',ensureAuthenticated, users);
app.use(htmlRoot + '/article',ensureAuthenticated, article);
app.use(htmlRoot + '/changes',ensureAuthenticated, changes);
app.use(htmlRoot + '/blog',ensureAuthenticated, blog);

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.

// error handlers

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  debug('app.use Error Handler');
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    debug('app.use Error Handler for Debug');
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err,
      layout:{htmlroot:htmlRoot}
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  debug('app.use status function');
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {},
    layout:{htmlroot:htmlRoot}
  });
});

module.exports = app;
<|endoftext|>


<commit_before>
'use strict'

/**
 * catogory
 */
var _ = require('lodash')
,local = require('../app/local')
,setting = require('../app/setting')
,tools = require('./tools')
,log = tools.log
,err = tools.err
,db = require('./db').db
,cf = require('./db').cf
,links = require('../doc/api/admin-page')
,accesses = require('../doc/api').accessesControlled

exports.login = function* (next) {

	try {

		this.render('views/page/login', this.local)

	} catch(e) {

		err('failed render admin page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

exports.admin = function* (next) {

	try {

		let params = this.params
		let page = params.page
		let user = this.session.user

		//check should reset password or not
		if(user.resetPassword) {
			this.session.redirect = this.path
			return this.redirect('/reset-password/' + user.resetPassword)
		}

		let path = this.path
		this.local.user = user
		this.local.links = getLinks(user)
		if(
			path.indexOf('page') > -1 ||
			path.indexOf('post') > -1
		) this.local.publicRoute = setting.publicRoute

		else if(path.indexOf('group') > -1) this.local.accesses = accesses

		this.render('views/admin/' + page, this.local)

	} catch(e) {

		err('failed render admin page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

function getLinks(user) {
	return _.filter(user.group.access, function(v) {
		return v.indexOf('/admin/') > -1
	})
	.map(function(v) {
		return links[v]
	})
}

exports.resetPasswordPage = function* (next) {
	//todo
	try {

		let params = this.params
		let id = params.id
		if(!id) return yield next

		let sea = {
			_id: id
			,state: 'init'
		}
		let rs = yield db.collection('reset_password').findOne(sea)

		if(!rs) return yield next

		this.local.resetPassword = rs

		this.render('views/page/reset-password', this.local)

	} catch(e) {

		err('failed render reset-password page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

exports.resetPasswordRequestPage = function* (next) {
	//todo
	try {

		this.render('views/page/reset-password-request', this.local)

	} catch(e) {

		err('failed render reset-password page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}<commit_msg>check login status in admin urls<commit_after>
'use strict'

/**
 * catogory
 */
var _ = require('lodash')
,local = require('../app/local')
,setting = require('../app/setting')
,tools = require('./tools')
,log = tools.log
,err = tools.err
,db = require('./db').db
,cf = require('./db').cf
,links = require('../doc/api/admin-page')
,accesses = require('../doc/api').accessesControlled

exports.login = function* (next) {

	try {

		this.render('views/page/login', this.local)

	} catch(e) {

		err('failed render admin page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

exports.admin = function* (next) {

	try {

		let params = this.params
		let page = params.page
		let user = this.session.user

		if(!user) return this.redirect('/login')

		//check should reset password or not
		if(user.resetPassword) {
			this.session.redirect = this.path
			return this.redirect('/reset-password/' + user.resetPassword)
		}

		let path = this.path
		this.local.user = user
		this.local.links = getLinks(user)
		if(
			path.indexOf('page') > -1 ||
			path.indexOf('post') > -1
		) this.local.publicRoute = setting.publicRoute

		else if(path.indexOf('group') > -1) this.local.accesses = accesses

		this.render('views/admin/' + page, this.local)

	} catch(e) {

		err('failed render admin page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

function getLinks(user) {
	return _.filter(user.group.access, function(v) {
		return v.indexOf('/admin/') > -1
	})
	.map(function(v) {
		return links[v]
	})
}

exports.resetPasswordPage = function* (next) {
	//todo
	try {

		let params = this.params
		let id = params.id
		if(!id) return yield next

		let sea = {
			_id: id
			,state: 'init'
		}
		let rs = yield db.collection('reset_password').findOne(sea)

		if(!rs) return yield next

		this.local.resetPassword = rs

		this.render('views/page/reset-password', this.local)

	} catch(e) {

		err('failed render reset-password page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}

exports.resetPasswordRequestPage = function* (next) {
	//todo
	try {

		this.render('views/page/reset-password-request', this.local)

	} catch(e) {

		err('failed render reset-password page', e)
		this.status = 500
		this.local.error = e
		this.render('views/page/500', this.local)

	}

}<|endoftext|>