<commit_before>var path = require('path');
var fs = require('graceful-fs');
var crypto = require('crypto');
var mm = require('minimatch');

var log = require('./logger').create('preprocess');

var sha1 = function(data) {
  var hash = crypto.createHash('sha1');
  hash.update(data);
  return hash.digest('hex');
};

var isBinary = Object.create(null);
[
  'adp', 'au', 'mid', 'mp4a', 'mpga', 'oga', 's3m', 'sil', 'eol', 'dra', 'dts', 'dtshd', 'lvp',
  'pya', 'ecelp4800', 'ecelp7470', 'ecelp9600', 'rip', 'weba', 'aac', 'aif', 'caf', 'flac', 'mka',
  'm3u', 'wax', 'wma', 'wav', 'xm', 'flac', '3gp', '3g2', 'h261', 'h263', 'h264', 'jpgv', 'jpm',
  'mj2', 'mp4', 'mpeg', 'ogv', 'qt', 'uvh', 'uvm', 'uvp', 'uvs', 'dvb', 'fvt', 'mxu', 'pyv', 'uvu',
  'viv', 'webm', 'f4v', 'fli', 'flv', 'm4v', 'mkv', 'mng', 'asf', 'vob', 'wm', 'wmv', 'wmx', 'wvx',
  'movie', 'smv', 'ts', 'bmp', 'cgm', 'g3', 'gif', 'ief', 'jpg', 'jpeg', 'ktx', 'png', 'btif',
  'sgi', 'tiff', 'psd', 'uvi', 'sub', 'djvu', 'dwg', 'dxf', 'fbs', 'fpx', 'fst', 'mmr',
  'rlc', 'mdi', 'wdp', 'npx', 'wbmp', 'xif', 'webp', '3ds', 'ras', 'cmx', 'fh', 'ico', 'pcx', 'pic',
  'pnm', 'pbm', 'pgm', 'ppm', 'rgb', 'tga', 'xbm', 'xpm', 'xwd', 'zip', 'rar', 'tar', 'bz2', 'eot',
  'ttf', 'woff', 'dat'
].forEach(function(extension) {
  isBinary['.' + extension] = true;
});

// TODO(vojta): instantiate preprocessors at the start to show warnings immediately
var createPreprocessor = function(config, basePath, injector) {
  var patterns = Object.keys(config);
  var alreadyDisplayedWarnings = Object.create(null);

  return function(file, done) {
    var thisFileIsBinary = isBinary[path.extname(file.originalPath)];
    var preprocessors = [];
    var nextPreprocessor = function(error, content) {
      // normalize B-C
      if (arguments.length === 1 && typeof error === 'string') {
        content = error;
        error = null;
      }

      if (error) {
        file.content = null;
        file.contentPath = null;
        return done(error);
      }

      if (!preprocessors.length) {
        file.contentPath = null;
        file.content = content;
        return done();
      }

      preprocessors.shift()(content, file, nextPreprocessor);
    };
    var instantiatePreprocessor = function(name) {
      if (alreadyDisplayedWarnings[name]) {
        return;
      }

      try {
        preprocessors.push(injector.get('preprocessor:' + name));
      } catch (e) {
        if (e.message.indexOf('No provider for "preprocessor:' + name + '"') !== -1) {
          log.warn('Can not load "%s", it is not registered!\n  ' +
                   'Perhaps you are missing some plugin?', name);
        } else {
          log.warn('Can not load "%s"!\n  ' + e.stack, name);
        }

        alreadyDisplayedWarnings[name] = true;
      }
    };

    // collects matching preprocessors
    // TODO(vojta): should we cache this ?
    for (var i = 0; i < patterns.length; i++) {
      if (mm(file.originalPath, patterns[i])) {
        if (thisFileIsBinary) {
          log.warn('Ignoring preprocessing (%s) %s because it is a binary file.',
              config[patterns[i]].join(', '), file.originalPath);
        } else {
          config[patterns[i]].forEach(instantiatePreprocessor);
        }
      }
    }

    return fs.readFile(file.originalPath, function(err, buffer) {
      file.sha = sha1(buffer);
      nextPreprocessor(null, thisFileIsBinary ? buffer : buffer.toString());
    });
  };
};
createPreprocessor.$inject = ['config.preprocessors', 'config.basePath', 'injector'];

exports.createPreprocessor = createPreprocessor;
<commit_msg>fix(preprocessor): serve NaCl binaries<commit_after>var path = require('path');
var fs = require('graceful-fs');
var crypto = require('crypto');
var mm = require('minimatch');

var log = require('./logger').create('preprocess');

var sha1 = function(data) {
  var hash = crypto.createHash('sha1');
  hash.update(data);
  return hash.digest('hex');
};

var isBinary = Object.create(null);
[
  'adp', 'au', 'mid', 'mp4a', 'mpga', 'oga', 's3m', 'sil', 'eol', 'dra', 'dts', 'dtshd', 'lvp',
  'pya', 'ecelp4800', 'ecelp7470', 'ecelp9600', 'rip', 'weba', 'aac', 'aif', 'caf', 'flac', 'mka',
  'm3u', 'wax', 'wma', 'wav', 'xm', 'flac', '3gp', '3g2', 'h261', 'h263', 'h264', 'jpgv', 'jpm',
  'mj2', 'mp4', 'mpeg', 'ogv', 'qt', 'uvh', 'uvm', 'uvp', 'uvs', 'dvb', 'fvt', 'mxu', 'pyv', 'uvu',
  'viv', 'webm', 'f4v', 'fli', 'flv', 'm4v', 'mkv', 'mng', 'asf', 'vob', 'wm', 'wmv', 'wmx', 'wvx',
  'movie', 'smv', 'ts', 'bmp', 'cgm', 'g3', 'gif', 'ief', 'jpg', 'jpeg', 'ktx', 'png', 'btif',
  'sgi', 'tiff', 'psd', 'uvi', 'sub', 'djvu', 'dwg', 'dxf', 'fbs', 'fpx', 'fst', 'mmr',
  'rlc', 'mdi', 'wdp', 'npx', 'wbmp', 'xif', 'webp', '3ds', 'ras', 'cmx', 'fh', 'ico', 'pcx', 'pic',
  'pnm', 'pbm', 'pgm', 'ppm', 'rgb', 'tga', 'xbm', 'xpm', 'xwd', 'zip', 'rar', 'tar', 'bz2', 'eot',
  'ttf', 'woff', 'dat', 'nexe', 'pexe'
].forEach(function(extension) {
  isBinary['.' + extension] = true;
});

// TODO(vojta): instantiate preprocessors at the start to show warnings immediately
var createPreprocessor = function(config, basePath, injector) {
  var patterns = Object.keys(config);
  var alreadyDisplayedWarnings = Object.create(null);

  return function(file, done) {
    var thisFileIsBinary = isBinary[path.extname(file.originalPath)];
    var preprocessors = [];
    var nextPreprocessor = function(error, content) {
      // normalize B-C
      if (arguments.length === 1 && typeof error === 'string') {
        content = error;
        error = null;
      }

      if (error) {
        file.content = null;
        file.contentPath = null;
        return done(error);
      }

      if (!preprocessors.length) {
        file.contentPath = null;
        file.content = content;
        return done();
      }

      preprocessors.shift()(content, file, nextPreprocessor);
    };
    var instantiatePreprocessor = function(name) {
      if (alreadyDisplayedWarnings[name]) {
        return;
      }

      try {
        preprocessors.push(injector.get('preprocessor:' + name));
      } catch (e) {
        if (e.message.indexOf('No provider for "preprocessor:' + name + '"') !== -1) {
          log.warn('Can not load "%s", it is not registered!\n  ' +
                   'Perhaps you are missing some plugin?', name);
        } else {
          log.warn('Can not load "%s"!\n  ' + e.stack, name);
        }

        alreadyDisplayedWarnings[name] = true;
      }
    };

    // collects matching preprocessors
    // TODO(vojta): should we cache this ?
    for (var i = 0; i < patterns.length; i++) {
      if (mm(file.originalPath, patterns[i])) {
        if (thisFileIsBinary) {
          log.warn('Ignoring preprocessing (%s) %s because it is a binary file.',
              config[patterns[i]].join(', '), file.originalPath);
        } else {
          config[patterns[i]].forEach(instantiatePreprocessor);
        }
      }
    }

    return fs.readFile(file.originalPath, function(err, buffer) {
      file.sha = sha1(buffer);
      nextPreprocessor(null, thisFileIsBinary ? buffer : buffer.toString());
    });
  };
};
createPreprocessor.$inject = ['config.preprocessors', 'config.basePath', 'injector'];

exports.createPreprocessor = createPreprocessor;
<|endoftext|>


