<commit_before>'use strict';

var is = require('is_js');

var debug = function () {};

var GET_RE = /.*(get).*/gi;
var POST_RE = /.*(post).*/gi;
var PUT_RE = /.*(put).*/gi;
var DELETE_RE = /.*(delete).*/gi;
var $1 = '$1';

/**
 * Returns a clean, lower case method name.
 */
function clean(method) {
  if (method.match(GET_RE)) {
    return method.replace(GET_RE, $1).toLowerCase();
  }

  if (method.match(POST_RE)) {
    return method.replace(POST_RE, $1).toLowerCase();
  }

  if (method.match(PUT_RE)) {
    return method.replace(PUT_RE, $1).toLowerCase();
  }

  if (method.match(DELETE_RE)) {
    return method.replace(DELETE_RE, $1).toLowerCase();
  }

  throw new Error("Invalid method [" + method + "]!");
}

/**
 * Normalizes a route object.
 */
function normalize(route) {
  if (is.not.array(route.path) && is.not.string(route.path)) {
    throw new Error("The route's path must be a [String] or an [Array] of [String]s!");
  }

  if (is.array(route.method)) {
    /* If method is an array */
    route.method.forEach(function (method, index) {
      route.method[index] = clean(method);
    });
  }

  /* If method is a string */
  if (is.string(route.method)) {
    route.method = clean(route.method);
  }

  return route;
}

/**
 * Authorizes a route for the current session.
 *
 * @type Express Middleware.
 *
 * @param {Object} route The route object.
 * @param {Object} req Express' req object.
 * @param {Object} res Express' res object.
 * @param {Function} next Express' next function.
 */
function authorize(req, res, next) {
  var allowed = true;

  if (is.array(req.allows)) {
    allowed = req.route.allows.indexOf(req.session.authorized) > -1;
  } else if (is.string(req.route.allows)) {
    allowed = req.route.allows === req.session.authorized;
  }

  debug(req.method + " " + req.path + " [" + req.route.allows + "][" + req.session.authorized + "] : " + (allowed ? "OK" : "DENY"));

  if (allowed) {
    return next();
  }

  res.status(403).end();
}

/**
 * Generates the Express middleware to associate the allowed values to the route.
 */
function generate(allows) {
  return function (req, res, next) {
    req.route.allows = allows;

    next();
  };
}

/**
 * Initializes and registers route athuorizations.
 *
 * @param {Object} app Express application.
 * @param {Object} config Configuration object.
 */
function auth(app, config) {
  /* Ensure authorizer */
  if (is.not.function(config.authorizer)) {
    throw new Error("Authorizer must be a [Function]!");
  }

  /* Check debug type */
  if (is.function(config.debug)) {
    debug = config.debug;
  } else if (config.debug) {
    debug = console.log;
  }

  /* Set the authorized property in 'req.session' */
  app.use(function (req, res, next) {
    req.session.authorized = config.authorizer(req);

    next();
  });

  function onEachRoute(route) {
    route = normalize(route);

    debug(route.method + " " + route.path + " --> " + route.allows);

    var router = app.route(route.path);

    if (is.array(route.method) && route.method.length) {
      route.method.forEach(function (method) {
        router[method](generate(route.allows), authorize);
      });
    } else if (is.string(route.method)) {
      router[route.method](generate(route.allows), authorize);
    } else /* Defaults to all */ {
      router.all(generate(route.allows), authorize);
    }
  }

  /* Set authorization rules for each route */
  config.routes.forEach(onEachRoute);
}

module.exports = auth;
<commit_msg>Improved comments<commit_after>'use strict';

var is = require('is_js');

var debug = function () {};

var GET_RE = /.*(get).*/gi;
var POST_RE = /.*(post).*/gi;
var PUT_RE = /.*(put).*/gi;
var DELETE_RE = /.*(delete).*/gi;
var $1 = '$1';

/**
 * Returns a clean, lower case method name.
 */
function clean(method) {
  if (method.match(GET_RE)) {
    return method.replace(GET_RE, $1).toLowerCase();
  }

  if (method.match(POST_RE)) {
    return method.replace(POST_RE, $1).toLowerCase();
  }

  if (method.match(PUT_RE)) {
    return method.replace(PUT_RE, $1).toLowerCase();
  }

  if (method.match(DELETE_RE)) {
    return method.replace(DELETE_RE, $1).toLowerCase();
  }

  throw new Error("Invalid method [" + method + "]!");
}

/**
 * Normalizes a route object.
 */
function normalize(route) {
  if (is.not.array(route.path) && is.not.string(route.path)) {
    throw new Error("The route's path must be a [String] or an [Array] of [String]s!");
  }

  if (is.array(route.method)) {
    /* If method is an array */
    route.method.forEach(function (method, index) {
      route.method[index] = clean(method);
    });
  }

  /* If method is a string */
  if (is.string(route.method)) {
    route.method = clean(route.method);
  }

  return route;
}

/**
 * Authorizes a route for the current session.
 *
 * @type Express Middleware.
 */
function authorize(req, res, next) {
  var allowed = true;

  if (is.array(req.allows)) {
    allowed = req.route.allows.indexOf(req.session.authorized) > -1;
  } else if (is.string(req.route.allows)) {
    allowed = req.route.allows === req.session.authorized;
  }

  debug(req.method + " " + req.path + " [" + req.route.allows + "][" + req.session.authorized + "] : " + (allowed ? "OK" : "DENY"));

  if (allowed) {
    return next();
  }

  res.status(403).end();
}

/**
 * Generates the Express middleware to associate the allowed values to the route.
 */
function generate(allows) {
  return function (req, res, next) {
    req.route.allows = allows;

    next();
  };
}

/**
 * Initializes and registers route athuorizations.
 *
 * @param {Object} app Express application.
 * @param {Object} config Configuration object.
 */
function auth(app, config) {
  /* Ensure authorizer */
  if (is.not.function(config.authorizer)) {
    throw new Error("Authorizer must be a [Function]!");
  }

  /* Check debug type */
  if (is.function(config.debug)) {
    debug = config.debug;
  } else if (config.debug) {
    debug = console.log;
  }

  /* Set the authorized property in 'req.session' */
  app.use(function (req, res, next) {
    req.session.authorized = config.authorizer(req);

    next();
  });

  function onEachRoute(route) {
    route = normalize(route);

    debug(route.method + " " + route.path + " --> " + route.allows);

    var router = app.route(route.path);

    if (is.array(route.method) && route.method.length) {
      route.method.forEach(function (method) {
        router[method](generate(route.allows), authorize);
      });
    } else if (is.string(route.method)) {
      router[route.method](generate(route.allows), authorize);
    } else /* Defaults to all */ {
      router.all(generate(route.allows), authorize);
    }
  }

  /* Set authorization rules for each route */
  config.routes.forEach(onEachRoute);
}

module.exports = auth;
<|endoftext|>


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

var ads = require('ad-params');
var clone = require('clone');
var cookie = require('cookie');
var extend = require('extend');
var integration = require('analytics.js-integration');
var json = require('segmentio/json@1.0.0');
var localstorage = require('store');
var protocol = require('protocol');
var send = require('send-json');
var topDomain = require('top-domain');
var utm = require('utm-params');
var uuid = require('uuid');

/**
 * Cookie options
 */

var cookieOptions = {
  // 1 year
  maxage: 31536000000,
  secure: false,
  path: '/'
};

/**
 * Expose `Astronomer` integration.
 */

var Astronomer = exports = module.exports = integration('astronomer')
  // .option('apiKey', '');
  .option('appId', ''),
  .option('streamName', null);

/**
 * Get the store.
 *
 * @return {Function}
 */

exports.storage = function() {
  return protocol() === 'file:' || protocol() === 'chrome-extension:' ? localstorage : cookie;
};

/**
 * Expose global for testing.
 */

exports.global = window;

/**
 * Initialize.
 *
 * https://github.com/segmentio/segmentio/blob/master/modules/segmentjs/segment.js/v1/segment.js
 *
 * @api public
 */

