<commit_before>'use strict';

/**
 * An interface for a list of items.
 *
 * @constructor
 * @param {Array.<*>} values
 */

function DatalistInterface(values) {
    this.values = [];
    this.add.apply(this, values);
}

/**
 * Add all arguments.
 *
 * @this DatalistInterface
 * @param {...*} values
 * @return DatalistInterface Self.
 */

function add(/* values... */) {
    var self;

    self = this;

    self.values.push.apply(self.values, arguments);

    return self;
}

/**
 * Remove all arguments.
 *
 * @this DatalistInterface
 * @param {...*} values
 * @return DatalistInterface Self.
 */

function remove(/* values... */) {
    var values,
        index,
        position;

    values = this.values;
    index = arguments.length;

    while (index--) {
        position = values.indexOf(arguments[index]);

        if (position !== -1) {
            values.splice(position, 1);
        }
    }

    return this;
}

/**
 * Whether or not `value` is in context.
 *
 * @this DatalistInterface
 * @param {*} value
 * @return {boolean}
 */

function is(value) {
    return this.values.indexOf(value) !== -1;
}

/**
 * Get all values.
 *
 * @this DatalistInterface
 * @return {Array.<*>}
 */

function all() {
    return this.values.concat();
}

/**
 * Stringify all values.
 *
 * @this DatalistInterface
 * @return {string}
 */

function toString() {
    return this.values.toString();
}

/**
 * Expose methods on prototype.
 */

var datalistInterfacePrototype;

datalistInterfacePrototype = DatalistInterface.prototype;

datalistInterfacePrototype.add = add;
datalistInterfacePrototype.remove = remove;
datalistInterfacePrototype.is = is;
datalistInterfacePrototype.all = all;
datalistInterfacePrototype.toString = toString;

/**
 * Expose `DatalistInterface`.
 */

module.exports = DatalistInterface;
<commit_msg>Add `valueOf()` method (same as `all()`)<commit_after>'use strict';

/**
 * An interface for a list of items.
 *
 * @constructor
 * @param {Array.<*>} values
 */

function DatalistInterface(values) {
    this.values = [];
    this.add.apply(this, values);
}

/**
 * Add all arguments.
 *
 * @this DatalistInterface
 * @param {...*} values
 * @return DatalistInterface Self.
 */

function add(/* values... */) {
    var self;

    self = this;

    self.values.push.apply(self.values, arguments);

    return self;
}

/**
 * Remove all arguments.
 *
 * @this DatalistInterface
 * @param {...*} values
 * @return DatalistInterface Self.
 */

function remove(/* values... */) {
    var values,
        index,
        position;

    values = this.values;
    index = arguments.length;

    while (index--) {
        position = values.indexOf(arguments[index]);

        if (position !== -1) {
            values.splice(position, 1);
        }
    }

    return this;
}

/**
 * Whether or not `value` is in context.
 *
 * @this DatalistInterface
 * @param {*} value
 * @return {boolean}
 */

function is(value) {
    return this.values.indexOf(value) !== -1;
}

/**
 * Get all values.
 *
 * @this DatalistInterface
 * @return {Array.<*>}
 */

function all() {
    return this.values.concat();
}

/**
 * Stringify all values.
 *
 * @this DatalistInterface
 * @return {string}
 */

function toString() {
    return this.values.toString();
}

/**
 * Expose methods on prototype.
 */

var datalistInterfacePrototype;

datalistInterfacePrototype = DatalistInterface.prototype;

datalistInterfacePrototype.add = add;
datalistInterfacePrototype.remove = remove;
datalistInterfacePrototype.is = is;
datalistInterfacePrototype.all = all;
datalistInterfacePrototype.valueOf = all;
datalistInterfacePrototype.toString = toString;

/**
 * Expose `DatalistInterface`.
 */

module.exports = DatalistInterface;
<|endoftext|>


<commit_before>#!/usr/bin/node

var fs = require('fs'),
    connect = require('connect'),
    request = require('request'),

    oauthHtml = fs.readFileSync('resources/oauth.html', 'utf-8'),

    CLIENT_ID = process.env.GH_BASIC_CLIENT_ID,
    CLIENT_SECRET = process.env.GH_BASIC_SECRET_ID,

    oauthPitcher, oauthCatcher,
    travisHandler;

oauthHtml = oauthHtml.replace('{{client_id}}', CLIENT_ID);

oauthCatcher = function(req, res, next) {
    // ignore all URLs that don't start /oauth_callback
    if (req.url.substr(0,15) != '/oauth_callback') {
        return next();
    }
    var sessionCode = req.query.code;
    request.post(
        {
            url: 'https://github.com/login/oauth/access_token',
            oauth: {
                client_id: CLIENT_ID,
                client_secret: CLIENT_SECRET,
                code: sessionCode
            }
        },
        function(err, oauthRes, body) {
            var accessToken = JSON.parse(body).access_token;
            console.log('access token: ' + accessToken);
            res.end();
        }
    );
};

oauthPitcher = function(req, res, next) {
    if (req.url != '/') {
        return next();
    }
    res.end(oauthHtml);
};

travisHandler = function(req, res, next) {
    // ignore all URLs that don't start /travis
    if (req.url.substr(0,7) != '/travis') {
        return next();
    }
    console.log(req.body);
    res.end();
};

connect()
    .use(connect.logger('dev'))
    .use(connect.bodyParser())
    .use(oauthCatcher)
    .use(oauthPitcher)
    .use(travisHandler)
    .listen(3031);
<commit_msg>About to switch to using connect-auth module.<commit_after>#!/usr/bin/node

var fs = require('fs'),
	url = require('url'),
    connect = require('connect'),
    request = require('request'),

	oauthHtml = fs.readFileSync('resources/oauth.html', 'utf-8'),

    CLIENT_ID = process.env.GH_BASIC_CLIENT_ID,
    CLIENT_SECRET = process.env.GH_BASIC_SECRET_ID,
	oauthRequestUrl = 'https://github.com/login/oauth/authorize?client_id=' + CLIENT_ID,
	accessToken,

    oauthPitcher, oauthCatcher,
    travisHandler;

oauthHtml = oauthHtml.replace('{{client_id}}', CLIENT_ID);

oauthPitcher = function(req, res, next) {
    if (req.url != '/') {
        return next();
    }
    res.end(oauthHtml);
};

oauthCatcher = function(req, res, next) {
    // ignore all URLs that don't start /oauth_callback
    if (req.url.substr(0,15) != '/oauth_callback') {
        return next();
    }
    var sessionCode = url.parse(req.url, true).query.code;
	console.log('session code: ' + sessionCode);
    request.post(
        {
            url: 'https://github.com/login/oauth/access_token',
			json: {
                client_id: CLIENT_ID,
                client_secret: CLIENT_SECRET,
                code: sessionCode
            }
        },
        function(err, oauthRes, body) {
            accessToken = body.access_token;
            console.log('access token: ' + accessToken);
            res.end();
        }
    );
};

travisHandler = function(req, res, next) {
    // ignore all URLs that don't start /travis
    if (req.url.substr(0,7) != '/travis') {
        return next();
    }
    console.log(req.body);
    res.end();
};

connect()
    .use(connect.logger('dev'))
    .use(connect.bodyParser())
    .use(oauthPitcher)
    .use(oauthCatcher)
    .use(travisHandler)
    .listen(3031);

<|endoftext|>


<commit_before>'use strict';
var dns = require('native-dns');
var net = require('net');
var eachAsync = require('each-async');
var onetime = require('onetime');
var roots = require('root-hints')('A');

var timeout = 1000;
var domains = [
	'www.google.com',
	'www.cloudflare.com',
	'www.baidu.com',
	'www.yandex.ru'
];

module.exports = function (cb) {
	cb = onetime(cb);

	// Pick a random root server to query
	var server = roots[Math.floor(Math.random() * roots.length)];

	// Set up a DNS request that requests the authoritative information for
	// the 'com' zone
	var req = dns.Request({
		question: dns.Question({
			name: 'com',
			type: 'NS'
		}),
		server: {
			address: server
		},
		timeout: timeout
	});

	req.on('timeout', function () {
		// We ran into the timeout, we're offline with high confidence
		cb(null, false);
	});

	req.on('message', function (err, answer) {
		if (answer.authority.length && answer._socket.address === server) {
			// We got an answer and the source matches the queried server,
			// we're online with high confidence
			cb(null, true);
		} else {
			// Either DNS intercepting is in place or the response in mangled,
			// try connecting to our domains on port 80, and if one handshake
			// succeeds, we're definitely online
			eachAsync(domains, function (domain, i, done) {
				var socket = new net.Socket();
				socket.setTimeout(timeout);
				socket.on('error', function () {
					socket.destroy();
				});
				socket.connect(80, domain, function () {
					cb(null, true);
					socket.end();
					done(new Error()); // skip to end
				});
			}, function () {
				cb(null, false);
			});
		}
	});

	req.send();
};
<commit_msg>Restore done callback - #16<commit_after>'use strict';
var dns = require('native-dns');
var net = require('net');
var eachAsync = require('each-async');
var onetime = require('onetime');
var roots = require('root-hints')('A');

var timeout = 1000;
var domains = [
	'www.google.com',
	'www.cloudflare.com',
	'www.baidu.com',
	'www.yandex.ru'
];

module.exports = function (cb) {
	cb = onetime(cb);

	// Pick a random root server to query
	var server = roots[Math.floor(Math.random() * roots.length)];

	// Set up a DNS request that requests the authoritative information for
	// the 'com' zone
	var req = dns.Request({
		question: dns.Question({
			name: 'com',
			type: 'NS'
		}),
		server: {
			address: server
		},
		timeout: timeout
	});

	req.on('timeout', function () {
		// We ran into the timeout, we're offline with high confidence
		cb(null, false);
	});

	req.on('message', function (err, answer) {
		if (answer.authority.length && answer._socket.address === server) {
			// We got an answer and the source matches the queried server,
			// we're online with high confidence
			cb(null, true);
		} else {
			// Either DNS intercepting is in place or the response in mangled,
			// try connecting to our domains on port 80, and if one handshake
			// succeeds, we're definitely online
			eachAsync(domains, function (domain, i, done) {
				var socket = new net.Socket();
				socket.setTimeout(timeout);
				socket.on('error', function () {
					socket.destroy();
					done();
				});
				socket.connect(80, domain, function () {
					cb(null, true);
					socket.end();
					done(new Error()); // skip to end
				});
			}, function () {
				cb(null, false);
			});
		}
	});

	req.send();
};
<|endoftext|>


<commit_before>/*jshint node:true */
'use strict';
/**
 * @fileOverview
 * Global proxy settings.
 */
var globalTunnel = exports;
exports.constructor = function globalTunnel(){};

var http = require('http');
var https = require('https');
var urlParse = require('url').parse;

var _ = require('lodash');
var tunnel = require('tunnel');

var agents = require('./lib/agents');
exports.agents = agents;

// save the original globalAgents for restoration later.
var ORIGINALS = {
  http: _.pick(http, 'globalAgent', 'request'),
  https: _.pick(https, 'globalAgent', 'request')
};
function resetGlobals() {
  _.assign(http, ORIGINALS.http);
  _.assign(https, ORIGINALS.https);
}