<commit_before>steal('can/util', 'can/model', 'can/observe/backup', function(can){

	var cleanAttrs = function(changedAttrs, attrs){
			var newAttrs = can.extend(true, {}, attrs),
				attr, current, path;
			if(changedAttrs){
				for(var i = 0; i < changedAttrs.length; i++){
					current = newAttrs;
					path    = changedAttrs[i].split('.');
					while(path.length > 1){
						current = current && current[path.shift()];
					}
					current && delete current[path.shift()];
				}
			}
			return newAttrs;
		},
		queueRequests = function( success, error, method, callback) {
			this._requestQueue = this._requestQueue || [];
			this._changedAttrs = this._changedAttrs || [];

			var def          = new can.Deferred,
				self         = this,
				attrs        = this.attr(),
				queue        = this._requestQueue,
				changedAttrs = this._changedAttrs,
				reqFn, index;

			reqFn = (function(self, type, success, error){
				// Function that performs actual request
				return function(){
					return self.constructor._makeRequest([self, attrs], type, success, error, callback)
				}
				// we shouldn't pass this, instead we need to pass something like
				// [this, this.serialize()]
			})(this, method || (this.isNew() ? 'create' : 'update'), function(){
				// resolve deferred with results from the request
				def.resolveWith(self, arguments);
				// remove current deferred from the queue
				queue.splice(0, 1);
				if(queue.length > 0){
					// replace queued wrapper function with deferred
					// returned from the makeRequest function so we
					// can access it's `abort` function
					queue[0] = queue[0]();
				} else {
					changedAttrs.splice(0);
				}

			}, function(){
				// reject deferred with results from the request
				def.rejectWith(self, arguments);
				// since we failed remove all pending requests from the queue
				queue.splice(0);
				changedAttrs.splice(0);
			})

			// Add our fn to the queue
			index = queue.push(reqFn) - 1;

			// If there is only one request in the queue, run
			// it immediately.
			if(queue.length === 1){
				// replace queued wrapper function with deferred
				// returned from the makeRequest function so we
				// can access it's `abort` function
				queue[0] = queue[0]();
			}

			def.abort = function(){
				var abort;
				// check if this request is running, if it's not
				// just remove it from the queue
				//
				// also all subsequent requests should be removed too
				abort = queue[index].abort && queue[index].abort();
				// remove aborted request and any requests after it
				queue.splice(index);
				changedAttrs.splice(0);
				return abort;
			}
			// deferred will be resolved with original success and
			// error functions
			def.then(success, error);

			return def;
		},
		_changes  = can.Model.prototype._changes,
		destroyFn = can.Model.prototype.destroy;

	can.each(["created", "updated", "destroyed"], function(fn){
		var prototypeFn = can.Model.prototype[fn];

		can.Model.prototype[fn] = function(attrs){
			if(attrs && typeof attrs == 'object'){
				attrs = attrs.attr ? attrs.attr() : attrs;
				this._backupStore = attrs;
				attrs = cleanAttrs(this._changedAttrs || [], attrs);
			}
			prototypeFn.call(this, attrs);
		}
	})

	can.extend(can.Model.prototype, {
		_changes: function(ev, attr, how,newVal, oldVal){
			// record changes if there is a request running
			this._changedAttrs && this._changedAttrs.push(attr);
			_changes.apply(this, arguments);
		},
		hasQueuedRequests : function(){
			return this._requestQueue && this._requestQueue.length > 1;
		},
		save : function(){
			return queueRequests.apply(this, arguments);
		},
		destroy : function(success, error){
			if(this.isNew()){
				return destroyFn.call(this, success, error);
			}
			return queueRequests.call(this, success, error, 'destroy', 'destroyed');
		}
	})
})<commit_msg>Make requestQueue list an observe so it's live-bindable<commit_after>steal('can/util', 'can/model', 'can/observe/backup', function(can){

	var cleanAttrs = function(changedAttrs, attrs){
			var newAttrs = can.extend(true, {}, attrs),
				attr, current, path;
			if(changedAttrs){
				for(var i = 0; i < changedAttrs.length; i++){
					current = newAttrs;
					path    = changedAttrs[i].split('.');
					while(path.length > 1){
						current = current && current[path.shift()];
					}
					current && delete current[path.shift()];
				}
			}
			return newAttrs;
		},
		queueRequests = function( success, error, method, callback) {
			this._changedAttrs = this._changedAttrs || [];

			var def          = new can.Deferred,
				self         = this,
				attrs        = this.attr(),
				queue        = this._requestQueue,
				changedAttrs = this._changedAttrs,
				reqFn, index;

			reqFn = (function(self, type, success, error){
				// Function that performs actual request
				return function(){
					return self.constructor._makeRequest([self, attrs], type, success, error, callback)
				}
				// we shouldn't pass this, instead we need to pass something like
				// [this, this.serialize()]
			})(this, method || (this.isNew() ? 'create' : 'update'), function(){
				// resolve deferred with results from the request
				def.resolveWith(self, arguments);
				// remove current deferred from the queue
				queue.splice(0, 1);
				if(queue.length > 0){
					// replace queued wrapper function with deferred
					// returned from the makeRequest function so we
					// can access it's `abort` function
					queue[0] = queue[0]();
				} else {
					changedAttrs.splice(0);
				}

			}, function(){
				// reject deferred with results from the request
				def.rejectWith(self, arguments);
				// since we failed remove all pending requests from the queue
				queue.splice(0);
				changedAttrs.splice(0);
			})

			// Add our fn to the queue
			index = queue.push(reqFn) - 1;

			// If there is only one request in the queue, run
			// it immediately.
			if(queue.length === 1){
				// replace queued wrapper function with deferred
				// returned from the makeRequest function so we
				// can access it's `abort` function
				queue[0] = queue[0]();
			}

			def.abort = function(){
				var abort;
				// check if this request is running, if it's not
				// just remove it from the queue
				//
				// also all subsequent requests should be removed too
				abort = queue[index].abort && queue[index].abort();
				// remove aborted request and any requests after it
				queue.splice(index);
				changedAttrs.splice(0);
				return abort;
			}
			// deferred will be resolved with original success and
			// error functions
			def.then(success, error);

			return def;
		},
		_changes  = can.Model.prototype._changes,
		destroyFn = can.Model.prototype.destroy,
		setupFn   = can.Model.prototype.setup;

	can.each(["created", "updated", "destroyed"], function(fn){
		var prototypeFn = can.Model.prototype[fn];

		can.Model.prototype[fn] = function(attrs){
			if(attrs && typeof attrs == 'object'){
				attrs = attrs.attr ? attrs.attr() : attrs;
				this._backupStore = attrs;
				attrs = cleanAttrs(this._changedAttrs || [], attrs);
			}
			prototypeFn.call(this, attrs);
		}
	})

	can.extend(can.Model.prototype, {
		setup: function(){
			setupFn.apply(this, arguments);
			this._requestQueue = new can.Observe.List;
		},
		_changes: function(ev, attr, how,newVal, oldVal){
			// record changes if there is a request running
			this._changedAttrs && this._changedAttrs.push(attr);
			_changes.apply(this, arguments);
		},
		hasQueuedRequests : function(){
			return this._requestQueue.attr('length') > 1;
		},
		save : function(){
			return queueRequests.apply(this, arguments);
		},
		destroy : function(success, error){
			if(this.isNew()){
				return destroyFn.call(this, success, error);
			}
			return queueRequests.call(this, success, error, 'destroy', 'destroyed');
		}
	})
})<|endoftext|>


<commit_before>Milestones = new Mongo.Collection('milestones');

Milestones.validTypes = ['strategic', 'year', 'month', 'week'];

Milestones.attachSchema(new SimpleSchema({
  period: {
    type: String,
    optional: true
  },
  type: {
    type: String,
    allowedValues: Milestones.validTypes
  },
  userId: {
    type: String
  },
  startsAt: {
    type: Date,
    optional: true,
    label: 'Start Period'
  },
  endsAt: {
    type: Date,
    optional: true,
    label: 'End Period'
  }
}));

Milestones.boundsFor = (period, type) => {
  if (type === 'strategic') {
    [firstYear, lastYear] = period.split('-');

    if (+lastYear < +firstYear) {
      // TODO: come up with other error message
      throw new Meteor.Error('period-invalid',
        'Last year should be greater than first'
      );
    }

    return {
      startsAt: moment(firstYear, 'YYYY').toDate(),
      endsAt: moment(lastYear, 'YYYY').endOf('year').toDate()
    };
  }

  const date = moment(period);
  const isoType = type === 'week' ? 'isoWeek' : type;

  return {
    startsAt: Milestones.bound(date.clone().startOf(isoType), 'start').toDate(),
    endsAt: Milestones.bound(date.clone().endOf(isoType), 'end').toDate()
  };
};

// Returns nearest week bound for given date
Milestones.bound = (date, type = 'start') => {
  if (type === 'start' && date.day() > 4)  date.add(1, 'w');
  if (type === 'end'   && date.day() <= 4) date.subtract(1, 'w');
  return date[`${type}Of`]('isoWeek');
};

Milestones.relativeType = (type, levelDiff) => {
  return Milestones.validTypes[Milestones.validTypes.indexOf(type) + levelDiff];
};

Milestones.periodFormats = extended => ({
  year: { parse: 'YYYY', display: 'YYYY' },
  month: { parse: 'YYYY-MM', display: extended ? 'MMMM YYYY' : 'MMM' },
  week: { parse: '', display: extended ? 'DD MMMM YYYY' : 'DD MMM' }
});

Milestones.helpers({
  goals: function(query) {
    return Goals.find({...query, milestoneId: this._id}, {sort: {rank: 1}});
  },
  parent: function() {
    return Milestones.findOne({
      type: Milestones.relativeType(this.type, -1),
      userId: this.userId,
      startsAt: { $lte: this.startsAt },
      endsAt: { $gte: this.endsAt }
    });
  },
  children: function() {
    return Milestones.find({
      type: Milestones.relativeType(this.type, +1),
      userId: this.userId,
      startsAt: { $gte: this.startsAt },
      endsAt: { $lte: this.endsAt }
    }, {sort: {startsAt: -1}});
  },
  title: function(extended) {
    let format = Milestones.periodFormats(extended)[this.type];
    if (this.type === 'strategic') return this.period || 'Strategic';
    if (this.type === 'week') {
      let periods = [
        moment(this.period).startOf('week').format('DD'),
        moment(this.period).endOf('week').format(format.display)
      ];
      return periods.join('-');
    }

    return moment(this.period, format.parse).format(format.display);
  },
  newGoalPriority: function() {
    let priority = 0;
    let goalWithMaxPriority = Goals.findOne(
      {milestoneId: this._id},
      {sort: {priority: -1}});
    if (goalWithMaxPriority && !Number.isNaN(goalWithMaxPriority.priority)) {
      priority = goalWithMaxPriority.priority + 1;
    }
    return priority;
  },
  newGoalRank: function() {
    let lastGoal = Goals.findOne({milestoneId: this._id}, {sort: {rank: -1}});
    let lastRank = lastGoal && lastGoal.rank || 0;
    return lastRank + 1;
  },
  progress: function() {
    let sum = this.goals()
      .map(goal => goal.completedPct)
      .filter(Number)
      .reduce((a, b) => a + b, 0);
    return Math.round(sum / this.goals().count());
  },
  isCurrent: function() {
    return moment(this.startsAt).isSameOrBefore() &&
      moment(this.endsAt).isSameOrAfter();
  }
});

Milestones.allow({
  insert: function(userId, doc) {
    let milestone = Milestones.findOne({
      userId: userId,
      period: doc.period,
      type: doc.type
    });
    if (milestone) {
      throw new Meteor.Error('period-invalid',
        'Milestone for this period already created!');
    }
    return userId === doc.userId && !milestone;
  },
  update: function(userId, doc) { return userId === doc.userId; },
  remove: function() { return false; }
});
<commit_msg>removed newGoalPriority helper.<commit_after>Milestones = new Mongo.Collection('milestones');

Milestones.validTypes = ['strategic', 'year', 'month', 'week'];

Milestones.attachSchema(new SimpleSchema({
  period: {
    type: String,
    optional: true
  },
  type: {
    type: String,
    allowedValues: Milestones.validTypes
  },
  userId: {
    type: String
  },
  startsAt: {
    type: Date,
    optional: true,
    label: 'Start Period'
  },
  endsAt: {
    type: Date,
    optional: true,
    label: 'End Period'
  }
}));

Milestones.boundsFor = (period, type) => {
  if (type === 'strategic') {
    [firstYear, lastYear] = period.split('-');

    if (+lastYear < +firstYear) {
      // TODO: come up with other error message
      throw new Meteor.Error('period-invalid',
        'Last year should be greater than first'
      );
    }

    return {
      startsAt: moment(firstYear, 'YYYY').toDate(),
      endsAt: moment(lastYear, 'YYYY').endOf('year').toDate()
    };
  }

  const date = moment(period);
  const isoType = type === 'week' ? 'isoWeek' : type;

  return {
    startsAt: Milestones.bound(date.clone().startOf(isoType), 'start').toDate(),
    endsAt: Milestones.bound(date.clone().endOf(isoType), 'end').toDate()
  };
};

// Returns nearest week bound for given date
Milestones.bound = (date, type = 'start') => {
  if (type === 'start' && date.day() > 4)  date.add(1, 'w');
  if (type === 'end'   && date.day() <= 4) date.subtract(1, 'w');
  return date[`${type}Of`]('isoWeek');
};

Milestones.relativeType = (type, levelDiff) => {
  return Milestones.validTypes[Milestones.validTypes.indexOf(type) + levelDiff];
};

Milestones.periodFormats = extended => ({
  year: { parse: 'YYYY', display: 'YYYY' },
  month: { parse: 'YYYY-MM', display: extended ? 'MMMM YYYY' : 'MMM' },
  week: { parse: '', display: extended ? 'DD MMMM YYYY' : 'DD MMM' }
});