Astronomer.prototype.initialize = function() {
  console.log("initialize ast");
  var self = this;
  this.ready();
  this.analytics.on('invoke', function(msg) {
    var action = msg.action();
    var listener = 'on' + msg.action();
    self.debug('%s %o', action, msg);
    if (self[listener]) self[listener](msg);
    self.ready();
  });
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */

Astronomer.prototype.loaded = function() {
  return true;
};

/**
 * Page.
 *
 * @api public
 * @param {Page} page
 */

Astronomer.prototype.onpage = function(page) {
  this.send('/p', page.json());
};

/**
 * Identify.
 *
 * @api public
 * @param {Identify} identify
 */

Astronomer.prototype.onidentify = function(identify) {
  this.send('/i', identify.json());
};

/**
 * Group.
 *
 * @api public
 * @param {Group} group
 */

Astronomer.prototype.ongroup = function(group) {
  this.send('/g', group.json());
};

/**
 * ontrack.
 *
 * TODO: Document this.
 *
 * @api private
 * @param {Track} track
 */

Astronomer.prototype.ontrack = function(track) {
  var json = track.json();
  // TODO: figure out why we need traits.
  delete json.traits;
  this.send('/t', json);
};

/**
 * Alias.
 *
 * @api public
 * @param {Alias} alias
 */

Astronomer.prototype.onalias = function(alias) {
  var json = alias.json();
  var user = this.analytics.user();
  json.previousId = json.previousId || json.from || user.id() || user.anonymousId();
  json.userId = json.userId || json.to;
  delete json.from;
  delete json.to;
  this.send('/a', json);
};

/**
 * Normalize the given `msg`.
 *
 * @api private
 * @param {Object} msg
 */

Astronomer.prototype.normalize = function(msg) {
  this.debug('normalize %o', msg);
  var user = this.analytics.user();
  var global = exports.global;
  var query = global.location.search;
  var ctx = msg.context = msg.context || msg.options || {};
  delete msg.options;
  // msg.writeKey = this.options.apiKey;
  msg.appId = this.options.appId;
  ctx.userAgent = navigator.userAgent;
  if (!ctx.library) ctx.library = { name: 'analytics.js', version: this.analytics.VERSION };
  if (query) ctx.campaign = utm(query);
  this.referrerId(query, ctx);
  msg.userId = msg.userId || user.id();
  msg.anonymousId = user.anonymousId();
  msg.messageId = uuid();
  msg.sentAt = new Date();
  this.debug('normalized %o', msg);
  return msg;
};

/**
 * Send `obj` to `path`.
 *
 * @api private
 * @param {string} path
 * @param {Object} obj
 * @param {Function} fn
 */

Astronomer.prototype.send = function(path, msg, fn) {
  var url = scheme() + '//api.astronomer.io/v1' + path;
  if (this.options.streamName) {
    url += "?streamName=" + this.options.streamName;
  }
  console.log(url);
  var headers = { 'Content-Type': 'text/plain' };
  fn = fn || noop;
  var self = this;

  // msg
  msg = this.normalize(msg);

  // send
  send(url, msg, headers, function(err, res) {
    self.debug('sent %O, received %O', msg, arguments);
    if (err) return fn(err);
    res.url = url;
    fn(null, res);
  });
};

/**
 * Gets/sets cookies on the appropriate domain.
 *
 * @api private
 * @param {string} name
 * @param {*} val
 */

Astronomer.prototype.cookie = function(name, val) {
  var store = Segment.storage();
  if (arguments.length === 1) return store(name);
  var global = exports.global;
  var href = global.location.href;
  var domain = '.' + topDomain(href);
  if (domain === '.') domain = '';
  this.debug('store domain %s -> %s', href, domain);
  var opts = clone(cookieOptions);
  opts.domain = domain;
  this.debug('store %s, %s, %o', name, val, opts);
  store(name, val, opts);
  if (store(name)) return;
  delete opts.domain;
  this.debug('fallback store %s, %s, %o', name, val, opts);
  store(name, val, opts);
};

/**
 * Add referrerId to context.
 *
 * TODO: remove.
 *
 * @api private
 * @param {Object} query
 * @param {Object} ctx
 */

Astronomer.prototype.referrerId = function(query, ctx) {
  var stored = this.cookie('s:context.referrer');
  var ad;

  if (stored) stored = json.parse(stored);
  if (query) ad = ads(query);

  ad = ad || stored;

  if (!ad) return;
  ctx.referrer = extend(ctx.referrer || {}, ad);
  this.cookie('s:context.referrer', json.stringify(ad));
};

/**
 * Get the scheme.
 *
 * The function returns `http:`
 * if the protocol is `http:` and
 * `https:` for other protocols.
 *
 * @api private
 * @return {string}
 */

function scheme() {
  return protocol() === 'http:' ? 'http:' : 'https:';
}

/**
 * Noop.
 */

function noop() {}
<commit_msg>SAVEPOINT<commit_after>
/**
 * Module dependencies.
 */

var ads = require('ad-params');
var clone = require('clone');
var cookie = require('cookie');
var extend = require('extend');
var integration = require('analytics.js-integration');
var json = require('segmentio/json@1.0.0');
var localstorage = require('store');
var protocol = require('protocol');
var send = require('send-json');
var topDomain = require('top-domain');
var utm = require('utm-params');
var uuid = require('uuid');

/**
 * Cookie options
 */

var cookieOptions = {
  // 1 year
  maxage: 31536000000,
  secure: false,
  path: '/'
};

/**
 * Expose `Astronomer` integration.
 */

var Astronomer = exports = module.exports = integration('astronomer')
  // .option('apiKey', '');
  .option('appId', ''),
  .option('streamName', null);

/**
 * Get the store.
 *
 * @return {Function}
 */

exports.storage = function() {
  return protocol() === 'file:' || protocol() === 'chrome-extension:' ? localstorage : cookie;
};

/**
 * Expose global for testing.
 */

exports.global = window;

/**
 * Initialize.
 *
 * https://github.com/segmentio/segmentio/blob/master/modules/segmentjs/segment.js/v1/segment.js
 *
 * @api public
 */

Astronomer.prototype.initialize = function() {
  console.log("initialize ast");
  var self = this;
  this.ready();
  this.analytics.on('invoke', function(msg) {
    var action = msg.action();
    var listener = 'on' + msg.action();
    self.debug('%s %o', action, msg);
    if (self[listener]) self[listener](msg);
    self.ready();
  });
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */

Astronomer.prototype.loaded = function() {
  return true;
};

/**
 * Page.
 *
 * @api public
 * @param {Page} page
 */

Astronomer.prototype.onpage = function(page) {
  this.send('/p', page.json());
};

/**
 * Identify.
 *
 * @api public
 * @param {Identify} identify
 */

Astronomer.prototype.onidentify = function(identify) {
  this.send('/i', identify.json());
};

/**
 * Group.
 *
 * @api public
 * @param {Group} group
 */

Astronomer.prototype.ongroup = function(group) {
  this.send('/g', group.json());
};

/**
 * ontrack.
 *
 * TODO: Document this.
 *
 * @api private
 * @param {Track} track
 */

Astronomer.prototype.ontrack = function(track) {
  var json = track.json();
  // TODO: figure out why we need traits.
  delete json.traits;
  this.send('/t', json);
};

/**
 * Alias.
 *
 * @api public
 * @param {Alias} alias
 */

Astronomer.prototype.onalias = function(alias) {
  var json = alias.json();
  var user = this.analytics.user();
  json.previousId = json.previousId || json.from || user.id() || user.anonymousId();
  json.userId = json.userId || json.to;
  delete json.from;
  delete json.to;
  this.send('/a', json);
};

/**
 * Normalize the given `msg`.
 *
 * @api private
 * @param {Object} msg
 */

Astronomer.prototype.normalize = function(msg) {
  this.debug('normalize %o', msg);
  var user = this.analytics.user();
  var global = exports.global;
  var query = global.location.search;
  var ctx = msg.context = msg.context || msg.options || {};
  delete msg.options;
  // msg.writeKey = this.options.apiKey;
  msg.appId = this.options.appId;
  ctx.userAgent = navigator.userAgent;
  if (!ctx.library) ctx.library = { name: 'analytics.js', version: this.analytics.VERSION };
  if (query) ctx.campaign = utm(query);
  this.referrerId(query, ctx);
  msg.userId = msg.userId || user.id();
  msg.anonymousId = user.anonymousId();
  msg.messageId = uuid();
  msg.sentAt = new Date();
  this.debug('normalized %o', msg);
  return msg;
};

/**
 * Send `obj` to `path`.
 *
 * @api private
 * @param {string} path
 * @param {Object} obj
 * @param {Function} fn
 */

Astronomer.prototype.send = function(path, msg, fn) {
  var url = scheme() + '//api.astronomer.io/v1' + path;
  if (this.options.streamName) {
    var qs = "?streamName=" + this.options.streamName;
    url += qs;
  }
  console.log(url);
  var headers = { 'Content-Type': 'text/plain' };
  fn = fn || noop;
  var self = this;

  // msg
  msg = this.normalize(msg);

  // send
  send(url, msg, headers, function(err, res) {
    self.debug('sent %O, received %O', msg, arguments);
    if (err) return fn(err);
    res.url = url;
    fn(null, res);
  });
};

/**
 * Gets/sets cookies on the appropriate domain.
 *
 * @api private
 * @param {string} name
 * @param {*} val
 */

Astronomer.prototype.cookie = function(name, val) {
  var store = Segment.storage();
  if (arguments.length === 1) return store(name);
  var global = exports.global;
  var href = global.location.href;
  var domain = '.' + topDomain(href);
  if (domain === '.') domain = '';
  this.debug('store domain %s -> %s', href, domain);
  var opts = clone(cookieOptions);
  opts.domain = domain;
  this.debug('store %s, %s, %o', name, val, opts);
  store(name, val, opts);
  if (store(name)) return;
  delete opts.domain;
  this.debug('fallback store %s, %s, %o', name, val, opts);
  store(name, val, opts);
};

/**
 * Add referrerId to context.
 *
 * TODO: remove.
 *
 * @api private
 * @param {Object} query
 * @param {Object} ctx
 */

Astronomer.prototype.referrerId = function(query, ctx) {
  var stored = this.cookie('s:context.referrer');
  var ad;

  if (stored) stored = json.parse(stored);
  if (query) ad = ads(query);

  ad = ad || stored;

  if (!ad) return;
  ctx.referrer = extend(ctx.referrer || {}, ad);
  this.cookie('s:context.referrer', json.stringify(ad));
};

/**
 * Get the scheme.
 *
 * The function returns `http:`
 * if the protocol is `http:` and
 * `https:` for other protocols.
 *
 * @api private
 * @return {string}
 */

function scheme() {
  return protocol() === 'http:' ? 'http:' : 'https:';
}

/**
 * Noop.
 */

function noop() {}
<|endoftext|>


<commit_before>const util = require('util');

const errorLevels = {
	debug: 0,
	info: 1,
	warn: 2,
	error: 3,
	fatal: 4
};

const config = {
	handlers: {
		debug: defaultHandler,
		info: defaultHandler,
		warn: defaultHandler,
		error: defaultHandler,
		fatal: defaultHandler
	},

	httpStatusMap: {},
	minLogLevel: 0
};

function defaultHandler(level, error) {
	if (errorLevels[level] < config.minLogLevel)
		return;

	var message = level + ':' + JSON.stringify(error);

	var method = level == 'fatal' ? 'error' : level;
	if (typeof console[method] === 'function')
		console[method](message);
	else
		console.log(message);
}

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);

	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	CuvvaError.super_(code);
	Error.captureStackTrace(this, this.constructor);

	Object.defineProperty(this, 'name', { get: function () { return 'CuvvaError'; } });
	Object.defineProperty(this, 'message', { get: function () { return this.code; } });

	this.code = code;
	this.meta = meta;
	this.reasons = reasons;
}

util.inherits(CuvvaError, Error);
module.exports.Error = CuvvaError;

function handleError(level, error) {
	if (!config.handlers[level])
		return;

	config.handlers[level](level, error);
}

module.exports.setHandler = function (level, handler) {
	if (typeof handler === 'undefined') {
		handler = level;

		if (typeof handler !== 'function')
			throw new Error('Handler is not a function');

		for (var prop in config.handlers)
			config.handlers[prop] = handler;

		return;
	}

	if (typeof handler !== 'function')
		throw new Error('Handler is not a function');

	config.handlers[level] = handler;
};

module.exports.setMinLogLevel = function (n) {
	config.minLogLevel = errorLevels[n];
};

module.exports.setHttpStatuses = function (statusMap) {
	for (var code in statusMap)
		config.httpStatusMap[code] = statusMap[code];
};

module.exports.coerceError = function (error) {
	if (error instanceof CuvvaError)
		return error;

	if (error instanceof Error)
		return new CuvvaError(error.message, { stack: error.stack });

	return new CuvvaError('unknown_runtime_error', { error: error });
};

function logger(level) {
	return function (code, reasons, meta) {
		if (code instanceof CuvvaError) {
			handleError(level, code);
			return code;
		}

		var err = new CuvvaError(code, reasons, meta);

		handleError(level, err);

		return err;
	};
}

module.exports.debug = logger('debug');
module.exports.info = logger('info');
module.exports.warn = logger('warn');
module.exports.error = logger('error');
module.exports.fatal = logger('fatal');
<commit_msg>Don't support logging existing 'CuvvaError' objects<commit_after>const util = require('util');

const errorLevels = {
	debug: 0,
	info: 1,
	warn: 2,
	error: 3,
	fatal: 4
};

const config = {
	handlers: {
		debug: defaultHandler,
		info: defaultHandler,
		warn: defaultHandler,
		error: defaultHandler,
		fatal: defaultHandler
	},

	httpStatusMap: {},
	minLogLevel: 0
};

function defaultHandler(level, error) {
	if (errorLevels[level] < config.minLogLevel)
		return;

	var message = level + ':' + JSON.stringify(error);

	var method = level == 'fatal' ? 'error' : level;
	if (typeof console[method] === 'function')
		console[method](message);
	else
		console.log(message);
}

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);

	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	CuvvaError.super_(code);
	Error.captureStackTrace(this, this.constructor);

	Object.defineProperty(this, 'name', { get: function () { return 'CuvvaError'; } });
	Object.defineProperty(this, 'message', { get: function () { return this.code; } });

	this.code = code;
	this.meta = meta;
	this.reasons = reasons;
}

util.inherits(CuvvaError, Error);
module.exports.Error = CuvvaError;

function handleError(level, error) {
	if (!config.handlers[level])
		return;

	config.handlers[level](level, error);
}

module.exports.setHandler = function (level, handler) {
	if (typeof handler === 'undefined') {
		handler = level;

		if (typeof handler !== 'function')
			throw new Error('Handler is not a function');

		for (var prop in config.handlers)
			config.handlers[prop] = handler;

		return;
	}

	if (typeof handler !== 'function')
		throw new Error('Handler is not a function');

	config.handlers[level] = handler;
};

module.exports.setMinLogLevel = function (n) {
	config.minLogLevel = errorLevels[n];
};