/**
 * Parses the de facto `http_proxy` environment.
 */
function tryParse(url) {
  if (!url) {
    return null;
  }

  var conf = {};
  var parsed = urlParse(url);
  conf.protocol = parsed.protocol;
  conf.host = parsed.hostname;
  conf.port = parseInt(parsed.port,10);
  return conf;
}

globalTunnel.isProxying = false;

/**
 * Overrides the node http/https `globalAgent`s to use the configured proxy.
 *
 * If the config is empty, the `http_proxy` environment variable is checked. If
 * that's not present, no proxying will be enabled.
 *
 * @param {object} conf
 * @param {string} conf.host
 * @param {int} conf.port
 * @param {int} [conf.sockets] maximum number of sockets to pool (falsy uses
 * node's default).
 */
globalTunnel.initialize = function(conf) {
  if (globalTunnel.isProxying) {
    return;
  }

  conf = conf || {};
  if (typeof conf === 'string') {
    conf = tryParse(conf);
  }

  if (_.isEmpty(conf)) {
    conf = tryParse(process.env['http_proxy']);
    if (!conf) {
      globalTunnel.isProxying = false;
      return;
    }
  }
  conf = _.clone(conf);

  if (!conf.host) {
    throw new Error('upstream proxy host is required');
  }
  if (!conf.port) {
    throw new Error('upstream proxy port is required');
  }

  if (conf.protocol === undefined) {
    conf.protocol = 'http:'; // default to proxy speaking http
  }
  if (!/:$/.test(conf.protocol)) {
    conf.protocol = conf.protocol + ':';
  }

  if (!conf.connect) {
    conf.connect = 'https'; // just HTTPS by default
  }
  switch(conf.connect) {
  case 'both':
    conf.connectHttp = true;
    conf.connectHttps = true;
    break;
  case 'neither':
    conf.connectHttp = false;
    conf.connectHttps = false;
    break;
  case 'https':
    conf.connectHttp = false;
    conf.connectHttps = true;
    break;
  default:
    throw new Error('valid connect options are "neither", "https", or "both"');
  }

  if (conf.httpsOptions) {
    conf.outerHttpsOpts = conf.innerHttpsOpts = conf.httpsOptions;
  }

  try {
    http.globalAgent  = globalTunnel._makeAgent(conf, 'http', conf.connectHttp);
    https.globalAgent = globalTunnel._makeAgent(conf, 'https', conf.connectHttps);

    http.request = globalTunnel._defaultedAgentRequest.bind(http, 'http');
    https.request = globalTunnel._defaultedAgentRequest.bind(https, 'https');

    globalTunnel.isProxying = true;
  } catch (e) {
    resetGlobals();
    throw e;
  }
};

/**
 * Construct an agent based on:
 * - is the connection to the proxy secure?
 * - is the connection to the origin secure?
 * - the address of the proxy
 */
globalTunnel._makeAgent = function(conf, innerProtocol, useCONNECT) {
  var outerProtocol = conf.protocol;
  innerProtocol = innerProtocol + ':';

  var opts = {
    proxy: _.pick(conf, 'host','port','protocol','localAddress'),
    maxSockets: conf.sockets
  };
  opts.proxy.innerProtocol = innerProtocol;

  if (useCONNECT) {
    if (conf.proxyHttpsOptions) {
      _.assign(opts.proxy, conf.proxyHttpsOptions);
    }
    if (conf.originHttpsOptions) {
      _.assign(opts, conf.originHttpsOptions);
    }

    if (outerProtocol === 'https:') {
      if (innerProtocol === 'https:') {
        return tunnel.httpsOverHttps(opts);
      } else {
        return tunnel.httpOverHttps(opts);
      }
    } else {
      if (innerProtocol === 'https:') {
        return tunnel.httpsOverHttp(opts);
      } else {
        return tunnel.httpOverHttp(opts);
      }
    }

  } else {
    if (conf.originHttpsOptions) {
      throw new Error('originHttpsOptions must be combined with a tunnel:true option');
    }
    if (conf.proxyHttpsOptions) {
      // NB: not opts.
      _.assign(opts, conf.proxyHttpsOptions);
    }

    if (outerProtocol === 'https:') {
      return new agents.OuterHttpsAgent(opts);
    } else {
      return new agents.OuterHttpAgent(opts);
    }
  }
};

/**
 * Override for http.request and https.request, makes sure to default the agent
 * to the global agent. Due to how node implements it in lib/http.js, the
 * globalAgent we define won't get used (node uses a module-scoped variable,
 * not the exports field).
 * @param {string} protocol bound during initialization
 * @param {string|object} options http/https request url or options
 * @param {function} [cb]
 * @private
 */
globalTunnel._defaultedAgentRequest = function(protocol, options, callback) {
  var httpOrHttps = this;

  if (typeof options === 'string') {
    options = urlParse(options);
  } else {
    options = _.clone(options);
  }

  // A literal `false` means "no agent at all", other falsey values should use
  // our global agent.
  if (!options.agent && options.agent !== false) {
    options.agent = httpOrHttps.globalAgent;
  }

  return ORIGINALS[protocol].request.call(httpOrHttps, options, callback);
};

/**
 * Restores global http/https agents.
 */
globalTunnel.end = function() {
  resetGlobals();
  globalTunnel.isProxying = false;
};
<commit_msg>Add support for proxy auth<commit_after>/*jshint node:true */
'use strict';
/**
 * @fileOverview
 * Global proxy settings.
 */
var globalTunnel = exports;
exports.constructor = function globalTunnel(){};

var http = require('http');
var https = require('https');
var urlParse = require('url').parse;

var _ = require('lodash');
var tunnel = require('tunnel');

var agents = require('./lib/agents');
exports.agents = agents;

// save the original globalAgents for restoration later.
var ORIGINALS = {
  http: _.pick(http, 'globalAgent', 'request'),
  https: _.pick(https, 'globalAgent', 'request')
};
function resetGlobals() {
  _.assign(http, ORIGINALS.http);
  _.assign(https, ORIGINALS.https);
}

/**
 * Parses the de facto `http_proxy` environment.
 */
function tryParse(url) {
  if (!url) {
    return null;
  }

  var conf = {};
  var parsed = urlParse(url);
  conf.protocol = parsed.protocol;
  conf.host = parsed.hostname;
  conf.port = parseInt(parsed.port,10);
  conf.proxyAuth = parsed.auth;
  return conf;
}

globalTunnel.isProxying = false;

/**
 * Overrides the node http/https `globalAgent`s to use the configured proxy.
 *
 * If the config is empty, the `http_proxy` environment variable is checked. If
 * that's not present, no proxying will be enabled.
 *
 * @param {object} conf
 * @param {string} conf.host
 * @param {int} conf.port
 * @param {int} [conf.sockets] maximum number of sockets to pool (falsy uses
 * node's default).
 */
globalTunnel.initialize = function(conf) {
  if (globalTunnel.isProxying) {
    return;
  }

  conf = conf || {};
  if (typeof conf === 'string') {
    conf = tryParse(conf);
  }

  if (_.isEmpty(conf)) {
    conf = tryParse(process.env['http_proxy']);
    if (!conf) {
      globalTunnel.isProxying = false;
      return;
    }
  }
  conf = _.clone(conf);

  if (!conf.host) {
    throw new Error('upstream proxy host is required');
  }
  if (!conf.port) {
    throw new Error('upstream proxy port is required');
  }

  if (conf.protocol === undefined) {
    conf.protocol = 'http:'; // default to proxy speaking http
  }
  if (!/:$/.test(conf.protocol)) {
    conf.protocol = conf.protocol + ':';
  }

  if (!conf.connect) {
    conf.connect = 'https'; // just HTTPS by default
  }
  switch(conf.connect) {
  case 'both':
    conf.connectHttp = true;
    conf.connectHttps = true;
    break;
  case 'neither':
    conf.connectHttp = false;
    conf.connectHttps = false;
    break;
  case 'https':
    conf.connectHttp = false;
    conf.connectHttps = true;
    break;
  default:
    throw new Error('valid connect options are "neither", "https", or "both"');
  }

  if (conf.httpsOptions) {
    conf.outerHttpsOpts = conf.innerHttpsOpts = conf.httpsOptions;
  }

  try {
    http.globalAgent  = globalTunnel._makeAgent(conf, 'http', conf.connectHttp);
    https.globalAgent = globalTunnel._makeAgent(conf, 'https', conf.connectHttps);

    http.request = globalTunnel._defaultedAgentRequest.bind(http, 'http');
    https.request = globalTunnel._defaultedAgentRequest.bind(https, 'https');

    globalTunnel.isProxying = true;
  } catch (e) {
    resetGlobals();
    throw e;
  }
};

/**
 * Construct an agent based on:
 * - is the connection to the proxy secure?
 * - is the connection to the origin secure?
 * - the address of the proxy
 */
globalTunnel._makeAgent = function(conf, innerProtocol, useCONNECT) {
  var outerProtocol = conf.protocol;
  innerProtocol = innerProtocol + ':';

  var opts = {
    proxy: _.pick(conf, 'host','port','protocol','localAddress', 'proxyAuth'),
    maxSockets: conf.sockets
  };
  opts.proxy.innerProtocol = innerProtocol;

  if (useCONNECT) {
    if (conf.proxyHttpsOptions) {
      _.assign(opts.proxy, conf.proxyHttpsOptions);
    }
    if (conf.originHttpsOptions) {
      _.assign(opts, conf.originHttpsOptions);
    }

    if (outerProtocol === 'https:') {
      if (innerProtocol === 'https:') {
        return tunnel.httpsOverHttps(opts);
      } else {
        return tunnel.httpOverHttps(opts);
      }
    } else {
      if (innerProtocol === 'https:') {
        return tunnel.httpsOverHttp(opts);
      } else {
        return tunnel.httpOverHttp(opts);
      }
    }

  } else {
    if (conf.originHttpsOptions) {
      throw new Error('originHttpsOptions must be combined with a tunnel:true option');
    }
    if (conf.proxyHttpsOptions) {
      // NB: not opts.
      _.assign(opts, conf.proxyHttpsOptions);
    }

    if (outerProtocol === 'https:') {
      return new agents.OuterHttpsAgent(opts);
    } else {
      return new agents.OuterHttpAgent(opts);
    }
  }
};

/**
 * Override for http.request and https.request, makes sure to default the agent
 * to the global agent. Due to how node implements it in lib/http.js, the
 * globalAgent we define won't get used (node uses a module-scoped variable,
 * not the exports field).
 * @param {string} protocol bound during initialization
 * @param {string|object} options http/https request url or options
 * @param {function} [cb]
 * @private
 */
globalTunnel._defaultedAgentRequest = function(protocol, options, callback) {
  var httpOrHttps = this;

  if (typeof options === 'string') {
    options = urlParse(options);
  } else {
    options = _.clone(options);
  }

  // A literal `false` means "no agent at all", other falsey values should use
  // our global agent.
  if (!options.agent && options.agent !== false) {
    options.agent = httpOrHttps.globalAgent;
  }

  return ORIGINALS[protocol].request.call(httpOrHttps, options, callback);
};

