<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 */
(function(global) {
	'use strict';

	var replaceShouldBeRegExp = /%s/g;

	var i18n = function(rule, language) {
		var space = i18n.data[language || i18n.currentLanguage];
		return space[rule];
	};

	function error(errors, rule, parent, key, path, shouldBe) {
		if (path && key)
			path += '.';
		path = key ? (path + key) : path;

		if (!path)
			path = 'root';

		errors.valid = false;
		errors.map[path] = errors.map[path] || {
			value: (parent && key) ? parent[key] : parent,
			errors: []
		};
		var msg = i18n(rule);
		if (!msg)
			msg = 'missing error message for ' + rule;
		if (shouldBe)
			msg = msg.replace(replaceShouldBeRegExp, shouldBe);
		errors.map[path].errors.push(msg);
		return false;
	}

	i18n.currentLanguage = 'en';
	i18n.data = {
		en: {
			string: 'should be a string',
			object: 'should be an object',
			array: 'should be an array',
			'boolean': 'should be a boolean',
			number: 'should be a number',
			'null': 'should be null',
			'enum': 'enum failed (should be one of : %s)',
			equal: 'equality failed (should be : %s)',
			format: 'format failed',
			unmanaged: 'unmanaged property',
			missing: 'missing property',
			minLength: 'too short (length should be at least : %s)',
			maxLength: 'too long (length should be at max : %s)',
			minimum: 'too small (should be at minimum : %s)',
			maximum: 'too big (should be at max : %s)',
			or: '"or" rule not satisfied',
			not: '"not" rule not satisfied'
		}
	};

	var formats = {
		email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
	};

	var rules = {};

	function is(type) {
		return function() {
			return this.enqueue('this', function(input, path) {
				if (typeof input !== type)
					return error(this, type, input, null, path, type);
				return true;
			});
		};
	}

	function prop(type) {
		return function(name, rule) {
			return this.enqueue(name, function(input, path) {
				if (!input)
					return error(this, 'missing', input, name, path);
				if (typeof input[name] === 'undefined') {
					if (!rule || rule.required !== false)
						return error(this, 'missing', input, name, path);
					return true;
				}
				if (typeof input[name] !== type)
					return error(this, type, input, name, path, type);
				if (!rule)
					return true;
				return rule.call(this, input[name], path ? (path + '.' + name) : name);
			});
		};
	}

	//_______________________________ VALIDATOR

	var Validator = function() {
		this._rules = {};
	};

	Validator.prototype = {
		validate: function(input) {
			var errors = {
				valid: true,
				map: {}
			};
			this.call(errors, input, '');
			if (errors.valid)
				return true;
			errors.value = input;
			return errors;
		},
		call: function(errors, entry, path) {
			var ok = true;

			if (this.required !== false && typeof entry === 'undefined')
				return error(errors, 'missing', entry, null, path);

			if (this._rules['this'])
				this._rules['this'].forEach(function(rule) {
					ok = ok && rule.call(errors, entry, path);
				});

			if (!ok)
				return false;

			if (typeof entry !== 'object' || (entry && entry.forEach))
				return ok;

			var keys = {},
				i;
			for (i in entry)
				keys[i] = true;

			for (i in this._rules)
				if (i === 'this')
					continue;
				else {
					var k = this._rules[i].call(errors, entry, path);
					keys[i] = false;
					ok = ok && k;
				}

			for (i in keys)
				if (keys[i])
					ok = error(errors, 'unmanaged', entry, i, path);
			return ok;
		},
		enqueue: function(key, rule) {
			if (typeof rule === 'string')
				rule = rules[rule];
			if (key === 'this')
				(this._rules[key] = this._rules[key] || []).push(rule);
			else
				this._rules[key] = rule;
			return this;
		},
		rule: function(key, rule) {
			if (!rule) {
				rule = key;
				key = null;
			}
			if (typeof rule === 'string')
				rule = rules[rule];
			return this.enqueue(key || 'this', function(input, path) {
				input = key ? input[key] : input;
				if (key)
					path = path ? (path + '.' + key) : key;
				return rule.call(this, input, path);
			});
		},
		//____________________________________
		or: function() {
			var rules = [].slice.call(arguments);
			return this.enqueue('this', function(input, path) {
				var errors = {
						map: {}
					},
					ok = rules.some(function(rule) {
						return rule.call(errors, input, path);
					});
				if (!ok)
					return error(this, 'or', input, null, path);
				return true;
			});
		},
		not: function(rule) {
			return this.enqueue('this', function(input, path) {
				var errors = {
					map: {}
				};
				if (rule.call(errors, input, path))
					return error(this, 'not', input, null, path);
				return true;
			});
		},
		// ___________________________________
		required: function(yes) {
			this.required = yes;
			return this;
		},
		minLength: function(min) {
			return this.enqueue('this', function(input, path) {
				if (input.length < min)
					return error(this, 'minLength', input, null, path, min);
				return true;
			});
		},
		maxLength: function(max) {
			return this.enqueue('this', function(input, path) {
				if (input.length > max)
					return error(this, 'maxLength', input, null, path, max);
				return true;
			});
		},
		minimum: function(min) {
			return this.enqueue('this', function(input, path) {
				if (input < min)
					return error(this, 'minimum', input, null, path, min);
				return true;
			});
		},
		maximum: function(max) {
			return this.enqueue('this', function(input, path) {
				if (input > max)
					return error(this, 'maximum', input, null, path, max);
				return true;
			});
		},
		format: function(exp) {
			if (typeof exp === 'string')
				exp = formats[exp];
			return this.enqueue('this', function(input, path) {
				if (!exp.test(input))
					return error(this, 'format', input, null, path);
				return true;
			});
		},
		enumerable: function(values) {
			return this.enqueue('this', function(input, path) {
				if (values.indexOf(input) === -1)
					return error(this, 'enum', input, null, path, values.join(', '));
				return true;
			});
		},
		item: function(rule) {
			return this.enqueue('this', function(input, path) {
				var self = this,
					index = 0;
				return input.every(function(item) {
					return rule.call(self, item, path + '.' + (index++));
				});
			});
		},

		equal: function(value) {
			return this.enqueue('this', function(input, path) {
				if (input !== value)
					return error(this, 'equal', input, null, path, value);
				return true;
			});
		},

		type: function() {
			var types = [];
			for (var i = 0, len = arguments.length; i < len; ++i)
				types.push(v()['is' + arguments[i][0].toUpperCase() + arguments[i].substring(1)]());
			return this.or.apply(this, types);
		},

		isObject: is('object'),
		isString: is('string'),
		isNumber: is('number'),
		isBool: is('boolean'),
		isFunction: is('function'),
		isArray: function() {
			return this.enqueue('this', function(input, path) {
				if (typeof input !== 'object' || !input.forEach)
					return error(this, 'array', input, null, path);
				return true;
			});
		},
		isNull: function() {
			return this.enqueue('this', function(input, path) {
				if (input !== null)
					return error(this, 'null', input, null, path);
				return true;
			});
		},

		object: prop('object'),
		string: prop('string'),
		func: prop('function'),
		bool: prop('boolean'),
		number: prop('number'),
		'null': function(name) {
			return this.enqueue(name, function(input, path) {
				if (input[name] !== null)
					return error(this, 'null', input, name, path);
				return true;
			});
		},
		array: function(name, rule) {
			return this.enqueue(name, function(input, path) {
				if (typeof input[name] === 'undefined') {
					if (!rule || rule.required !== false)
						return error(this, 'missing', input, name, path);
					return true;
				}
				if (typeof input[name] !== 'object' || !input[name].forEach)
					return error(this, 'array', input, name, path);
				if (!rule)
					return true;
				return rule.call(this, input[name], path ? (path + '.' + name) : name);
			});
		}
	};

	var v = function() {
		return new Validator();
	};

	rules.email = v().isString().format('email').minLength(6);

	var aright = {
		v: v,
		Validator: Validator,
		rules: rules,
		i18n: i18n,
		formats: formats,
		error: error
	};

	if (typeof module !== 'undefined' && module.exports)
		module.exports = aright;
	else
		global.aright = aright;
})(this);
<commit_msg>clean .or and .not, add .between and .instanceOf<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 */
(function(global) {
	'use strict';

	var replaceShouldBeRegExp = /%s/g;

	var i18n = function(rule, language) {
		var space = i18n.data[language || i18n.currentLanguage];
		return space[rule];
	};

	function error(errors, rule, parent, key, path, shouldBe) {
		if (path && key)
			path += '.';
		path = key ? (path + key) : path;

		if (!path)
			path = 'root';

		errors.valid = false;
		errors.map[path] = errors.map[path] || {
			value: (parent && key) ? parent[key] : parent,
			errors: []
		};
		var msg = i18n(rule);
		if (!msg)
			msg = 'missing error message for ' + rule;
		if (shouldBe)
			msg = msg.replace(replaceShouldBeRegExp, shouldBe);
		errors.map[path].errors.push(msg);
		return false;
	}

	i18n.currentLanguage = 'en';
	i18n.data = {
		en: {
			string: 'should be a string',
			object: 'should be an object',
			array: 'should be an array',
			'boolean': 'should be a boolean',
			number: 'should be a number',
			'null': 'should be null',
			'enum': 'enum failed (should be one of : %s)',
			equal: 'equality failed (should be : %s)',
			format: 'format failed',
			unmanaged: 'unmanaged property',
			missing: 'missing property',
			minLength: 'too short (length should be at least : %s)',
			maxLength: 'too long (length should be at max : %s)',
			minimum: 'too small (should be at minimum : %s)',
			maximum: 'too big (should be at max : %s)',
			instanceOf: 'should be %s',
			or: '"or" rule not satisfied',
			not: '"not" rule not satisfied'
		}
	};

	var formats = {
		email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
	};

	var rules = {};

	function is(type) {
		return function() {
			return this.enqueue('this', function(input, path) {
				if (typeof input !== type)
					return error(this, type, input, null, path, type);
				return true;
			});
		};
	}

	function prop(type) {
		return function(name, rule) {
			return this.enqueue(name, function(input, path) {
				if (!input)
					return error(this, 'missing', input, name, path);
				if (typeof input[name] === 'undefined') {
					if (!rule || rule.required !== false)
						return error(this, 'missing', input, name, path);
					return true;
				}
				if (typeof input[name] !== type)
					return error(this, type, input, name, path, type);
				if (!rule)
					return true;
				return rule.call(this, input[name], path ? (path + '.' + name) : name);
			});
		};
	}

	//_______________________________ VALIDATOR

	var Validator = function() {
		this._rules = {};
	};

	Validator.prototype = {
		validate: function(input) {
			var errors = {
				valid: true,
				map: {}
			};
			this.call(errors, input, '');
			if (errors.valid)
				return true;
			errors.value = input;
			return errors;
		},
		call: function(errors, entry, path) {
			var ok = true;

			if (this.required !== false && typeof entry === 'undefined')
				return error(errors, 'missing', entry, null, path);

			if (this._rules['this'])
				this._rules['this'].forEach(function(rule) {
					ok = ok && rule.call(errors, entry, path);
				});

			if (!ok)
				return false;

			if (typeof entry !== 'object' || (entry && entry.forEach))
				return ok;

			var keys = {},
				i;
			for (i in entry)
				keys[i] = true;

			for (i in this._rules)
				if (i === 'this')
					continue;
				else {
					var k = this._rules[i].call(errors, entry, path);
					keys[i] = false;
					ok = ok && k;
				}

			for (i in keys)
				if (keys[i])
					ok = error(errors, 'unmanaged', entry, i, path);
			return ok;
		},
		enqueue: function(key, rule) {
			if (typeof rule === 'string')
				rule = rules[rule];
			if (key === 'this')
				(this._rules[key] = this._rules[key] || []).push(rule);
			else
				this._rules[key] = rule;
			return this;
		},
		rule: function(key, rule) {
			if (!rule) {
				rule = key;
				key = null;
			}
			if (typeof rule === 'string')
				rule = rules[rule];
			return this.enqueue(key || 'this', function(input, path) {
				input = key ? input[key] : input;
				if (key)
					path = path ? (path + '.' + key) : key;
				return rule.call(this, input, path);
			});
		},
		//____________________________________
		or: function() {
			var rules = [].slice.call(arguments);
			return this.enqueue('this', function(input, path) {
				var errors = { map: {} }, // fake error object
					ok = rules.some(function(rule) {
						return rule.call(errors, input, path);
					});
				if (!ok)
					return error(this, 'or', input, null, path);
				return true;
			});
		},
		not: function(rule) {
			return this.enqueue('this', function(input, path) {
				var errors = { map: {} }; // fake error object
				if (rule.call(errors, input, path))
					return error(this, 'not', input, null, path);
				return true;
			});
		},
		// ___________________________________
		required: function(yes) {
			this.required = yes;
			return this;
		},
		minLength: function(min) {
			return this.enqueue('this', function(input, path) {
				if (input.length < min)
					return error(this, 'minLength', input, null, path, min);
				return true;
			});
		},
		maxLength: function(max) {
			return this.enqueue('this', function(input, path) {
				if (input.length > max)
					return error(this, 'maxLength', input, null, path, max);
				return true;
			});
		},
		minimum: function(min) {
			return this.enqueue('this', function(input, path) {
				if (input < min)
					return error(this, 'minimum', input, null, path, min);
				return true;
			});
		},
		maximum: function(max) {
			return this.enqueue('this', function(input, path) {
				if (input > max)
					return error(this, 'maximum', input, null, path, max);
				return true;
			});
		},
		between: function(min, max) {
			return this.minimum(min).maximum(max);
		},
		format: function(exp) {
			if (typeof exp === 'string')
				exp = formats[exp];
			return this.enqueue('this', function(input, path) {
				if (!exp.test(input))
					return error(this, 'format', input, null, path);
				return true;
			});
		},
		enumerable: function(values) {
			return this.enqueue('this', function(input, path) {
				if (values.indexOf(input) === -1)
					return error(this, 'enum', input, null, path, values.join(', '));
				return true;
			});
		},
		item: function(rule) {
			return this.enqueue('this', function(input, path) {
				var self = this,
					index = 0;
				return input.every(function(item) {
					return rule.call(self, item, path + '.' + (index++));
				});
			});
		},

		equal: function(value) {
			return this.enqueue('this', function(input, path) {
				if (input !== value)
					return error(this, 'equal', input, null, path, value);
				return true;
			});
		},

		instanceOf: function(cl) {
			return this.enqueue('this', function(input, path) {
				if (!(input instanceof cl))
					return error(this, 'instanceOf', input, null, path, cl);
				return true;
			});
		},

		type: function() {
			var types = [];
			for (var i = 0, len = arguments.length; i < len; ++i)
				types.push(v()['is' + arguments[i][0].toUpperCase() + arguments[i].substring(1)]());
			return this.or.apply(this, types);
		},

		isObject: is('object'),
		isString: is('string'),
		isNumber: is('number'),
		isBool: is('boolean'),
		isFunction: is('function'),
		isArray: function() {
			return this.enqueue('this', function(input, path) {
				if (typeof input !== 'object' || !input.forEach)
					return error(this, 'array', input, null, path);
				return true;
			});
		},
		isNull: function() {
			return this.enqueue('this', function(input, path) {
				if (input !== null)
					return error(this, 'null', input, null, path);
				return true;
			});
		},

		object: prop('object'),
		string: prop('string'),
		func: prop('function'),
		bool: prop('boolean'),
		number: prop('number'),
		'null': function(name) {
			return this.enqueue(name, function(input, path) {
				if (input[name] !== null)
					return error(this, 'null', input, name, path);
				return true;
			});
		},
		array: function(name, rule) {
			return this.enqueue(name, function(input, path) {
				if (typeof input[name] === 'undefined') {
					if (!rule || rule.required !== false)
						return error(this, 'missing', input, name, path);
					return true;
				}
				if (typeof input[name] !== 'object' || !input[name].forEach)
					return error(this, 'array', input, name, path);
				if (!rule)
					return true;
				return rule.call(this, input[name], path ? (path + '.' + name) : name);
			});
		}
	};

	var v = function() {
		return new Validator();
	};

	rules.email = v().isString().format('email').minLength(6);

	var aright = {
		v: v,
		Validator: Validator,
		rules: rules,
		i18n: i18n,
		formats: formats,
		error: error
	};

	if (typeof module !== 'undefined' && module.exports)
		module.exports = aright;
	else
		global.aright = aright;
})(this);
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var _ = require('lodash');