Milestones.helpers({
  goals: function(query) {
    return Goals.find({...query, milestoneId: this._id}, {sort: {rank: 1}});
  },
  parent: function() {
    return Milestones.findOne({
      type: Milestones.relativeType(this.type, -1),
      userId: this.userId,
      startsAt: { $lte: this.startsAt },
      endsAt: { $gte: this.endsAt }
    });
  },
  children: function() {
    return Milestones.find({
      type: Milestones.relativeType(this.type, +1),
      userId: this.userId,
      startsAt: { $gte: this.startsAt },
      endsAt: { $lte: this.endsAt }
    }, {sort: {startsAt: -1}});
  },
  title: function(extended) {
    let format = Milestones.periodFormats(extended)[this.type];
    if (this.type === 'strategic') return this.period || 'Strategic';
    if (this.type === 'week') {
      let periods = [
        moment(this.period).startOf('week').format('DD'),
        moment(this.period).endOf('week').format(format.display)
      ];
      return periods.join('-');
    }

    return moment(this.period, format.parse).format(format.display);
  },
  newGoalRank: function() {
    let lastGoal = Goals.findOne({milestoneId: this._id}, {sort: {rank: -1}});
    let lastRank = lastGoal && lastGoal.rank || 0;
    return lastRank + 1;
  },
  progress: function() {
    let sum = this.goals()
      .map(goal => goal.completedPct)
      .filter(Number)
      .reduce((a, b) => a + b, 0);
    return Math.round(sum / this.goals().count());
  },
  isCurrent: function() {
    return moment(this.startsAt).isSameOrBefore() &&
      moment(this.endsAt).isSameOrAfter();
  }
});

Milestones.allow({
  insert: function(userId, doc) {
    let milestone = Milestones.findOne({
      userId: userId,
      period: doc.period,
      type: doc.type
    });
    if (milestone) {
      throw new Meteor.Error('period-invalid',
        'Milestone for this period already created!');
    }
    return userId === doc.userId && !milestone;
  },
  update: function(userId, doc) { return userId === doc.userId; },
  remove: function() { return false; }
});
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

let treeNode = (address, setUp) => new Promise(
    function(resolveNode, rejectNode) {
  let internal = {};
  let payload = {};
  let runnableNode = {};

  internal.errors = [];
  internal.children = [];
  internal.addLogger = function(logger) {
    payload.log = newAddressedLogFunction(address, logger);
  };

  payload.runBefore = () => {};
  payload.run = () => {};
  payload.runAfter = () => {};

  payload.add = function(childSetUp) {
    internal.children.push(
      treeNode(address.concat(internal.children.length),
               childSetUp))
  };

  runnableNode.run = logger => new Promise(
      function(resolveRun, rejectRun) {
    internal.addLogger(logger);
    payload.log("begin");

    let runningChildren = [];
    let throwError = function() {
      rejectRun({
        description: "root",
        children: {length: 2},
        messages: []
      });
    };

    Promise.resolve(payload.runBefore()).then(function() {
      return Promise.resolve(payload.run());

    }, function(error) {
      rejectRun();

    }).then(function() {
      for (let child of runnableNode.children)
        runningChildren.push(child.run(logger));

      return Promise.all(runningChildren);

    }, function(error) {
      rejectRun();

    }).then(function() {
      return Promise.resolve(payload.runAfter());

    }, function(error) {
      let errorResolutions = [];
      let childErrors = [];

      for (let child of runningChildren) {
        errorResolutions.push(new Promise(function(resolveError) {
          child.then(function(value) {
            resolveError();
          }, function(childError) {
            childErrors.push(childError);
            resolveError();
          });
        }));
      }

      return new Promise(function(good, bad) {
        Promise.all(errorResolutions).then(function(value) {
          let result = {
            description: "root",
            children: childErrors,
            messages: []
          };

          bad(result);
        });
      });

    }).then(function() {
      payload.log("done");
      resolveRun();

    }, function(error) {
      rejectRun(error);
    });
  });

  runAndWait(function() { setUp(payload); }).then(function(value) {
    return Promise.all(internal.children);

  }, function(error) {
    internal.errors.push(error);
    return Promise.all(internal.children);

  }).then(function(childIterator) {
    runnableNode.children = [...childIterator];
    runnableNode.getLogTree = function() {
      let result = {};

      if (payload.description)
        result.d = payload.description;

      result.c = [];
      for (let leaf of runnableNode.children)
        result.c.push(leaf.getLogTree());

      return result;
    };

    if (internal.errors.length == 0)
      resolveNode(runnableNode);

    else
      rejectNode({
        description: payload.description,
        messages: internal.errors,
        children: []
      });

  }, function(error) {
    let errorResolutions = [];
    let childErrors = [];

    for (let child of internal.children) {
      errorResolutions.push(new Promise(function(resolveError) {
        child.then(function(value) {
          resolveError();
        }, function(childError) {
          childErrors.push(childError);
          resolveError();
        });
      }));
    }

    Promise.all(errorResolutions).then(function(value) {
      rejectNode({
        description: payload.description,
        messages: internal.errors,
        children: childErrors
      });
    });
  });
});

let newAddressedLogFunction = (address, logger) =>
  (code, message) => new Promise((resolve, reject) => {
    let fullMessage = [Date.now(), code].concat(address);
    fullMessage.push(message || "");

    Promise.resolve(logger.log(fullMessage)).then(value => {
      resolve(value);
    }, passError(reject));
});

let passError = function(reject) {
  return function(error) {
    reject(error);
  };
};

let runAndWait = function(thingToRun) {
  try {
    return Promise.resolve(thingToRun());

  } catch (error) {
    return Promise.reject(error);
  }
};

module.exports = (newLogger, setUp) => new Promise(
    function(resolve, reject) {
  treeNode([], setUp).then(function(root) {
    let logger = newLogger(root.getLogTree());
    logger.storeProcess(root.run(logger));

    resolve(logger);

  }, passError(reject));
});
<commit_msg>:muscle: Remove unused function<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

let treeNode = (address, setUp) => new Promise(
    function(resolveNode, rejectNode) {
  let internal = {};
  let payload = {};
  let runnableNode = {};

  internal.errors = [];
  internal.children = [];
  internal.addLogger = function(logger) {
    payload.log = newAddressedLogFunction(address, logger);
  };

  payload.runBefore = () => {};
  payload.run = () => {};
  payload.runAfter = () => {};

  payload.add = function(childSetUp) {
    internal.children.push(
      treeNode(address.concat(internal.children.length),
               childSetUp))
  };

  runnableNode.run = logger => new Promise(
      function(resolveRun, rejectRun) {
    internal.addLogger(logger);
    payload.log("begin");

    let runningChildren = [];

    Promise.resolve(payload.runBefore()).then(function() {
      return Promise.resolve(payload.run());

    }, function(error) {
      rejectRun();

    }).then(function() {
      for (let child of runnableNode.children)
        runningChildren.push(child.run(logger));

      return Promise.all(runningChildren);

    }, function(error) {
      rejectRun();

    }).then(function() {
      return Promise.resolve(payload.runAfter());

    }, function(error) {
      let errorResolutions = [];
      let childErrors = [];

      for (let child of runningChildren) {
        errorResolutions.push(new Promise(function(resolveError) {
          child.then(function(value) {
            resolveError();
          }, function(childError) {
            childErrors.push(childError);
            resolveError();
          });
        }));
      }

      return new Promise(function(good, bad) {
        Promise.all(errorResolutions).then(function(value) {
          let result = {
            description: "root",
            children: childErrors,
            messages: []
          };

          bad(result);
        });
      });

    }).then(function() {
      payload.log("done");
      resolveRun();

    }, function(error) {
      rejectRun(error);
    });
  });

  runAndWait(function() { setUp(payload); }).then(function(value) {
    return Promise.all(internal.children);

  }, function(error) {
    internal.errors.push(error);
    return Promise.all(internal.children);

  }).then(function(childIterator) {
    runnableNode.children = [...childIterator];
    runnableNode.getLogTree = function() {
      let result = {};

      if (payload.description)
        result.d = payload.description;

      result.c = [];
      for (let leaf of runnableNode.children)
        result.c.push(leaf.getLogTree());

      return result;
    };

    if (internal.errors.length == 0)
      resolveNode(runnableNode);

    else
      rejectNode({
        description: payload.description,
        messages: internal.errors,
        children: []
      });

  }, function(error) {
    let errorResolutions = [];
    let childErrors = [];

    for (let child of internal.children) {
      errorResolutions.push(new Promise(function(resolveError) {
        child.then(function(value) {
          resolveError();
        }, function(childError) {
          childErrors.push(childError);
          resolveError();
        });
      }));
    }

    Promise.all(errorResolutions).then(function(value) {
      rejectNode({
        description: payload.description,
        messages: internal.errors,
        children: childErrors
      });
    });
  });
});

let newAddressedLogFunction = (address, logger) =>
  (code, message) => new Promise((resolve, reject) => {
    let fullMessage = [Date.now(), code].concat(address);
    fullMessage.push(message || "");

    Promise.resolve(logger.log(fullMessage)).then(value => {
      resolve(value);
    }, passError(reject));
});

let passError = function(reject) {
  return function(error) {
    reject(error);
  };
};

let runAndWait = function(thingToRun) {
  try {
    return Promise.resolve(thingToRun());

  } catch (error) {
    return Promise.reject(error);
  }
};

module.exports = (newLogger, setUp) => new Promise(
    function(resolve, reject) {
  treeNode([], setUp).then(function(root) {
    let logger = newLogger(root.getLogTree());
    logger.storeProcess(root.run(logger));

    resolve(logger);

  }, passError(reject));
});
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

let processTree = (newLogger, setUp) => new Promise(
    function(resolve, reject) {
  treeNode([], setUp).then(function(root) {
    let logger = newLogger(root.getLogTree());
    logger.storeProcess(root.run(logger));

    resolve(logger);

  }, passError(reject));
});

let treeNode = (address, setUp) => new Promise(
    function(resolve, reject) {
  let payload = {};
  let internal = {
    'address':address,
    'resolve':resolve,
    'reject':reject,
    'setUp':setUp
  };

  initInternal(internal, payload);
  initPayload(internal, payload);
  createRunMethod(internal, payload);
  attemptSetUp(internal, payload);
});

let initInternal = function(internal, payload) {
  internal.runnableNode = {};
  internal.errors = [];
  internal.children = [];
  internal.setPayloadLogger = function(logger) {
    payload.log = newAddressedLogFunction(internal.address, logger);
  };
};

let initPayload = function(internal, payload) {
  payload.runBefore = () => {};
  payload.run = () => {};
  payload.runAfter = () => {};
  payload.add = function(childSetUp) {
    internal.children.push(
      treeNode(internal.address.concat(internal.children.length),
               childSetUp))
  };
};