module.exports.setHttpStatuses = function (statusMap) {
	for (var code in statusMap)
		config.httpStatusMap[code] = statusMap[code];
};

module.exports.coerceError = function (error) {
	if (error instanceof CuvvaError)
		return error;

	if (error instanceof Error)
		return new CuvvaError(error.message, { stack: error.stack });

	return new CuvvaError('unknown_runtime_error', { error: error });
};

function logger(level) {
	return function (code, reasons, meta) {
		var err = new CuvvaError(code, reasons, meta);

		handleError(level, err);

		return err;
	};
}

module.exports.debug = logger('debug');
module.exports.info = logger('info');
module.exports.warn = logger('warn');
module.exports.error = logger('error');
module.exports.fatal = logger('fatal');
<|endoftext|>


<commit_before>/**
 * Super simple scheduler with cron, timeout, and date support.
 *
 * @package schedule-me
 * @author Gustav Rydstedt <gustav.rydstedt@gmail.com>
 */

var cron = require('cron');

var ScheduleMe, ScheduleMeJob;

module.exports = ScheduleMe;

/**
 * ScheduleMe Constructor
 */
function ScheduleMe(options) {

  this.options = options || {};

  this.logger = this.options.logger || console;

  // Job array
  this.jobs = [];

  this.started = false;
};

/**
 * Start running jobs
 */
ScheduleMe.prototype.start = function() {
  this.logger.log('Starting scheduler');

  if(this.started) throw new Error('Scheduler is already started');

  this.jobs.forEach(function(job) {
    job.start();
  });

  this.started = true;
};

/**
 * Stop running all jobs
 */
ScheduleMe.prototype.stop = function() {
  this.logger.log('Stopping scheduler');

  this.jobs.forEach(function(job) {
    job.stop();
  });

  this.started = false;
};

/**
 * Schedule a job
 */
ScheduleMe.prototype.schedule = function(func, when, name) {

  var options;

  if(typeof(func) === 'object') {
    options = func;
  } else {
    options =
    {
      job: func,
      when: when,
      name: name || 'Unknown',
      logger: this.logger
    }
  }

  var job = new ScheduleMeJob(options);

  this.jobs.push(job);

  return job;
};

/**
 * Schedule multiple jobs
 */
ScheduleMe.prototype.scheduleAll = function(jobs) {
  var _this = this;

  if(typeof(jobs) == 'object') {
    // Just one
    return _this.schedule(jobs);
  }

  // Array

  jobs.forEach(jobs, function(j) {
    // Allow for array of arrays of job
    if(typeof(j) == 'array') {
      j.forEach(function(j2) {
        _this.schedule(j);
      });
    } else {
      _this.schedule(j);
    }
  });

  return this.jobs;
};

/**
 * ScheduleMeJob Constructor
 */
function ScheduleMeJob(options) {

  this.options = options || {};

  this.logger = this.options.logger || console;

  this.job = this.options.job;

  if(!this.job) throw new Error('No job given');

  this.when = this.options.when;

  if(!this.when) throw new Error('No "when" given');

  this.name = this.options.name || 'Unknown';

};

/**
 * Start running job
 */
ScheduleMeJob.prototype.start = function() {

  if(this.options.immediate) this.job();

  if(typeof(this.when) == 'string') {
    this.logger.log('Scheduling cron job [%s] with setting %s', this.name, this.when);
    // Cron job
    this.cronJob = new cron.CronJob(this.when, this.job, null, true);
  }

  if(typeof(this.when) == 'number') {
    this.logger.log('Scheduling interval job [%s] with interval %s', this.name, this.when);
    // Interval
    this.interval = setInterval(this.job, this.when);
  }

  if(this.when.getMonth) {
    this.logger.log('Scheduling date job [%s] with date %s', this.name, this.when);
    var msUntilDate = (this.when - new Date());
    if(msUntilDate < 0) {
      throw new Error('Job is in the past ' + this.when)
    }
    // Execute on date
    this.dateTimeout = setTimeout(this.job, msUntilDate);
  }

};

/**
 * Stop running job
 */
ScheduleMeJob.prototype.stop = function() {

  if(typeof(this.when) == 'string') {
    // Cron job
    this.cronJob.stop();
  }

  if(typeof(this.when) == 'number') {
    // Interval
    clearInterval(this.interval);
  }

  if(this.when.getMonth) {
    // Date
    clearTimeout(this.dateTimeout)
  }

};
<commit_msg>Object fix<commit_after>/**
 * Super simple scheduler with cron, timeout, and date support.
 *
 * @package schedule-me
 * @author Gustav Rydstedt <gustav.rydstedt@gmail.com>
 */

var cron = require('cron');

var ScheduleMe, ScheduleMeJob;

module.exports = ScheduleMe;

/**
 * ScheduleMe Constructor
 */
function ScheduleMe(options) {

  this.options = options || {};

  this.logger = this.options.logger || console;

  // Job array
  this.jobs = [];

  this.started = false;
};

/**
 * Start running jobs
 */
ScheduleMe.prototype.start = function() {
  this.logger.log('Starting scheduler');

  if(this.started) throw new Error('Scheduler is already started');

  this.jobs.forEach(function(job) {
    job.start();
  });

  this.started = true;
};

/**
 * Stop running all jobs
 */
ScheduleMe.prototype.stop = function() {
  this.logger.log('Stopping scheduler');

  this.jobs.forEach(function(job) {
    job.stop();
  });

  this.started = false;
};

/**
 * Schedule a job
 */
ScheduleMe.prototype.schedule = function(func, when, name) {

  var options;

  if(typeof(func) === 'object') {
    options = func;
  } else {
    options =
    {
      job: func,
      when: when,
      name: name || 'Unknown',
      logger: this.logger
    }
  }

  var job = new ScheduleMeJob(options);

  this.jobs.push(job);

  return job;
};

/**
 * Schedule multiple jobs
 */
ScheduleMe.prototype.scheduleAll = function(jobs) {
  var _this = this;

  if(jobs.job) {
    // Just one
    return _this.schedule(jobs);
  }

  // Array

  jobs.forEach(jobs, function(j) {
    // Allow for array of arrays of job
    if(typeof(j) == 'array') {
      j.forEach(function(j2) {
        _this.schedule(j);
      });
    } else {
      _this.schedule(j);
    }
  });

  return this.jobs;
};

/**
 * ScheduleMeJob Constructor
 */
function ScheduleMeJob(options) {

  this.options = options || {};

  this.logger = this.options.logger || console;

  this.job = this.options.job;

  if(!this.job) throw new Error('No job given');

  this.when = this.options.when;

  if(!this.when) throw new Error('No "when" given');

  this.name = this.options.name || 'Unknown';

};

/**
 * Start running job
 */
ScheduleMeJob.prototype.start = function() {

  if(this.options.immediate) this.job();

  if(typeof(this.when) == 'string') {
    this.logger.log('Scheduling cron job [%s] with setting %s', this.name, this.when);
    // Cron job
    this.cronJob = new cron.CronJob(this.when, this.job, null, true);
  }

  if(typeof(this.when) == 'number') {
    this.logger.log('Scheduling interval job [%s] with interval %s', this.name, this.when);
    // Interval
    this.interval = setInterval(this.job, this.when);
  }

  if(this.when.getMonth) {
    this.logger.log('Scheduling date job [%s] with date %s', this.name, this.when);
    var msUntilDate = (this.when - new Date());
    if(msUntilDate < 0) {
      throw new Error('Job is in the past ' + this.when)
    }
    // Execute on date
    this.dateTimeout = setTimeout(this.job, msUntilDate);
  }

};

/**
 * Stop running job
 */
ScheduleMeJob.prototype.stop = function() {

  if(typeof(this.when) == 'string') {
    // Cron job
    this.cronJob.stop();
  }

  if(typeof(this.when) == 'number') {
    // Interval
    clearInterval(this.interval);
  }

  if(this.when.getMonth) {
    // Date
    clearTimeout(this.dateTimeout)
  }

};
<|endoftext|>


<commit_before>'use strict';

const Promise = require('pinkie-promise');
const globby  = require('globby');
const pify    = require('pify');
const tar     = require('tar-stream');
const fs      = require('fs');
const _       = require('lodash');

/**
 * Writes the given file to the given tar pack
 * @param {string} file
 * @param {Pack} pack
 * @returns {Promise.<boolean>} A promise for whether the file was packed
 */
const packFile = function (file, pack) {
    return pify(fs.stat)(file)
        .then(stat => !stat.isFile() ? Promise.resolve(false) : new Promise((resolve, reject) => {
            let entry = pack.entry(_.assign(stat, {name: file}), err => err ? reject(err) : resolve(true));
            fs.createReadStream(file).pipe(entry);
        }));
};

/**
 * Writes the given files to the given tar pack
 * @param {string[]} paths
 * @param {Pack} pack
 * @returns {Promise.<string[]>} A promise for an array of packed files
 */
const packAll = function (paths, pack) {
    let entries = [];
    return _.reduce(paths, (queue, path) => queue.then(() => packFile(path, pack).then(packed => {
            if (packed) entries.push(path);
        })), Promise.resolve())
        .then(() => entries);
};

/**
 * Creates a tar archive containing all files matched by the given input glob(s). The directory structure is preserved.
 * @param {string|string[]} globs
 * @param {string} [output]
 * @returns {stream.Readable|Promise.<string[]>} A readable stream of the tar archive if no output argument is provided,
 *      or a promise for writing the tar archive to the given output destination.
 */
const nectar = function (globs, output) {
    let writeStream   = _.isString(output) ? fs.createWriteStream(output) : null;
    let pack          = tar.pack();
    let awaitWriteAll = globby(globs)
        .then(paths => packAll(paths, pack))
        .then(entries => {
            pack.finalize();
            return entries;
        });
    if (writeStream !== null) {
        pack.pipe(writeStream);
        let awaitEndStream = new Promise(resolve => pack.on('end', resolve));
        return Promise.all([awaitWriteAll, awaitEndStream]).then(values => values[0]);
    } else
        return pack;
};

module.exports = nectar;<commit_msg>Fix lint error<commit_after>'use strict';

const Promise = require('pinkie-promise');
const globby  = require('globby');
const pify    = require('pify');
const tar     = require('tar-stream');
const fs      = require('fs');
const _       = require('lodash');

/**
 * Writes the given file to the given tar pack
 * @param {string} file
 * @param {Pack} pack
 * @returns {Promise.<boolean>} A promise for whether the file was packed
 */
const packFile = function (file, pack) {
    return pify(fs.stat)(file)
        .then(stat => !stat.isFile() ? Promise.resolve() : new Promise((resolve, reject) => {
            let entry = pack.entry(_.assign(stat, {name: file}), err => err ? reject(err) : resolve(true));
            fs.createReadStream(file).pipe(entry);
        }));
};

/**
 * Writes the given files to the given tar pack
 * @param {string[]} paths
 * @param {Pack} pack
 * @returns {Promise.<string[]>} A promise for an array of packed files
 */
const packAll = function (paths, pack) {
    let entries = [];
    return _.reduce(paths, (queue, path) => queue.then(() =>
            packFile(path, pack).then(packed => packed ? entries.push(path) : true)), Promise.resolve())
        .then(() => entries);
};

/**
 * Creates a tar archive containing all files matched by the given input glob(s). The directory structure is preserved.
 * @param {string|string[]} globs
 * @param {string} [output]
 * @returns {stream.Readable|Promise.<string[]>} A readable stream of the tar archive if no output argument is provided,
 *      or a promise for writing the tar archive to the given output destination.
 */