var urlToRequest = require('loader-utils').urlToRequest;
var parseQuery = require('loader-utils').parseQuery;

var genPlaceholder = require('dir-loader/lib/util').genPlaceholder;
var genReplacer = require('dir-loader/lib/util').genReplacer;

var requirePlaceholder = genPlaceholder('require');
var requireReplacer = genReplacer('require', function (str) { return "require(" + str + ")"; });

function isSelected(filter, name, fullPath) {
  if (!filter) return true;
  if (_.isRegExp(filter)) return filter.test(name);
  if (_.isFunction(filter)) return filter(name, fullPath);
  return true;
}

function serializeStat(stat) {
  _.forEach(stat, function(value, key) { if (_.isDate(value)) stat[key] = value.getTime(); })
  return stat;
}

function readFile(fullPath, options, stat) {
  var requirePath = options.pathTransform(urlToRequest(path.relative(options.webpackContext, fullPath)));
  var contents = requirePlaceholder(requirePath);

  var name = fullPath.split(path.sep).pop();
  return {
    data: {
      name: name,
      contents: contents,
      stat: serializeStat(stat)
    },
  };
}

function readDirectory(fullPath, options, stat) {
  var children = [];
  fs.readdirSync(fullPath).map(function(filename) {
    var childPath = path.join(fullPath, filename);
    var stat = fs.statSync(childPath);
    if (stat.isDirectory()) {
      if (!isSelected(options.dirFilter, filename, childPath)) return;
      children.push(readDirectory(childPath, options, stat));
    }
    else {
      if (!isSelected(options.filter, filename, childPath)) return;
      children.push(readFile(childPath, options, stat));
    }
  });

  var name = fullPath.split(path.sep).pop();
  return {
    data: {
      name: name,
      isDirectory: true,
      stat: serializeStat(stat)
    },
    children: children
  };
}

module.exports = function(source) {
  !this.cacheable || this.cacheable();
  var options = this.exec(source, this.resource);
  var webpackContext = this.context;

  // check options
  var required = ['path'];
  for (var i = 0; i < required.length; i++) {
    var k = required[i];
    if (!options[k]) throw new Error("The option " + k + " is required for fs-loader");
  }
  if (!webpackContext || typeof webpackContext !== "string") {
    throw Error("Could not initialize webpack context", webpackContext);
  }

  options.pathTransform = options.pathTransform || (function(_) {return _;});
  options.webpackContext = webpackContext;

  var fullPath = options.path;
  options.directory = fullPath.split(path.sep).pop();
  var output = readDirectory(fullPath, options);
  output = JSON.stringify(output, undefined, 2);
  output = requireReplacer(output);

  return "module.exports = " + output + ";";
};
<commit_msg>Remove isDirectory check<commit_after>var fs = require('fs');
var path = require('path');
var _ = require('lodash');

var urlToRequest = require('loader-utils').urlToRequest;
var parseQuery = require('loader-utils').parseQuery;

var genPlaceholder = require('dir-loader/lib/util').genPlaceholder;
var genReplacer = require('dir-loader/lib/util').genReplacer;

var requirePlaceholder = genPlaceholder('require');
var requireReplacer = genReplacer('require', function (str) { return "require(" + str + ")"; });

function isSelected(filter, name, fullPath) {
  if (!filter) return true;
  if (_.isRegExp(filter)) return filter.test(name);
  if (_.isFunction(filter)) return filter(name, fullPath);
  return true;
}

function serializeStat(stat) {
  _.forEach(stat, function(value, key) { if (_.isDate(value)) stat[key] = value.getTime(); })
  return stat;
}

function readFile(fullPath, options, stat) {
  var requirePath = options.pathTransform(urlToRequest(path.relative(options.webpackContext, fullPath)));
  var contents = requirePlaceholder(requirePath);

  var name = fullPath.split(path.sep).pop();
  return {
    data: {
      name: name,
      contents: contents,
      stat: serializeStat(stat)
    },
  };
}