/**
 * Restores global http/https agents.
 */
globalTunnel.end = function() {
  resetGlobals();
  globalTunnel.isProxying = false;
};
<|endoftext|>


<commit_before>var chalk = require('chalk');
var moment = require('moment');
var keypress = require('keypress');

keypress(process.stdin);
process.stdin.setRawMode(true);
process.stdin.resume();

process.stdin.on('keypress', (ch, key) => {
    if(key && key.ctrl && key.name === 'c'){
        process.stdin.pause();
        process.exit(1);
    }

    if(game.status <= Status.READY) start(); else if(game.status === Status.STARTED) switch(ch){
        case 'e': toggleFlag(cursor); break;
        case 'q': uncoverField(cursor); break;

        case 'w': cursor.w(); break;
        case 'd': cursor.d(); break;
        case 's': cursor.s(); break;
        case 'a': cursor.a(); break;

        default: if(key) switch(key.name){
            case 'up':    cursor.w(); break;
            case 'right': cursor.d(); break;
            case 'down':  cursor.s(); break;
            case 'left':  cursor.a(); break;
            default: return;
        }
    }

    printAll();
});

const FieldType = {
    GROUND: 0,
    BLANK: 1,
    MINE: 2
};

const Border = {
    TOP: '▄', BOTTOM: '▀', CENTER: '█', LEFT: '▐', RIGHT: '▌',
    COLOR: chalk.yellow,
    SELECTION_COLOR: chalk.yellow.bold
};

var consoleWidth = () => process.stdout.columns;
var consoleHeight = () => process.stdout.rows;

var fieldWidth = Math.min(2048, consoleWidth() - 2);
var fieldHeight = Math.min(2048, consoleHeight() - 3);

var fields = Array.apply(null, Array(fieldWidth)).map((v, x) => Array.apply(null, Array(fieldHeight)).map((v, y) => ({
    x: x, y: y,
    type: FieldType.GROUND,
    flagged: false
})));

var flatFields = () => fields.reduce((a, b) => a.concat(b));

var cursor = {
    x: Math.floor(fieldWidth / 2),
    y: Math.floor(fieldHeight / 2),
    w: () => cursor.y = Math.max(0, cursor.y - 1),
    d: () => cursor.x = Math.min(fieldWidth - 1, cursor.x + 1),
    s: () => cursor.y = Math.min(fieldHeight - 1, cursor.y + 1),
    a: () => cursor.x = Math.max(0, cursor.x - 1)
};

const Status = {
    READY: 0,
    STARTED: 1,
    FAILED: 2,
    SUCCEEDED: 3
};

var game = {
    status: Status.READY,
    startedTime: null,

    flagCount: 0,
    mineCount: Math.floor((fieldWidth * fieldHeight) / 20),
    mineInstalled: false,
};

var vectorToField = (x, y) => {
    if(x && x.hasOwnProperty('x')){
        y = x.y; x = x.x;
    }

    return (fields[x] && fields[x][y]) || null;
};

var toggleFlag = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;
    if(field.type === FieldType.BLANK) return;

    if(field.flagged = !field.flagged) game.flagCount++; else game.flagCount--;
    if(game.flagCount === game.mineCount && flatFields().filter(field => field.flagged).every(field => field.type === FieldType.MINE)) game.status = Status.SUCCEEDED;

    printAll();
};

var mineCount = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;

    var xx, yy, count = 0;
    for(var i = -1; i <= 1; i++) for(var j = -1; j <= 1; j++) if((i !== 0 || j !== 0) && (xx = field.x + i) >= 0 && (yy = field.y + j) >= 0 && xx < fieldWidth && yy < fieldHeight && fields[xx][yy].type === FieldType.MINE) count++;
    return count;
};

var uncoverField = (x, y) => {
    var field = vectorToField(x, y); if(!field || field.flagged) return;
    if(!game.mineInstalled){
        game.mineInstalled = true;

        var exception = {}; exception[field.x + ':' + field.y] = true;
        randomVectorArray(game.mineCount, exception).forEach((vector) => fields[vector[0]][vector[1]].type = FieldType.MINE);
    }

    switch(field.type){
        case FieldType.MINE:
            game.status = Status.FAILED;
            setTimeout(() => process.exit(0), 3000);
            break;

        case FieldType.GROUND:
            field.type = FieldType.BLANK;

            uncoverGround(field.x, field.y - 1); //w
            uncoverGround(field.x + 1, field.y); //d
            uncoverGround(field.x, field.y + 1); //s
            uncoverGround(field.x - 1, field.y); //a
            break;

        default: return;
    }
};

var uncoverGround = (x, y) => {
    var queue = [vectorToField(x, y)];
    var check = {};

    while(queue.length > 0){
        var field = queue.shift();
        if(!field || field.type !== FieldType.GROUND) continue;

        var key = field.x + ':' + field.y;
        if(check[key]) continue; check[key] = true;

        if(mineCount(field) !== 0) continue;
        field.type = FieldType.BLANK;

        queue.push(vectorToField(field.x, field.y - 1)); //w
        queue.push(vectorToField(field.x + 1, field.y)); //d
        queue.push(vectorToField(field.x, field.y + 1)); //s
        queue.push(vectorToField(field.x - 1, field.y)); //a
    }
};

var buffer = '';

var write = (text) => buffer += text;
var flush = () => {
    process.stdout.write(buffer);
    buffer = '';
};

var clear = () => write('\033c');
var newLine = () => write('\n');

var repeat = (theChalk, text, count) => {
    for(var i = 0; i < count; i++) theChalk ? write(theChalk(text)) : write(text);
};

var capitalize = (str) => str && str.charAt(0).toUpperCase() + str.slice(1);

var random = (min, max) => {
    if(max === undefined){
        max = min; min = 0;
    }

    return min + Math.floor(Math.random() * (max - min));
};

var randomVectorArray = (count, exception) => {
    var check = {};
    var vectors = [];

    while(vectors.length < count){
        var vector = [random(fieldWidth), random(fieldHeight)]; var key = vector.join(':');
        if(!check[key] && !exception[key]){
            check[key] = true;
            vectors.push(vector);
        }
    }
    return vectors;
};

const Title = {
    COLOR: chalk.yellow.bold
};

var printTitle = (text, align) => {
    var spaces = consoleWidth() - text.length;

    switch(align){
        case 'left':
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces);
            break;

        default:
        case 'center':
            var leftSpaces = Math.floor(spaces / 2);
            repeat(Title.COLOR, ' ', leftSpaces);
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces - leftSpaces);
            break;

        case 'right':
            repeat(Title.COLOR, ' ', spaces);
            write(Title.COLOR(text));
            break;
    }

    newLine();
};

var blankColor = (count) => {
    if(count >= 7) return 'red';
    if(count >= 5) return 'blue';
    if(count >= 3) return 'yellow';
    else return 'black';
};

var getFieldString = (x, y) => {
    var field = fields[x][y];
    var output = {
        background: 'white', foreground: 'black', text: ' ', special: null
    };

    if(field.flagged){
        output.text = 'X';
        output.background = 'cyan';
    }

    else switch(field.type){
        case FieldType.GROUND:
        case FieldType.MINE:
            output.text = '?';
            output.background = 'black';
            break;

        case FieldType.BLANK:
            var count = mineCount(x, y);
            output.foreground = blankColor(count);
            if(count > 0) output.text = Math.min(count, 9).toString(10);
            break;
    }

    if(cursor.x === x && cursor.y === y) output.background = 'green';

    var theChalk = chalk['bg' + capitalize(output.background)][output.foreground];
    if(output.special) theChalk = theChalk[output.special];

    return theChalk(output.text);
};

var getElapsedTime = () => moment.utc(moment().diff(game.startedTime)).format("HH:mm:ss");

var printAll = (title) => {
    clear();
    var marginTop = Math.round((consoleHeight() - fieldHeight - 3) / 2);
    var marginLeft = Math.round((consoleWidth() - fieldWidth - 2) / 2);

    repeat(null, '\n', marginTop);
    printTitle((game.status === Status.FAILED && 'Failed!') || (game.status === Status.SUCCEEDED && 'Succeeded!') || title || (getElapsedTime() + ' | ' + game.flagCount + '/' + game.mineCount + ' | (' + cursor.x + ', ' + cursor.y + ')'));

    repeat(null, ' ', marginLeft);
    repeat(Border.COLOR, Border.TOP, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.TOP));
    repeat(Border.COLOR, Border.TOP, fieldWidth - cursor.x);
    newLine();

    for(var y = 0; y < fieldHeight; y++){
        var border = (y === cursor.y ? Border.SELECTION_COLOR : Border.COLOR)(Border.CENTER);
        repeat(null, ' ', marginLeft); write(border); for(var x = 0; x < fieldWidth; x++) write(getFieldString(x, y)); write(border); newLine();
    }

    repeat(null, ' ', marginLeft); repeat(Border.COLOR, Border.BOTTOM, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.BOTTOM));
    repeat(Border.COLOR, Border.BOTTOM, fieldWidth - cursor.x);

    flush();
};

var printer = null;

var start = () => {
    if(game.status > Status.READY) return;

    game.status = Status.STARTED;
    game.startedTime = moment();

    printAll(); printer = setInterval(printAll, 200);
};

printAll("Press any key to start...");
<commit_msg>Added finish()<commit_after>var chalk = require('chalk');
var moment = require('moment');
var keypress = require('keypress');

keypress(process.stdin);
process.stdin.setRawMode(true);
process.stdin.resume();

process.stdin.on('keypress', (ch, key) => {
    if(key && key.ctrl && key.name === 'c'){
        process.stdin.pause();
        process.exit(1);
    }

    if(game.status <= Status.READY) start(); else if(game.status === Status.STARTED) switch(ch){
        case 'e': toggleFlag(cursor); break;
        case 'q': uncoverField(cursor); break;

        case 'w': cursor.w(); break;
        case 'd': cursor.d(); break;
        case 's': cursor.s(); break;
        case 'a': cursor.a(); break;

        default: if(key) switch(key.name){
            case 'up':    cursor.w(); break;
            case 'right': cursor.d(); break;
            case 'down':  cursor.s(); break;
            case 'left':  cursor.a(); break;
            default: return;
        }
    }

    printAll();
});

const FieldType = {
    GROUND: 0,
    BLANK: 1,
    MINE: 2
};

const Border = {
    TOP: '▄', BOTTOM: '▀', CENTER: '█', LEFT: '▐', RIGHT: '▌',
    COLOR: chalk.yellow,
    SELECTION_COLOR: chalk.yellow.bold
};

var consoleWidth = () => process.stdout.columns;
var consoleHeight = () => process.stdout.rows;

var fieldWidth = Math.min(2048, consoleWidth() - 2);
var fieldHeight = Math.min(2048, consoleHeight() - 3);

var fields = Array.apply(null, Array(fieldWidth)).map((v, x) => Array.apply(null, Array(fieldHeight)).map((v, y) => ({
    x: x, y: y,
    type: FieldType.GROUND,
    flagged: false
})));