const nectar = function (globs, output) {
    let writeStream   = _.isString(output) ? fs.createWriteStream(output) : null;
    let pack          = tar.pack();
    let awaitWriteAll = globby(globs)
        .then(paths => packAll(paths, pack))
        .then(entries => {
            pack.finalize();
            return entries;
        });
    if (writeStream !== null) {
        pack.pipe(writeStream);
        let awaitEndStream = new Promise(resolve => pack.on('end', resolve));
        return Promise.all([awaitWriteAll, awaitEndStream]).then(values => values[0]);
    } else
        return pack;
};

module.exports = nectar;<|endoftext|>


<commit_before>/**
 * phantomas CommonJS module
 */
'use strict';

var Browser = require('./browser'),
	EventEmitter = require('events').EventEmitter,
	debug = require('debug')('phantomas:core'),
	loader = require('./loader'),
	puppeteer = require("puppeteer"),
	path = require('path'),
	Results = require('../core/results'),
	util = require('util'),
	VERSION = require('./../package').version;

/**
 * Main CommonJS module entry point
 *
 * @param {string} url
 * @param {Object} opts
 * @returns {browser}
 */
function phantomas(url, opts) {
	var events = new EventEmitter(),
		browser, options;

	debug('OS: %s %s', process.platform, process.arch);
	debug('Node.js: %s', process.version);
	debug('phantomas: %s', VERSION);
	debug('Puppeteer: preferred revision r%s', puppeteer._launcher._preferredRevision);
	debug('URL: <%s>', url);
	debug('Options: %s', JSON.stringify(opts));

	// options handling
	options = util._extend({}, opts || {}); // use util._extend to avoid #563
	options.url = options.url || url || false;

	// log emitted events
	events._emit = events.emit;
	events.log = require('debug')('phantomas:events');
	events.emit = function() {
		this.log('emit: %s', arguments[0]);
		this._emit.apply(this, arguments);
	}

	var results = new Results();
	results.setUrl(url);
	results.setGenerator('phantomas v' + VERSION);

	// TODO: prepare a small instance object that will be passed to modules and extensions on init
	const scope = {
		getParam: () => false, // TODO
		getVersion: () => VERSION,
		on: events.on.bind(events),
		once: events.once.bind(events),
		setMetric: results.setMetric
	};

	// load modules and extensions
	debug('Loading core modules...');
	loader.loadCoreModules(scope);

	debug('Loading extensions...');
	loader.loadExtensions(scope);

	debug('Loading modules...');
	loader.loadModules(scope);

	// set up and run Puppeteer
	browser = new Browser();
	browser.bind(events);

	var promise = new Promise(async (resolve, reject) => {
		try {
			await browser.init();
			await browser.visit(url);

			// your last chance to add metrics
			events.emit('report');

			// resolve our run
			await browser.close();
			resolve(results);
		}
		catch(ex) {
			reject(ex);
		}
	});

	promise.on = events.on.bind(events);

	return promise;
}

phantomas.metadata = require(__dirname + '/metadata/metadata.json');
phantomas.path = path.normalize(__dirname + '/..');
phantomas.version = VERSION;

module.exports = phantomas;
<commit_msg>MaxListenersExceededWarning: Possible EventEmitter memory leak detected<commit_after>/**
 * phantomas CommonJS module
 */
'use strict';

var Browser = require('./browser'),
	EventEmitter = require('events').EventEmitter,
	debug = require('debug')('phantomas:core'),
	loader = require('./loader'),
	puppeteer = require("puppeteer"),
	path = require('path'),
	Results = require('../core/results'),
	util = require('util'),
	VERSION = require('./../package').version;

/**
 * Main CommonJS module entry point
 *
 * @param {string} url
 * @param {Object} opts
 * @returns {browser}
 */
function phantomas(url, opts) {
	var events = new EventEmitter(),
		browser, options;

	debug('OS: %s %s', process.platform, process.arch);
	debug('Node.js: %s', process.version);
	debug('phantomas: %s', VERSION);
	debug('Puppeteer: preferred revision r%s', puppeteer._launcher._preferredRevision);
	debug('URL: <%s>', url);
	debug('Options: %s', JSON.stringify(opts));

	// options handling
	options = util._extend({}, opts || {}); // use util._extend to avoid #563
	options.url = options.url || url || false;

	// log emitted events
	events._emit = events.emit;
	events.log = require('debug')('phantomas:events');
	events.emit = function() {
		this.log('emit: %s', arguments[0]);
		this._emit.apply(this, arguments);
	}

	events.setMaxListeners(100); // MaxListenersExceededWarning: Possible EventEmitter memory leak detected.

	var results = new Results();
	results.setUrl(url);
	results.setGenerator('phantomas v' + VERSION);

	// TODO: prepare a small instance object that will be passed to modules and extensions on init
	const scope = {
		getParam: () => false, // TODO
		getVersion: () => VERSION,
		on: events.on.bind(events),
		once: events.once.bind(events),
		setMetric: results.setMetric
	};

	// load modules and extensions
	debug('Loading core modules...');
	loader.loadCoreModules(scope);

	debug('Loading extensions...');
	loader.loadExtensions(scope);

	debug('Loading modules...');
	loader.loadModules(scope);

	// set up and run Puppeteer
	browser = new Browser();
	browser.bind(events);

	var promise = new Promise(async (resolve, reject) => {
		try {
			await browser.init();
			await browser.visit(url);

			// your last chance to add metrics
			events.emit('report');

			// resolve our run
			await browser.close();
			resolve(results);
		}
		catch(ex) {
			reject(ex);
		}
	});

	promise.on = events.on.bind(events);

	return promise;
}

phantomas.metadata = require(__dirname + '/metadata/metadata.json');
phantomas.path = path.normalize(__dirname + '/..');
phantomas.version = VERSION;

module.exports = phantomas;
<|endoftext|>


<commit_before>/*
 * index.js
 */

const camelCase = require('lodash.camelcase')
const snakeCase = require('lodash.snakecase')

let gi;
try {
    gi = require('../build/Release/node-gtk');
} catch(e) {
    gi = require('../build/Debug/node-gtk');
}

// The bootstrap from C here contains functions and methods for each object,
// namespaced with underscores. See gi.cc for more information.
const GIRepository = gi.Bootstrap();

// The GIRepository API is fairly poor, and contains methods on classes,
// methods on objects, and what should be methods interpreted as functions,
// because the scanner does not interpret methods on typedefs correctly.

// We extend this bootstrap'd repo to define all flags / enums, which
// are all we need to start declaring objects.
bootstrapGIRepository(GIRepository)

function bootstrapGIRepository(GIRepository) {
    const repo = GIRepository.Repository_get_default()
    const ns = 'GIRepository'

    // First, grab InfoType so we can find enums / flags.
    const InfoType = makeEnum(GIRepository.Repository_find_by_name.call(repo, ns, 'InfoType'))

    // Now, define all enums / flags.
    const nInfos = GIRepository.Repository_get_n_infos.call(repo, ns)
    for (let i = 0; i < nInfos; i++) {
        const info = GIRepository.Repository_get_info.call(repo, ns, i)
        const name = GIRepository.BaseInfo_get_name.call(info)
        const type = GIRepository.BaseInfo_get_type.call(info)

        if (type === InfoType.ENUM || type === InfoType.FLAGS)
            GIRepository[name] = makeEnum(info)
    }
}

// We also define GObject#on and friends, to keep NodeJS EventEmitter
// semantics. They are implemented in terms of the native .connect()
// and .disconnect() methods.
const GObject = gi.GetBaseClass()
extendGObject(GObject)

function extendGObject(GObject) {
    GObject.prototype.on = function on(event, callback) {
        defineListeners(this)

        if (!this._listeners.has(event))
            this._listeners.set(event, new WeakMap())

        const fnMap = this._listeners.get(event)
        const handlerID = this.connect(event, callback)
        fnMap.set(callback, handlerID)
    }

    GObject.prototype.off = function off(event, callback) {
        defineListeners(this)

        if (!this._listeners.has(event))
            return

        const fnMap = this._listeners.get(event)
        if (!fnMap.has(callback))
            return

        const handlerID = fnMap.get(callback)
        this.disconnect(handlerID)
        fnMap.delete(callback)
    }

    GObject.prototype.once = function once(event, callback) {
        const newCallback = (...args) => {
            callback(...args)
            this.off(event, newCallback)
        }
        this.on(event, newCallback)
    }

    function defineListeners(object) {
        if (object._listeners !== undefined)
            return
        Object.defineProperty(object, '_listeners', {
            value: new Map()
        })
    }
}

function addFunction(object, info) {
    const fn = gi.MakeFunction(info);
    const name = getInfoName(info);
    const flags = GIRepository.function_info_get_flags(info);
    const isMethod = ((flags & GIRepository.FunctionInfoFlags.IS_METHOD) != 0 &&
                      (flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) == 0);
    const target = (isMethod) ? object.prototype : object;
    Object.defineProperty(target, name, {
        configurable: true,
        writable: true,
        value: fn
    })
}

function addVirtualFunction(object, info, implementor) {
    const fn = gi.MakeVirtualFunction(info, implementor);
    const name = getInfoName(info);
    const flags = GIRepository.function_info_get_flags(info);
    const isMethod = ((flags & GIRepository.FunctionInfoFlags.IS_METHOD) != 0 &&
                      (flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) == 0);
    const target = (isMethod) ? object.prototype : object;
    Object.defineProperty(target, name, {
        configurable: true,
        writable: true,
        value: fn
    })
}

function fieldGetter(fieldInfo) {
    return function() {
        return gi.StructFieldGetter(this, fieldInfo);
    };
}

function fieldSetter(fieldInfo) {
    return function(value) {
        return gi.StructFieldSetter(this, fieldInfo, value);
    };
}

function addField(object, fieldInfo) {
    const flags = GIRepository.field_info_get_flags(fieldInfo)
    const writable = (flags & GIRepository.FieldInfoFlags.WRITABLE) !== 0
    const readable = (flags & GIRepository.FieldInfoFlags.READABLE) !== 0

    const name = getInfoName(fieldInfo)

    Object.defineProperty(object, name, {
        configurable: true,
        enumerable: readable,
        get: readable ? fieldGetter(fieldInfo) : undefined,
        set: writable ? fieldSetter(fieldInfo) : undefined
    })
}

function propertyGetter(propertyName) {
    return function() {
        return gi.ObjectPropertyGetter(this, propertyName);
    };
}

function propertySetter(propertyName) {
    return function(value) {
        return gi.ObjectPropertySetter(this, propertyName, value);
    };
}

function addProperty(object, property) {
    const propertyName = getName(property);
    const name = getInfoName(property)
    Object.defineProperty(object, name, {
        configurable: true,
        enumerable: true,
        get: propertyGetter(propertyName),
        set: propertySetter(propertyName),
    });
}

function addConstant(object, constantInfo) {
    const name = getInfoName(constantInfo)
    Object.defineProperty(object, name, {
        configurable: false,
        writable: false,
        enumerable: true,
        value: makeConstant(constantInfo)
    })
}

function makeConstant(info) {
    return gi.GetConstantValue(info)
}

function makeFunction(info) {
    return gi.MakeFunction(info)
}

function makeVirtualFunction(info, implementor) {
    return gi.MakeVirtualFunction(info, implementor)
}