function readDirectory(fullPath, options, stat) {
  var children = [];
  fs.readdirSync(fullPath).map(function(filename) {
    var childPath = path.join(fullPath, filename);
    var stat = fs.statSync(childPath);
    if (stat.isDirectory()) {
      if (!isSelected(options.dirFilter, filename, childPath)) return;
      children.push(readDirectory(childPath, options, stat));
    }
    else {
      if (!isSelected(options.filter, filename, childPath)) return;
      children.push(readFile(childPath, options, stat));
    }
  });

  var name = fullPath.split(path.sep).pop();
  return {
    data: {
      name: name,
      stat: serializeStat(stat)
    },
    children: children
  };
}

module.exports = function(source) {
  !this.cacheable || this.cacheable();
  var options = this.exec(source, this.resource);
  var webpackContext = this.context;

  // check options
  var required = ['path'];
  for (var i = 0; i < required.length; i++) {
    var k = required[i];
    if (!options[k]) throw new Error("The option " + k + " is required for fs-loader");
  }
  if (!webpackContext || typeof webpackContext !== "string") {
    throw Error("Could not initialize webpack context", webpackContext);
  }

  options.pathTransform = options.pathTransform || (function(_) {return _;});
  options.webpackContext = webpackContext;

  var fullPath = options.path;
  options.directory = fullPath.split(path.sep).pop();
  var output = readDirectory(fullPath, options);
  output = JSON.stringify(output, undefined, 2);
  output = requireReplacer(output);

  return "module.exports = " + output + ";";
};
<|endoftext|>


<commit_before>const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

const { attachTo } = require("sdk/content/mod");
const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm");
const { getFavicon } = require("sdk/places/favicon");
const self = require("sdk/self");
const { Style } = require("sdk/stylesheet/style");
const tabs = require("sdk/tabs");
const tabsUtils = require("sdk/tabs/utils");
const { viewFor } = require("sdk/view/core");
const webExtension = require("sdk/webextension");
const windows = require("sdk/windows");
const windowUtils = require("sdk/window/utils");

let ContainerService = {
  _identitiesState: {},

  init() {
    // Enabling preferences

    let prefs = [
      [ "privacy.userContext.enabled", true ],
      [ "privacy.userContext.ui.enabled", true ],
      [ "privacy.usercontext.about_newtab_segregation.enabled", true ],
      [ "privacy.usercontext.longPressBehavior", 1 ]
    ];

    const prefService = require("sdk/preferences/service");
    prefs.forEach((pref) => {
      prefService.set(pref[0], pref[1]);
    });

    // Message routing

    // only these methods are allowed. We have a 1:1 mapping between messages
    // and methods. These methods must return a promise.
    let methods = [
      "hideTabs",
      "showTabs",
      "sortTabs",
      "getTabs",
      "showTab",
      "openTab",
      "moveTabsToWindow",
      "queryIdentities",
      "getIdentity"
    ];

    // Map of identities.
    ContextualIdentityService.getIdentities().forEach(identity => {
      this._identitiesState[identity.userContextId] = {
        hiddenTabUrls: [],
        openTabs: 0
      };
    });

    // It can happen that this jsm is loaded after the opening a container tab.
    for (const tab of tabs) {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId) {
        ++this._identitiesState[userContextId].openTabs;
      }
    }

    tabs.on("open", tab => {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId) {
        ++this._identitiesState[userContextId].openTabs;
      }
    });

    tabs.on("close", tab => {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId && this._identitiesState[userContextId].openTabs) {
        --this._identitiesState[userContextId].openTabs;
      }
    });

    // Modify CSS and other stuff for each window.

    for (let window of windows.browserWindows) {
      this.configureWindow(viewFor(window));
    }

    windows.browserWindows.on("open", window => {
      this.configureWindow(viewFor(window));
    });

    // WebExtension startup

    webExtension.startup().then(api => {
      api.browser.runtime.onMessage.addListener((message, sender, sendReply) => {
        if ("method" in message && methods.indexOf(message.method) !== -1) {
          sendReply(this[message.method](message));
        }
      });
    });
  },

  // utility methods

  _convert(identity) {
    // In FF 50-51, the icon is the full path, in 52 and following
    // releases, we have IDs to be used with a svg file. In this function
    // we map URLs to svg IDs.
    let image, color;

    if (identity.icon === "fingerprint" ||
        identity.icon === "chrome://browser/skin/usercontext/personal.svg") {
      image = "fingerprint";
    } else if (identity.icon === "briefcase" ||
             identity.icon === "chrome://browser/skin/usercontext/work.svg") {
      image = "briefcase";
    } else if (identity.icon === "dollar" ||
             identity.icon === "chrome://browser/skin/usercontext/banking.svg") {
      image = "dollar";
    } else if (identity.icon === "cart" ||
             identity.icon === "chrome://browser/skin/usercontext/shopping.svg") {
      image = "cart";
    } else {
      image = "circle";
    }

    if (identity.color === "#00a7e0") {
      color = "blue";
    } else if (identity.color === "#f89c24") {
      color = "orange";
    } else if (identity.color === "#7dc14c") {
      color = "green";
    } else if (identity.color === "#ee5195") {
      color = "pink";
    } else if (["blue", "turquoise", "green", "yellow", "orange", "red", "pink", "purple"].indexOf(identity.color) !== -1) {
      color = identity.color;
    } else {
      color = "";
    }

    return {
      name: ContextualIdentityService.getUserContextLabel(identity.userContextId),
      image,
      color,
      userContextId: identity.userContextId,
      hasHiddenTabs: !!this._identitiesState[identity.userContextId].hiddenTabUrls.length,
      hasOpenTabs: !!this._identitiesState[identity.userContextId].openTabs
    };
  },

  _getUserContextIdFromTab(tab) {
    return parseInt(viewFor(tab).getAttribute("usercontextid") || 0, 10);
  },

  _getTabList(userContextId) {
    let list = [];
    for (const tab of tabs) {
      if (userContextId === this._getUserContextIdFromTab(tab)) {
        let object = { title: tab.title, url: tab.url, id: tab.id };
        list.push(object);
      }
    }

    return list;
  },

  // Tabs management

  hideTabs(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("hideTabs must be called with userContextId argument.");
        return;
      }

      for (const tab of tabs) {
        if (args.userContextId !== this._getUserContextIdFromTab(tab)) {
          continue;
        }

        this._identitiesState[args.userContextId].hiddenTabUrls.push(tab.url);
        tab.close();
      }

      resolve(null);
    });
  },

  showTabs(args) {
    if (!("userContextId" in args)) {
      Promise.reject("showTabs must be called with userContextId argument.");
      return;
    }

    let promises = [];

    for (let url of this._identitiesState[args.userContextId].hiddenTabUrls) {
      promises.push(this.openTab({ userContextId: args.userContextId, url }));
    }

    this._identitiesState[args.userContextId].hiddenTabUrls = [];

    return Promise.all(promises);
  },

  sortTabs() {
    return new Promise(resolve => {
      for (let window of windows.browserWindows) {
        // First the pinned tabs, then the normal ones.
        this._sortTabsInternal(window, true);
        this._sortTabsInternal(window, false);
      }
      resolve(null);
    });
  },

  _sortTabsInternal(window, pinnedTabs) {
    // From model to XUL window.
    const xulWindow = viewFor(window);

    const tabs = tabsUtils.getTabs(xulWindow);
    let pos = 0;

    // Let's collect UCIs/tabs for this window.
    let map = new Map;
    for (const tab of tabs) {
      if (pinnedTabs && !tabsUtils.isPinned(tab)) {
        // We don't have, or we already handled all the pinned tabs.
        break;
      }

      if (!pinnedTabs && tabsUtils.isPinned(tab)) {
        // pinned tabs must be consider as taken positions.
        ++pos;
        continue;
      }

      const userContextId = this._getUserContextIdFromTab(tab);
      if (!map.has(userContextId)) {
        map.set(userContextId, []);
      }
      map.get(userContextId).push(tab);
    }

    // Let's sort the map.
    const sortMap = new Map([...map.entries()].sort((a, b) => a[0] > b[0]));

    // Let's move tabs.
    sortMap.forEach(tabs => {
      for (const tab of tabs) {
        xulWindow.gBrowser.moveTabTo(tab, pos++);
      }
    });
  },

  getTabs(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("getTabs must be called with userContextId argument.");
        return;
      }

      const list = this._getTabList(args.userContextId);
      let promises = [];

      for (let object of list) {
        promises.push(getFavicon(object.url).then(url => {
          object.favicon = url;
        }, () => {
          object.favicon = "";
        }));
      }

      Promise.all(promises).then(() => {
        resolve(list);
      });
    });
  },

  showTab(args) {
    return new Promise((resolve, reject) => {
      if (!("tabId" in args)) {
        reject("showTab must be called with tabId argument.");
        return;
      }

      for (const tab of tabs) {
        if (tab.id === args.tabId) {
          tab.window.activate();
          tab.activate();
          break;
        }
      }

      resolve(null);
    });
  },

  moveTabsToWindow(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("moveTabsToWindow must be called with userContextId argument.");
        return;
      }

      // Let"s create a list of the tabs.
      const list = this._getTabList(args.userContextId);

      // Nothing to do
      if (list.length === 0) {
        resolve(null);
        return;
      }

      windows.browserWindows.open({
        url: "about:blank",
        onOpen: window => {
          const newBrowserWindow = viewFor(window);

          // Let's move the tab to the new window.
          for (const tab of list) {
            const newTab = newBrowserWindow.gBrowser.addTab("about:blank");
            newBrowserWindow.gBrowser.swapBrowsersAndCloseOther(newTab, tab);
            // swapBrowsersAndCloseOther is an internal method of gBrowser
            // an it's not supported by addon SDK. This means that we
            // don't receive an 'open' event, but only the 'close' one.
            // We have to force a +1 in our tab counter.
            ++this._identitiesState[args.userContextId].openTabs;
          }

          // Let's close all the normal tab in the new window. In theory it
          // should be only the first tab, but maybe there are addons doing
          // crazy stuff.
          for (const tab of window.tabs) {
            const userContextId = this._getUserContextIdFromTab(tab);
            if (args.userContextId !== userContextId) {
              newBrowserWindow.gBrowser.removeTab(viewFor(tab));
            }
          }
          resolve(null);
        },
      });
    });
  },

  openTab(args) {
    return new Promise(resolve => {
      let browserWin = windowUtils.getMostRecentBrowserWindow();

      // This should not really happen.
      if (!browserWin || !browserWin.gBrowser) {
        return Promise.resolve(false);
      }

      let userContextId = 0;
      if ("userContextId" in args) {
        userContextId = args.userContextId;
      }

      let tab = browserWin.gBrowser.addTab(args.url || null, { userContextId });
      browserWin.gBrowser.selectedTab = tab;
      resolve(true);
    });
  },

  // Identities management

  queryIdentities() {
    return new Promise(resolve => {
      let identities = [];

      ContextualIdentityService.getIdentities().forEach(identity => {
        let convertedIdentity = this._convert(identity);
        identities.push(convertedIdentity);
      });

      resolve(identities);
    });
  },

  getIdentity(args) {
    if (!("userContextId" in args)) {
      Promise.reject("getIdentity must be called with userContextId argument.");
      return;
    }

    let identity = ContextualIdentityService.getIdentityFromId(args.userContextId);
    return Promise.resolve(identity ? this._convert(identity) : null);
  },

  // Styling the window

  configureWindow(window) {
    var tabsElement = window.document.getElementById("tabbrowser-tabs");
    var button = window.document.getAnonymousElementByAttribute(tabsElement, "anonid", "tabs-newtab-button");

    while (button.firstChild) {
      button.removeChild(button.firstChild);
    }

    button.setAttribute("type", "menu");
    let popup = window.document.createElementNS(XUL_NS, "menupopup");

    popup.setAttribute("anonid", "newtab-popup");
    popup.className = "new-tab-popup";
    popup.setAttribute("position", "after_end");

    ContextualIdentityService.getIdentities().forEach(identity => {
      identity = this._convert(identity);

      var menuItem = window.document.createElementNS(XUL_NS, "menuitem");
      menuItem.setAttribute("class", "menuitem-iconic");
      menuItem.setAttribute("label", identity.name);
      menuItem.setAttribute("image", self.data.url("usercontext.svg") + "#" + identity.image);

      menuItem.addEventListener("command", (event) => {
        this.openTab({userContextId: identity.userContextId});
        event.stopPropagation();
      });

      popup.appendChild(menuItem);
    });

    button.appendChild(popup);
    let style = Style({ uri: self.data.url("chrome.css") });

    attachTo(style, viewFor(window));
  }
};