var flatFields = () => fields.reduce((a, b) => a.concat(b));

var cursor = {
    x: Math.floor(fieldWidth / 2),
    y: Math.floor(fieldHeight / 2),
    w: () => cursor.y = Math.max(0, cursor.y - 1),
    d: () => cursor.x = Math.min(fieldWidth - 1, cursor.x + 1),
    s: () => cursor.y = Math.min(fieldHeight - 1, cursor.y + 1),
    a: () => cursor.x = Math.max(0, cursor.x - 1)
};

const Status = {
    READY: 0,
    STARTED: 1,
    FAILED: 2,
    SUCCEEDED: 3
};

var game = {
    status: Status.READY,
    startedTime: null,
    finishedTime: null,

    flagCount: 0,
    mineCount: Math.floor((fieldWidth * fieldHeight) / 25),
    mineInstalled: false,
};

var vectorToField = (x, y) => {
    if(x && x.hasOwnProperty('x')){
        y = x.y; x = x.x;
    }

    return (fields[x] && fields[x][y]) || null;
};

var toggleFlag = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;
    if(field.type === FieldType.BLANK) return;

    if(field.flagged = !field.flagged) game.flagCount++; else game.flagCount--;
    if(game.flagCount === game.mineCount && flatFields().filter(field => field.flagged).every(field => field.type === FieldType.MINE)) return finish(true);

    printAll();
};

var mineCount = (x, y) => {
    var field = vectorToField(x, y); if(!field) return;

    var xx, yy, count = 0;
    for(var i = -1; i <= 1; i++) for(var j = -1; j <= 1; j++) if((i !== 0 || j !== 0) && (xx = field.x + i) >= 0 && (yy = field.y + j) >= 0 && xx < fieldWidth && yy < fieldHeight && fields[xx][yy].type === FieldType.MINE) count++;
    return count;
};

var uncoverField = (x, y) => {
    var field = vectorToField(x, y); if(!field || field.flagged) return;
    if(!game.mineInstalled){
        game.mineInstalled = true;

        var exception = {}; exception[field.x + ':' + field.y] = true;
        randomVectorArray(game.mineCount, exception).forEach((vector) => fields[vector[0]][vector[1]].type = FieldType.MINE);
    }

    switch(field.type){
        case FieldType.MINE:
            finish(false);
            break;

        case FieldType.GROUND:
            field.type = FieldType.BLANK;

            uncoverGround(field.x, field.y - 1); //w
            uncoverGround(field.x + 1, field.y); //d
            uncoverGround(field.x, field.y + 1); //s
            uncoverGround(field.x - 1, field.y); //a
            break;

        default: return;
    }
};

var uncoverGround = (x, y) => {
    var queue = [vectorToField(x, y)];
    var check = {};

    while(queue.length > 0){
        var field = queue.shift();
        if(!field || field.type !== FieldType.GROUND) continue;

        var key = field.x + ':' + field.y;
        if(check[key]) continue; check[key] = true;

        if(mineCount(field) !== 0) continue;
        field.type = FieldType.BLANK;

        queue.push(vectorToField(field.x, field.y - 1)); //w
        queue.push(vectorToField(field.x + 1, field.y)); //d
        queue.push(vectorToField(field.x, field.y + 1)); //s
        queue.push(vectorToField(field.x - 1, field.y)); //a
    }
};

var buffer = '';

var write = (text) => buffer += text;
var flush = () => {
    process.stdout.write(buffer);
    buffer = '';
};

var clear = () => write('\033c');
var newLine = () => write('\n');

var repeat = (theChalk, text, count) => {
    for(var i = 0; i < count; i++) theChalk ? write(theChalk(text)) : write(text);
};

var capitalize = (str) => str && str.charAt(0).toUpperCase() + str.slice(1);

var random = (min, max) => {
    if(max === undefined){
        max = min; min = 0;
    }

    return min + Math.floor(Math.random() * (max - min));
};

var randomVectorArray = (count, exception) => {
    var check = {};
    var vectors = [];

    while(vectors.length < count){
        var vector = [random(fieldWidth), random(fieldHeight)]; var key = vector.join(':');
        if(!check[key] && !exception[key]){
            check[key] = true;
            vectors.push(vector);
        }
    }
    return vectors;
};

const Title = {
    COLOR: chalk.yellow.bold
};

var printTitle = (text, align) => {
    var spaces = consoleWidth() - text.length;

    switch(align){
        case 'left':
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces);
            break;

        default:
        case 'center':
            var leftSpaces = Math.floor(spaces / 2);
            repeat(Title.COLOR, ' ', leftSpaces);
            write(Title.COLOR(text));
            repeat(Title.COLOR, ' ', spaces - leftSpaces);
            break;

        case 'right':
            repeat(Title.COLOR, ' ', spaces);
            write(Title.COLOR(text));
            break;
    }

    newLine();
};

var blankColor = (count) => {
    if(count >= 7) return 'red';
    if(count >= 5) return 'blue';
    if(count >= 3) return 'yellow';
    else return 'black';
};

var getFieldString = (x, y) => {
    var field = fields[x][y];
    var output = {
        background: 'white', foreground: 'black', text: ' ', special: null
    };

    if(field.flagged){
        output.text = 'X';
        output.background = 'cyan';
    }

    else switch(field.type){
        case FieldType.GROUND:
        case FieldType.MINE:
            output.text = '?';
            output.background = 'black';
            break;

        case FieldType.BLANK:
            var count = mineCount(x, y);
            output.foreground = blankColor(count);
            if(count > 0) output.text = Math.min(count, 9).toString(10);
            break;
    }

    if(cursor.x === x && cursor.y === y) output.background = 'green';

    var theChalk = chalk['bg' + capitalize(output.background)][output.foreground];
    if(output.special) theChalk = theChalk[output.special];

    return theChalk(output.text);
};

var getElapsedTime = (now) => moment.utc((now || moment()).diff(game.startedTime)).format("HH:mm:ss");

var printAll = (title) => {
    clear();
    var marginTop = Math.round((consoleHeight() - fieldHeight - 3) / 2);
    var marginLeft = Math.round((consoleWidth() - fieldWidth - 2) / 2);

    repeat(null, '\n', marginTop);

    switch(game.status){
        case Status.READY:
            printTitle("Press any key to start...");
            break;

        case Status.STARTED:
            var title = getElapsedTime() + ' | ' + game.flagCount + '/' + game.mineCount;
            var cursorText = ' | (' + cursor.x + ', ' + cursor.y + ')';
            printTitle((title.length + cursorText.length) < consoleWidth() ? title + cursorText : title);
            break;

        case Status.FAILED:
            printTitle(getElapsedTime(game.finishedTime) + " | Failed");
            break;

        case Status.SUCCEEDED:
            printTitle(getElapsedTime(game.finishedTime) + " | Succeeded");
            break;
    }

    repeat(null, ' ', marginLeft);
    repeat(Border.COLOR, Border.TOP, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.TOP));
    repeat(Border.COLOR, Border.TOP, fieldWidth - cursor.x);
    newLine();

    for(var y = 0; y < fieldHeight; y++){
        var border = (y === cursor.y ? Border.SELECTION_COLOR : Border.COLOR)(Border.CENTER);
        repeat(null, ' ', marginLeft); write(border); for(var x = 0; x < fieldWidth; x++) write(getFieldString(x, y)); write(border); newLine();
    }

    repeat(null, ' ', marginLeft); repeat(Border.COLOR, Border.BOTTOM, cursor.x + 1);
    write(Border.SELECTION_COLOR(Border.BOTTOM));
    repeat(Border.COLOR, Border.BOTTOM, fieldWidth - cursor.x);

    flush();
};

var printer = null;

var start = () => {
    if(game.status > Status.READY) return;

    game.status = Status.STARTED;
    game.startedTime = moment();

    printAll();
};

var finish = (succeeded) => {
    if(game.status > Status.STARTED) return;

    game.status = succeeded ? Status.SUCCEEDED : Status.FAILED;
    game.finishedTime = moment();

    printAll();
    setTimeout(() => process.exit(0), 3000);
};

game.status = Status.READY; printAll();
printer = setInterval(printAll, 200);
<|endoftext|>


<commit_before>var assert = require("assert");
var getDefaultOptions = require("./options.js").getDefaults;
var Cache = require("./cache.js");
var compileCache; // Lazily initialized.
var parseOptions = {
  sourceType: "module",
  strictMode: false,
  allowImportExportEverywhere: true,
  allowReturnOutsideFunction: true,
  plugins: [
    "asyncFunctions",
    "asyncGenerators",
    "classConstructorCall",
    "classProperties",
    "decorators",
    "doExpressions",
    "exponentiationOperator",
    "exportExtensions",
    "flow",
    "functionBind",
    "functionSent",
    "jsx",
    "objectRestSpread",
    "trailingFunctionCommas"
  ]
};

// Make sure that module.import and module.export are defined in the
// current Node process.
require("reify/node/runtime");

// Options passed to compile will completely replace the default options,
// so if you only want to modify the default options, call this function
// first, modify the result, and then pass those options to compile.
exports.getDefaultOptions = getDefaultOptions;

function parse(source) {
  return require("babylon").parse(source, parseOptions);
}
exports.parse = parse;

exports.compile = function compile(source, options, deps) {
  options = options || getDefaultOptions();
  if (! compileCache) {
    setCacheDir();
  }
  return compileCache.get(source, options, deps);
};

function setCacheDir(cacheDir) {
  if (compileCache && compileCache.dir === cacheDir) {
    return;
  }

  var reifyCompiler = require("reify/lib/compiler");

  compileCache = new Cache(function (source, options) {
    var reifyResult = reifyCompiler.compile(source, {
      // Use Babel's parser during Reify compilation.
      parse: parse,
      // Return the modified AST as reifyResult.ast.
      ast: true,
      // Generate let declarations for imported symbols.
      generateLetDeclarations: true
    });

    return require("babel-core").transformFromAst(
      reifyResult.ast,
      reifyResult.code,
      options
    );
  }, cacheDir);
}
exports.setCacheDir = setCacheDir;

exports.runtime = // Legacy name; prefer installRuntime.
exports.installRuntime = function installRuntime() {
  return require("./runtime.js");
};

exports.defineHelpers = function defineHelpers() {
  return require("meteor-babel-helpers");
};
<commit_msg>Decompose compile function in meteor-babel/index.js.<commit_after>var assert = require("assert");
var getDefaultOptions = require("./options.js").getDefaults;
var Cache = require("./cache.js");
var compileCache; // Lazily initialized.
var reifyCompiler = require("reify/lib/compiler");
var parseOptions = {
  sourceType: "module",
  strictMode: false,
  allowImportExportEverywhere: true,
  allowReturnOutsideFunction: true,
  plugins: [
    "asyncFunctions",
    "asyncGenerators",
    "classConstructorCall",
    "classProperties",
    "decorators",
    "doExpressions",
    "exponentiationOperator",
    "exportExtensions",
    "flow",
    "functionBind",
    "functionSent",
    "jsx",
    "objectRestSpread",
    "trailingFunctionCommas"
  ]
};