function makeEnum(info) {
    const object = {}

    const nValues = GIRepository.enum_info_get_n_values(info);
    for (let i = 0; i < nValues; i++) {
        const valueInfo = GIRepository.enum_info_get_value(info, i);
        const valueName = getName(valueInfo).toUpperCase()
        const value = GIRepository.value_info_get_value(valueInfo)
        Object.defineProperty(object, valueName, {
            configurable: true,
            enumerable: true,
            value: value,
        })
        Object.defineProperty(object, value, {
            configurable: true,
            enumerable: false,
            value: valueName,
        })
    }

    const nMethods = GIRepository.enum_info_get_n_methods(info)
    for (let i = 0; i < nMethods; i++) {
        const methodInfo = GIRepository.enum_info_get_method(info, i)
        const methodName = camelCase(getName(methodInfo))
        const method = gi.MakeFunction(methodInfo)
        Object.defineProperty(object, methodName, {
            configurable: true,
            writable: true,
            value: method
        })
    }

    return object;
}

function makeObject(info) {
    const constructor = gi.MakeObjectClass(info);

    loop(info, GIRepository.object_info_get_n_methods, GIRepository.object_info_get_method, (methodInfo) => {
        addFunction(constructor, methodInfo);
    })

    loop(info, GIRepository.object_info_get_n_properties, GIRepository.object_info_get_property, (propertyInfo) => {
        addProperty(constructor.prototype, propertyInfo)
    })

    loop(info, GIRepository.object_info_get_n_constants, GIRepository.object_info_get_constant, (constantInfo) => {
        addConstant(constructor, constantInfo)
    })

    /*
     * Define interface-implemented things
     */

    constructor.implements = []

    loop(info, GIRepository.object_info_get_n_interfaces, GIRepository.object_info_get_interface, (interfaceInfo) => {
        interfaceInfo.name = getInfoName(interfaceInfo);
        constructor.implements.push(interfaceInfo);

        loop(interfaceInfo, GIRepository.interface_info_get_n_properties, GIRepository.interface_info_get_property, (propInfo) => {
            addProperty(constructor.prototype, propInfo);
        })

        loop(interfaceInfo, GIRepository.interface_info_get_n_methods, GIRepository.interface_info_get_method, (methodInfo) => {
            addFunction(constructor, methodInfo);
        })

        loop(interfaceInfo, GIRepository.interface_info_get_n_constants, GIRepository.interface_info_get_constant, (constantInfo) => {
            addConstant(constructor, constantInfo)
        })

        /* GIRepository.interface_info_get_n_signals
         * GIRepository.interface_info_get_signal */

        /* loop(interfaceInfo, GIRepository.interface_info_get_n_vfuncs, GIRepository.interface_info_get_vfunc, (methodInfo) => {
         *     addVirtualFunction(constructor, methodInfo, constructor.gtype);
         * }) */
    })

    return constructor;
}

function makeBoxed(info) {
    if (getType(info) == GIRepository.InfoType.UNION) {
        return makeUnion(info)
    } else {
        return makeStruct(info)
    }
}

function makeUnion(info) {
    const constructor = gi.MakeBoxedClass(info);

    const nMethods = GIRepository.union_info_get_n_methods(info);
    for (let i = 0; i < nMethods; i++) {
        const methodInfo = GIRepository.union_info_get_method(info, i);
        addFunction(constructor, methodInfo);
    }

    const nFields = GIRepository.union_info_get_n_fields(info);
    for (let i = 0; i < nFields; i++) {
        const fieldInfo = GIRepository.union_info_get_field(info, i);
        addField(constructor.prototype, fieldInfo);
    }

    return constructor
}

function makeStruct(info) {
    const constructor = gi.MakeBoxedClass(info);

    const nMethods = GIRepository.struct_info_get_n_methods(info);
    for (let i = 0; i < nMethods; i++) {
        var methodInfo = GIRepository.struct_info_get_method(info, i);
        addFunction(constructor, methodInfo);
    }

    const nFields = GIRepository.struct_info_get_n_fields(info);
    for (let i = 0; i < nFields; i++) {
        const fieldInfo = GIRepository.struct_info_get_field(info, i);
        addField(constructor.prototype, fieldInfo);
    }

    return constructor
}

function makeInterface(info) {
    const object = function() {}
    object.info = info;
    object.gtype = GIRepository.registered_type_info_get_g_type(info);
    object.properties = Object.create(null);

    const n_properties = GIRepository.interface_info_get_n_properties(info);
    for (let i = 0; i < n_properties; i++) {
        const propertyInfo = GIRepository.interface_info_get_property(info, i);
        const propertyName = getInfoName(propertyInfo);
        object.properties[propertyName] = propertyInfo;
    }

    return object;
}

function makeInfo(info) {
    const type = getType(info);
    switch (type) {
        case GIRepository.InfoType.FUNCTION:
            return makeFunction(info);

        // case GIRepository.InfoType.VFUNC:
            // return makeVirtualFunction(info, ...args);

        case GIRepository.InfoType.STRUCT:
            if (GIRepository.struct_info_is_gtype_struct(info))
                return null; // Not needed
            // else fallthrough
        case GIRepository.InfoType.BOXED:
        case GIRepository.InfoType.UNION:
            return makeBoxed(info);

        case GIRepository.InfoType.ENUM:
        case GIRepository.InfoType.FLAGS:
            return makeEnum(info);

        case GIRepository.InfoType.OBJECT:
            return makeObject(info);

        case GIRepository.InfoType.INTERFACE: // FIXME
            return makeInterface(info);

        case GIRepository.InfoType.CONSTANT:
            return makeConstant(info);

        // INVALID_0
        // SIGNAL
        // VFUNC
        // PROPERTY
        // FIELD
        // ARG
        // TYPE
        // UNRESOLVED
        // INVALID
        // CALLBACK
    }
}

function getInfoName(info) {
    const type = getType(info)
    const name = getName(info)

    switch (type) {
        case GIRepository.InfoType.FUNCTION:
        case GIRepository.InfoType.VFUNC:
            return camelCase(name) // lowerCamelCase (snake_case by default)

        case GIRepository.InfoType.FIELD:
            return camelCase(name) // lowerCamelCase (snake_case by default)

        case GIRepository.InfoType.PROPERTY:
            return camelCase(name) // lowerCamelCase (dash-case by default)

        case GIRepository.InfoType.STRUCT:
        case GIRepository.InfoType.BOXED:
        case GIRepository.InfoType.UNION:
            return name // UpperCamelCase

        case GIRepository.InfoType.ENUM:
        case GIRepository.InfoType.FLAGS:
            return name // UpperCamelCase

        case GIRepository.InfoType.OBJECT:
            return name // UpperCamelCase

        case GIRepository.InfoType.INTERFACE:
            return name // UpperCamelCase

        case GIRepository.InfoType.CONSTANT:
            return name // ALL_CAPS by default

        case GIRepository.InfoType.VALUE: // enum's value
            return name.toUpperCase() // ALL_CAPS

        // INVALID_0
        // SIGNAL
        // ARG
        // TYPE
        // UNRESOLVED
        // INVALID
        // CALLBACK
    }
}

// Namespace loading

/**
 * Module cache
 */
const cache = Object.create(null);

/**
 * Require module & version. Automatically loads dependencies.
 */
function giRequire(ns, version) {
    const namespace = cache[ns] || (cache[ns] = Object.create(null))
    version = version || null // null for latest version

    if (namespace[version])
        return namespace[version]

    if (version == null && namespace.length > 0) {
        version = Object.keys(namespace)[0]
        return namespace[version]
    }

    const module = namespace[version] = Object.create(null)

    const repo = GIRepository.Repository_get_default()
    GIRepository.Repository_require.call(repo, ns, version, 0)
    version = version || GIRepository.Repository_get_version.call(repo, ns)

    const nInfos = GIRepository.Repository_get_n_infos.call(repo, ns);
    for (let i = 0; i < nInfos; i++) {
        const info = GIRepository.Repository_get_info.call(repo, ns, i);
        const item = makeInfo(info);

        if (item)
            module[getInfoName(info)] = item
    }

    try {
        const override = require(`./overrides/${[ns, version].join('-')}.js`)
        override.apply(module)
    } catch(e) {
        try {
            const override = require(`./overrides/${ns}.js`)
            override.apply(module)
        } catch(e) { /* No override */ }
    }

    loadDependencies(ns, version)

    return module
}

/**
 * Loads dependencies of a library
 */
function loadDependencies(ns, version) {
    const repo = GIRepository.Repository_get_default()
    const dependencies = GIRepository.Repository_get_immediate_dependencies.call(repo, ns, version)

    dependencies.forEach(dependency => {
        const [name, version] = dependency.split('-')
        giRequire(name, version)
    })
}

/**
 * Check if module version is loaded
 */
function _isLoaded(ns, version) {
    var namespace = cache[ns] || (cache[ns] = Object.create(null));
    version = version || null;

    if (namespace[version])
        return true;

    if (version == null && namespace.length > 0) {
        console.log(Object.keys(namespace)[0]);
        return true;
    }

    return false;
}

/*
 * Exports
 */

// Public API
exports.require = giRequire;
exports.startLoop = gi.StartLoop;

// Private API
exports._isLoaded = _isLoaded;
exports._cache = cache;
exports._c = gi;
exports._GIRepository = GIRepository;
exports._InfoType = GIRepository.InfoType;

/*
 * Helpers
 */

function getName(info) {
    return GIRepository.BaseInfo_get_name.call(info);
}

function getType (info) {
    return GIRepository.BaseInfo_get_type.call(info);
}

function loop(info, lengthFn, itemFn, fn) {
    const length = lengthFn(info)
    for (let i = 0; i < length; i++) {
        const item = itemFn(info, i)
        fn(item, i)
    }
}
<commit_msg>index.js: clean<commit_after>/*
 * index.js
 */

const camelCase = require('lodash.camelcase')
const snakeCase = require('lodash.snakecase')

let gi;
try {
    gi = require('../build/Release/node-gtk');
} catch(e) {
    gi = require('../build/Debug/node-gtk');
}

// The bootstrap from C here contains functions and methods for each object,
// namespaced with underscores. See gi.cc for more information.
const GIRepository = gi.Bootstrap();

// The GIRepository API is fairly poor, and contains methods on classes,
// methods on objects, and what should be methods interpreted as functions,
// because the scanner does not interpret methods on typedefs correctly.

// We extend this bootstrap'd repo to define all flags / enums, which
// are all we need to start declaring objects.
bootstrapGIRepository(GIRepository)

function bootstrapGIRepository(GIRepository) {
    const repo = GIRepository.Repository_get_default()
    const ns = 'GIRepository'

    // First, grab InfoType so we can find enums / flags.
    const InfoType = makeEnum(GIRepository.Repository_find_by_name.call(repo, ns, 'InfoType'))

    // Now, define all enums / flags.
    const nInfos = GIRepository.Repository_get_n_infos.call(repo, ns)
    for (let i = 0; i < nInfos; i++) {
        const info = GIRepository.Repository_get_info.call(repo, ns, i)
        const name = GIRepository.BaseInfo_get_name.call(info)
        const type = GIRepository.BaseInfo_get_type.call(info)

        if (type === InfoType.ENUM || type === InfoType.FLAGS)
            GIRepository[name] = makeEnum(info)
    }
}

// We also define GObject#on and friends, to keep NodeJS EventEmitter
// semantics. They are implemented in terms of the native .connect()
// and .disconnect() methods.
const GObject = gi.GetBaseClass()
extendGObject(GObject)