let createRunMethod = function(internal, payload) {
  internal.runnableNode.run = logger => new Promise(function(resolve, reject) {
    internal.setPayloadLogger(logger);
    payload.log("begin");

    let errors = [];
    let runningChildren = [];
    let errorOutWithChildren = function(children) {
      reject({
        "description": payload.description,
        "messages": errors,
        "children": children
      });
    };

    let errorOutWithMessage = function (message) {
      errors.push(message);
      errorOutWithChildren([]);
    };

    runAndWait(payload.runBefore).then(function() {
      runAndWait(payload.run).then(function() {
        for (let child of internal.runnableNode.children)
          runningChildren.push(child.run(logger));

        awaitOrCollectAllErrors(runningChildren).then(function() {
          runAndWait(payload.runAfter).then(function() {
            payload.log("done");
            resolve();

          }, errorOutWithMessage);
        }, errorOutWithChildren);
      }, errorOutWithMessage);
    }, errorOutWithMessage);
  });
};

let attemptSetUp = function(internal, payload) {
  runAndWait(function() {
    internal.setUp(payload);

  }).then(function() {
    return awaitOrCollectAllErrors(internal.children);

  }, function(error) {
    internal.errors.push(error);
    return awaitOrCollectAllErrors(internal.children);

  }).then(function(childIterator) {
    if (internal.errors.length > 0)
      internal.reject({
        description: payload.description,
        messages: internal.errors,
        children: []
      });

    internal.runnableNode.children = [...childIterator];
    resolveWithRunnableNode(internal, payload);

  }, function(error) {
    internal.reject({
      description: payload.description,
      messages: internal.errors,
      children: error
    });
  });
};

let resolveWithRunnableNode = function(internal, payload) {
  internal.runnableNode.getLogTree = function() {
    let result = {};

    if (payload.description)
      result.d = payload.description;

    result.c = [];
    for (let leaf of internal.runnableNode.children)
      result.c.push(leaf.getLogTree());

    return result;
  };

  internal.resolve(internal.runnableNode);
};

let awaitOrCollectAllErrors = promises => new Promise(
    function(resolve, reject) {
  Promise.all(promises).then(function(value) { resolve(value); },
    function(anError) {
      Promise.all(getListOfErrorPromises(promises)).then(
          rejectWithOrderedListOfErrors(reject));
    });
});

let getListOfErrorPromises = function(promises) {
  let errorPromises = [];

  for (let promise of promises) {
    errorPromises.push(new Promise(function(alwaysSucceed) {
      promise.then(function(value) {
        alwaysSucceed(null);

      }, function(error) {
        alwaysSucceed(error);
      });
    }));
  }

  return errorPromises;
};

let rejectWithOrderedListOfErrors = function(rejectMethod) {
  return function(errorValues) {
    let allErrors = [];

    for (let errorValue of errorValues) {
      if (errorValue !== null)
        allErrors.push(errorValue);
    }

    rejectMethod(allErrors);
  };
};

let newAddressedLogFunction = (address, logger) =>
  (code, message) => new Promise((resolve, reject) => {
    let fullMessage = [Date.now(), code].concat(address);
    fullMessage.push(message || "");

    Promise.resolve(logger.log(fullMessage)).then(value => {
      resolve(value);
    }, passError(reject));
});

let passError = function(reject) {
  return function(error) {
    reject(error);
  };
};

let runAndWait = function(thingToRun) {
  try {
    return Promise.resolve(thingToRun());

  } catch (error) {
    return Promise.reject(error);
  }
};

module.exports = processTree;
<commit_msg>:muscle: Extract errorOut() method for setUp<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

let processTree = (newLogger, setUp) => new Promise(
    function(resolve, reject) {
  treeNode([], setUp).then(function(root) {
    let logger = newLogger(root.getLogTree());
    logger.storeProcess(root.run(logger));

    resolve(logger);

  }, passError(reject));
});

let treeNode = (address, setUp) => new Promise(
    function(resolve, reject) {
  let payload = {};
  let internal = {
    'address':address,
    'resolve':resolve,
    'reject':reject,
    'setUp':setUp
  };

  initInternal(internal, payload);
  initPayload(internal, payload);
  createRunMethod(internal, payload);
  attemptSetUp(internal, payload);
});

let initInternal = function(internal, payload) {
  internal.runnableNode = {};
  internal.errors = [];
  internal.children = [];
  internal.setPayloadLogger = function(logger) {
    payload.log = newAddressedLogFunction(internal.address, logger);
  };
};

let initPayload = function(internal, payload) {
  payload.runBefore = () => {};
  payload.run = () => {};
  payload.runAfter = () => {};
  payload.add = function(childSetUp) {
    internal.children.push(
      treeNode(internal.address.concat(internal.children.length),
               childSetUp))
  };
};

let createRunMethod = function(internal, payload) {
  internal.runnableNode.run = logger => new Promise(function(resolve, reject) {
    internal.setPayloadLogger(logger);
    payload.log("begin");

    let errors = [];
    let runningChildren = [];

    let errorOutWithChildren = function(children) {
      reject({
        "description": payload.description,
        "messages": errors,
        "children": children
      });
    };

    let errorOutWithMessage = function (message) {
      errors.push(message);
      errorOutWithChildren([]);
    };

    runAndWait(payload.runBefore).then(function() {
      runAndWait(payload.run).then(function() {
        for (let child of internal.runnableNode.children)
          runningChildren.push(child.run(logger));

        awaitOrCollectAllErrors(runningChildren).then(function() {
          runAndWait(payload.runAfter).then(function() {
            payload.log("done");
            resolve();

          }, errorOutWithMessage);
        }, errorOutWithChildren);
      }, errorOutWithMessage);
    }, errorOutWithMessage);
  });
};

let attemptSetUp = function(internal, payload) {
  let errorOut = function(children) {
    internal.reject({
      "description": payload.description,
      "messages": internal.errors,
      "children": children
    });
  };

  runAndWait(function() {
    internal.setUp(payload);

  }).then(function() {
    return awaitOrCollectAllErrors(internal.children);

  }, function(error) {
    internal.errors.push(error);
    return awaitOrCollectAllErrors(internal.children);

  }).then(function(childIterator) {
    if (internal.errors.length > 0)
      errorOut([]);

    internal.runnableNode.children = [...childIterator];
    resolveWithRunnableNode(internal, payload);

  }, errorOut);
};

let resolveWithRunnableNode = function(internal, payload) {
  internal.runnableNode.getLogTree = function() {
    let result = {};

    if (payload.description)
      result.d = payload.description;

    result.c = [];
    for (let leaf of internal.runnableNode.children)
      result.c.push(leaf.getLogTree());

    return result;
  };

  internal.resolve(internal.runnableNode);
};

let awaitOrCollectAllErrors = promises => new Promise(
    function(resolve, reject) {
  Promise.all(promises).then(function(value) { resolve(value); },
    function(anError) {
      Promise.all(getListOfErrorPromises(promises)).then(
          rejectWithOrderedListOfErrors(reject));
    });
});

let getListOfErrorPromises = function(promises) {
  let errorPromises = [];

  for (let promise of promises) {
    errorPromises.push(new Promise(function(alwaysSucceed) {
      promise.then(function(value) {
        alwaysSucceed(null);

      }, function(error) {
        alwaysSucceed(error);
      });
    }));
  }

  return errorPromises;
};

let rejectWithOrderedListOfErrors = function(rejectMethod) {
  return function(errorValues) {
    let allErrors = [];

    for (let errorValue of errorValues) {
      if (errorValue !== null)
        allErrors.push(errorValue);
    }

    rejectMethod(allErrors);
  };
};

let newAddressedLogFunction = (address, logger) =>
  (code, message) => new Promise((resolve, reject) => {
    let fullMessage = [Date.now(), code].concat(address);
    fullMessage.push(message || "");

    Promise.resolve(logger.log(fullMessage)).then(value => {
      resolve(value);
    }, passError(reject));
});

let passError = function(reject) {
  return function(error) {
    reject(error);
  };
};

let runAndWait = function(thingToRun) {
  try {
    return Promise.resolve(thingToRun());

  } catch (error) {
    return Promise.reject(error);
  }
};

module.exports = processTree;
<|endoftext|>


<commit_before>/**
 * @file Puzzle piece - methods to handle pieces
 * @author StefanoMagrassi <stefano.magrassi@gmail.com>
 */

// Imports
// -------
import dom from './dom';
import _filter from 'lodash/filter';

// Exports
// -------
export default {
  element  : element,
  addTo    : addTo,
  onCell   : onCell,
  list     : list,
  removeAll: removeAll
};

// Constants
// ---------
/**
 * @constant {string} ELEMENT_TYPE - Puzzle piece html element type
 * @public
 */
export const ELEMENT_TYPE = 'span';
/**
 * @constant {string} CSS_CLASS - Puzzle piece css class
 * @public
 */
export const CSS_CLASS = 'img-puzzle_piece';

// Public methods
// --------------
/**
 * Creates a new puzzle piece as html element.
 * @public
 * @param  {object} cell - Cell object
 * @param  {object} item - Item object
 * @param  {string} src  - Source of puzzle's image
 * @return {HTMLElement} Puzzle piece as html element
 */
function element(cell, item, src) {
  let piece = document.createElement(ELEMENT_TYPE);

  piece.className                = CSS_CLASS;
  piece.style.width              = cell.width + 'px';
  piece.style.height             = cell.height + 'px';
  piece.style.backgroundImage    = `url("${src}")`;
  piece.style.backgroundPosition = `${item.bgX}px ${item.bgY}px`;

  return piece;
}

/**
 * Moves piece on cell.
 * @public
 * @param  {HTMLElement} piece - Piece html element
 * @param  {object}      cell  - Cell object
 * @return {HTMLElement} Piece html element
 */
function onCell(piece, cell) {
  piece.style.left = cell.x + 'px';
  piece.style.top  = cell.y + 'px';

  return piece;
}

/**
* Adds puzzle piece to image.
* @public
* @param  {HTMLImageElement} image - Puzzle image element
* @param  {HTMLElement}      piece - Piece html element
* @return {HTMLElement} Piece html element
*/
function addTo(image, piece) {
  return dom.parent(image).appendChild(piece);
}

/**
 * Gets all puzzle pieces in container.
 * @public
 * @param  {HTMLElement} container - Container html element
 * @return {array} Collection of html element
 */
function list(container) {
  return _filter(dom.siblings(container), (element) => dom.hasClass(element, CSS_CLASS));
}

/**
 * Removes all puzzle pieces in container.
 * @public
 * @param  {HTMLElement} container - Container html element
 * @return {undefined}
 */
function removeAll(container) {
  return list(container).forEach(item => dom.remove(item));
}
<commit_msg>puzzle-piece with ramda<commit_after>/**
 * @file Puzzle piece - methods to handle pieces
 * @author StefanoMagrassi <stefano.magrassi@gmail.com>
 */

// Imports
// -------
import dom from './dom';
import R from 'ramda';

// Exports
// -------
export default {
  element  : element,
  addTo    : addTo,
  onCell   : onCell,
  list     : list,
  removeAll: removeAll
};

// Constants
// ---------
/**
 * @constant {string} ELEMENT_TYPE - Puzzle piece html element type
 * @public
 */
export const ELEMENT_TYPE = 'span';
/**
 * @constant {string} CSS_CLASS - Puzzle piece css class
 * @public
 */
export const CSS_CLASS = 'img-puzzle_piece';