ContainerService.init();
<commit_msg>createIdentity, removeIdentity, updateIdentity (#78)<commit_after>const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

const { attachTo } = require("sdk/content/mod");
const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm");
const { getFavicon } = require("sdk/places/favicon");
const self = require("sdk/self");
const { Style } = require("sdk/stylesheet/style");
const tabs = require("sdk/tabs");
const tabsUtils = require("sdk/tabs/utils");
const { viewFor } = require("sdk/view/core");
const webExtension = require("sdk/webextension");
const windows = require("sdk/windows");
const windowUtils = require("sdk/window/utils");

let ContainerService = {
  _identitiesState: {},

  init() {
    // Enabling preferences

    let prefs = [
      [ "privacy.userContext.enabled", true ],
      [ "privacy.userContext.ui.enabled", true ],
      [ "privacy.usercontext.about_newtab_segregation.enabled", true ],
      [ "privacy.usercontext.longPressBehavior", 1 ]
    ];

    const prefService = require("sdk/preferences/service");
    prefs.forEach((pref) => {
      prefService.set(pref[0], pref[1]);
    });

    // Message routing

    // only these methods are allowed. We have a 1:1 mapping between messages
    // and methods. These methods must return a promise.
    let methods = [
      "hideTabs",
      "showTabs",
      "sortTabs",
      "getTabs",
      "showTab",
      "openTab",
      "moveTabsToWindow",
      "queryIdentities",
      "getIdentity",
      "createIdentity",
      "removeIdentity",
      "updateIdentity",
    ];

    // Map of identities.
    ContextualIdentityService.getIdentities().forEach(identity => {
      this._identitiesState[identity.userContextId] = {
        hiddenTabUrls: [],
        openTabs: 0
      };
    });

    // It can happen that this jsm is loaded after the opening a container tab.
    for (const tab of tabs) {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId) {
        ++this._identitiesState[userContextId].openTabs;
      }
    }

    tabs.on("open", tab => {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId) {
        ++this._identitiesState[userContextId].openTabs;
      }
    });

    tabs.on("close", tab => {
      const userContextId = this._getUserContextIdFromTab(tab);
      if (userContextId && this._identitiesState[userContextId].openTabs) {
        --this._identitiesState[userContextId].openTabs;
      }
    });

    // Modify CSS and other stuff for each window.

    for (let window of windows.browserWindows) {
      this.configureWindow(viewFor(window));
    }

    windows.browserWindows.on("open", window => {
      this.configureWindow(viewFor(window));
    });

    // WebExtension startup

    webExtension.startup().then(api => {
      api.browser.runtime.onMessage.addListener((message, sender, sendReply) => {
        if ("method" in message && methods.indexOf(message.method) !== -1) {
          sendReply(this[message.method](message));
        }
      });
    });
  },

  // utility methods

  _convert(identity) {
    // In FF 50-51, the icon is the full path, in 52 and following
    // releases, we have IDs to be used with a svg file. In this function
    // we map URLs to svg IDs.
    let image, color;

    if (identity.icon === "fingerprint" ||
        identity.icon === "chrome://browser/skin/usercontext/personal.svg") {
      image = "fingerprint";
    } else if (identity.icon === "briefcase" ||
             identity.icon === "chrome://browser/skin/usercontext/work.svg") {
      image = "briefcase";
    } else if (identity.icon === "dollar" ||
             identity.icon === "chrome://browser/skin/usercontext/banking.svg") {
      image = "dollar";
    } else if (identity.icon === "cart" ||
             identity.icon === "chrome://browser/skin/usercontext/shopping.svg") {
      image = "cart";
    } else {
      image = "circle";
    }

    if (identity.color === "#00a7e0") {
      color = "blue";
    } else if (identity.color === "#f89c24") {
      color = "orange";
    } else if (identity.color === "#7dc14c") {
      color = "green";
    } else if (identity.color === "#ee5195") {
      color = "pink";
    } else if (["blue", "turquoise", "green", "yellow", "orange", "red", "pink", "purple"].indexOf(identity.color) !== -1) {
      color = identity.color;
    } else {
      color = "";
    }

    return {
      name: ContextualIdentityService.getUserContextLabel(identity.userContextId),
      image,
      color,
      userContextId: identity.userContextId,
      hasHiddenTabs: !!this._identitiesState[identity.userContextId].hiddenTabUrls.length,
      hasOpenTabs: !!this._identitiesState[identity.userContextId].openTabs
    };
  },

  _getUserContextIdFromTab(tab) {
    return parseInt(viewFor(tab).getAttribute("usercontextid") || 0, 10);
  },

  _getTabList(userContextId) {
    let list = [];
    for (const tab of tabs) {
      if (userContextId === this._getUserContextIdFromTab(tab)) {
        let object = { title: tab.title, url: tab.url, id: tab.id };
        list.push(object);
      }
    }

    return list;
  },

  // Tabs management

  hideTabs(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("hideTabs must be called with userContextId argument.");
        return;
      }

      for (const tab of tabs) {
        if (args.userContextId !== this._getUserContextIdFromTab(tab)) {
          continue;
        }

        this._identitiesState[args.userContextId].hiddenTabUrls.push(tab.url);
        tab.close();
      }

      resolve(null);
    });
  },

  showTabs(args) {
    if (!("userContextId" in args)) {
      Promise.reject("showTabs must be called with userContextId argument.");
      return;
    }

    let promises = [];

    for (let url of this._identitiesState[args.userContextId].hiddenTabUrls) {
      promises.push(this.openTab({ userContextId: args.userContextId, url }));
    }

    this._identitiesState[args.userContextId].hiddenTabUrls = [];

    return Promise.all(promises);
  },

  sortTabs() {
    return new Promise(resolve => {
      for (let window of windows.browserWindows) {
        // First the pinned tabs, then the normal ones.
        this._sortTabsInternal(window, true);
        this._sortTabsInternal(window, false);
      }
      resolve(null);
    });
  },

  _sortTabsInternal(window, pinnedTabs) {
    // From model to XUL window.
    const xulWindow = viewFor(window);

    const tabs = tabsUtils.getTabs(xulWindow);
    let pos = 0;

    // Let's collect UCIs/tabs for this window.
    let map = new Map;
    for (const tab of tabs) {
      if (pinnedTabs && !tabsUtils.isPinned(tab)) {
        // We don't have, or we already handled all the pinned tabs.
        break;
      }

      if (!pinnedTabs && tabsUtils.isPinned(tab)) {
        // pinned tabs must be consider as taken positions.
        ++pos;
        continue;
      }

      const userContextId = this._getUserContextIdFromTab(tab);
      if (!map.has(userContextId)) {
        map.set(userContextId, []);
      }
      map.get(userContextId).push(tab);
    }

    // Let's sort the map.
    const sortMap = new Map([...map.entries()].sort((a, b) => a[0] > b[0]));

    // Let's move tabs.
    sortMap.forEach(tabs => {
      for (const tab of tabs) {
        xulWindow.gBrowser.moveTabTo(tab, pos++);
      }
    });
  },

  getTabs(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("getTabs must be called with userContextId argument.");
        return;
      }

      const list = this._getTabList(args.userContextId);
      let promises = [];

      for (let object of list) {
        promises.push(getFavicon(object.url).then(url => {
          object.favicon = url;
        }, () => {
          object.favicon = "";
        }));
      }

      Promise.all(promises).then(() => {
        resolve(list);
      });
    });
  },

  showTab(args) {
    return new Promise((resolve, reject) => {
      if (!("tabId" in args)) {
        reject("showTab must be called with tabId argument.");
        return;
      }

      for (const tab of tabs) {
        if (tab.id === args.tabId) {
          tab.window.activate();
          tab.activate();
          break;
        }
      }

      resolve(null);
    });
  },

  moveTabsToWindow(args) {
    return new Promise((resolve, reject) => {
      if (!("userContextId" in args)) {
        reject("moveTabsToWindow must be called with userContextId argument.");
        return;
      }

      // Let"s create a list of the tabs.
      const list = this._getTabList(args.userContextId);

      // Nothing to do
      if (list.length === 0) {
        resolve(null);
        return;
      }

      windows.browserWindows.open({
        url: "about:blank",
        onOpen: window => {
          const newBrowserWindow = viewFor(window);

          // Let's move the tab to the new window.
          for (const tab of list) {
            const newTab = newBrowserWindow.gBrowser.addTab("about:blank");
            newBrowserWindow.gBrowser.swapBrowsersAndCloseOther(newTab, tab);
            // swapBrowsersAndCloseOther is an internal method of gBrowser
            // an it's not supported by addon SDK. This means that we
            // don't receive an 'open' event, but only the 'close' one.
            // We have to force a +1 in our tab counter.
            ++this._identitiesState[args.userContextId].openTabs;
          }

          // Let's close all the normal tab in the new window. In theory it
          // should be only the first tab, but maybe there are addons doing
          // crazy stuff.
          for (const tab of window.tabs) {
            const userContextId = this._getUserContextIdFromTab(tab);
            if (args.userContextId !== userContextId) {
              newBrowserWindow.gBrowser.removeTab(viewFor(tab));
            }
          }
          resolve(null);
        },
      });
    });
  },

  openTab(args) {
    return new Promise(resolve => {
      let browserWin = windowUtils.getMostRecentBrowserWindow();

      // This should not really happen.
      if (!browserWin || !browserWin.gBrowser) {
        return Promise.resolve(false);
      }

      let userContextId = 0;
      if ("userContextId" in args) {
        userContextId = args.userContextId;
      }

      let tab = browserWin.gBrowser.addTab(args.url || null, { userContextId });
      browserWin.gBrowser.selectedTab = tab;
      resolve(true);
    });
  },

  // Identities management

  queryIdentities() {
    return new Promise(resolve => {
      let identities = [];

      ContextualIdentityService.getIdentities().forEach(identity => {
        let convertedIdentity = this._convert(identity);
        identities.push(convertedIdentity);
      });

      resolve(identities);
    });
  },

  getIdentity(args) {
    if (!("userContextId" in args)) {
      Promise.reject("getIdentity must be called with userContextId argument.");
      return;
    }

    let identity = ContextualIdentityService.getIdentityFromId(args.userContextId);
    return Promise.resolve(identity ? this._convert(identity) : null);
  },

  createIdentity(args) {
    for (const arg of [ "name", "color", "icon"]) {
      if (!(arg in args)) {
        Promise.reject("createIdentity must be called with " + arg + " argument.");
        return;
      }
    }

    // FIXME: icon and color conversion based on FF version.
    const identity = ContextualIdentityService.create(args.name, args.icon, args.color);
    return Promise.resolve(this._convert(identity));
  },

  updateIdentity(args) {
    if (!("userContextId" in args)) {
      Promise.reject("updateIdentity must be called with userContextId argument.");
      return;
    }

    let identity = ContextualIdentityService.getIdentityFromId(args.userContextId);
    for (const arg of [ "name", "color", "icon"]) {
      if ((arg in args)) {
        identity[arg] = args[arg];
      }
    }

    // FIXME: icon and color conversion based on FF version.
    // FIXME: color/name update propagation
    return Promise.resolve(ContextualIdentityService.update(args.userContextId,
                                                            identity.name,
                                                            identity.icon,
                                                            identity.color));
  },

  removeIdentity(args) {
    if (!("userContextId" in args)) {
      Promise.reject("removeIdentity must be called with userContextId argument.");
      return;
    }
    return Promise.resolve(ContextualIdentityService.remove(args.userContextId));
  },

  // Styling the window

  configureWindow(window) {
    var tabsElement = window.document.getElementById("tabbrowser-tabs");
    var button = window.document.getAnonymousElementByAttribute(tabsElement, "anonid", "tabs-newtab-button");

    while (button.firstChild) {
      button.removeChild(button.firstChild);
    }

    button.setAttribute("type", "menu");
    let popup = window.document.createElementNS(XUL_NS, "menupopup");

    popup.setAttribute("anonid", "newtab-popup");
    popup.className = "new-tab-popup";
    popup.setAttribute("position", "after_end");

    ContextualIdentityService.getIdentities().forEach(identity => {
      identity = this._convert(identity);

      var menuItem = window.document.createElementNS(XUL_NS, "menuitem");
      menuItem.setAttribute("class", "menuitem-iconic");
      menuItem.setAttribute("label", identity.name);
      menuItem.setAttribute("image", self.data.url("usercontext.svg") + "#" + identity.image);

      menuItem.addEventListener("command", (event) => {
        this.openTab({userContextId: identity.userContextId});
        event.stopPropagation();
      });

      popup.appendChild(menuItem);
    });

    button.appendChild(popup);
    let style = Style({ uri: self.data.url("chrome.css") });

    attachTo(style, viewFor(window));
  }
};