function extendGObject(GObject) {
    GObject.prototype.on = function on(event, callback) {
        defineListeners(this)

        if (!this._listeners.has(event))
            this._listeners.set(event, new WeakMap())

        const fnMap = this._listeners.get(event)
        const handlerID = this.connect(event, callback)
        fnMap.set(callback, handlerID)
    }

    GObject.prototype.off = function off(event, callback) {
        defineListeners(this)

        if (!this._listeners.has(event))
            return

        const fnMap = this._listeners.get(event)
        if (!fnMap.has(callback))
            return

        const handlerID = fnMap.get(callback)
        this.disconnect(handlerID)
        fnMap.delete(callback)
    }

    GObject.prototype.once = function once(event, callback) {
        const newCallback = (...args) => {
            callback(...args)
            this.off(event, newCallback)
        }
        this.on(event, newCallback)
    }

    function defineListeners(object) {
        if (object._listeners !== undefined)
            return
        Object.defineProperty(object, '_listeners', {
            value: new Map()
        })
    }
}

function addFunction(object, info) {
    const fn = gi.MakeFunction(info);
    const name = getInfoName(info);
    const flags = GIRepository.function_info_get_flags(info);
    const isMethod = ((flags & GIRepository.FunctionInfoFlags.IS_METHOD) != 0 &&
                      (flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) == 0);
    const target = (isMethod) ? object.prototype : object;
    Object.defineProperty(target, name, {
        configurable: true,
        writable: true,
        value: fn
    })
}

function addVirtualFunction(object, info, implementor) {
    const fn = gi.MakeVirtualFunction(info, implementor);
    const name = getInfoName(info);
    const flags = GIRepository.function_info_get_flags(info);
    const isMethod = ((flags & GIRepository.FunctionInfoFlags.IS_METHOD) != 0 &&
                      (flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) == 0);
    const target = (isMethod) ? object.prototype : object;
    Object.defineProperty(target, name, {
        configurable: true,
        writable: true,
        value: fn
    })
}

function fieldGetter(fieldInfo) {
    return function() {
        return gi.StructFieldGetter(this, fieldInfo);
    };
}

function fieldSetter(fieldInfo) {
    return function(value) {
        return gi.StructFieldSetter(this, fieldInfo, value);
    };
}

function addField(object, fieldInfo) {
    const flags = GIRepository.field_info_get_flags(fieldInfo)
    const writable = (flags & GIRepository.FieldInfoFlags.WRITABLE) !== 0
    const readable = (flags & GIRepository.FieldInfoFlags.READABLE) !== 0

    const name = getInfoName(fieldInfo)

    Object.defineProperty(object, name, {
        configurable: true,
        enumerable: readable,
        get: readable ? fieldGetter(fieldInfo) : undefined,
        set: writable ? fieldSetter(fieldInfo) : undefined
    })
}

function propertyGetter(propertyName) {
    return function() {
        return gi.ObjectPropertyGetter(this, propertyName);
    };
}

function propertySetter(propertyName) {
    return function(value) {
        return gi.ObjectPropertySetter(this, propertyName, value);
    };
}

function addProperty(object, property) {
    const propertyName = getName(property);
    const name = getInfoName(property)
    Object.defineProperty(object, name, {
        configurable: true,
        enumerable: true,
        get: propertyGetter(propertyName),
        set: propertySetter(propertyName),
    });
}

function addConstant(object, constantInfo) {
    const name = getInfoName(constantInfo)
    Object.defineProperty(object, name, {
        configurable: false,
        writable: false,
        enumerable: true,
        value: makeConstant(constantInfo)
    })
}

function makeConstant(info) {
    return gi.GetConstantValue(info)
}

function makeFunction(info) {
    return gi.MakeFunction(info)
}

function makeVirtualFunction(info, implementor) {
    return gi.MakeVirtualFunction(info, implementor)
}

function makeEnum(info) {
    const object = {}

    const nValues = GIRepository.enum_info_get_n_values(info);
    for (let i = 0; i < nValues; i++) {
        const valueInfo = GIRepository.enum_info_get_value(info, i);
        const valueName = getName(valueInfo).toUpperCase()
        const value = GIRepository.value_info_get_value(valueInfo)
        Object.defineProperty(object, valueName, {
            configurable: true,
            enumerable: true,
            value: value,
        })
        Object.defineProperty(object, value, {
            configurable: true,
            enumerable: false,
            value: valueName,
        })
    }

    const nMethods = GIRepository.enum_info_get_n_methods(info)
    for (let i = 0; i < nMethods; i++) {
        const methodInfo = GIRepository.enum_info_get_method(info, i)
        const methodName = camelCase(getName(methodInfo))
        const method = gi.MakeFunction(methodInfo)
        Object.defineProperty(object, methodName, {
            configurable: true,
            writable: true,
            value: method
        })
    }

    return object;
}

function makeObject(info) {
    const constructor = gi.MakeObjectClass(info);

    loop(info, GIRepository.object_info_get_n_methods, GIRepository.object_info_get_method, (methodInfo) => {
        addFunction(constructor, methodInfo);
    })

    loop(info, GIRepository.object_info_get_n_properties, GIRepository.object_info_get_property, (propertyInfo) => {
        addProperty(constructor.prototype, propertyInfo)
    })

    loop(info, GIRepository.object_info_get_n_constants, GIRepository.object_info_get_constant, (constantInfo) => {
        addConstant(constructor, constantInfo)
    })

    /*
     * Define interface-implemented things
     */

    loop(info, GIRepository.object_info_get_n_interfaces, GIRepository.object_info_get_interface, (interfaceInfo) => {
        interfaceInfo.name = getInfoName(interfaceInfo);

        loop(interfaceInfo, GIRepository.interface_info_get_n_properties, GIRepository.interface_info_get_property, (propInfo) => {
            addProperty(constructor.prototype, propInfo);
        })

        loop(interfaceInfo, GIRepository.interface_info_get_n_methods, GIRepository.interface_info_get_method, (methodInfo) => {
            addFunction(constructor, methodInfo);
        })

        loop(interfaceInfo, GIRepository.interface_info_get_n_constants, GIRepository.interface_info_get_constant, (constantInfo) => {
            addConstant(constructor, constantInfo)
        })

        /* GIRepository.interface_info_get_n_signals
         * GIRepository.interface_info_get_signal */

        /* loop(interfaceInfo, GIRepository.interface_info_get_n_vfuncs, GIRepository.interface_info_get_vfunc, (methodInfo) => {
         *     addVirtualFunction(constructor, methodInfo, constructor.gtype);
         * }) */
    })

    return constructor;
}

function makeBoxed(info) {
    if (getType(info) == GIRepository.InfoType.UNION) {
        return makeUnion(info)
    } else {
        return makeStruct(info)
    }
}

function makeUnion(info) {
    const constructor = gi.MakeBoxedClass(info);

    const nMethods = GIRepository.union_info_get_n_methods(info);
    for (let i = 0; i < nMethods; i++) {
        const methodInfo = GIRepository.union_info_get_method(info, i);
        addFunction(constructor, methodInfo);
    }

    const nFields = GIRepository.union_info_get_n_fields(info);
    for (let i = 0; i < nFields; i++) {
        const fieldInfo = GIRepository.union_info_get_field(info, i);
        addField(constructor.prototype, fieldInfo);
    }

    return constructor
}

function makeStruct(info) {
    const constructor = gi.MakeBoxedClass(info);

    const nMethods = GIRepository.struct_info_get_n_methods(info);
    for (let i = 0; i < nMethods; i++) {
        var methodInfo = GIRepository.struct_info_get_method(info, i);
        addFunction(constructor, methodInfo);
    }

    const nFields = GIRepository.struct_info_get_n_fields(info);
    for (let i = 0; i < nFields; i++) {
        const fieldInfo = GIRepository.struct_info_get_field(info, i);
        addField(constructor.prototype, fieldInfo);
    }

    return constructor
}

function makeInterface(info) {
    const object = function() {}
    object.info = info;
    object.gtype = GIRepository.registered_type_info_get_g_type(info);
    object.properties = Object.create(null);

    const n_properties = GIRepository.interface_info_get_n_properties(info);
    for (let i = 0; i < n_properties; i++) {
        const propertyInfo = GIRepository.interface_info_get_property(info, i);
        const propertyName = getInfoName(propertyInfo);
        object.properties[propertyName] = propertyInfo;
    }

    return object;
}

function makeInfo(info) {
    const type = getType(info);
    switch (type) {
        case GIRepository.InfoType.FUNCTION:
            return makeFunction(info);

        // case GIRepository.InfoType.VFUNC:
            // return makeVirtualFunction(info, ...args);

        case GIRepository.InfoType.STRUCT:
            if (GIRepository.struct_info_is_gtype_struct(info))
                return null; // Not needed
            // else fallthrough
        case GIRepository.InfoType.BOXED:
        case GIRepository.InfoType.UNION:
            return makeBoxed(info);

        case GIRepository.InfoType.ENUM:
        case GIRepository.InfoType.FLAGS:
            return makeEnum(info);

        case GIRepository.InfoType.OBJECT:
            return makeObject(info);

        case GIRepository.InfoType.INTERFACE: // FIXME
            return makeInterface(info);

        case GIRepository.InfoType.CONSTANT:
            return makeConstant(info);

        // INVALID_0
        // SIGNAL
        // VFUNC
        // PROPERTY
        // FIELD
        // ARG
        // TYPE
        // UNRESOLVED
        // INVALID
        // CALLBACK
    }
}

function getInfoName(info) {
    const type = getType(info)
    const name = getName(info)

    switch (type) {
        case GIRepository.InfoType.FUNCTION:
        case GIRepository.InfoType.VFUNC:
            return camelCase(name) // lowerCamelCase (snake_case by default)

        case GIRepository.InfoType.FIELD:
            return camelCase(name) // lowerCamelCase (snake_case by default)

        case GIRepository.InfoType.PROPERTY:
            return camelCase(name) // lowerCamelCase (dash-case by default)

        case GIRepository.InfoType.STRUCT:
        case GIRepository.InfoType.BOXED:
        case GIRepository.InfoType.UNION:
            return name // UpperCamelCase

        case GIRepository.InfoType.ENUM:
        case GIRepository.InfoType.FLAGS:
            return name // UpperCamelCase

        case GIRepository.InfoType.OBJECT:
            return name // UpperCamelCase

        case GIRepository.InfoType.INTERFACE:
            return name // UpperCamelCase

        case GIRepository.InfoType.CONSTANT:
            return name // ALL_CAPS by default

        case GIRepository.InfoType.VALUE: // enum's value
            return name.toUpperCase() // ALL_CAPS

        // INVALID_0
        // SIGNAL
        // ARG
        // TYPE
        // UNRESOLVED
        // INVALID
        // CALLBACK
    }
}

// Namespace loading

/**
 * Module cache
 */
const cache = Object.create(null);

/**
 * Require module & version. Automatically loads dependencies.
 */
function giRequire(ns, version) {
    const namespace = cache[ns] || (cache[ns] = Object.create(null))
    version = version || null // null for latest version

    if (namespace[version])
        return namespace[version]

    if (version == null && namespace.length > 0) {
        version = Object.keys(namespace)[0]
        return namespace[version]
    }

    const module = namespace[version] = Object.create(null)

    const repo = GIRepository.Repository_get_default()
    GIRepository.Repository_require.call(repo, ns, version, 0)
    version = version || GIRepository.Repository_get_version.call(repo, ns)

    const nInfos = GIRepository.Repository_get_n_infos.call(repo, ns);
    for (let i = 0; i < nInfos; i++) {
        const info = GIRepository.Repository_get_info.call(repo, ns, i);
        const item = makeInfo(info);

        if (item)
            module[getInfoName(info)] = item
    }

    try {
        const override = require(`./overrides/${[ns, version].join('-')}.js`)
        override.apply(module)
    } catch(e) {
        try {
            const override = require(`./overrides/${ns}.js`)
            override.apply(module)
        } catch(e) { /* No override */ }
    }

    loadDependencies(ns, version)

    return module
}