// Public methods
// --------------
/**
 * Creates a new puzzle piece as html element.
 * @public
 * @param  {object} cell - Cell object
 * @param  {object} item - Item object
 * @param  {string} src  - Source of puzzle's image
 * @return {HTMLElement} Puzzle piece as html element
 */
function element(cell, item, src) {
  let piece = document.createElement(ELEMENT_TYPE);

  piece.className                = CSS_CLASS;
  piece.style.width              = cell.width + 'px';
  piece.style.height             = cell.height + 'px';
  piece.style.backgroundImage    = `url("${src}")`;
  piece.style.backgroundPosition = `${item.bgX}px ${item.bgY}px`;

  return piece;
}

/**
 * Moves piece on cell.
 * @public
 * @param  {HTMLElement} piece - Piece html element
 * @param  {object}      cell  - Cell object
 * @return {HTMLElement} Piece html element
 */
function onCell(piece, cell) {
  piece.style.left = cell.x + 'px';
  piece.style.top  = cell.y + 'px';

  return piece;
}

/**
* Adds puzzle piece to image.
* @public
* @param  {HTMLImageElement} image - Puzzle image element
* @param  {HTMLElement}      piece - Piece html element
* @return {HTMLElement} Piece html element
*/
function addTo(image, piece) {
  return dom.parent(image).appendChild(piece);
}

/**
 * Gets all puzzle pieces in container.
 * @public
 * @param  {HTMLElement} container - Container html element
 * @return {array} Collection of html element
 */
function list(container) {
  return R.filter(isPiece, dom.siblings(container));
}

/**
 * Removes all puzzle pieces in container.
 * @public
 * @param  {HTMLElement} container - Container html element
 * @return {undefined}
 */
function removeAll(container) {
  return list(container).forEach(item => dom.remove(item));
}

// Private methods
// ---------------
/**
 * Checks if element is a piece.
 * @param  {HTMLElement}  element - Html element
 * @return {boolean} True if element has piece class
 */
function isPiece(element) {
  return dom.hasClass(element, CSS_CLASS);
}
<|endoftext|>


<commit_before>if (typeof(socket) == 'undefined') socket = {};
(function (socket) {
  var ws = null,
    protocol = 1;

  socket.onopen = null;
  socket.onclose = null;
  socket.onconnecting = null;
  socket.onupdatenodes = null;
  socket.onupdateposition = null;
  socket.onclearnodes = null;
  socket.ondrawline = null;
  socket.onaddnode = null;
  socket.onupdateleaderboard = null;
  socket.onsetborder = null;
  socket.onchatmessage = null;

  socket.event = {
    // events that can be used with socket.sendEvent
    spectate: 1,
    pressSpace: 17,
    pressQ: 18,
    releaseQ: 19,
    pressW: 21
  };

  socket.connect = function (url) {
    if (ws) {
      ws.onopen = null;
      ws.onmessage = null;
      ws.onclose = null;
      try {
        ws.close()
      } catch (e) {
      }
      ws = null;
    }
    if (!config.secure && url.slice(0, 'ws://'.length) != 'ws://') {
      url = 'ws://' + url;
    } else if (config.secure && url.slice(0, 'wss://'.length) != 'wss://') {
      url = 'wss://' + url;
    }
    if (this.onconnecting) {
      this.onconnecting();
    }
    tools.logging.log('Connecting to ' + url);
    ws = new WebSocket(url);
    ws.binaryType = 'arraybuffer';
    ws.onopen = openHandler;
    ws.onmessage = messageHandler;
    ws.onclose = closeHandler;
    ws.onerror = function () {
      tools.logging.err('Socket error');
    }
  };

  socket.isOpen = function () {
    return socket.ws != null && socket.ws.readyState == WebSocket.OPEN;
  };

  function openHandler() {
    var buffer = new ArrayBuffer(5),
      view = new DataView(buffer);
    view.setUint8(0, 254);
    view.setUint32(1, protocol, true);
    ws.send(buffer);
    buffer = new ArrayBuffer(5);
    view = new DataView(buffer);
    view.setUint8(0, 254);
    view.setUint32(1, 1332175218, true);
    ws.send(buffer);
    if (socket.onopen) {
      socket.onopen();
    }
  }

  function messageHandler(msg) {
    var view = new DataView(msg);
    var offset = 0;
    if (msg.getUint8(offset) == 240) {
      offset += 5;
    }
    switch (msg.getUint8(offset++)) {
      case 16: // update nodes
        updateNodes(msg, offset);
        break;
      case 17: // update position
        updatePosition(msg, offset);
        break;
      case 20: // clear nodes
        if (socket.onclearnodes) {
          socket.onclearnodes();
        }
        break;
      case 21: // draw line
        drawLine(msg, offset);
        break;
      case 32: // add node
        addNode(msg, offset);
        break;
      case 48: // update leaderboard (custom text)
        updateLB(msg, offset, 48);
        break;
      case 49: // update leaderboard (ffa)
        updateLB(msg, offset, 49);
        break;
      case 50: // update leaderboard (teams)
        updateLB(msg, offset, 50);
        break;
      case 64: // set border
        setBorder(msg, offset);
        break;
      case 99: // add chat message
        addChatMsg(msg, offset);
        break;
    }
  }

  function closeHandler() {
    tools.logging.log('Socket closed');
    if (socket.onclose) {
      socket.onclose();
    }
  }

  function updateNodes(msg, offset) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onupdatenodes) {
      var ret = {},
        queueLength = 0,
        nodeid;
      ret.timestamp = +new Date;
      queueLength = msg.getUint16(offset, true);
      offset += 2;
      ret.kills = [];
      for (var i = 0; i < queueLength; i++) {
        var tmp = {};
        tmp.killer = msg.getUint32(offset, true);
        tmp.nodeId = msg.getUint32(offset + 4, true);
        ret.kills.push(tmp);
        offset += 8;
      }
      ret.updates = [];
      while ((nodeid = msg.getUint32(offset, true)) != 0) {
        offset += 4;
        var tmp = {},
          char;
        tmp.nodeId = nodeid;
        tmp.position = {};
        tmp.position.x = msg.getUint16(offset, true);
        tmp.position.y = msg.getUint16(offset + 2, true);
        tmp.size = msg.getUint16(offset + 4, true);
        offset += 6;
        tmp.color = {};
        tmp.color.r = msg.getUint8(offset++);
        tmp.color.g = msg.getUint8(offset++);
        tmp.color.b = msg.getUint8(offset++);
        tmp.flags = msg.getUint8(offset++);
        if (tmp.flags & 2) {
          offset += 4;
        }
        if (tmp.flags & 4) {
          offset += 8;
        }
        if (tmp.flags & 8) {
          offset += 16;
        }
        tmp.isVirus = !!(tmp.flags & 1);
        tmp.isAgitated = !!(tmp.flags & 16);
        tmp.name = getString();
        ret.updates.push(tmp);
      }
      queueLength = msg.getUint32(offset + 4, true);
      offset += 8;
      ret.remove = [];
      for (var i = 0; i < queueLength; i++) {
        ret.remove.push(msg.getUint32(offset, true));
        offset += 4;
      }
      socket.onupdatenodes(ret);
    }
  }

  function updatePosition(msg, offset) {
    if (socket.onupdateposition) {
      var ret = {};
      ret.x = msg.getFloat32(offset, true);
      ret.y = msg.getFloat32(offset + 4, true);
      ret.size = msg.getFloat32(offset + 8, true);
      socket.onupdateposition(ret);
    }
  }

  function drawLine(msg, offset) {
    if (socket.ondrawline) {
      var ret = {};
      ret.x = msg.getInt16(offset, true);
      ret.y = msg.getInt16(offset + 2, true);
      socket.ondrawline(ret);
    }
  }

  function addNode(msg, offset) {
    if (socket.onaddnode) {
      var ret = {};
      ret.id = msg.getUint32(offset, true);
      socket.onaddnode(ret);
    }
  }

  function updateLB(msg, offset, type) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onupdateleaderboard) {
      var ret = {};
      ret.lb = [];
      ret.count = msg.getUint32(offset, true);
      offset += 4;
      if (type == 50) {
        ret.type = 'teams';
        for (var i = 0; i < ret.count; i++) {
          ret.lb.push(msg.getFloat32(offset, true));
          offset += 4;
        }
      } else {
        if (type == 48) {
          ret.type = 'custom';
        } else {
          ret.type = 'ffa';
        }
        for (var i = 0; i < ret.count; i++) {
          var nodeId = msg.getUint32(offset, true);
          offset += 4;
          ret.lb.push({id: nodeId, name: getString()});
        }
      }
      socket.onupdateleaderboard(ret);
    }
  }

  function setBorder(msg, offset) {
    if (socket.onsetborder) {
      var ret = {};
      ret.left = msg.getFloat64(offset, true);
      ret.top = msg.getFloat64(offset + 8, true);
      ret.right = msg.getFloat64(offset + 16, true);
      ret.bottom = msg.getFloat64(offset + 24, true);
      socket.onsetborder(ret);
    }
  }

  function addChatMsg(msg, offset) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onchatmessage) {
      var ret = {},
        flags = msg.getUint8(offset++);
      if (ret.flags & 2) {
        offset += 4;
      }
      if (ret.flags & 4) {
        offset += 8;
      }
      if (ret.flags & 8) {
        offset += 16;
      }
      ret.color = {};
      ret.color.r = msg.getUint8(offset++);
      ret.color.g = msg.getUint8(offset++);
      ret.color.b = msg.getUint8(offset++);
      ret.name = getString();
      ret.message = getString();
      socket.onchatmessage(ret);
    }
  }

  socket.sendEvent = function (value) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(1),
        view = new DataView(buffer);
      view.setUint8(0, value);
      ws.send(buffer);
    }
  };

  socket.sendMouse = function (x, y) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(21),
        view = new DataView(buffer);
      view.setUint8(0, 16);
      view.setFloat64(1, x, !0);
      view.setFloat64(9, y, !0);
      view.setUint32(17, 0, !0);
      ws.send(buffer);
    }
  };

  socket.sendName = function (name) {
    if (this.isOpen() && name != null) {
      var buffer = new ArrayBuffer(1 + 2 * name.length),
        view = new DataView(buffer);
      view.setUint8(0, 0);
      for (var i = 0; i < name.length; i++) {
        view.setUint16(1 + 2 * i, name.charCodeAt(i), false);
      }
      ws.send(buffer);
    }
  };

  socket.sendChatMessage = function (message, flags) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(2 + 2 * message.length),
        view = new DataView(buffer),
        offset = 0;
      view.setUint8(offset++, 99);
      if (!flags) {
        flags = 0;
      }
      view.setUint8(offset++, flags & 241); // make sure bits 2, 4, 8 don't get set
      for (var i = 0; i < message.length; i++) {
        view.setUint16(1 + 2 * i, message.charCodeAt(i), false);
      }
      ws.send(buffer);
    }
  }
}(socket));<commit_msg>More bugs...<commit_after>if (typeof(socket) == 'undefined') socket = {};
(function (socket) {
  var ws = null,
    protocol = 1;

  socket.onopen = null;
  socket.onclose = null;
  socket.onconnecting = null;
  socket.onupdatenodes = null;
  socket.onupdateposition = null;
  socket.onclearnodes = null;
  socket.ondrawline = null;
  socket.onaddnode = null;
  socket.onupdateleaderboard = null;
  socket.onsetborder = null;
  socket.onchatmessage = null;

  socket.event = {
    // events that can be used with socket.sendEvent
    spectate: 1,
    pressSpace: 17,
    pressQ: 18,
    releaseQ: 19,
    pressW: 21
  };

  socket.connect = function (url) {
    if (ws) {
      ws.onopen = null;
      ws.onmessage = null;
      ws.onclose = null;
      try {
        ws.close()
      } catch (e) {
      }
      ws = null;
    }
    if (!config.secure && url.slice(0, 'ws://'.length) != 'ws://') {
      url = 'ws://' + url;
    } else if (config.secure && url.slice(0, 'wss://'.length) != 'wss://') {
      url = 'wss://' + url;
    }
    if (this.onconnecting) {
      this.onconnecting();
    }
    tools.logging.log('Connecting to ' + url);
    ws = new WebSocket(url);
    ws.binaryType = 'arraybuffer';
    ws.onopen = openHandler;
    ws.onmessage = messageHandler;
    ws.onclose = closeHandler;
    ws.onerror = function () {
      tools.logging.err('Socket error');
    }
  };

  socket.isOpen = function () {
    return socket.ws != null && socket.ws.readyState == WebSocket.OPEN;
  };

  function openHandler() {
    var buffer = new ArrayBuffer(5),
      view = new DataView(buffer);
    view.setUint8(0, 254);
    view.setUint32(1, protocol, true);
    ws.send(buffer);
    buffer = new ArrayBuffer(5);
    view = new DataView(buffer);
    view.setUint8(0, 254);
    view.setUint32(1, 1332175218, true);
    ws.send(buffer);
    if (socket.onopen) {
      socket.onopen();
    }
  }

  function messageHandler(msg) {
    var view = new DataView(msg.data);
    var offset = 0;
    if (msg.getUint8(offset) == 240) {
      offset += 5;
    }
    switch (msg.getUint8(offset++)) {
      case 16: // update nodes
        updateNodes(msg, offset);
        break;
      case 17: // update position
        updatePosition(msg, offset);
        break;
      case 20: // clear nodes
        if (socket.onclearnodes) {
          socket.onclearnodes();
        }
        break;
      case 21: // draw line
        drawLine(msg, offset);
        break;
      case 32: // add node
        addNode(msg, offset);
        break;
      case 48: // update leaderboard (custom text)
        updateLB(msg, offset, 48);
        break;
      case 49: // update leaderboard (ffa)
        updateLB(msg, offset, 49);
        break;
      case 50: // update leaderboard (teams)
        updateLB(msg, offset, 50);
        break;
      case 64: // set border
        setBorder(msg, offset);
        break;
      case 99: // add chat message
        addChatMsg(msg, offset);
        break;
    }
  }

  function closeHandler() {
    tools.logging.log('Socket closed');
    if (socket.onclose) {
      socket.onclose();
    }
  }

  function updateNodes(msg, offset) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onupdatenodes) {
      var ret = {},
        queueLength = 0,
        nodeid;
      ret.timestamp = +new Date;
      queueLength = msg.getUint16(offset, true);
      offset += 2;
      ret.kills = [];
      for (var i = 0; i < queueLength; i++) {
        var tmp = {};
        tmp.killer = msg.getUint32(offset, true);
        tmp.nodeId = msg.getUint32(offset + 4, true);
        ret.kills.push(tmp);
        offset += 8;
      }
      ret.updates = [];
      while ((nodeid = msg.getUint32(offset, true)) != 0) {
        offset += 4;
        var tmp = {},
          char;
        tmp.nodeId = nodeid;
        tmp.position = {};
        tmp.position.x = msg.getUint16(offset, true);
        tmp.position.y = msg.getUint16(offset + 2, true);
        tmp.size = msg.getUint16(offset + 4, true);
        offset += 6;
        tmp.color = {};
        tmp.color.r = msg.getUint8(offset++);
        tmp.color.g = msg.getUint8(offset++);
        tmp.color.b = msg.getUint8(offset++);
        tmp.flags = msg.getUint8(offset++);
        if (tmp.flags & 2) {
          offset += 4;
        }
        if (tmp.flags & 4) {
          offset += 8;
        }
        if (tmp.flags & 8) {
          offset += 16;
        }
        tmp.isVirus = !!(tmp.flags & 1);
        tmp.isAgitated = !!(tmp.flags & 16);
        tmp.name = getString();
        ret.updates.push(tmp);
      }
      queueLength = msg.getUint32(offset + 4, true);
      offset += 8;
      ret.remove = [];
      for (var i = 0; i < queueLength; i++) {
        ret.remove.push(msg.getUint32(offset, true));
        offset += 4;
      }
      socket.onupdatenodes(ret);
    }
  }

  function updatePosition(msg, offset) {
    if (socket.onupdateposition) {
      var ret = {};
      ret.x = msg.getFloat32(offset, true);
      ret.y = msg.getFloat32(offset + 4, true);
      ret.size = msg.getFloat32(offset + 8, true);
      socket.onupdateposition(ret);
    }
  }

  function drawLine(msg, offset) {
    if (socket.ondrawline) {
      var ret = {};
      ret.x = msg.getInt16(offset, true);
      ret.y = msg.getInt16(offset + 2, true);
      socket.ondrawline(ret);
    }
  }

  function addNode(msg, offset) {
    if (socket.onaddnode) {
      var ret = {};
      ret.id = msg.getUint32(offset, true);
      socket.onaddnode(ret);
    }
  }

  function updateLB(msg, offset, type) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onupdateleaderboard) {
      var ret = {};
      ret.lb = [];
      ret.count = msg.getUint32(offset, true);
      offset += 4;
      if (type == 50) {
        ret.type = 'teams';
        for (var i = 0; i < ret.count; i++) {
          ret.lb.push(msg.getFloat32(offset, true));
          offset += 4;
        }
      } else {
        if (type == 48) {
          ret.type = 'custom';
        } else {
          ret.type = 'ffa';
        }
        for (var i = 0; i < ret.count; i++) {
          var nodeId = msg.getUint32(offset, true);
          offset += 4;
          ret.lb.push({id: nodeId, name: getString()});
        }
      }
      socket.onupdateleaderboard(ret);
    }
  }

  function setBorder(msg, offset) {
    if (socket.onsetborder) {
      var ret = {};
      ret.left = msg.getFloat64(offset, true);
      ret.top = msg.getFloat64(offset + 8, true);
      ret.right = msg.getFloat64(offset + 16, true);
      ret.bottom = msg.getFloat64(offset + 24, true);
      socket.onsetborder(ret);
    }
  }

  function addChatMsg(msg, offset) {
    function getString() {
      var text = '',
        char;
      while ((char = msg.getUint16(offset, true)) != 0) {
        offset += 2;
        text += String.fromCharCode(char);
      }
      offset += 2;
      return text;
    }

    if (socket.onchatmessage) {
      var ret = {},
        flags = msg.getUint8(offset++);
      if (ret.flags & 2) {
        offset += 4;
      }
      if (ret.flags & 4) {
        offset += 8;
      }
      if (ret.flags & 8) {
        offset += 16;
      }
      ret.color = {};
      ret.color.r = msg.getUint8(offset++);
      ret.color.g = msg.getUint8(offset++);
      ret.color.b = msg.getUint8(offset++);
      ret.name = getString();
      ret.message = getString();
      socket.onchatmessage(ret);
    }
  }

  socket.sendEvent = function (value) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(1),
        view = new DataView(buffer);
      view.setUint8(0, value);
      ws.send(buffer);
    }
  };

  socket.sendMouse = function (x, y) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(21),
        view = new DataView(buffer);
      view.setUint8(0, 16);
      view.setFloat64(1, x, !0);
      view.setFloat64(9, y, !0);
      view.setUint32(17, 0, !0);
      ws.send(buffer);
    }
  };

  socket.sendName = function (name) {
    if (this.isOpen() && name != null) {
      var buffer = new ArrayBuffer(1 + 2 * name.length),
        view = new DataView(buffer);
      view.setUint8(0, 0);
      for (var i = 0; i < name.length; i++) {
        view.setUint16(1 + 2 * i, name.charCodeAt(i), false);
      }
      ws.send(buffer);
    }
  };

  socket.sendChatMessage = function (message, flags) {
    if (this.isOpen()) {
      var buffer = new ArrayBuffer(2 + 2 * message.length),
        view = new DataView(buffer),
        offset = 0;
      view.setUint8(offset++, 99);
      if (!flags) {
        flags = 0;
      }
      view.setUint8(offset++, flags & 241); // make sure bits 2, 4, 8 don't get set
      for (var i = 0; i < message.length; i++) {
        view.setUint16(1 + 2 * i, message.charCodeAt(i), false);
      }
      ws.send(buffer);
    }
  }
}(socket));<|endoftext|>