// Make sure that module.import and module.export are defined in the
// current Node process.
require("reify/node/runtime");

// Options passed to compile will completely replace the default options,
// so if you only want to modify the default options, call this function
// first, modify the result, and then pass those options to compile.
exports.getDefaultOptions = getDefaultOptions;

function parse(source) {
  return require("babylon").parse(source, parseOptions);
}
exports.parse = parse;

exports.compile = function compile(source, options, deps) {
  options = options || getDefaultOptions();
  if (! compileCache) {
    setCacheDir();
  }
  return compileCache.get(source, options, deps);
};

function compile(source, options) {
  var reifyResult = reifyCompiler.compile(source, {
    // Use Babel's parser during Reify compilation.
    parse: parse,
    // Return the modified AST as reifyResult.ast.
    ast: true,
    // Generate let declarations for imported symbols.
    generateLetDeclarations: true
  });

  return require("babel-core").transformFromAst(
    reifyResult.ast,
    reifyResult.code,
    options
  );
}

function setCacheDir(cacheDir) {
  if (! (compileCache && compileCache.dir === cacheDir)) {
    compileCache = new Cache(compile, cacheDir);
  }
}
exports.setCacheDir = setCacheDir;

exports.runtime = // Legacy name; prefer installRuntime.
exports.installRuntime = function installRuntime() {
  return require("./runtime.js");
};

exports.defineHelpers = function defineHelpers() {
  return require("meteor-babel-helpers");
};
<|endoftext|>


<commit_before>// Homebridge Plugin for Mode Lighting System using Remote Control Interface
// Need to enhance with more error checking
var request = require('request');

var Service, Characteristic;

module.exports = function(homebridge) {

  // Service and Characteristic are from hap-nodejs
  Service = homebridge.hap.Service;
  Characteristic = homebridge.hap.Characteristic;
  homebridge.registerAccessory("homebridge-modelighting", "modelighting",
    ModeLightingAccessory);
}

function ModeLightingAccessory(log, config) {
  this.log = log;

  // Get Room Name from config.json
  this.name = config["name"];

  // Get Mode Lighting On/Off Scene Numbers for Room Name and
  // NPU IP Address from config.json
  this.on_scene = config["on_scene"];
  this.off_scene = config["off_scene"];
  this.NPU_IP = config["NPU_IP"];
}

ModeLightingAccessory.prototype = {

    setPowerState: function(powerOn, callback) {

      var scene;

      var NPU_IP = this.NPU_IP;

      if (powerOn) {
        scene = this.on_scene;
        this.log("setPowerState: Invoking on scene");
      } else {
        scene = this.off_scene;
        this.log("setPowerState: Invoking off scene");
      }

      request.post(
        'http://' + NPU_IP + '/gateway?', {
          json: {
            contentType: 'text/plain',
            dataType: 'text',
            data: '$scnrecall,' + scene + ';'
          }
        },
        function(error, response, body) {
          if (!error && response.statusCode == 200) {
            console.log(body);
          }
        }
      );

      callback(null);

      return (0);
    },

    getPowerState: function(callback) {

        var scene = this.on_scene;

        var NPU_IP = this.NPU_IP;

        request.post(
          'http://' + NPU_IP + '/gateway?', {
            json: {
              contentType: 'text/plain',
              dataType: 'text',
              data: '?scn,' + scene + ';'
            }
          },
          function(error, response, body) {

            console.log('getPowerState: Error is: ' + error);
            console.log('getPowerState: Response is: ' + response);
            console.log('getPowerState: Body is: ' + body);

            if (!error && response.statusCode == 200) {
              console.log(body);
            }

            if (body != "") {
              // Get Light Status & Return through callback
              var pos = body.lastIndexOf(";");
              callback(null, body.substring(pos - 5, pos - 4));
            } else {
              console.log('Body from webserver was blank!);}
              }
            );

            return (0);
          },

          identify: function(callback) {
            this.log("identify: Identify requested!");
            callback(); // success
          },

          getServices: function() {

            // you can OPTIONALLY create an information service if you wish to override
            // the default values for things like serial number, model, etc.
            var informationService = new Service.AccessoryInformation();

            informationService
              .setCharacteristic(Characteristic.Manufacturer, "Mode Lighting")
              .setCharacteristic(Characteristic.Model, "NPU SW000120.2.3.6.3")
              .setCharacteristic(Characteristic.SerialNumber, "");

            var switchService = new Service.Switch(this.name);

            switchService
              .getCharacteristic(Characteristic.On)
              .on('set', this.setPowerState.bind(this))
              .on('get', this.getPowerState.bind(this));

            return [switchService];
          }
        };
<commit_msg>fixed typo<commit_after>// Homebridge Plugin for Mode Lighting System using Remote Control Interface
// Need to enhance with more error checking
var request = require('request');

var Service, Characteristic;

module.exports = function(homebridge) {

  // Service and Characteristic are from hap-nodejs
  Service = homebridge.hap.Service;
  Characteristic = homebridge.hap.Characteristic;
  homebridge.registerAccessory("homebridge-modelighting", "modelighting",
    ModeLightingAccessory);
}

function ModeLightingAccessory(log, config) {
  this.log = log;

  // Get Room Name from config.json
  this.name = config["name"];

  // Get Mode Lighting On/Off Scene Numbers for Room Name and
  // NPU IP Address from config.json
  this.on_scene = config["on_scene"];
  this.off_scene = config["off_scene"];
  this.NPU_IP = config["NPU_IP"];
}

ModeLightingAccessory.prototype = {

    setPowerState: function(powerOn, callback) {

      var scene;

      var NPU_IP = this.NPU_IP;

      if (powerOn) {
        scene = this.on_scene;
        this.log("setPowerState: Invoking on scene");
      } else {
        scene = this.off_scene;
        this.log("setPowerState: Invoking off scene");
      }

      request.post(
        'http://' + NPU_IP + '/gateway?', {
          json: {
            contentType: 'text/plain',
            dataType: 'text',
            data: '$scnrecall,' + scene + ';'
          }
        },
        function(error, response, body) {
          if (!error && response.statusCode == 200) {
            console.log(body);
          }
        }
      );

      callback(null);

      return (0);
    },

    getPowerState: function(callback) {

        var scene = this.on_scene;

        var NPU_IP = this.NPU_IP;

        request.post(
          'http://' + NPU_IP + '/gateway?', {
            json: {
              contentType: 'text/plain',
              dataType: 'text',
              data: '?scn,' + scene + ';'
            }
          },
          function(error, response, body) {

            console.log('getPowerState: Error is: ' + error);
            console.log('getPowerState: Response is: ' + response);
            console.log('getPowerState: Body is: ' + body);

            if (!error && response.statusCode == 200) {
              console.log(body);
            }

            if (body != "") {
              // Get Light Status & Return through callback
              var pos = body.lastIndexOf(";");
              callback(null, body.substring(pos - 5, pos - 4));
            } else {
              console.log('Body from webserver was blank!');
            }

            return (0);
          },

          identify: function(callback) {
            this.log("identify: Identify requested!");
            callback(); // success
          },

          getServices: function() {

            // you can OPTIONALLY create an information service if you wish to override
            // the default values for things like serial number, model, etc.
            var informationService = new Service.AccessoryInformation();

            informationService
              .setCharacteristic(Characteristic.Manufacturer, "Mode Lighting")
              .setCharacteristic(Characteristic.Model, "NPU SW000120.2.3.6.3")
              .setCharacteristic(Characteristic.SerialNumber, "");

            var switchService = new Service.Switch(this.name);

            switchService
              .getCharacteristic(Characteristic.On)
              .on('set', this.setPowerState.bind(this))
              .on('get', this.getPowerState.bind(this));

            return [switchService];
          }
        };
<|endoftext|>


<commit_before>'use strict';

var electron      = require('electron');
var app           = electron.app;
var browserWindow = electron.BrowserWindow;
var shell         = electron.shell;
var Menu          = electron.Menu;

// electron.crashReporter.start();

var mainWindow = null;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new browserWindow({width: 500, height: 600, webPreferences: {webSecurity: false}});
  mainWindow.loadURL('file://' + __dirname + '/view/login.html');

  mainWindow.on('closed', function() {
    mainWindow = null;
  });

  // mainWindow.webContents.on('new-window', function(event, url) {
  //   event.preventDefault();
  //   shell.openExternal(url);
  // });

  // Menu.setApplicationMenu(menu);
});

var template = [
  {
    label: 'Edit',
    submenu: [
      {
        label: 'Copy',
        accelerator: 'CmdOrCtrl+C',
        role: 'copy'
      },
      {
        label: 'Paste',
        accelerator: 'CmdOrCtrl+V',
        role: 'paste'
      },
      {
        label: 'Cut',
        accelerator: 'CmdOrCtrl+X',
        role: 'cut'
      },
      {
        label: 'Select All',
        accelerator: 'CmdOrCtrl+A',
        role: 'selectall'
      }
    ]
  }
];

// var menu = Menu.buildFromTemplate(template);<commit_msg>画像表示用メソッドのコメントを外した<commit_after>'use strict';

var electron      = require('electron');
var app           = electron.app;
var browserWindow = electron.BrowserWindow;
var shell         = electron.shell;
var Menu          = electron.Menu;

// electron.crashReporter.start();

var mainWindow = null;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new browserWindow({width: 500, height: 600, webPreferences: {webSecurity: false}});
  mainWindow.loadURL('file://' + __dirname + '/view/login.html');

  mainWindow.on('closed', function() {
    mainWindow = null;
  });

  mainWindow.webContents.on('new-window', function(event, url) {
    event.preventDefault();
    shell.openExternal(url);
  });

  // Menu.setApplicationMenu(menu);
});

var template = [
  {
    label: 'Edit',
    submenu: [
      {
        label: 'Copy',
        accelerator: 'CmdOrCtrl+C',
        role: 'copy'
      },
      {
        label: 'Paste',
        accelerator: 'CmdOrCtrl+V',
        role: 'paste'
      },
      {
        label: 'Cut',
        accelerator: 'CmdOrCtrl+X',
        role: 'cut'
      },
      {
        label: 'Select All',
        accelerator: 'CmdOrCtrl+A',
        role: 'selectall'
      }
    ]
  }
];

// var menu = Menu.buildFromTemplate(template);<|endoftext|>


<commit_before>var Emitter = require('events/')
var noop    = (function(){})
var bl      = require('bl')

module.exports = wreq

function wreq(bundler) {
  var prevError = false
  var pending = false
  var buffer

  update()
  bundler.on('update', update)

  return handler

  function handler(req, res, next) {
    next = next || noop

    if (pending) {
      return pending.once('ready', function(err) {
        if (err) return next(err)
        return handler(req, res, next)
      })
    }

    if (prevError) return next(prevError)

    res.setHeader('content-type', 'text/javascript')
    return res.end(buffer)
  }

  function update() {
    var p = pending = new Emitter

    bundler.bundle().pipe(bl(function(err, _buffer) {
      if (p !== pending) return
      buffer = _buffer
      pending.emit('ready', prevError = err, pending = false)
    }))
  }
}
<commit_msg>next: call on success && default res.emit on err<commit_after>var Emitter = require('events/')
var bl      = require('bl')