ContainerService.init();
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */
var request = require('superagent')
  , path = require('JSONPath').eval
  , accounting = require('accounting')
  , currency = require('currency-symbol-map')
  , _ = require('underscore');

var endpoint = 'https://api.zanox.com/json/2011-03-01/products';

module.exports = function (opts) {
  return new Zanox(opts);
};

var Zanox = function Zanox (opts) {
  if ('object' === typeof opts) {
    this._keywords = opts.keywords;
  } else {
    this._keywords = opts;
  }

  // Setup defaults
  _.defaults(this, {
    _partnership: 'all'
  });
};

Zanox.prototype.id = function (id) {
  return this._id = id, this;
};

Zanox.prototype.keywords = function (kw) {
  return this._keywords = kw, this;
};

Zanox.prototype.country = function (country) {
  return this._country = country, this;
};

Zanox.prototype.category = function (category) {
  return this._category = category, this;
};

Zanox.prototype.program = function (program) {
  if (!this._programs) this._programs = [];

  return this._programs.push(program), this;
};

Zanox.prototype.minPrice = function (min) {
  return this._minPrice = min, this;
};

Zanox.prototype.maxPrice = function (max) {
  return this._maxPrice = max, this;
};

Zanox.prototype.price = function (price) {
  if (_.isArray(price)) {
    this._minPrice = price[0], this._maxPrice = price[1];
  } else if (_.isString(price)) {
    var split = price.split('..');

    if (split[0]) this._minPrice = split[0];
    if (split[1]) this._maxPrice = split[1];
  }

  return this;
};

Zanox.prototype.ean = function (ean) {
  return this._ean = ean, this;
};

Zanox.prototype.numItems = function (n) {
  return this._numItems = n, this;
};

Zanox.prototype.partnership = function (p) {
  return this._partnership = p, this;
};

Zanox.prototype.searchType = function (t) {
  return this._searchType = t, this;
};

Zanox.prototype.done = function (cb) {

  var r = request
    .get(endpoint)
    .query({searchtype: this._searchType})
    .query({connectid: this._id})
    .query({q: this._keywords})
    .query({region: this._country})
    .query({merchantcategory: this._category})
    .query({partnership: this._partnership})
    .query({minprice: this._minPrice})
    .query({maxprice: this._maxPrice})
    .query({ean: this._ean})
    .query({items: 1})
    .query({programs: this._programs && this._programs.join(',')})
    .end(function (err, res) {
      // Handle connection errors
      if (err) return cb(err);

      // Handle client errors
      if (res.body.message) return cb(new Error(res.body.message));

      // Callback
      return cb(null, parseResults(res.body, extractions));
    });
};

var formatPrice = function (p) {
  var amount = p.price
    , code = p.currency;

  if (!amount || !code) return null;
  return accounting.formatMoney(amount, currency(code));
};

var extractions = [
  { name: 'id', query: '$..@id' },
  { name: 'name', query: '$..name' },
  { name: 'url', query: '$..trackingLink..ppc' },
  { name: 'listPrice',
    query: '$..productItem[0]',
    transform: formatPrice
  }
];

var first = function (obj, query) {
  var res = path(obj, query);
  return res.length ? res[0] : null;
};

var parseResults = function (obj, extractions) {
  var that = this;

  var res = _
    .chain(extractions)
    .map(function (x) {
      var key = x.name
        , val = first(obj, x.query);

      // Transform value if we have a transform available
      if (x.transform && val !== null) val = x.transform.call(that, val);

      return [key, val];
    })
    .filter(function (x) {
      return x[1] !== null;
    })
    .object()
    .value();

  return _.keys(res).length ? res : null;
};
<commit_msg>Format differently for DE<commit_after>/**
 * Module dependencies
 */
var request = require('superagent')
  , path = require('JSONPath').eval
  , accounting = require('accounting')
  , currency = require('currency-symbol-map')
  , _ = require('underscore');

var endpoint = 'https://api.zanox.com/json/2011-03-01/products';

module.exports = function (opts) {
  return new Zanox(opts);
};

var Zanox = function Zanox (opts) {
  if ('object' === typeof opts) {
    this._keywords = opts.keywords;
  } else {
    this._keywords = opts;
  }

  // Setup defaults
  _.defaults(this, {
    _partnership: 'all'
  });
};

Zanox.prototype.id = function (id) {
  return this._id = id, this;
};

Zanox.prototype.keywords = function (kw) {
  return this._keywords = kw, this;
};

Zanox.prototype.country = function (country) {
  return this._country = country, this;
};

Zanox.prototype.category = function (category) {
  return this._category = category, this;
};

Zanox.prototype.program = function (program) {
  if (!this._programs) this._programs = [];

  return this._programs.push(program), this;
};

Zanox.prototype.minPrice = function (min) {
  return this._minPrice = min, this;
};

Zanox.prototype.maxPrice = function (max) {
  return this._maxPrice = max, this;
};

Zanox.prototype.price = function (price) {
  if (_.isArray(price)) {
    this._minPrice = price[0], this._maxPrice = price[1];
  } else if (_.isString(price)) {
    var split = price.split('..');

    if (split[0]) this._minPrice = split[0];
    if (split[1]) this._maxPrice = split[1];
  }

  return this;
};

Zanox.prototype.ean = function (ean) {
  return this._ean = ean, this;
};

Zanox.prototype.numItems = function (n) {
  return this._numItems = n, this;
};

Zanox.prototype.partnership = function (p) {
  return this._partnership = p, this;
};

Zanox.prototype.searchType = function (t) {
  return this._searchType = t, this;
};