<commit_before>"use strict";

var jsdom   = require('jsdom'),
    request = require('request'),
    is      = require('check-types'),
    config  = require('../config.json');

const DEFAULT_TITLE_TAG =

exports.convert = function (url, params, cb) {
  const self                 = this;

  params.title = params.title || {}

  self.cbPresent       = is.function(cb);
  self.articleSelector = params.articleQuery || 'article';
  self.tagsToInclude   = (is.array(params.tagQueries) && params.tagQueries.lenght > 0) ? params.tagQueries : ['p','img'];
  self.title           = {
    textOnly: params.title.textOnly || true,
    query:    params.title.query || (function () {
      let resStr = [];
      for(let i = 1; i < 7; i++) {
        resStr.push(`${self.articleSelector} h${i}:first`);
      }
      return resStr.join(', ');
    }())
  }

  self.tagsQuery = function () {
    let resultStrings = [];

    for(let i = 0; i < self.tagsToInclude.length; i++) {
      resultStrings.push(`${self.articleSelector} ${self.tagsToInclude[i]}`);
    }
    return resultStrings.join(', ')
  }

  request({ uri: url }, function (error, response, body) {

  if (error && response.statusCode !== 200) {
    cb(err, null);
  }

  jsdom.env({
    html: body,
    scripts: [
      config.jqueryUrl
    ],
    done: function (err, window) {
        if (is.assigned(err) && self.cbPresent) {
          cb(err, null);
        } else {
          let $     = window.jQuery,
              res   = "",
              title = (function () {
                let element = $(self.title.query).first();
                return (self.title.textOnly ? $('h2').html(element.text()) : element)[0].outerHTML;
              }())

          res += title;

          $(self.tagsQuery()).each(function (i, el) {
            res += el.outerHTML;
          });
          if(self.cbPresent) { cb(undefined, res); };
        }
      }
    });
  });
}
<commit_msg>Added tag to wrap for title that binds only text<commit_after>"use strict";

var jsdom   = require('jsdom'),
    request = require('request'),
    is      = require('check-types'),
    config  = require('../config.json');

const DEFAULT_TITLE_TAG =