module.exports = wreq

function wreq(bundler) {
  var prevError = null
  var pending = null
  var buffer = null

  update()
  bundler.on('update', update)

  return handler

  function update() {
    var p = pending = new Emitter

    bundler.bundle().pipe(bl(function(err, _buffer) {
      if (p !== pending) return
      buffer = _buffer
      pending.emit('ready', prevError = err, pending = false)
    }))
  }

  function handler(req, res, next) {
    next = next || send

    if (pending) {
      return pending.once('ready', function(err) {
        if (err) return next(err)
        return handler(req, res, next)
      })
    }

    if (prevError) return next(prevError)

    res.setHeader('content-type', 'text/javascript')

    return next(null, buffer)

    function send(err, body) {
      if (err) return res.emit(err)
      res.end(body)
    }
  }
}
<|endoftext|>


<commit_before>"use strict";

var Transform = require('readable-stream').Transform,
	inherits = require('util').inherits,
	qry = require('qry');

function QueryStream (query) {
	if (!(this instanceof QueryStream)) {
		return new QueryStream(query);
	}

	Transform.call(this, { objectMode : true });
	this.match = qry(query);
}

inherits(QueryStream, Transform);

QueryStream.prototype._transform = function (chunk, enc, next) {
	if (typeof chunk === 'undefined' || chunk === null) { this.push({}); }

	if (this.match(chunk)) {
		this.push(chunk);
	}

	next();
};

module.exports = QueryStream;
<commit_msg>Added support for stream options<commit_after>"use strict";

var Transform = require('readable-stream').Transform,
	inherits = require('util').inherits,
	qry = require('qry');

function QueryStream (query, options) {
	if (!(this instanceof QueryStream)) {
		return new QueryStream(query, options);
	}

	if (!(options instanceof Object)) {
		options = {};
	}

	options.objectMode = true;

	Transform.call(this, options);
	this.match = qry(query);
}

inherits(QueryStream, Transform);

QueryStream.prototype._transform = function (chunk, enc, next) {
	if (typeof chunk === 'undefined' || chunk === null) { this.push({}); }

	if (this.match(chunk)) {
		this.push(chunk);
	}

	next();
};

module.exports = QueryStream;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {
  View,
  StyleSheet,
  PanResponder,
  Animated,
  TouchableWithoutFeedback,
  Dimensions,
  Easing,
  BackHandler,
  Platform,
  Modal,
  Keyboard
} from 'react-native';

const {height: SCREEN_HEIGHT, width: SCREEN_WIDTH} = Dimensions.get('window');
const styles = StyleSheet.create({
  wrapper: {
    backgroundColor: 'white'
  },
  transparent: {
    zIndex: 2,
    backgroundColor: 'rgba(0,0,0,0)'
  },
  absolute: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  }
});

export default class ModalBox extends React.PureComponent {
  static propTypes = {
    isOpen: PropTypes.bool,
    isDisabled: PropTypes.bool,
    startOpen: PropTypes.bool,
    backdropPressToClose: PropTypes.bool,
    swipeToClose: PropTypes.bool,
    swipeThreshold: PropTypes.number,
    swipeArea: PropTypes.number,
    position: PropTypes.string,
    entry: PropTypes.string,
    backdrop: PropTypes.bool,
    backdropOpacity: PropTypes.number,
    backdropColor: PropTypes.string,
    backdropContent: PropTypes.element,
    animationDuration: PropTypes.number,
    backButtonClose: PropTypes.bool,
    easing: PropTypes.func,
    coverScreen: PropTypes.bool,
    keyboardTopOffset: PropTypes.number,
    onClosed: PropTypes.func,
    onOpened: PropTypes.func,
    onClosingState: PropTypes.func
  };

  static defaultProps = {
    startOpen: false,
    backdropPressToClose: true,
    swipeToClose: true,
    swipeThreshold: 50,
    position: 'center',
    backdrop: true,
    backdropOpacity: 0.5,
    backdropColor: 'black',
    backdropContent: null,
    animationDuration: 400,
    backButtonClose: false,
    easing: Easing.elastic(0.8),
    coverScreen: false,
    keyboardTopOffset: Platform.OS == 'ios' ? 22 : 0,
    useNativeDriver: true
  };

  constructor(props) {
    super(props);

    this.onBackPress = this.onBackPress.bind(this);
    this.handleOpenning = this.handleOpenning.bind(this);
    this.onKeyboardHide = this.onKeyboardHide.bind(this);
    this.onKeyboardChange = this.onKeyboardChange.bind(this);
    this.animateBackdropOpen = this.animateBackdropOpen.bind(this);
    this.animateBackdropClose = this.animateBackdropClose.bind(this);
    this.stopAnimateOpen = this.stopAnimateOpen.bind(this);
    this.animateOpen = this.animateOpen.bind(this);
    this.stopAnimateClose = this.stopAnimateClose.bind(this);
    this.animateClose = this.animateClose.bind(this);
    this.calculateModalPosition = this.calculateModalPosition.bind(this);
    this.createPanResponder = this.createPanResponder.bind(this);
    this.onViewLayout = this.onViewLayout.bind(this);
    this.onContainerLayout = this.onContainerLayout.bind(this);
    this.renderBackdrop = this.renderBackdrop.bind(this);
    this.renderContent = this.renderContent.bind(this);
    this.open = this.open.bind(this);
    this.close = this.close.bind(this);

    const position = props.startOpen
      ? new Animated.Value(0)
      : new Animated.Value(
          props.entry === 'top' ? -SCREEN_HEIGHT : SCREEN_HEIGHT
        );
    this.state = {
      position,
      backdropOpacity: new Animated.Value(0),
      isOpen: props.startOpen,
      isAnimateClose: false,
      isAnimateOpen: false,
      swipeToClose: false,
      height: SCREEN_HEIGHT,
      width: SCREEN_WIDTH,
      containerHeight: SCREEN_HEIGHT,
      containerWidth: SCREEN_WIDTH,
      isInitialized: false,
      keyboardOffset: 0,
      pan: this.createPanResponder(position)
    };

    // Needed for iOS because the keyboard covers the screen
    if (Platform.OS === 'ios') {
      this.subscriptions = [
        Keyboard.addListener('keyboardWillChangeFrame', this.onKeyboardChange),
        Keyboard.addListener('keyboardDidHide', this.onKeyboardHide)
      ];
    }
  }

  componentDidMount() {
    this.handleOpenning();
  }

  componentDidUpdate(prevProps) {
    if (this.props.isOpen != prevProps.isOpen) {
      this.handleOpenning();
    }
  }

  componentWillUnmount() {
    if (this.subscriptions) this.subscriptions.forEach(sub => sub.remove());
    if (this.props.backButtonClose && Platform.OS === 'android')
      BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
  }

  onBackPress() {
    this.close();
    return true;
  }

  handleOpenning() {
    if (typeof this.props.isOpen == 'undefined') return;
    if (this.props.isOpen) this.open();
    else this.close();
  }

  /****************** ANIMATIONS **********************/

  /*
   * The keyboard is hidden (IOS only)
   */
  onKeyboardHide(evt) {
    this.setState({keyboardOffset: 0});
  }

  /*
   * The keyboard frame changed, used to detect when the keyboard open, faster than keyboardDidShow (IOS only)
   */
  onKeyboardChange(evt) {
    if (!evt) return;
    if (!this.state.isOpen) return;
    const keyboardFrame = evt.endCoordinates;
    const keyboardHeight = this.state.containerHeight - keyboardFrame.screenY;

    this.setState({keyboardOffset: keyboardHeight}, () => {
      this.animateOpen();
    });
  }

  /*
   * Open animation for the backdrop, will fade in
   */
  animateBackdropOpen() {
    if (this.state.isAnimateBackdrop && this.state.animBackdrop) {
      this.state.animBackdrop.stop();
    }
    this.setState({isAnimateBackdrop: true});

    let animBackdrop = Animated.timing(this.state.backdropOpacity, {
      toValue: 1,
      duration: this.props.animationDuration,
      easing: this.props.easing,
      useNativeDriver: this.props.useNativeDriver
    }).start(() => {
      this.setState({
        isAnimateBackdrop: false,
        animBackdrop
      });
    });
  }

  /*
   * Close animation for the backdrop, will fade out
   */
  animateBackdropClose() {
    if (this.state.isAnimateBackdrop && this.state.animBackdrop) {
      this.state.animBackdrop.stop();
    }
    this.setState({isAnimateBackdrop: true});

    let animBackdrop = Animated.timing(this.state.backdropOpacity, {
      toValue: 0,
      duration: this.props.animationDuration,
      easing: this.props.easing,
      useNativeDriver: this.props.useNativeDriver
    }).start(() => {
      this.setState({
        isAnimateBackdrop: false,
        animBackdrop
      });
    });
  }

  /*
   * Stop opening animation
   */
  stopAnimateOpen() {
    if (this.state.isAnimateOpen) {
      if (this.state.animOpen) this.state.animOpen.stop();
      this.setState({isAnimateOpen: false});
    }
  }

  /*
   * Open animation for the modal, will move up
   */
  animateOpen() {
    this.stopAnimateClose();

    // Backdrop fadeIn
    if (this.props.backdrop) this.animateBackdropOpen();

    this.setState(
      {
        isAnimateOpen: true,
        isOpen: true
      },
      () => {
        requestAnimationFrame(() => {
          // Detecting modal position
          let positionDest = this.calculateModalPosition(
            this.state.containerHeight - this.state.keyboardOffset,
            this.state.containerWidth
          );
          if (
            this.state.keyboardOffset &&
            positionDest < this.props.keyboardTopOffset
          ) {
            positionDest = this.props.keyboardTopOffset;
          }
          let animOpen = Animated.timing(this.state.position, {
            toValue: positionDest,
            duration: this.props.animationDuration,
            easing: this.props.easing,
            useNativeDriver: this.props.useNativeDriver
          }).start(() => {
            this.setState({
              isAnimateOpen: false,
              animOpen,
              positionDest
            });
            if (this.props.onOpened) this.props.onOpened();
          });
        });
      }
    );
  }

  /*
   * Stop closing animation
   */
  stopAnimateClose() {
    if (this.state.isAnimateClose) {
      if (this.state.animClose) this.state.animClose.stop();
      this.setState({isAnimateClose: false});
    }
  }

  /*
   * Close animation for the modal, will move down
   */
  animateClose() {
    this.stopAnimateOpen();

    // Backdrop fadeout
    if (this.props.backdrop) this.animateBackdropClose();

    this.setState(
      {
        isAnimateClose: true,
        isOpen: false
      },
      () => {
        let animClose = Animated.timing(this.state.position, {
          toValue:
            this.props.entry === 'top'
              ? -this.state.containerHeight
              : this.state.containerHeight,
          duration: this.props.animationDuration,
          easing: this.props.easing,
          useNativeDriver: this.props.useNativeDriver
        }).start(() => {
          // Keyboard.dismiss();   // make this optional. Easily user defined in .onClosed() callback
          this.setState({
            isAnimateClose: false,
            animClose
          }, () => {
            /* Set the state to the starting position of the modal, preventing from animating where the swipe stopped */
            this.state.position.setValue(this.props.entry === 'top' ? -this.state.containerHeight : this.state.containerHeight);
          });
          if (this.props.onClosed) this.props.onClosed();
        });
      }
    );
  }