/**
 * Loads dependencies of a library
 */
function loadDependencies(ns, version) {
    const repo = GIRepository.Repository_get_default()
    const dependencies = GIRepository.Repository_get_immediate_dependencies.call(repo, ns, version)

    dependencies.forEach(dependency => {
        const [name, version] = dependency.split('-')
        giRequire(name, version)
    })
}

/**
 * Check if module version is loaded
 */
function _isLoaded(ns, version) {
    var namespace = cache[ns] || (cache[ns] = Object.create(null));
    version = version || null;

    if (namespace[version])
        return true;

    if (version == null && namespace.length > 0) {
        console.log(Object.keys(namespace)[0]);
        return true;
    }

    return false;
}

/*
 * Exports
 */

// Public API
exports.require = giRequire;
exports.startLoop = gi.StartLoop;

// Private API
exports._isLoaded = _isLoaded;
exports._cache = cache;
exports._c = gi;
exports._GIRepository = GIRepository;
exports._InfoType = GIRepository.InfoType;

/*
 * Helpers
 */

function getName(info) {
    return GIRepository.BaseInfo_get_name.call(info);
}

function getType (info) {
    return GIRepository.BaseInfo_get_type.call(info);
}

function loop(info, lengthFn, itemFn, fn) {
    const length = lengthFn(info)
    for (let i = 0; i < length; i++) {
        const item = itemFn(info, i)
        fn(item, i)
    }
}
<|endoftext|>


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

var http = require('http');
var read = require('fs').readFileSync;
var engine = require('engine.io');
var client = require('socket.io-client');
var clientVersion = require('socket.io-client/package').version;
var Client = require('./client');
var Emitter = require('events').EventEmitter;
var Namespace = require('./namespace');
var Adapter = require('socket.io-adapter');
var debug = require('debug')('socket.io:server');
var url = require('url');

/**
 * Module exports.
 */

module.exports = Server;

/**
 * Socket.IO client source.
 */

var clientSource = undefined;
var clientSourceMap = undefined;

/**
 * Server constructor.
 *
 * @param {http.Server|Number|Object} srv http server, port or options
 * @param {Object} [opts]
 * @api public
 */

function Server(srv, opts){
  if (!(this instanceof Server)) return new Server(srv, opts);
  if ('object' == typeof srv && srv instanceof Object && !srv.listen) {
    opts = srv;
    srv = null;
  }
  opts = opts || {};
  this.nsps = {};
  this.path(opts.path || '/socket.io');
  this.serveClient(false !== opts.serveClient);
  this.adapter(opts.adapter || Adapter);
  this.origins(opts.origins || '*:*');
  this.sockets = this.of('/');
  if (srv) this.attach(srv, opts);
}

/**
 * Server request verification function, that checks for allowed origins
 *
 * @param {http.IncomingMessage} req request
 * @param {Function} fn callback to be called with the result: `fn(err, success)`
 */

Server.prototype.checkRequest = function(req, fn) {
  var origin = req.headers.origin || req.headers.referer;

  // file:// URLs produce a null Origin which can't be authorized via echo-back
  if ('null' == origin || null == origin) origin = '*';

  if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
  if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
  if (origin) {
    try {
      var parts = url.parse(origin);
      var defaultPort = 'https:' == parts.protocol ? 443 : 80;
      parts.port = parts.port != null
        ? parts.port
        : defaultPort;
      var ok =
        ~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
        ~this._origins.indexOf(parts.hostname + ':*') ||
        ~this._origins.indexOf('*:' + parts.port);
      return fn(null, !!ok);
    } catch (ex) {
    }
  }
  fn(null, false);
};

/**
 * Sets/gets whether client code is being served.
 *
 * @param {Boolean} v whether to serve client code
 * @return {Server|Boolean} self when setting or value when getting
 * @api public
 */

Server.prototype.serveClient = function(v){
  if (!arguments.length) return this._serveClient;
  this._serveClient = v;

  if (v && !clientSource) {
    clientSource = read(require.resolve('socket.io-client/dist/socket.io.min.js'), 'utf-8');
    try {
      clientSourceMap = read(require.resolve('socket.io-client/dist/socket.io.js.map'), 'utf-8');
    } catch(err) {
      debug('could not load sourcemap file');
    }
  }

  return this;
};

/**
 * Old settings for backwards compatibility
 */

var oldSettings = {
  "transports": "transports",
  "heartbeat timeout": "pingTimeout",
  "heartbeat interval": "pingInterval",
  "destroy buffer size": "maxHttpBufferSize"
};

/**
 * Backwards compatibility.
 *
 * @api public
 */

Server.prototype.set = function(key, val){
  if ('authorization' == key && val) {
    this.use(function(socket, next) {
      val(socket.request, function(err, authorized) {
        if (err) return next(new Error(err));
        if (!authorized) return next(new Error('Not authorized'));
        next();
      });
    });
  } else if ('origins' == key && val) {
    this.origins(val);
  } else if ('resource' == key) {
    this.path(val);
  } else if (oldSettings[key] && this.eio[oldSettings[key]]) {
    this.eio[oldSettings[key]] = val;
  } else {
    console.error('Option %s is not valid. Please refer to the README.', key);
  }

  return this;
};

/**
 * Sets the client serving path.
 *
 * @param {String} v pathname
 * @return {Server|String} self when setting or value when getting
 * @api public
 */

Server.prototype.path = function(v){
  if (!arguments.length) return this._path;
  this._path = v.replace(/\/$/, '');
  return this;
};

/**
 * Sets the adapter for rooms.
 *
 * @param {Adapter} v pathname
 * @return {Server|Adapter} self when setting or value when getting
 * @api public
 */

Server.prototype.adapter = function(v){
  if (!arguments.length) return this._adapter;
  this._adapter = v;
  for (var i in this.nsps) {
    if (this.nsps.hasOwnProperty(i)) {
      this.nsps[i].initAdapter();
    }
  }
  return this;
};

/**
 * Sets the allowed origins for requests.
 *
 * @param {String} v origins
 * @return {Server|Adapter} self when setting or value when getting
 * @api public
 */

Server.prototype.origins = function(v){
  if (!arguments.length) return this._origins;

  this._origins = v;
  return this;
};

/**
 * Attaches socket.io to a server or port.
 *
 * @param {http.Server|Number} server or port
 * @param {Object} options passed to engine.io
 * @return {Server} self
 * @api public
 */

Server.prototype.listen =
Server.prototype.attach = function(srv, opts){
  if ('function' == typeof srv) {
    var msg = 'You are trying to attach socket.io to an express ' +
    'request handler function. Please pass a http.Server instance.';
    throw new Error(msg);
  }

  // handle a port as a string
  if (Number(srv) == srv) {
    srv = Number(srv);
  }

  if ('number' == typeof srv) {
    debug('creating http server and binding to %d', srv);
    var port = srv;
    srv = http.Server(function(req, res){
      res.writeHead(404);
      res.end();
    });
    srv.listen(port);

  }

  // set engine.io path to `/socket.io`
  opts = opts || {};
  opts.path = opts.path || this.path();
  // set origins verification
  opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);

  // initialize engine
  debug('creating engine.io instance with opts %j', opts);
  this.eio = engine.attach(srv, opts);

  // attach static file serving
  if (this._serveClient) this.attachServe(srv);

  // Export http server
  this.httpServer = srv;

  // bind to engine events
  this.bind(this.eio);

  return this;
};

/**
 * Attaches the static file serving.
 *
 * @param {Function|http.Server} srv http server
 * @api private
 */

Server.prototype.attachServe = function(srv){
  debug('attaching client serving req handler');
  var url = this._path + '/socket.io.js';
  var urlMap = this._path + '/socket.io.js.map';
  var evs = srv.listeners('request').slice(0);
  var self = this;
  srv.removeAllListeners('request');
  srv.on('request', function(req, res) {
    if (0 === req.url.indexOf(urlMap)) {
      self.serveMap(req, res);
    } else if (0 === req.url.indexOf(url)) {
      self.serve(req, res);
    } else {
      for (var i = 0; i < evs.length; i++) {
        evs[i].call(srv, req, res);
      }
    }
  });
};

/**
 * Handles a request serving `/socket.io.js`
 *
 * @param {http.Request} req
 * @param {http.Response} res
 * @api private
 */

Server.prototype.serve = function(req, res){
  // Per the standard, ETags must be quoted:
  // https://tools.ietf.org/html/rfc7232#section-2.3
  var expectedEtag = '"' + clientVersion + '"';

  var etag = req.headers['if-none-match'];
  if (etag) {
    if (expectedEtag == etag) {
      debug('serve client 304');
      res.writeHead(304);
      res.end();
      return;
    }
  }

  debug('serve client source');
  res.setHeader('Content-Type', 'application/javascript');
  res.setHeader('ETag', expectedEtag);
  res.setHeader('X-SourceMap', 'socket.io.js.map');
  res.writeHead(200);
  res.end(clientSource);
};

/**
 * Handles a request serving `/socket.io.js.map`
 *
 * @param {http.Request} req
 * @param {http.Response} res
 * @api private
 */

Server.prototype.serveMap = function(req, res){
  // Per the standard, ETags must be quoted:
  // https://tools.ietf.org/html/rfc7232#section-2.3
  var expectedEtag = '"' + clientVersion + '"';

  var etag = req.headers['if-none-match'];
  if (etag) {
    if (expectedEtag == etag) {
      debug('serve client 304');
      res.writeHead(304);
      res.end();
      return;
    }
  }

  debug('serve client sourcemap');
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('ETag', expectedEtag);
  res.writeHead(200);
  res.end(clientSourceMap);
};

/**
 * Binds socket.io to an engine.io instance.
 *
 * @param {engine.Server} engine engine.io (or compatible) server
 * @return {Server} self
 * @api public
 */

Server.prototype.bind = function(engine){
  this.engine = engine;
  this.engine.on('connection', this.onconnection.bind(this));
  return this;
};

/**
 * Called with each incoming transport connection.
 *
 * @param {engine.Socket} conn
 * @return {Server} self
 * @api public
 */

Server.prototype.onconnection = function(conn){
  debug('incoming connection with id %s', conn.id);
  var client = new Client(this, conn);
  client.connect('/');
  return this;
};

/**
 * Looks up a namespace.
 *
 * @param {String} name nsp name
 * @param {Function} [fn] optional, nsp `connection` ev handler
 * @api public
 */

Server.prototype.of = function(name, fn){
  if (String(name)[0] !== '/') name = '/' + name;

  var nsp = this.nsps[name];
  if (!nsp) {
    debug('initializing namespace %s', name);
    nsp = new Namespace(this, name);
    this.nsps[name] = nsp;
  }
  if (fn) nsp.on('connect', fn);
  return nsp;
};

/**
 * Closes server connection
 *
 * @param {Function} [fn] optional, called as `fn([err])` on error OR all conns closed
 * @api public
 */

Server.prototype.close = function(fn){
  for (var id in this.nsps['/'].sockets) {
    if (this.nsps['/'].sockets.hasOwnProperty(id)) {
      this.nsps['/'].sockets[id].onclose();
    }
  }

  this.engine.close();

  if (this.httpServer) {
    this.httpServer.close(fn);
  } else {
    fn && fn();
  }
};

/**
 * Expose main namespace (/).
 */

var emitterMethods = Object.keys(Emitter.prototype).filter(function(key){
  return typeof Emitter.prototype[key] === 'function';
});