exports.convert = function (url, params, cb) {
  const self                 = this;

  params.title = params.title || {}

  self.cbPresent       = is.function(cb);
  self.articleSelector = params.articleQuery || 'article';
  self.tagsToInclude   = (is.array(params.tagQueries) && params.tagQueries.lenght > 0) ? params.tagQueries : ['p','img'];
  self.title           = {
    textOnly:   params.title.textOnly   || true,
    tagToWrap:  params.title.tagToWrap  || 'h2',
    query:      params.title.query      || (function () {
      let resStr = [];
      for(let i = 1; i < 7; i++) {
        resStr.push(`${self.articleSelector} h${i}:first`);
      }
      return resStr.join(', ');
    }())
  }

  self.tagsQuery = function () {
    let resultStrings = [];

    for(let i = 0; i < self.tagsToInclude.length; i++) {
      resultStrings.push(`${self.articleSelector} ${self.tagsToInclude[i]}`);
    }
    return resultStrings.join(', ')
  }

  request({ uri: url }, function (error, response, body) {

  if (error && response.statusCode !== 200) {
    cb(err, null);
  }

  jsdom.env({
    html: body,
    scripts: [
      config.jqueryUrl
    ],
    done: function (err, window) {
        if (is.assigned(err) && self.cbPresent) {
          cb(err, null);
        } else {
          let $     = window.jQuery,
              res   = "",
              title = (function () {
                let element = $(self.title.query).first();
                return (self.title.textOnly ? $(self.title.tagToWrap).html(element.text()) : element)[0].outerHTML;
              }())

          res += title;

          $(self.tagsQuery()).each(function (i, el) {
            res += el.outerHTML;
          });
          if(self.cbPresent) { cb(undefined, res); };
        }
      }
    });
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
import '../../server/env';

import { ArgumentParser } from 'argparse';
import { get, intersection } from 'lodash';

import { MODERATION_CATEGORIES_ALIASES } from '../../server/constants/moderation-categories';
import orderStatus from '../../server/constants/order_status';
import { purgeCacheForCollective } from '../../server/lib/cache';
import logger from '../../server/lib/logger';
import { notifyAdminsOfCollective } from '../../server/lib/notifications';
import * as libPayments from '../../server/lib/payments';
import models, { Op, sequelize } from '../../server/models';

// Fetch all orders potentially affected: contributor flagged AND recipient setup rejection

const query = `SELECT "Orders"."id"
  FROM "Orders", "Collectives", "Collectives" as "FromCollectives"
  WHERE "Orders"."CollectiveId" = "Collectives"."id" AND "FromCollectives"."id" = "Orders"."FromCollectiveId"
  AND "Orders"."status" = 'ACTIVE'
  AND "Collectives"."settings"->'moderation'->'rejectedCategories' IS NOT NULL
  AND "FromCollectives"."data"->'categories' IS NOT NULL`;

const getContributorRejectedCategories = (fromCollective, collective) => {
  const rejectedCategories = get(collective, 'settings.moderation.rejectedCategories', []);
  const contributorCategories = get(fromCollective, 'data.categories', []);

  if (rejectedCategories.length === 0 || contributorCategories.length === 0) {
    return [];
  }

  // Example:
  // MODERATION_CATEGORIES_ALIASES = ['CASINO_GAMBLING': ['casino', 'gambling'], 'VPN_PROXY': ['vpn', 'proxy']]
  // - when contributorCategories = ['CASINO_GAMBLING'], returns ['CASINO_GAMBLING']
  // - when contributorCategories = ['vpn'] or ['proxy'], returns ['VPN_PROXY']
  const contributorRejectedCategories = Object.keys(MODERATION_CATEGORIES_ALIASES).filter(key => {
    return (
      contributorCategories.includes(key) ||
      intersection(MODERATION_CATEGORIES_ALIASES[key], contributorCategories).length !== 0
    );
  });

  return intersection(rejectedCategories, contributorRejectedCategories);
};

async function run({ dryRun, limit } = {}) {
  let rows = await sequelize.query(query, { type: sequelize.QueryTypes.SELECT });

  if (rows.length > 0 && limit) {
    rows = rows.slice(0, limit);
  }

  for (const row of rows) {
    const order = await models.Order.findByPk(row['id']);
    const collective = await models.Collective.findByPk(order.CollectiveId);
    const fromCollective = await models.Collective.findByPk(order.FromCollectiveId);

    logger.info(`Checking order #${order.id} from #${fromCollective.slug} to #${collective.slug}`);

    const rejectedCategories = getContributorRejectedCategories(fromCollective, collective);

    if (rejectedCategories.length === 0) {
      logger.info(`  - No rejected categories`);
      continue;
    }

    logger.info(`  - Found rejected categories: ${rejectedCategories.join(', ')}`);

    // Retrieve latest transaction
    const transaction = await models.Transaction.findOne({
      where: {
        OrderId: order.id,
        type: 'CREDIT',
        createdAt: { [Op.gte]: sequelize.literal("NOW() - INTERVAL '30 days'") },
      },
      order: [['createdAt', 'DESC']],
    });

    if (transaction) {
      logger.info(`  - Found transaction #${transaction.id}`);
      // Refund transaction if not already refunded
      if (!transaction.RefundTransactionId) {
        logger.info(`  - Refunding transaction`);
        if (!dryRun) {
          try {
            await libPayments.refundTransaction(transaction);
          } catch (e) {
            if (e.message.includes('has already been refunded')) {
              logger.info(`  - Transaction has already been refunded on Payment Provider`);
              const paymentMethodProvider = libPayments.findPaymentMethodProvider(transaction.PaymentMethod);
              if (paymentMethodProvider && paymentMethodProvider.refundTransactionOnlyInDatabase) {
                await paymentMethodProvider.refundTransactionOnlyInDatabase(transaction);
              }
            }
          }
        }
      } else {
        logger.info(`  - Transaction already refunded`);
      }
    } else {
      logger.info(`  - No transaction found`);
    }

    // Mark the Order as rejected
    logger.info(`  - Marking order #${order.id} as rejected `);
    if (!dryRun) {
      await order.update({ status: orderStatus.REJECTED });
    }

    // Deactivate subscription

    if (order.SubscriptionId) {
      const subscription = await models.Subscription.findByPk(order.SubscriptionId);
      if (subscription) {
        logger.info(`  - Deactivating subscription #${order.SubscriptionId}`);
        if (!dryRun) {
          await subscription.deactivate();
        }
      } else {
        logger.info(`  - Subscription not found`);
      }
    } else {
      logger.info(`  - No subscription to deactivate`);
    }

    // Remove memberships
    logger.info(`  - Deleting BACKER membership`);
    if (!dryRun) {
      await models.Member.destroy({
        where: {
          MemberCollectiveId: fromCollective.id,
          CollectiveId: collective.id,
          role: 'BACKER',
        },
      });
    }

    logger.info(`  - Purging cache for ${collective.slug}`);
    logger.info(`  - Purging cache for ${fromCollective.slug}`);
    if (!dryRun) {
      purgeCacheForCollective(collective.slug);
      purgeCacheForCollective(fromCollective.slug);
    }

    const activity = {
      type: 'contribution.rejected',
      data: {
        collective: { name: collective.name },
        rejectionReason: `${collective.name} banned some specific categories of contributors and there was a match with your profile.`,
      },
    };

    logger.info(`  - Notifying admins of ${fromCollective.slug}`);
    if (!dryRun) {
      await notifyAdminsOfCollective(fromCollective.id, activity);
    }
  }
}

/* eslint-disable camelcase */
function parseCommandLineArguments() {
  const parser = new ArgumentParser({
    add_help: true,
    description: 'Reject Contributions based on Categories',
  });
  parser.add_argument('--dryrun', {
    help: "Don't perform any change, just log.",
    default: false,
    action: 'store_const',
    const: true,
  });
  parser.add_argument('-l', '--limit', {
    help: 'Total matching orders to process',
  });
  const args = parser.parse_args();
  return {
    dryRun: args.dryrun,
    limit: args.limit,
  };
}

/* eslint-enable camelcase */

if (require.main === module) {
  run(parseCommandLineArguments())
    .then(() => {
      process.exit(0);
    })
    .catch(e => {
      console.error(e);
      process.exit(1);
    });
}
<commit_msg>ability to force refunds in reject-contributions<commit_after>#!/usr/bin/env node
import '../../server/env';

import { ArgumentParser } from 'argparse';
import { get, intersection } from 'lodash';

import { MODERATION_CATEGORIES_ALIASES } from '../../server/constants/moderation-categories';
import orderStatus from '../../server/constants/order_status';
import { purgeCacheForCollective } from '../../server/lib/cache';
import logger from '../../server/lib/logger';
import { notifyAdminsOfCollective } from '../../server/lib/notifications';
import * as libPayments from '../../server/lib/payments';
import models, { Op, sequelize } from '../../server/models';

// Fetch all orders potentially affected: contributor flagged AND recipient setup rejection

const query = `SELECT "Orders"."id"
  FROM "Orders", "Collectives", "Collectives" as "FromCollectives"
  WHERE "Orders"."CollectiveId" = "Collectives"."id" AND "FromCollectives"."id" = "Orders"."FromCollectiveId"
  AND "Orders"."status" = 'ACTIVE'
  AND "Collectives"."settings"->'moderation'->'rejectedCategories' IS NOT NULL
  AND "FromCollectives"."data"->'categories' IS NOT NULL`;

const getContributorRejectedCategories = (fromCollective, collective) => {
  const rejectedCategories = get(collective, 'settings.moderation.rejectedCategories', []);
  const contributorCategories = get(fromCollective, 'data.categories', []);

  if (rejectedCategories.length === 0 || contributorCategories.length === 0) {
    return [];
  }

  // Example:
  // MODERATION_CATEGORIES_ALIASES = ['CASINO_GAMBLING': ['casino', 'gambling'], 'VPN_PROXY': ['vpn', 'proxy']]
  // - when contributorCategories = ['CASINO_GAMBLING'], returns ['CASINO_GAMBLING']
  // - when contributorCategories = ['vpn'] or ['proxy'], returns ['VPN_PROXY']
  const contributorRejectedCategories = Object.keys(MODERATION_CATEGORIES_ALIASES).filter(key => {
    return (
      contributorCategories.includes(key) ||
      intersection(MODERATION_CATEGORIES_ALIASES[key], contributorCategories).length !== 0
    );
  });

  return intersection(rejectedCategories, contributorRejectedCategories);
};

async function run({ dryRun, limit, force } = {}) {
  let rows = await sequelize.query(query, { type: sequelize.QueryTypes.SELECT });

  if (rows.length > 0 && limit) {
    rows = rows.slice(0, limit);
  }

  for (const row of rows) {
    const order = await models.Order.findByPk(row['id']);
    const collective = await models.Collective.findByPk(order.CollectiveId);
    const fromCollective = await models.Collective.findByPk(order.FromCollectiveId);

    logger.info(`Checking order #${order.id} from #${fromCollective.slug} to #${collective.slug}`);

    const rejectedCategories = getContributorRejectedCategories(fromCollective, collective);

    if (rejectedCategories.length === 0) {
      logger.info(`  - No rejected categories`);
      continue;
    }

    logger.info(`  - Found rejected categories: ${rejectedCategories.join(', ')}`);

    // Retrieve latest transaction
    const transaction = await models.Transaction.findOne({
      where: {
        OrderId: order.id,
        type: 'CREDIT',
        createdAt: { [Op.gte]: sequelize.literal("NOW() - INTERVAL '30 days'") },
      },
      order: [['createdAt', 'DESC']],
    });

    if (transaction) {
      logger.info(`  - Found transaction #${transaction.id}`);
      // Refund transaction if not already refunded
      if (!transaction.RefundTransactionId) {
        logger.info(`  - Refunding transaction`);
        if (!libPayments.refundTransaction) {
          if (force) {
            logger.info(`  - refundTransaction not available. Creating refundTransaction in the database only.`);
          } else {
            logger.info(`  - refundTransaction not available. Use 'force' to refundTransaction in the database only.`);
          }
        }
        if (!dryRun) {
          try {
            if (libPayments.refundTransaction) {
              await libPayments.refundTransaction(transaction);
            } else if (force) {
              await libPayments.createRefundTransaction(transaction, 0, null);
            }
          } catch (e) {
            if (e.message.includes('has already been refunded')) {
              logger.info(`  - Transaction has already been refunded on Payment Provider`);
              const paymentMethodProvider = libPayments.findPaymentMethodProvider(transaction.PaymentMethod);
              if (paymentMethodProvider && paymentMethodProvider.refundTransactionOnlyInDatabase) {
                await paymentMethodProvider.refundTransactionOnlyInDatabase(transaction);
              }
            }
          }
        }
      } else {
        logger.info(`  - Transaction already refunded`);
      }
    } else {
      logger.info(`  - No transaction found`);
    }

    // Mark the Order as rejected
    logger.info(`  - Marking order #${order.id} as rejected `);
    if (!dryRun) {
      await order.update({ status: orderStatus.REJECTED });
    }

    // Deactivate subscription

    if (order.SubscriptionId) {
      const subscription = await models.Subscription.findByPk(order.SubscriptionId);
      if (subscription) {
        logger.info(`  - Deactivating subscription #${order.SubscriptionId}`);
        if (!dryRun) {
          await subscription.deactivate();
        }
      } else {
        logger.info(`  - Subscription not found`);
      }
    } else {
      logger.info(`  - No subscription to deactivate`);
    }

    // Remove memberships
    logger.info(`  - Deleting BACKER membership`);
    if (!dryRun) {
      await models.Member.destroy({
        where: {
          MemberCollectiveId: fromCollective.id,
          CollectiveId: collective.id,
          role: 'BACKER',
        },
      });
    }

    logger.info(`  - Purging cache for ${collective.slug}`);
    logger.info(`  - Purging cache for ${fromCollective.slug}`);
    if (!dryRun) {
      purgeCacheForCollective(collective.slug);
      purgeCacheForCollective(fromCollective.slug);
    }

    const activity = {
      type: 'contribution.rejected',
      data: {
        collective: { name: collective.name },
        rejectionReason: `${collective.name} banned some specific categories of contributors and there was a match with your profile.`,
      },
    };

    logger.info(`  - Notifying admins of ${fromCollective.slug}`);
    if (!dryRun) {
      await notifyAdminsOfCollective(fromCollective.id, activity);
    }
  }
}

/* eslint-disable camelcase */
function parseCommandLineArguments() {
  const parser = new ArgumentParser({
    add_help: true,
    description: 'Reject Contributions based on Categories',
  });
  parser.add_argument('--dryrun', {
    help: "Don't perform any change, just log.",
    default: false,
    action: 'store_const',
    const: true,
  });
  parser.add_argument('-l', '--limit', {
    help: 'Total matching orders to process',
  });
  parser.add_argument('--force', {
    help: "Force refunds even if payment provider doesn't support it.",
    default: false,
    action: 'store_const',
    const: true,
  });
  const args = parser.parse_args();
  return {
    dryRun: args.dryrun,
    limit: args.limit,
    force: args.force,
  };
}

/* eslint-enable camelcase */

if (require.main === module) {
  run(parseCommandLineArguments())
    .then(() => {
      process.exit(0);
    })
    .catch(e => {
      console.error(e);
      process.exit(1);
    });
}
<|endoftext|>


<commit_before>'use strict'

module.exports = RedisClient

function RedisClient(client, getTimestamp) {
  this.client = client
  this.getTimestamp = getTimestamp || (() => new Date().getTime())
}

function expectResult(expected, func) {
  return new Promise((resolve, reject) => {
    func((err, result) => err ? reject(err) : resolve(result === expected))
  })
}

RedisClient.prototype.userExists = function(userId) {
  return expectResult(1, done => this.client.exists(userId, done))
}

RedisClient.prototype.findOrCreateUser = function(userId) {
  return this.userExists(userId)
    .then(exists => {
      if (exists) {
        return false
      }
      return expectResult(1, done => this.client.lpush(userId, '', done))
    })
}

RedisClient.prototype.getLink = function(link) {
  return new Promise((resolve, reject) => {
    this.client.hgetall(link, (err, linkData) => {
      if (err) {
        return reject(err)
      } else if (linkData && linkData.clicks) {
        linkData.clicks = parseInt(linkData.clicks)
      }
      resolve(linkData)
    })
  })
}

RedisClient.prototype.getLinks = function() {
  var links = []

  const collectResults = ([cursor, results]) => {
    links.push(...results)
    return (parseInt(cursor) !== 0) ? scan(cursor) : links
  }

  const scan = (start = 0) => {
    return new Promise((resolve, reject) => {
      this.client.scan(start, 'match', '/*', (err, results) => err ?
        reject(err) : resolve(results))
    }).then(collectResults)
  }

  return scan().then((links) => Promise.all(links.map(link =>
      this.getLink(link).then(linkData => {
        linkData.link = link
        return linkData
      }))
  ))
}

RedisClient.prototype.recordAccess = function(link) {
  return new Promise((resolve, reject) => {
    this.client.hincrby(link, 'clicks', 1, err => err ? reject(err) : resolve())
  })
}

RedisClient.prototype.addLinkToOwner = function(owner, link) {
  return new Promise((resolve, reject) => {
    this.client.lpushx(owner, link, (err, result) => {
      err ? reject(err) : resolve(result !== 0)
    })
  })
}

RedisClient.prototype.removeLinkFromOwner = function(owner, link) {
  return expectResult(1, done => this.client.lrem(owner, 1, link, done))
}

RedisClient.prototype.createLink = function(link, target, owner) {
  return new Promise((resolve, reject) => {
    var createdStamp = this.getTimestamp()

    this.client.hsetnx(link, 'owner', owner, (err, result) => {
      if (err) {
        return reject(err)
      } else if (result === 0) {
        return resolve(false)
      }
      this.client.hmset(link,
        'target', target,
        'created', createdStamp,
        'updated', createdStamp,
        'clicks', 0,
        err => {
          if (err) {
            return reject(new Error(link + ' created, ' +
              'but failed to set target, clicks, and timestamps: ' + err))
          }
          resolve(true)
        })
    })
  })
}

RedisClient.prototype.getOwnedLinks = function(owner) {
  return new Promise((resolve, reject) => {
    this.client.lrange(owner, 0, -1, (err, data) => {
      if (err) {
        return reject(err)
      }
      // Since the model is that users are created with the empty string as the
      // first list element, pop that before returning links.
      data.pop()
      resolve(data)
    })
  })
}

RedisClient.prototype.updateProperty = function(link, property, value) {
  return this.getLink(link)
    .then(linkData => {
      if (!linkData) {
        return Promise.resolve(false)
      }
      return expectResult('OK', done => {
        this.client.hmset(link,
          property, value,
          'updated', this.getTimestamp(),
          done)
      })
    })
}

RedisClient.prototype.deleteLink = function(link) {
  return expectResult(1, done => this.client.del(link, done))
}
<commit_msg>Lower the cognitive complexity of the getLinks function<commit_after>'use strict'

module.exports = RedisClient

function RedisClient(client, getTimestamp) {
  this.client = client
  this.getTimestamp = getTimestamp || (() => new Date().getTime())
}

function expectResult(expected, func) {
  return new Promise((resolve, reject) => {
    func((err, result) => err ? reject(err) : resolve(result === expected))
  })
}

RedisClient.prototype.userExists = function(userId) {
  return expectResult(1, done => this.client.exists(userId, done))
}

RedisClient.prototype.findOrCreateUser = function(userId) {
  return this.userExists(userId)
    .then(exists => {
      if (exists) {
        return false
      }
      return expectResult(1, done => this.client.lpush(userId, '', done))
    })
}

RedisClient.prototype.getLink = function(link) {
  return new Promise((resolve, reject) => {
    this.client.hgetall(link, (err, linkData) => {
      if (err) {
        return reject(err)
      } else if (linkData && linkData.clicks) {
        linkData.clicks = parseInt(linkData.clicks)
      }
      resolve(linkData)
    })
  })
}

RedisClient.prototype.getLinks = function() {
  var links = []
  var cursor = 0

  const collectResults = ([cursorNext, results]) => {
    links.push(...results)
    cursor = parseInt(cursorNext)
    return cursor ? scan() : links
  }

  const processResults = (resolve, reject) => {
    this.client.scan(cursor, 'match', '/*',
      (err, results) => err ? reject(err) : resolve(results))
  }

  const scan = () => {
    return new Promise(processResults).then(collectResults)
  }

  return scan().then((links) => Promise.all(links.map(link =>
      this.getLink(link).then(linkData => {
        linkData.link = link
        return linkData
      }))
  ))
}

RedisClient.prototype.recordAccess = function(link) {
  return new Promise((resolve, reject) => {
    this.client.hincrby(link, 'clicks', 1, err => err ? reject(err) : resolve())
  })
}

RedisClient.prototype.addLinkToOwner = function(owner, link) {
  return new Promise((resolve, reject) => {
    this.client.lpushx(owner, link, (err, result) => {
      err ? reject(err) : resolve(result !== 0)
    })
  })
}

RedisClient.prototype.removeLinkFromOwner = function(owner, link) {
  return expectResult(1, done => this.client.lrem(owner, 1, link, done))
}

RedisClient.prototype.createLink = function(link, target, owner) {
  return new Promise((resolve, reject) => {
    var createdStamp = this.getTimestamp()

    this.client.hsetnx(link, 'owner', owner, (err, result) => {
      if (err) {
        return reject(err)
      } else if (result === 0) {
        return resolve(false)
      }
      this.client.hmset(link,
        'target', target,
        'created', createdStamp,
        'updated', createdStamp,
        'clicks', 0,
        err => {
          if (err) {
            return reject(new Error(link + ' created, ' +
              'but failed to set target, clicks, and timestamps: ' + err))
          }
          resolve(true)
        })
    })
  })
}

RedisClient.prototype.getOwnedLinks = function(owner) {
  return new Promise((resolve, reject) => {
    this.client.lrange(owner, 0, -1, (err, data) => {
      if (err) {
        return reject(err)
      }
      // Since the model is that users are created with the empty string as the
      // first list element, pop that before returning links.
      data.pop()
      resolve(data)
    })
  })
}

RedisClient.prototype.updateProperty = function(link, property, value) {
  return this.getLink(link)
    .then(linkData => {
      if (!linkData) {
        return Promise.resolve(false)
      }
      return expectResult('OK', done => {
        this.client.hmset(link,
          property, value,
          'updated', this.getTimestamp(),
          done)
      })
    })
}

RedisClient.prototype.deleteLink = function(link) {
  return expectResult(1, done => this.client.del(link, done))
}
<|endoftext|>