  /*
   * Calculate when should be placed the modal
   */
  calculateModalPosition(containerHeight, containerWidth) {
    let position = 0;

    if (this.props.position == 'bottom') {
      position = containerHeight - this.state.height;
    } else if (this.props.position == 'center') {
      position = containerHeight / 2 - this.state.height / 2;
    }
    // Checking if the position >= 0
    if (position < 0) position = 0;
    return position;
  }

  /*
   * Create the pan responder to detect gesture
   * Only used if swipeToClose is enabled
   */
  createPanResponder(position) {
    let closingState = false;
    let inSwipeArea = false;

    const onPanStart = (evt, state) => {
      if (
        !this.props.swipeToClose ||
        this.props.isDisabled ||
        (this.props.swipeArea &&
          evt.nativeEvent.pageY - this.state.positionDest >
            this.props.swipeArea)
      ) {
        inSwipeArea = false;
        return false;
      }
      inSwipeArea = true;
      return true;
    };

    const animEvt = Animated.event([null, {customY: position}]);

    const onPanMove = (evt, state) => {
      const newClosingState =
        this.props.entry === 'top'
          ? -state.dy > this.props.swipeThreshold
          : state.dy > this.props.swipeThreshold;
      if (this.props.entry === 'top' ? state.dy > 0 : state.dy < 0) return;
      if (newClosingState != closingState && this.props.onClosingState)
        this.props.onClosingState(newClosingState);
      closingState = newClosingState;
      state.customY = state.dy + this.state.positionDest;

      animEvt(evt, state);
    };

    const onPanRelease = (evt, state) => {
      if (!inSwipeArea) return;
      inSwipeArea = false;
      if (
        this.props.entry === 'top'
          ? -state.dy > this.props.swipeThreshold
          : state.dy > this.props.swipeThreshold
      ) {
        this.close();
      } else if (!this.state.isOpen) {
        this.animateOpen();
      }
    };

    return PanResponder.create({
      onStartShouldSetPanResponder: onPanStart,
      onPanResponderMove: onPanMove,
      onPanResponderRelease: onPanRelease,
      onPanResponderTerminate: onPanRelease
    });
  }

  /*
   * Event called when the modal view layout is calculated
   */
  onViewLayout(evt) {
    const height = evt.nativeEvent.layout.height;
    const width = evt.nativeEvent.layout.width;

    // If the dimensions are still the same we're done
    let newState = {};
    if (height !== this.state.height) newState.height = height;
    if (width !== this.state.width) newState.width = width;
    this.setState(newState);

    if (this.onViewLayoutCalculated) this.onViewLayoutCalculated();
  }

  /*
   * Event called when the container view layout is calculated
   */
  onContainerLayout(evt) {
    const height = evt.nativeEvent.layout.height;
    const width = evt.nativeEvent.layout.width;

    // If the container size is still the same we're done
    if (
      height == this.state.containerHeight &&
      width == this.state.containerWidth
    ) {
      this.setState({isInitialized: true});
      return;
    }

    if (this.state.isOpen || this.state.isAnimateOpen) {
      this.animateOpen();
    }

    if (this.props.onLayout) this.props.onLayout(evt);
    this.setState({
      isInitialized: true,
      containerHeight: height,
      containerWidth: width
    });
  }

  /*
   * Render the backdrop element
   */
  renderBackdrop() {
    let backdrop = null;

    if (this.props.backdrop) {
      backdrop = (
        <TouchableWithoutFeedback
          onPress={this.props.backdropPressToClose ? this.close : null}>
          <Animated.View
            importantForAccessibility="no"
            style={[styles.absolute, {opacity: this.state.backdropOpacity}]}>
            <View
              style={[
                styles.absolute,
                {
                  backgroundColor: this.props.backdropColor,
                  opacity: this.props.backdropOpacity
                }
              ]}
            />
            {this.props.backdropContent || []}
          </Animated.View>
        </TouchableWithoutFeedback>
      );
    }

    return backdrop;
  }

  renderContent() {
    const size = {
      height: this.state.containerHeight,
      width: this.state.containerWidth
    };
    const offsetX = (this.state.containerWidth - this.state.width) / 2;

    return (
      <Animated.View
        onLayout={this.onViewLayout}
        style={[
          styles.wrapper,
          size,
          this.props.style,
          {
            transform: [
              {translateY: this.state.position},
              {translateX: offsetX}
            ]
          }
        ]}
        {...this.state.pan.panHandlers}>
        {this.props.backdropPressToClose && (
          <TouchableWithoutFeedback onPress={this.close}>
            <View style={[styles.absolute]} />
          </TouchableWithoutFeedback>
        )}
        {this.props.children}
      </Animated.View>
    );
  }

  /*
   * Render the component
   */
  render() {
    const visible =
      this.state.isOpen ||
      this.state.isAnimateOpen ||
      this.state.isAnimateClose;

    if (!visible) return <View />;

    const content = (
      <View
        importantForAccessibility="yes"
        accessibilityViewIsModal={true}
        style={[styles.transparent, styles.absolute]}
        pointerEvents={'box-none'}>
        <View
          style={{flex: 1}}
          pointerEvents={'box-none'}
          onLayout={this.onContainerLayout}>
          {visible && this.renderBackdrop()}
          {visible && this.renderContent()}
        </View>
      </View>
    );

    if (!this.props.coverScreen) return content;

    return (
      <Modal
        onRequestClose={() => {
          if (this.props.backButtonClose) {
            this.close();
          }
        }}
        supportedOrientations={[
          'landscape',
          'portrait',
          'portrait-upside-down'
        ]}
        transparent
        visible={visible}
        hardwareAccelerated={true}>
        {content}
      </Modal>
    );
  }

  /****************** PUBLIC METHODS **********************/

  open() {
    if (this.props.isDisabled) return;
    if (
      !this.state.isAnimateOpen &&
      (!this.state.isOpen || this.state.isAnimateClose)
    ) {
      this.onViewLayoutCalculated = () => {
        this.animateOpen();
        if (this.props.backButtonClose && Platform.OS === 'android')
          BackHandler.addEventListener('hardwareBackPress', this.onBackPress);
        this.onViewLayoutCalculated = null;
      };
      this.setState({isAnimateOpen: true});
    }
  }

  close() {
    if (this.props.isDisabled) return;
    if (
      !this.state.isAnimateClose &&
      (this.state.isOpen || this.state.isAnimateOpen)
    ) {
      this.animateClose();
      if (this.props.backButtonClose && Platform.OS === 'android')
        BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
    }
  }
}
<commit_msg>Fix backdrop issue<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {
  View,
  StyleSheet,
  PanResponder,
  Animated,
  TouchableWithoutFeedback,
  Dimensions,
  Easing,
  BackHandler,
  Platform,
  Modal,
  Keyboard
} from 'react-native';

const {height: SCREEN_HEIGHT, width: SCREEN_WIDTH} = Dimensions.get('window');
const styles = StyleSheet.create({
  wrapper: {
    backgroundColor: 'white'
  },
  transparent: {
    zIndex: 2,
    backgroundColor: 'rgba(0,0,0,0)'
  },
  absolute: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  }
});

export default class ModalBox extends React.PureComponent {
  static propTypes = {
    isOpen: PropTypes.bool,
    isDisabled: PropTypes.bool,
    startOpen: PropTypes.bool,
    backdropPressToClose: PropTypes.bool,
    swipeToClose: PropTypes.bool,
    swipeThreshold: PropTypes.number,
    swipeArea: PropTypes.number,
    position: PropTypes.string,
    entry: PropTypes.string,
    backdrop: PropTypes.bool,
    backdropOpacity: PropTypes.number,
    backdropColor: PropTypes.string,
    backdropContent: PropTypes.element,
    animationDuration: PropTypes.number,
    backButtonClose: PropTypes.bool,
    easing: PropTypes.func,
    coverScreen: PropTypes.bool,
    keyboardTopOffset: PropTypes.number,
    onClosed: PropTypes.func,
    onOpened: PropTypes.func,
    onClosingState: PropTypes.func
  };

  static defaultProps = {
    startOpen: false,
    backdropPressToClose: true,
    swipeToClose: true,
    swipeThreshold: 50,
    position: 'center',
    backdrop: true,
    backdropOpacity: 0.5,
    backdropColor: 'black',
    backdropContent: null,
    animationDuration: 400,
    backButtonClose: false,
    easing: Easing.elastic(0.8),
    coverScreen: false,
    keyboardTopOffset: Platform.OS == 'ios' ? 22 : 0,
    useNativeDriver: true
  };

  constructor(props) {
    super(props);

    this.onBackPress = this.onBackPress.bind(this);
    this.handleOpenning = this.handleOpenning.bind(this);
    this.onKeyboardHide = this.onKeyboardHide.bind(this);
    this.onKeyboardChange = this.onKeyboardChange.bind(this);
    this.animateBackdropOpen = this.animateBackdropOpen.bind(this);
    this.animateBackdropClose = this.animateBackdropClose.bind(this);
    this.stopAnimateOpen = this.stopAnimateOpen.bind(this);
    this.animateOpen = this.animateOpen.bind(this);
    this.stopAnimateClose = this.stopAnimateClose.bind(this);
    this.animateClose = this.animateClose.bind(this);
    this.calculateModalPosition = this.calculateModalPosition.bind(this);
    this.createPanResponder = this.createPanResponder.bind(this);
    this.onViewLayout = this.onViewLayout.bind(this);
    this.onContainerLayout = this.onContainerLayout.bind(this);
    this.renderBackdrop = this.renderBackdrop.bind(this);
    this.renderContent = this.renderContent.bind(this);
    this.open = this.open.bind(this);
    this.close = this.close.bind(this);

    const position = props.startOpen
      ? new Animated.Value(0)
      : new Animated.Value(
          props.entry === 'top' ? -SCREEN_HEIGHT : SCREEN_HEIGHT
        );
    this.state = {
      position,
      backdropOpacity: new Animated.Value(0),
      isOpen: props.startOpen,
      isAnimateClose: false,
      isAnimateOpen: false,
      swipeToClose: false,
      height: SCREEN_HEIGHT,
      width: SCREEN_WIDTH,
      containerHeight: SCREEN_HEIGHT,
      containerWidth: SCREEN_WIDTH,
      isInitialized: false,
      keyboardOffset: 0,
      pan: this.createPanResponder(position)
    };

    // Needed for iOS because the keyboard covers the screen
    if (Platform.OS === 'ios') {
      this.subscriptions = [
        Keyboard.addListener('keyboardWillChangeFrame', this.onKeyboardChange),
        Keyboard.addListener('keyboardDidHide', this.onKeyboardHide)
      ];
    }
  }

  componentDidMount() {
    this.handleOpenning();
  }

  componentDidUpdate(prevProps) {
    if (this.props.isOpen != prevProps.isOpen) {
      this.handleOpenning();
    }
  }