Zanox.prototype.done = function (cb) {
  var that = this;

  var r = request
    .get(endpoint)
    .query({searchtype: this._searchType})
    .query({connectid: this._id})
    .query({q: this._keywords})
    .query({region: this._country})
    .query({merchantcategory: this._category})
    .query({partnership: this._partnership})
    .query({minprice: this._minPrice})
    .query({maxprice: this._maxPrice})
    .query({ean: this._ean})
    .query({items: 1})
    .query({programs: this._programs && this._programs.join(',')})
    .end(function (err, res) {
      // Handle connection errors
      if (err) return cb(err);

      // Handle client errors
      if (res.body.message) return cb(new Error(res.body.message));

      // Callback
      return cb(null, parseResults.call(that, res.body, extractions));
    });
};

var formatPrice = function (p) {
  var amount = p.price
    , code = p.currency
    , decimal, thousand;

  if (!amount || !code) return null;

  if (~['DE'].indexOf(this._country)) {
    decimal = ','; thousand = '.';
  } else {
    decimal = '.'; thousand = ',';
  }

  return accounting.formatMoney(amount, currency(code), null, thousand, decimal);
};

var extractions = [
  { name: 'id', query: '$..@id' },
  { name: 'name', query: '$..name' },
  { name: 'url', query: '$..trackingLink..ppc' },
  { name: 'listPrice',
    query: '$..productItem[0]',
    transform: formatPrice
  }
];

var first = function (obj, query) {
  var res = path(obj, query);
  return res.length ? res[0] : null;
};

var parseResults = function (obj, extractions) {
  var that = this;

  var res = _
    .chain(extractions)
    .map(function (x) {
      var key = x.name
        , val = first(obj, x.query);

      // Transform value if we have a transform available
      if (x.transform && val !== null) val = x.transform.call(that, val);

      return [key, val];
    })
    .filter(function (x) {
      return x[1] !== null;
    })
    .object()
    .value();

  return _.keys(res).length ? res : null;
};
<|endoftext|>


<commit_before>var { NativeModules } = require('react-native');
var ReactCBLite = NativeModules.ReactCBLite;

var base64 = require('base-64');

var manager = function (databaseUrl, databaseName) {
  this.authHeader = "Basic " + base64.encode(databaseUrl.split("//")[1].split('@')[0]);
  this.databaseUrl = databaseUrl;
  this.databaseName = databaseName;
};

manager.prototype = {

  /**
   * Construct a new Couchbase object given a database URL and database name
   *
   * @returns {*|promise}
   */
  createDatabase: function() {
    return this.makeRequest("PUT", this.databaseUrl + this.databaseName, null, null);
  },

  /**
   * Delete the database
   *
   * @returns {*|promise}
   */
  deleteDatabase: function() {
    return this.makeRequest("DELETE", this.databaseUrl + this.databaseName, null, null);
  },

  /*
   * Create a new design document with views
   *
   * @param    string designDocumentName
   * @param    object designDocumentViews
   * @return   promise
   */
  createDesignDocument: function(designDocumentName, designDocumentViews) {
    var data = {
      views: designDocumentViews
    };
    return this.makeRequest("PUT", this.databaseUrl + this.databaseName + "/" + designDocumentName, {}, data);
  },

  /*
   * Get a design document and all views associated to insert
   *
   * @param    string designDocumentName
   * @return   promise
   */
  getDesignDocument: function(designDocumentName) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + designDocumentName);
  },

  /*
   * Query a particular database view
   *
   * @param    string designDocumentName
   * @param    string viewName
   * @param    object options
   * @return   promise
   */
  queryView: function(designDocumentName, viewName, options) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + designDocumentName + "/_view/" + viewName, options);
  },

  /**
   * Create a new database document
   *
   * @param object jsonDocument
   * @returns {*|promise}
   */
  createDocument: function (jsonDocument) {
    return this.makeRequest("POST", this.databaseUrl + this.databaseName, {}, jsonDocument);
  },

  /**
   * Delete a particular document based on its id and revision
   *
   * @param documentId
   * @param documentRevision
   * @return promise
   */
  deleteDocument: function(documentId, documentRevision) {
    return this.makeRequest("DELETE", this.databaseUrl + this.databaseName + "/" + documentId + "?rev=" + documentRevision);
  },

  /*
   * Get a document from the database
   *
   * @param    string documentId
   * @return   promise
   */
  getDocument: function(documentId) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + documentId);
  },

  /**
   * Get all documents from the database
   *
   * @returns {*|promise}
   */
  getAllDocuments: function() {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/_all_docs?include_docs=true");
  },

  /**
   * Replicate in a single direction whether that be remote from local or local to remote
   *
   * @param source
   * @param target
   * @param continuous
   * @returns {*|promise}
   */
  replicate: function(source, target, continuous) {
    return this.makeRequest("POST", this.databaseUrl + "_replicate", {}, {
      source: source,
      target: target,
      continuous: continuous
    });
  },

  /**
   * Make a RESTful request to an endpoint while providing parameters or data or both
   *
   * @param string method
   * @param string url
   * @param object params
   * @param object data
   * @returns {*|promise}
   */
  makeRequest: function(method, url, params, data) {
    var settings = {
      method: method,
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': this.authHeader
      }
    };
    if (params) {
      settings.params = params;
    }
    if (data) {
      settings.body = JSON.stringify(data);
    }
    return fetch(url, settings).then((res) => {
      if (res.status == 401) {
        console.log(res);
      }
      return res.json();
    }).catch((err) => { throw err; });
  }
};

module.exports = {manager, ReactCBLite};<commit_msg>Fix doc sections for syntax highlighting<commit_after>var { NativeModules } = require('react-native');
var ReactCBLite = NativeModules.ReactCBLite;

var base64 = require('base-64');

var manager = function (databaseUrl, databaseName) {
  this.authHeader = "Basic " + base64.encode(databaseUrl.split("//")[1].split('@')[0]);
  this.databaseUrl = databaseUrl;
  this.databaseName = databaseName;
};

manager.prototype = {

  /**
   * Construct a new Couchbase object given a database URL and database name
   *
   * @returns {*|promise}
   */
  createDatabase: function() {
    return this.makeRequest("PUT", this.databaseUrl + this.databaseName, null, null);
  },

  /**
   * Delete the database
   *
   * @returns {*|promise}
   */
  deleteDatabase: function() {
    return this.makeRequest("DELETE", this.databaseUrl + this.databaseName, null, null);
  },

  /**
   * Create a new design document with views
   *
   * @param    string designDocumentName
   * @param    object designDocumentViews
   * @return   promise
   */
  createDesignDocument: function(designDocumentName, designDocumentViews) {
    var data = {
      views: designDocumentViews
    };
    return this.makeRequest("PUT", this.databaseUrl + this.databaseName + "/" + designDocumentName, {}, data);
  },

  /**
   * Get a design document and all views associated to insert
   *
   * @param    string designDocumentName
   * @return   promise
   */
  getDesignDocument: function(designDocumentName) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + designDocumentName);
  },

  /**
   * Query a particular database view
   *
   * @param    string designDocumentName
   * @param    string viewName
   * @param    object options
   * @return   promise
   */
  queryView: function(designDocumentName, viewName, options) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + designDocumentName + "/_view/" + viewName, options);
  },

  /**
   * Create a new database document
   *
   * @param object jsonDocument
   * @returns {*|promise}
   */
  createDocument: function (jsonDocument) {
    return this.makeRequest("POST", this.databaseUrl + this.databaseName, {}, jsonDocument);
  },

  /**
   * Delete a particular document based on its id and revision
   *
   * @param documentId
   * @param documentRevision
   * @return promise
   */
  deleteDocument: function(documentId, documentRevision) {
    return this.makeRequest("DELETE", this.databaseUrl + this.databaseName + "/" + documentId + "?rev=" + documentRevision);
  },

  /**
   * Get a document from the database
   *
   * @param    string documentId
   * @return   promise
   */
  getDocument: function(documentId) {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + documentId);
  },

  /**
   * Get all documents from the database
   *
   * @returns {*|promise}
   */
  getAllDocuments: function() {
    return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/_all_docs?include_docs=true");
  },

  /**
   * Replicate in a single direction whether that be remote from local or local to remote
   *
   * @param source
   * @param target
   * @param continuous
   * @returns {*|promise}
   */
  replicate: function(source, target, continuous) {
    return this.makeRequest("POST", this.databaseUrl + "_replicate", {}, {
      source: source,
      target: target,
      continuous: continuous
    });
  },

  /**
   * Make a RESTful request to an endpoint while providing parameters or data or both
   *
   * @param string method
   * @param string url
   * @param object params
   * @param object data
   * @returns {*|promise}
   */
  makeRequest: function(method, url, params, data) {
    var settings = {
      method: method,
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': this.authHeader
      }
    };
    if (params) {
      settings.params = params;
    }
    if (data) {
      settings.body = JSON.stringify(data);
    }
    return fetch(url, settings).then((res) => {
      if (res.status == 401) {
        console.log(res);
      }
      return res.json();
    }).catch((err) => { throw err; });
  }
};

module.exports = {manager, ReactCBLite};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var fs = require('fs')
  , path = require('path')
  , repl = require('repl')
  , colony = require('colony')
  , net = require('net')
  , spawn = require('child_process').spawn;

var choices = require('choices')
  , colors = require('colors')
  , async = require('async')
  , portscanner = require('portscanner')
  , optimist = require('optimist');

var argv = optimist.argv;

function usage () {
  console.error("Tessel CLI\nUsage:\n" +
    "       tessel <filename>\n" +
    "       tessel listen\n" +
    "       tessel push <filename> [-r <ip:port>]\n" +
    "       tessel wifi <ssid> <pass>\n");
}

if (process.argv.length < 3) {
  usage();
  process.exit(1);
}

// Compile a filename to code, detect error situation.

function compile (file, safe, next) {
  try {
    colony.bundleFiles(path.join(process.cwd(), file), {
      tessel: __dirname + '/node_modules/tessel-lib'
    }, function (luacode) {
      next(new Buffer(luacode));
    });
  } catch (e) {
    if (!safe) {
      // console.error('Invalid JavaScript code (error ', code + '), aborting.');
      console.error(e);
      process.on('exit', function() {
        process.exit(1);
      });
    } else {
      next(null);
    }
  }
}

function repeatstr (str, n) {
  return Array(n + 1).join(str);
}