emitterMethods.concat(['to', 'in', 'use', 'send', 'write', 'clients', 'compress']).forEach(function(fn){
  Server.prototype[fn] = function(){
    return this.sockets[fn].apply(this.sockets, arguments);
  };
});

Namespace.flags.forEach(function(flag){
  Object.defineProperty(Server.prototype, flag, {
    get: function() {
      this.sockets.flags = this.sockets.flags || {};
      this.sockets.flags[flag] = true;
      return this;
    }
  });
});

/**
 * BC with `io.listen`
 */

Server.listen = Server;
<commit_msg>[fix] Use path.resolve by default and require.resolve as a fallback (#2797)<commit_after>
/**
 * Module dependencies.
 */

var http = require('http');
var read = require('fs').readFileSync;
var path = require('path');
var exists = require('fs').existsSync;
var engine = require('engine.io');
var client = require('socket.io-client');
var clientVersion = require('socket.io-client/package').version;
var Client = require('./client');
var Emitter = require('events').EventEmitter;
var Namespace = require('./namespace');
var Adapter = require('socket.io-adapter');
var debug = require('debug')('socket.io:server');
var url = require('url');

/**
 * Module exports.
 */

module.exports = Server;

/**
 * Socket.IO client source.
 */

var clientSource = undefined;
var clientSourceMap = undefined;

/**
 * Server constructor.
 *
 * @param {http.Server|Number|Object} srv http server, port or options
 * @param {Object} [opts]
 * @api public
 */

function Server(srv, opts){
  if (!(this instanceof Server)) return new Server(srv, opts);
  if ('object' == typeof srv && srv instanceof Object && !srv.listen) {
    opts = srv;
    srv = null;
  }
  opts = opts || {};
  this.nsps = {};
  this.path(opts.path || '/socket.io');
  this.serveClient(false !== opts.serveClient);
  this.adapter(opts.adapter || Adapter);
  this.origins(opts.origins || '*:*');
  this.sockets = this.of('/');
  if (srv) this.attach(srv, opts);
}

/**
 * Server request verification function, that checks for allowed origins
 *
 * @param {http.IncomingMessage} req request
 * @param {Function} fn callback to be called with the result: `fn(err, success)`
 */

Server.prototype.checkRequest = function(req, fn) {
  var origin = req.headers.origin || req.headers.referer;

  // file:// URLs produce a null Origin which can't be authorized via echo-back
  if ('null' == origin || null == origin) origin = '*';

  if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
  if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
  if (origin) {
    try {
      var parts = url.parse(origin);
      var defaultPort = 'https:' == parts.protocol ? 443 : 80;
      parts.port = parts.port != null
        ? parts.port
        : defaultPort;
      var ok =
        ~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
        ~this._origins.indexOf(parts.hostname + ':*') ||
        ~this._origins.indexOf('*:' + parts.port);
      return fn(null, !!ok);
    } catch (ex) {
    }
  }
  fn(null, false);
};

/**
 * Sets/gets whether client code is being served.
 *
 * @param {Boolean} v whether to serve client code
 * @return {Server|Boolean} self when setting or value when getting
 * @api public
 */

Server.prototype.serveClient = function(v){
  if (!arguments.length) return this._serveClient;
  this._serveClient = v;
  var resolvePath = function(file){
    var filepath = path.resolve(__dirname, './../../', file);
    if (exists(filepath)) {
      return filepath;
    }
    return require.resolve(file);
  };
  if (v && !clientSource) {
    clientSource = read(resolvePath( 'socket.io-client/dist/socket.io.min.js'), 'utf-8');
    try {
      clientSourceMap = read(resolvePath( 'socket.io-client/dist/socket.io.js.map'), 'utf-8');
    } catch(err) {
      debug('could not load sourcemap file');
    }
  }
  return this;
};

/**
 * Old settings for backwards compatibility
 */

var oldSettings = {
  "transports": "transports",
  "heartbeat timeout": "pingTimeout",
  "heartbeat interval": "pingInterval",
  "destroy buffer size": "maxHttpBufferSize"
};

/**
 * Backwards compatibility.
 *
 * @api public
 */

Server.prototype.set = function(key, val){
  if ('authorization' == key && val) {
    this.use(function(socket, next) {
      val(socket.request, function(err, authorized) {
        if (err) return next(new Error(err));
        if (!authorized) return next(new Error('Not authorized'));
        next();
      });
    });
  } else if ('origins' == key && val) {
    this.origins(val);
  } else if ('resource' == key) {
    this.path(val);
  } else if (oldSettings[key] && this.eio[oldSettings[key]]) {
    this.eio[oldSettings[key]] = val;
  } else {
    console.error('Option %s is not valid. Please refer to the README.', key);
  }

  return this;
};

/**
 * Sets the client serving path.
 *
 * @param {String} v pathname
 * @return {Server|String} self when setting or value when getting
 * @api public
 */

Server.prototype.path = function(v){
  if (!arguments.length) return this._path;
  this._path = v.replace(/\/$/, '');
  return this;
};

/**
 * Sets the adapter for rooms.
 *
 * @param {Adapter} v pathname
 * @return {Server|Adapter} self when setting or value when getting
 * @api public
 */

Server.prototype.adapter = function(v){
  if (!arguments.length) return this._adapter;
  this._adapter = v;
  for (var i in this.nsps) {
    if (this.nsps.hasOwnProperty(i)) {
      this.nsps[i].initAdapter();
    }
  }
  return this;
};

/**
 * Sets the allowed origins for requests.
 *
 * @param {String} v origins
 * @return {Server|Adapter} self when setting or value when getting
 * @api public
 */

Server.prototype.origins = function(v){
  if (!arguments.length) return this._origins;

  this._origins = v;
  return this;
};

/**
 * Attaches socket.io to a server or port.
 *
 * @param {http.Server|Number} server or port
 * @param {Object} options passed to engine.io
 * @return {Server} self
 * @api public
 */

Server.prototype.listen =
Server.prototype.attach = function(srv, opts){
  if ('function' == typeof srv) {
    var msg = 'You are trying to attach socket.io to an express ' +
    'request handler function. Please pass a http.Server instance.';
    throw new Error(msg);
  }

  // handle a port as a string
  if (Number(srv) == srv) {
    srv = Number(srv);
  }

  if ('number' == typeof srv) {
    debug('creating http server and binding to %d', srv);
    var port = srv;
    srv = http.Server(function(req, res){
      res.writeHead(404);
      res.end();
    });
    srv.listen(port);

  }

  // set engine.io path to `/socket.io`
  opts = opts || {};
  opts.path = opts.path || this.path();
  // set origins verification
  opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);

  // initialize engine
  debug('creating engine.io instance with opts %j', opts);
  this.eio = engine.attach(srv, opts);

  // attach static file serving
  if (this._serveClient) this.attachServe(srv);

  // Export http server
  this.httpServer = srv;

  // bind to engine events
  this.bind(this.eio);

  return this;
};

/**
 * Attaches the static file serving.
 *
 * @param {Function|http.Server} srv http server
 * @api private
 */

Server.prototype.attachServe = function(srv){
  debug('attaching client serving req handler');
  var url = this._path + '/socket.io.js';
  var urlMap = this._path + '/socket.io.js.map';
  var evs = srv.listeners('request').slice(0);
  var self = this;
  srv.removeAllListeners('request');
  srv.on('request', function(req, res) {
    if (0 === req.url.indexOf(urlMap)) {
      self.serveMap(req, res);
    } else if (0 === req.url.indexOf(url)) {
      self.serve(req, res);
    } else {
      for (var i = 0; i < evs.length; i++) {
        evs[i].call(srv, req, res);
      }
    }
  });
};

/**
 * Handles a request serving `/socket.io.js`
 *
 * @param {http.Request} req
 * @param {http.Response} res
 * @api private
 */

Server.prototype.serve = function(req, res){
  // Per the standard, ETags must be quoted:
  // https://tools.ietf.org/html/rfc7232#section-2.3
  var expectedEtag = '"' + clientVersion + '"';

  var etag = req.headers['if-none-match'];
  if (etag) {
    if (expectedEtag == etag) {
      debug('serve client 304');
      res.writeHead(304);
      res.end();
      return;
    }
  }

  debug('serve client source');
  res.setHeader('Content-Type', 'application/javascript');
  res.setHeader('ETag', expectedEtag);
  res.setHeader('X-SourceMap', 'socket.io.js.map');
  res.writeHead(200);
  res.end(clientSource);
};

/**
 * Handles a request serving `/socket.io.js.map`
 *
 * @param {http.Request} req
 * @param {http.Response} res
 * @api private
 */

Server.prototype.serveMap = function(req, res){
  // Per the standard, ETags must be quoted:
  // https://tools.ietf.org/html/rfc7232#section-2.3
  var expectedEtag = '"' + clientVersion + '"';

  var etag = req.headers['if-none-match'];
  if (etag) {
    if (expectedEtag == etag) {
      debug('serve client 304');
      res.writeHead(304);
      res.end();
      return;
    }
  }

  debug('serve client sourcemap');
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('ETag', expectedEtag);
  res.writeHead(200);
  res.end(clientSourceMap);
};

/**
 * Binds socket.io to an engine.io instance.
 *
 * @param {engine.Server} engine engine.io (or compatible) server
 * @return {Server} self
 * @api public
 */

Server.prototype.bind = function(engine){
  this.engine = engine;
  this.engine.on('connection', this.onconnection.bind(this));
  return this;
};

/**
 * Called with each incoming transport connection.
 *
 * @param {engine.Socket} conn
 * @return {Server} self
 * @api public
 */

Server.prototype.onconnection = function(conn){
  debug('incoming connection with id %s', conn.id);
  var client = new Client(this, conn);
  client.connect('/');
  return this;
};

/**
 * Looks up a namespace.
 *
 * @param {String} name nsp name
 * @param {Function} [fn] optional, nsp `connection` ev handler
 * @api public
 */

Server.prototype.of = function(name, fn){
  if (String(name)[0] !== '/') name = '/' + name;

  var nsp = this.nsps[name];
  if (!nsp) {
    debug('initializing namespace %s', name);
    nsp = new Namespace(this, name);
    this.nsps[name] = nsp;
  }
  if (fn) nsp.on('connect', fn);
  return nsp;
};

/**
 * Closes server connection
 *
 * @param {Function} [fn] optional, called as `fn([err])` on error OR all conns closed
 * @api public
 */

Server.prototype.close = function(fn){
  for (var id in this.nsps['/'].sockets) {
    if (this.nsps['/'].sockets.hasOwnProperty(id)) {
      this.nsps['/'].sockets[id].onclose();
    }
  }

  this.engine.close();

  if (this.httpServer) {
    this.httpServer.close(fn);
  } else {
    fn && fn();
  }
};

/**
 * Expose main namespace (/).
 */

var emitterMethods = Object.keys(Emitter.prototype).filter(function(key){
  return typeof Emitter.prototype[key] === 'function';
});

emitterMethods.concat(['to', 'in', 'use', 'send', 'write', 'clients', 'compress']).forEach(function(fn){
  Server.prototype[fn] = function(){
    return this.sockets[fn].apply(this.sockets, arguments);
  };
});

Namespace.flags.forEach(function(flag){
  Object.defineProperty(Server.prototype, flag, {
    get: function() {
      this.sockets.flags = this.sockets.flags || {};
      this.sockets.flags[flag] = true;
      return this;
    }
  });
});

/**
 * BC with `io.listen`
 */

Server.listen = Server;
<|endoftext|>