  componentWillUnmount() {
    if (this.subscriptions) this.subscriptions.forEach(sub => sub.remove());
    if (this.props.backButtonClose && Platform.OS === 'android')
      BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
  }

  onBackPress() {
    this.close();
    return true;
  }

  handleOpenning() {
    if (typeof this.props.isOpen == 'undefined') return;
    if (this.props.isOpen) this.open();
    else this.close();
  }

  /****************** ANIMATIONS **********************/

  /*
   * The keyboard is hidden (IOS only)
   */
  onKeyboardHide(evt) {
    this.setState({keyboardOffset: 0});
  }

  /*
   * The keyboard frame changed, used to detect when the keyboard open, faster than keyboardDidShow (IOS only)
   */
  onKeyboardChange(evt) {
    if (!evt) return;
    if (!this.state.isOpen) return;
    const keyboardFrame = evt.endCoordinates;
    const keyboardHeight = this.state.containerHeight - keyboardFrame.screenY;

    this.setState({keyboardOffset: keyboardHeight}, () => {
      this.animateOpen();
    });
  }

  /*
   * Open animation for the backdrop, will fade in
   */
  animateBackdropOpen() {
    if (this.state.isAnimateBackdrop && this.state.animBackdrop) {
      this.state.animBackdrop.stop();
    }
    this.setState({isAnimateBackdrop: true});

    let animBackdrop = Animated.timing(this.state.backdropOpacity, {
      toValue: 1,
      duration: this.props.animationDuration,
      easing: this.props.easing,
      useNativeDriver: this.props.useNativeDriver
    }).start(() => {
      this.setState({
        isAnimateBackdrop: false,
        animBackdrop
      });
    });
  }

  /*
   * Close animation for the backdrop, will fade out
   */
  animateBackdropClose() {
    if (this.state.isAnimateBackdrop && this.state.animBackdrop) {
      this.state.animBackdrop.stop();
    }
    this.setState({isAnimateBackdrop: true});

    let animBackdrop = Animated.timing(this.state.backdropOpacity, {
      toValue: 0,
      duration: this.props.animationDuration,
      easing: this.props.easing,
      useNativeDriver: this.props.useNativeDriver
    }).start(() => {
      this.setState({
        isAnimateBackdrop: false,
        animBackdrop
      });
    });
  }

  /*
   * Stop opening animation
   */
  stopAnimateOpen() {
    if (this.state.isAnimateOpen) {
      if (this.state.animOpen) this.state.animOpen.stop();
      this.setState({isAnimateOpen: false});
    }
  }

  /*
   * Open animation for the modal, will move up
   */
  animateOpen() {
    this.stopAnimateClose();

    // Backdrop fadeIn
    if (this.props.backdrop) this.animateBackdropOpen();

    this.setState(
      {
        isAnimateOpen: true,
        isOpen: true
      },
      () => {
        requestAnimationFrame(() => {
          // Detecting modal position
          let positionDest = this.calculateModalPosition(
            this.state.containerHeight - this.state.keyboardOffset,
            this.state.containerWidth
          );
          if (
            this.state.keyboardOffset &&
            positionDest < this.props.keyboardTopOffset
          ) {
            positionDest = this.props.keyboardTopOffset;
          }
          let animOpen = Animated.timing(this.state.position, {
            toValue: positionDest,
            duration: this.props.animationDuration,
            easing: this.props.easing,
            useNativeDriver: this.props.useNativeDriver
          }).start(() => {
            this.setState({
              isAnimateOpen: false,
              animOpen,
              positionDest
            });
            if (this.props.onOpened) this.props.onOpened();
          });
        });
      }
    );
  }

  /*
   * Stop closing animation
   */
  stopAnimateClose() {
    if (this.state.isAnimateClose) {
      if (this.state.animClose) this.state.animClose.stop();
      this.setState({isAnimateClose: false});
    }
  }

  /*
   * Close animation for the modal, will move down
   */
  animateClose() {
    this.stopAnimateOpen();

    // Backdrop fadeout
    if (this.props.backdrop) this.animateBackdropClose();

    this.setState(
      {
        isAnimateClose: true,
        isOpen: false
      },
      () => {
        let animClose = Animated.timing(this.state.position, {
          toValue:
            this.props.entry === 'top'
              ? -this.state.containerHeight
              : this.state.containerHeight,
          duration: this.props.animationDuration,
          easing: this.props.easing,
          useNativeDriver: this.props.useNativeDriver
        }).start(() => {
          // Keyboard.dismiss();   // make this optional. Easily user defined in .onClosed() callback
          this.setState({
            isAnimateClose: false,
            animClose
          }, () => {
            /* Set the state to the starting position of the modal, preventing from animating where the swipe stopped */
            this.state.position.setValue(this.props.entry === 'top' ? -this.state.containerHeight : this.state.containerHeight);
          });
          if (this.props.onClosed) this.props.onClosed();
        });
      }
    );
  }

  /*
   * Calculate when should be placed the modal
   */
  calculateModalPosition(containerHeight, containerWidth) {
    let position = 0;

    if (this.props.position == 'bottom') {
      position = containerHeight - this.state.height;
    } else if (this.props.position == 'center') {
      position = containerHeight / 2 - this.state.height / 2;
    }
    // Checking if the position >= 0
    if (position < 0) position = 0;
    return position;
  }

  /*
   * Create the pan responder to detect gesture
   * Only used if swipeToClose is enabled
   */
  createPanResponder(position) {
    let closingState = false;
    let inSwipeArea = false;

    const onPanStart = (evt, state) => {
      if (
        !this.props.swipeToClose ||
        this.props.isDisabled ||
        (this.props.swipeArea &&
          evt.nativeEvent.pageY - this.state.positionDest >
            this.props.swipeArea)
      ) {
        inSwipeArea = false;
        return false;
      }
      inSwipeArea = true;
      return true;
    };

    const animEvt = Animated.event([null, {customY: position}]);

    const onPanMove = (evt, state) => {
      const newClosingState =
        this.props.entry === 'top'
          ? -state.dy > this.props.swipeThreshold
          : state.dy > this.props.swipeThreshold;
      if (this.props.entry === 'top' ? state.dy > 0 : state.dy < 0) return;
      if (newClosingState != closingState && this.props.onClosingState)
        this.props.onClosingState(newClosingState);
      closingState = newClosingState;
      state.customY = state.dy + this.state.positionDest;

      animEvt(evt, state);
    };

    const onPanRelease = (evt, state) => {
      if (!inSwipeArea) return;
      inSwipeArea = false;
      if (
        this.props.entry === 'top'
          ? -state.dy > this.props.swipeThreshold
          : state.dy > this.props.swipeThreshold
      ) {
        this.close();
      } else if (!this.state.isOpen) {
        this.animateOpen();
      }
    };

    return PanResponder.create({
      onStartShouldSetPanResponder: onPanStart,
      onPanResponderMove: onPanMove,
      onPanResponderRelease: onPanRelease,
      onPanResponderTerminate: onPanRelease
    });
  }

  /*
   * Event called when the modal view layout is calculated
   */
  onViewLayout(evt) {
    const height = evt.nativeEvent.layout.height;
    const width = evt.nativeEvent.layout.width;

    // If the dimensions are still the same we're done
    let newState = {};
    if (height !== this.state.height) newState.height = height;
    if (width !== this.state.width) newState.width = width;
    this.setState(newState);

    if (this.onViewLayoutCalculated) this.onViewLayoutCalculated();
  }

  /*
   * Event called when the container view layout is calculated
   */
  onContainerLayout(evt) {
    const height = evt.nativeEvent.layout.height;
    const width = evt.nativeEvent.layout.width;

    // If the container size is still the same we're done
    if (
      height == this.state.containerHeight &&
      width == this.state.containerWidth
    ) {
      this.setState({isInitialized: true});
      return;
    }

    if (this.state.isOpen || this.state.isAnimateOpen) {
      this.animateOpen();
    }

    if (this.props.onLayout) this.props.onLayout(evt);
    this.setState({
      isInitialized: true,
      containerHeight: height,
      containerWidth: width
    });
  }

  /*
   * Render the backdrop element
   */
  renderBackdrop() {
    let backdrop = null;

    if (this.props.backdrop) {
      backdrop = (
        <TouchableWithoutFeedback
          onPress={this.props.backdropPressToClose ? this.close : null}>
          <Animated.View
            importantForAccessibility="no"
            style={[styles.absolute, {opacity: this.state.backdropOpacity}]}>
            <View
              style={[
                styles.absolute,
                {
                  backgroundColor: this.props.backdropColor,
                  opacity: this.props.backdropOpacity
                }
              ]}
            />
            {this.props.backdropContent || []}
          </Animated.View>
        </TouchableWithoutFeedback>
      );
    }

    return backdrop;
  }

  renderContent() {
    const size = {
      height: this.state.containerHeight,
      width: this.state.containerWidth
    };
    const offsetX = (this.state.containerWidth - this.state.width) / 2;

    return (
      <Animated.View
        onLayout={this.onViewLayout}
        style={[
          styles.wrapper,
          size,
          this.props.style,
          {
            transform: [
              {translateY: this.state.position},
              {translateX: offsetX}
            ]
          }
        ]}
        {...this.state.pan.panHandlers}>
        {this.props.children}
      </Animated.View>
    );
  }

  /*
   * Render the component
   */
  render() {
    const visible =
      this.state.isOpen ||
      this.state.isAnimateOpen ||
      this.state.isAnimateClose;

    if (!visible) return <View />;

    const content = (
      <View
        importantForAccessibility="yes"
        accessibilityViewIsModal={true}
        style={[styles.transparent, styles.absolute]}
        pointerEvents={'box-none'}>
        <View
          style={{flex: 1}}
          pointerEvents={'box-none'}
          onLayout={this.onContainerLayout}>
          {visible && this.renderBackdrop()}
          {visible && this.renderContent()}
        </View>
      </View>
    );

    if (!this.props.coverScreen) return content;

    return (
      <Modal
        onRequestClose={() => {
          if (this.props.backButtonClose) {
            this.close();
          }
        }}
        supportedOrientations={[
          'landscape',
          'portrait',
          'portrait-upside-down'
        ]}
        transparent
        visible={visible}
        hardwareAccelerated={true}>
        {content}
      </Modal>
    );
  }

  /****************** PUBLIC METHODS **********************/

  open() {
    if (this.props.isDisabled) return;
    if (
      !this.state.isAnimateOpen &&
      (!this.state.isOpen || this.state.isAnimateClose)
    ) {
      this.onViewLayoutCalculated = () => {
        this.animateOpen();
        if (this.props.backButtonClose && Platform.OS === 'android')
          BackHandler.addEventListener('hardwareBackPress', this.onBackPress);
        this.onViewLayoutCalculated = null;
      };
      this.setState({isAnimateOpen: true});
    }
  }

  close() {
    if (this.props.isDisabled) return;
    if (
      !this.state.isAnimateClose &&
      (this.state.isOpen || this.state.isAnimateOpen)
    ) {
      this.animateClose();
      if (this.props.backButtonClose && Platform.OS === 'android')
        BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
    }
  }
}
<|endoftext|>