var header = {
  init: function () {
    header._msg('TESSEL? '.grey);
  },
  _unwrite: function (n) {
    process.stdout.write(repeatstr('\b', n));
    header.len = 0;
  },
  _msg: function (str) {
    header._unwrite(header.len || 0);
    header.len = str.stripColors.length;
    process.stdout.write(str);
  },
  nofound: function () {
    header._msg('TESSEL? No Tessel found, waiting...'.grey);
  },
  connecting: function (modem) {
    header._msg('TESSEL? Connecting to '.grey + modem.grey + '...');
  },
  connected: function (modem) {
    header._msg('TESSEL!'.bold.cyan + ' Connected to '.cyan + modem.green + '.          \n'.cyan);
  }
}

var net = require('net');

// TCP
// if (process.argv[2] == 'remotepush') {
//   if (process.argv.length < 6) {
//     usage();
//     process.exit(1);
//   }

//   var filename = process.argv[3];
//   var ip = process.argv[4];
//   var port = process.argv[5];

//   var net = require('net');
//   var fs = require('fs');

//   compile(filename, false, function (luacode) {
//     console.log('Writing', luacode.length, 'bytes by TCP...');
//     var client = net.connect(port, ip, function () {
//       console.log('connected');
//       var sizebuf = new Buffer(4);
//       sizebuf.writeInt32LE(luacode.length, 0);
//       client.write(Buffer.concat([sizebuf, luacode]), function () {
//         console.log('written');
//         // client.end();
//       });
//     });
//     client.on('end', function () {
//       console.log('disconnected');
//     });
//   });
// } else {
  header.init();

  if (argv.r) {
    var args = argv.r.split(':');
    host = args[0];
    port = args[1];
    onconnect('[remote]', port, host);
  } else {
    detectDevice(function (modem) {
      // Listening.
      // if (process.argv[2] == '-l') {
      handshake(modem, function () {
        onconnect(modem, 6540, 'localhost');
      });
    });
  }

  function onconnect (modem, port, host) {
    var tesselclient = net.connect(port, host);
    tesselclient.pipe(process.stdout);
    tesselclient.on('connect', function () {
      header.connected(modem);
    });

    if (process.argv[2] == 'push') {
      if (process.argv.length < 4) {
        usage();
        process.exit(1);
      }

      compile(process.argv[3], false, function (luacode) {
        upload(tesselclient, luacode);
      });
    } else if (process.argv[2] == 'wifi') {
      var ssid = process.argv[3];
      var pass = process.argv[4];

      if (process.argv.length < 5) {
        usage();
        process.exit(1);
      }

      tesselclient.on('connect', function () {
        console.log(('Connecting to ' + ssid + ':' + pass + '...').yellow);
      });

      var outbuf = new Buffer(96);
      outbuf.fill(0);
      new Buffer(ssid).copy(outbuf, 0, 0, 32);
      new Buffer(pass).copy(outbuf, 32, 0, 64);

      var sizebuf = new Buffer(5);
      sizebuf.writeUInt8('W'.charCodeAt(0), 0);
      sizebuf.writeInt32LE(outbuf.length, 1);

      tesselclient.write(Buffer.concat([sizebuf, outbuf]), function () {
        // console.log(String('[it is written]').grey);
      });
    } else if (process.argv[2] == 'listen') {
      // nop
    } else {
      usage();
      process.exit(1);
    }
  }
  // }

  // Interactive.
  // handshake(modem, function (serial) {
  //   if (process.argv[2] == '-i') {
  //     console.log('[connected]'.grey);

  //     repl.start({
  //       prompt: "",
  //       input: process.stdin,
  //       output: process.stdout,
  //       ignoreUndefined: true,
  //       eval: function eval(cmd, context, filename, callback) {
  //         cmd = cmd.replace(/^.|\n.$/g, '');
  //         runeval(cmd, function () {
  //           callback(null, undefined);
  //         });
  //       }
  //     }).on('exit', function (code) {
  //       process.exit(code);
  //     })

  //     // process.stdin.on('data', function (data) {

  //     function runeval (data, next) {
  //       fs.writeFileSync(path.join(__dirname, 'tmp', 'repl.js'), data);
  //       compile(path.join(__dirname, 'tmp', 'repl.js'), true, function (luacode) {
  //         if (luacode) {
  //           upload(serial, luacode);
  //           next();
  //         } else {
  //           process.stdout.write('> ');
  //           next();
  //         }
  //       });
  //     }

  //     serial.once('data', function () {
  //       console.log('global.board = require(\'tm\')');
  //       runeval('global.board = require(\'tm\')', function () { });
  //     })

  //   } else {
  //     compile(process.argv[2], false, function (luacode) {
  //       upload(serial, luacode);
  //     });
  //   }
  // });
// }

function detectDevice (next) {
  var modems = fs.readdirSync('/dev').filter(function (file) {
    return file.match(/^cu.usbmodem.*$/);
  });

  if (modems.length == 0) {
    if (!detectDevice.firstNoDevicesFound) {
      header.nofound();
      detectDevice.firstNoDevicesFound = true;
    }
    return setTimeout(detectDevice, 10, next);
  }

  if (modems.length > 1) {
    choices('Select a device: ', modems, function (i) {
      next('/dev/' + modems[i]);
    });
  } else {
    next('/dev/' + modems[0]);
  }
}

function handshake (modem, next) {
  header.connecting(modem);

  portscanner.checkPortStatus(6540, 'localhost', function (err, status) {
    if (status != 'open') {
      var child = spawn(process.argv[0], [__dirname + '/server.js', modem], {
        stdio: [0, 1, 2, 'ipc'],
        detached: true
      });
      child.on('message', function (m) {
        if (m.ready) {
          // child.unref();
          // child.disconnect();
          next(null);
        }
      });
    } else {
      next(null);
    }
  });
}

function upload (client, luacode) {
  var sizebuf = new Buffer(5);
  sizebuf.writeUInt8('U'.charCodeAt(0), 0);
  sizebuf.writeInt32LE(luacode.length, 1);
  client.write(Buffer.concat([sizebuf, luacode]), function () {
    // console.log(String('[it is written]').grey);
  });
}<commit_msg>Abrupt fix for Node 0.8<commit_after>#!/usr/bin/env node

var fs = require('fs')
  , path = require('path')
  , repl = require('repl')
  , colony = require('colony')
  , net = require('net')
  , spawn = require('child_process').spawn;

var choices = require('choices')
  , colors = require('colors')
  , async = require('async')
  , portscanner = require('portscanner')
  , optimist = require('optimist');

var argv = optimist.argv;

function usage () {
  console.error("Tessel CLI\nUsage:\n" +
    "       tessel <filename>\n" +
    "       tessel listen\n" +
    "       tessel push <filename> [-r <ip:port>]\n" +
    "       tessel wifi <ssid> <pass>\n");
}

if (process.argv.length < 3) {
  usage();
  process.exit(1);
}

// Compile a filename to code, detect error situation.

function compile (file, safe, next) {
  try {
    colony.bundleFiles(path.join(process.cwd(), file), {
      tessel: __dirname + '/node_modules/tessel-lib'
    }, function (luacode) {
      next(new Buffer(luacode));
    });
  } catch (e) {
    if (!safe) {
      // console.error('Invalid JavaScript code (error ', code + '), aborting.');
      console.error(e);
      process.on('exit', function() {
        process.exit(1);
      });
    } else {
      next(null);
    }
  }
}

function repeatstr (str, n) {
  return Array(n + 1).join(str);
}

var header = {
  init: function () {
    header._msg('TESSEL? '.grey);
  },
  _unwrite: function (n) {
    process.stdout.write(repeatstr('\b', n));
    header.len = 0;
  },
  _msg: function (str) {
    header._unwrite(header.len || 0);
    header.len = str.stripColors.length;
    process.stdout.write(str);
  },
  nofound: function () {
    header._msg('TESSEL? No Tessel found, waiting...'.grey);
  },
  connecting: function (modem) {
    header._msg('TESSEL? Connecting to '.grey + modem.grey + '...');
  },
  connected: function (modem) {
    header._msg('TESSEL!'.bold.cyan + ' Connected to '.cyan + modem.green + '.          \n'.cyan);
  }
}

var net = require('net');

// TCP
// if (process.argv[2] == 'remotepush') {
//   if (process.argv.length < 6) {
//     usage();
//     process.exit(1);
//   }

//   var filename = process.argv[3];
//   var ip = process.argv[4];
//   var port = process.argv[5];

//   var net = require('net');
//   var fs = require('fs');

//   compile(filename, false, function (luacode) {
//     console.log('Writing', luacode.length, 'bytes by TCP...');
//     var client = net.connect(port, ip, function () {
//       console.log('connected');
//       var sizebuf = new Buffer(4);
//       sizebuf.writeInt32LE(luacode.length, 0);
//       client.write(Buffer.concat([sizebuf, luacode]), function () {
//         console.log('written');
//         // client.end();
//       });
//     });
//     client.on('end', function () {
//       console.log('disconnected');
//     });
//   });
// } else {
  header.init();

  if (argv.r) {
    var args = argv.r.split(':');
    host = args[0];
    port = args[1];
    onconnect('[remote]', port, host);
  } else {
    detectDevice(function (modem) {
      // Listening.
      // if (process.argv[2] == '-l') {
      handshake(modem, function () {
        onconnect(modem, 6540, 'localhost');
      });
    });
  }

  function onconnect (modem, port, host) {
    var tesselclient = net.connect(port, host);
    tesselclient.pipe(process.stdout);
    tesselclient.on('connect', function () {
      header.connected(modem);
    });

    if (process.argv[2] == 'push') {
      if (process.argv.length < 4) {
        usage();
        process.exit(1);
      }

      compile(process.argv[3], false, function (luacode) {
        upload(tesselclient, luacode);
      });
    } else if (process.argv[2] == 'wifi') {
      var ssid = process.argv[3];
      var pass = process.argv[4];

      if (process.argv.length < 5) {
        usage();
        process.exit(1);
      }

      tesselclient.on('connect', function () {
        console.log(('Connecting to ' + ssid + ':' + pass + '...').yellow);
      });

      var outbuf = new Buffer(96);
      outbuf.fill(0);
      // TODO use byteslength for node 0.8
      new Buffer(ssid).copy(outbuf, 0, 0, ssid.length);
      new Buffer(pass).copy(outbuf, 32, 0, pass.length);

      var sizebuf = new Buffer(5);
      sizebuf.writeUInt8('W'.charCodeAt(0), 0);
      sizebuf.writeInt32LE(outbuf.length, 1);

      tesselclient.write(Buffer.concat([sizebuf, outbuf]), function () {
        // console.log(String('[it is written]').grey);
      });
    } else if (process.argv[2] == 'listen') {
      // nop
    } else {
      usage();
      process.exit(1);
    }
  }
  // }

  // Interactive.
  // handshake(modem, function (serial) {
  //   if (process.argv[2] == '-i') {
  //     console.log('[connected]'.grey);

  //     repl.start({
  //       prompt: "",
  //       input: process.stdin,
  //       output: process.stdout,
  //       ignoreUndefined: true,
  //       eval: function eval(cmd, context, filename, callback) {
  //         cmd = cmd.replace(/^.|\n.$/g, '');
  //         runeval(cmd, function () {
  //           callback(null, undefined);
  //         });
  //       }
  //     }).on('exit', function (code) {
  //       process.exit(code);
  //     })

  //     // process.stdin.on('data', function (data) {

  //     function runeval (data, next) {
  //       fs.writeFileSync(path.join(__dirname, 'tmp', 'repl.js'), data);
  //       compile(path.join(__dirname, 'tmp', 'repl.js'), true, function (luacode) {
  //         if (luacode) {
  //           upload(serial, luacode);
  //           next();
  //         } else {
  //           process.stdout.write('> ');
  //           next();
  //         }
  //       });
  //     }

  //     serial.once('data', function () {
  //       console.log('global.board = require(\'tm\')');
  //       runeval('global.board = require(\'tm\')', function () { });
  //     })

  //   } else {
  //     compile(process.argv[2], false, function (luacode) {
  //       upload(serial, luacode);
  //     });
  //   }
  // });
// }

function detectDevice (next) {
  var modems = fs.readdirSync('/dev').filter(function (file) {
    return file.match(/^cu.usbmodem.*$/);
  });

  if (modems.length == 0) {
    if (!detectDevice.firstNoDevicesFound) {
      header.nofound();
      detectDevice.firstNoDevicesFound = true;
    }
    return setTimeout(detectDevice, 10, next);
  }

  if (modems.length > 1) {
    choices('Select a device: ', modems, function (i) {
      next('/dev/' + modems[i]);
    });
  } else {
    next('/dev/' + modems[0]);
  }
}

function handshake (modem, next) {
  header.connecting(modem);

  portscanner.checkPortStatus(6540, 'localhost', function (err, status) {
    if (status != 'open') {
      var child = spawn(process.argv[0], [__dirname + '/server.js', modem], {
        stdio: [0, 1, 2, 'ipc'],
        detached: true
      });
      child.on('message', function (m) {
        if (m.ready) {
          // child.unref();
          // child.disconnect();
          next(null);
        }
      });
    } else {
      next(null);
    }
  });
}

function upload (client, luacode) {
  var sizebuf = new Buffer(5);
  sizebuf.writeUInt8('U'.charCodeAt(0), 0);
  sizebuf.writeInt32LE(luacode.length, 1);
  client.write(Buffer.concat([sizebuf, luacode]), function () {
    // console.log(String('[it is written]').grey);
  });
}<|endoftext|>


<commit_before>/**
 * Load Modules
 */
var http = require('http'),
	request = require('request'),
	fs = require('fs'),
	events = require('events'),
	emitter = new events.EventEmitter(),
	Notification = require('node-notifier'),
	Slack = require('node-slack'),
	slack = false
;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Local Variables
 */
var options = {
		url:    'http://sirocco.accuweather.com/adc_images2/english/feature/400x300/worstwx.jpg',
		log:    __dirname + '/last-modified.txt',
		images: __dirname + '/images',
		slack:  __dirname + '/slack.json'
	},
	config = {}
;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Enable Slack
 */
fs.exists(options.slack, function(exists) {
	if ( ! exists ) return;

	config = require(options.slack);
	slack = new Slack(config.token.webhook);
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Local Last Modified Time
 */
function getLocalModified() {
	fs.exists(options.log, function(exists) {
		if ( ! exists ) {
			emitter.emit('localModified', exists);
			return;
		}

		fs.readFile(options.log, 'utf8', function(error, data) {
			if (error) {
				return console.log(error);
			}

			emitter.emit('localModified', data);
		});
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Remote Last Modified Time
 *
 * @param string|bool modified
 */
emitter.on('localModified', function(modified) {
	http.get(options.url, function(response) {
		if ( modified === response.headers['last-modified'] ) return;

		writeImage(response);
		updateLocal(response.headers['last-modified']);
	}).on('error', function(error) {
		console.log(error);
	});
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Update Local Last Modified
 *
 * @param string modified
 */
function updateLocal(modified) {
	fs.writeFile(options.log, modified, function(error) {
		if (error) return console.log(error);
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Write Remote Image to Local Directory
 *
 * @param object response
 */
function writeImage(response) {
	var imagedata = '',
		now = new Date(),
		filename = now.getFullYear() + '_' + (now.getMonth() + 1) + '_' + now.getDate() + '.jpg'
	;

	if ( ! fs.existsSync(options.images) ) {
		fs.mkdirSync(options.images);
	}

	response.setEncoding('binary');

	response.on('data', function(chunk) {
		imagedata += chunk;
	});

	response.on('end', function() {
		fs.writeFile(options.images + '/' + filename, imagedata, 'binary', function(error){
			if (error) return console.log(error);

			emitter.emit('newImage', options.images + '/' + filename);
		});
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send Desktop Notification
 *
 * @param string image
 */
function sendNotification(image) {
	var notifier = new Notification();

	notifier.notify({
		title:       'AccuWeather',
		message:     'Today’s Worst Weather',
		contentImage: image,
		appIcon:      __dirname + '/accuweather.png',
		open:         'file://' + image
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send Slack Message
 *
 * @param string image
 */
function sendSlack(image) {
	if ( ! slack ) return;

	if ( ! config.token.api ) {
		emitter.emit('slackMessage', options.url);
		return;
	}

	var	data = {
		'channels': '#accuweather',
		'token': config.token.api,
		'file': fs.createReadStream(image)
	};

	request.post({url: 'https://slack.com/api/files.upload', formData: data}, function(err, res, body) {
		if (err) return console.log(err);

		var data = JSON.parse(body);
		emitter.emit('slackMessage', data.file.url);
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

emitter.on('slackMessage', function(url) {
	slack.send({
		text: 'Today’s Worst Weather ' + url,
		channel: config.channel,
		username: 'AccuWeather',
		icon_emoji: ':sunny:',
		unfurl_links: true
	}, function(error, response) {
		if (error) console.log(error);
	});
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * New Image Listeners
 */
emitter.on('newImage', function(image) {
	sendNotification(image);
	sendSlack(image);
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Init
 */
getLocalModified();<commit_msg>Allow the channel to be set in the config.<commit_after>/**
 * Load Modules
 */
var http = require('http'),
	request = require('request'),
	fs = require('fs'),
	events = require('events'),
	emitter = new events.EventEmitter(),
	Notification = require('node-notifier'),
	Slack = require('node-slack'),
	slack = false
;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Local Variables
 */
var options = {
		url:    'http://sirocco.accuweather.com/adc_images2/english/feature/400x300/worstwx.jpg',
		log:    __dirname + '/last-modified.txt',
		images: __dirname + '/images',
		slack:  __dirname + '/slack.json'
	},
	config = {}
;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Enable Slack
 */
fs.exists(options.slack, function(exists) {
	if ( ! exists ) return;

	config = require(options.slack);
	slack = new Slack(config.token.webhook);
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Local Last Modified Time
 */
function getLocalModified() {
	fs.exists(options.log, function(exists) {
		if ( ! exists ) {
			emitter.emit('localModified', exists);
			return;
		}

		fs.readFile(options.log, 'utf8', function(error, data) {
			if (error) {
				return console.log(error);
			}

			emitter.emit('localModified', data);
		});
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Remote Last Modified Time
 *
 * @param string|bool modified
 */
emitter.on('localModified', function(modified) {
	http.get(options.url, function(response) {
		if ( modified === response.headers['last-modified'] ) return;

		writeImage(response);
		updateLocal(response.headers['last-modified']);
	}).on('error', function(error) {
		console.log(error);
	});
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Update Local Last Modified
 *
 * @param string modified
 */
function updateLocal(modified) {
	fs.writeFile(options.log, modified, function(error) {
		if (error) return console.log(error);
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Write Remote Image to Local Directory
 *
 * @param object response
 */
function writeImage(response) {
	var imagedata = '',
		now = new Date(),
		filename = now.getFullYear() + '_' + (now.getMonth() + 1) + '_' + now.getDate() + '.jpg'
	;

	if ( ! fs.existsSync(options.images) ) {
		fs.mkdirSync(options.images);
	}

	response.setEncoding('binary');

	response.on('data', function(chunk) {
		imagedata += chunk;
	});

	response.on('end', function() {
		fs.writeFile(options.images + '/' + filename, imagedata, 'binary', function(error){
			if (error) return console.log(error);

			emitter.emit('newImage', options.images + '/' + filename);
		});
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send Desktop Notification
 *
 * @param string image
 */
function sendNotification(image) {
	var notifier = new Notification();

	notifier.notify({
		title:       'AccuWeather',
		message:     'Today’s Worst Weather',
		contentImage: image,
		appIcon:      __dirname + '/accuweather.png',
		open:         'file://' + image
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Send Slack Message
 *
 * @param string image
 */
function sendSlack(image) {
	if ( ! slack ) return;

	if ( ! config.token.api ) {
		emitter.emit('slackMessage', options.url);
		return;
	}

	var	data = {
		channels: config.channel,
		token   : config.token.api,
		file    : fs.createReadStream(image)
	};

	request.post({url: 'https://slack.com/api/files.upload', formData: data}, function(err, res, body) {
		if (err) return console.log(err);

		var data = JSON.parse(body);

		emitter.emit('slackMessage', data.file.url);
	});
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

emitter.on('slackMessage', function(url) {
	slack.send({
		text: 'Today’s Worst Weather ' + url,
		channel: config.channel,
		username: 'AccuWeather',
		icon_emoji: ':sunny:',
		unfurl_links: true
	}, function(error, response) {
		if (error) console.log(error);
	});
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * New Image Listeners
 */
emitter.on('newImage', function(image) {
	sendNotification(image);
	sendSlack(image);
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * Init
 */
getLocalModified();<|endoftext|>