<commit_before>'use strict';

var EventEmitter = require('eventemitter3')
  , Tick = require('tick-tock');

/**
 * Generate a somewhat unique UUID.
 *
 * @see stackoverflow.com/q/105034
 * @returns {String} UUID.
 * @api private
 */
function UUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function gen(c) {
    var random = Math.random() * 16 | 0
      , value = c !== 'x'
        ? (random & 0x3 | 0x8)
        : random;

    return value.toString(16);
  });
}

/**
 * Representation of a single node in the cluster.
 *
 * Options:
 *
 * - `id`: An unique id of this given node.
 * - `heartbeat min`: Minimum heartbeat timeout.
 * - `heartbeat max`: Maximum heartbeat timeout.
 * - `election min`: Minimum election timeout.
 * - `election max`: Maximum election timeout.
 * - `threshold`: Threshold when the heartbeat RTT is close to the election
 *   timeout.
 *
 * @constructor
 * @param {Object} options Node configuration.
 * @api public
 */
function Node(options) {
  if (!(this instanceof Node)) return new Node(options);

  options = options || {};

  this.election = {
    min: Tick.parse(options['election min'] || '150 ms'),
    max: Tick.parse(options['election max'] || '300 ms')
  };

  this.beat = {
    min: Tick.parse(options['heartbeat min'] || '50 ms'),
    max: Tick.parse(options['heartbeat max'] || '70 ms')
  };

  this.votes = {
    for: null,                // Who did we vote for in this current term.
    granted: 0                // How many votes we're granted to us.
  };

  this.threshold = options.threshold || 0.8;
  this.name = options.name || UUID();
  this.timers = new Tick(this);

  //
  // 5.2: When a server starts, it's always started as Follower and it will
  // remain in this state until receive a message from a Leader or Candidate.
  //
  this.state = Node.FOLLOWER; // Our current state.
  this.leader = null;         // Leader in our cluster.
  this.term = 0;              // Our current term.

  this.initialize();
}

//
// Add some sugar and spice and everything nice. Oh, and also inheritance.
//
Node.extend = require('extendable');
Node.prototype = new EventEmitter();
Node.prototype.emits = require('emits');
Node.prototype.constructor = Node;

/**
 * The different states that a node can have.
 *
 * @type {Number}
 * @private
 */
Node.LEADER    = 1;   // We're selected as leader process.
Node.CANDIDATE = 2;   // We want to be promoted to leader.
Node.FOLLOWER  = 3;   // We're just following a leader.
Node.STOPPED   = 4;   // Assume we're dead.

/**
 * Initialize the node.
 *
 * @api private
 */
Node.prototype.initialize = function initialize() {
  this.on('term change', function change() {
    //
    // Reset our vote as we're starting a new term. Votes only last one term.
    //
    this.votes.for = null;
    this.votes.granted = 0;
  });

  this.on('data', function incoming(data) {
    if ('object' !== typeof data) return; /* Invalid data structure, G.T.F.O. */

    //
    // We're waiting for votes to come in as we're promoted to a candidate but
    // a new node with a leadership role just send us a message. If his term is
    // greater then ours we will step down as candidate and acknowledge their
    // leadership.
    //
    if (
         Node.CANDIDATE === this.state
      && Node.LEADER === this.state
    ) {
      if (data.term >= this.term) {
        this.change({
          state: Node.FOLLOWER,
          term: data.term
        });
      }
      else return; /* We need to ignore the RPC as it's in an incorrect state */
    }

    switch (data.type) {
      case 'heartbeat':
        if (Node.LEADER === data.state) {
          this.heartbeat(data.data);
        }
      break;

      //
      // A node asked us to vote on them. We can only vote to them if they
      // represent a higher term (and last log term, last log index).
      //
      case 'vote':
        //
        // If the request is coming from an old term we should deny it.
        //
        if (data.term < this.term) {
          return this.write('vote', { accepted: false });
        }

        //
        // The term of the vote is bigger then ours so we need to update it. If
        // it's the same and we already voted, we need to deny the vote.
        //
        if (data.term > this.term) this.change({ term: data.term });
        else if (this.votes.for && this.votes.for !== data.name) {
          return this.write('vote', { accepted: false });
        }

        //
        // If we maintain a log, check if the candidates log is as up to date as
        // ours.
        //

        //
        // We've made our decision, we haven't voted for this term yet and this
        // candidate came in first so it gets our vote as all requirements are
        // met.
        //
        this.votes.for = data.name;
        this.write('vote', { accepted: true });
      break;

      //
      // A new incoming vote.
      //
      case 'voted':
        //
        // Only accepts votes while we're still in a CANDIDATE state.
        //
        if (Node.CANDIDATE !== this.state) return;

        //
        // Increment our received votes when our voting request has been
        // accepted by the node that received the data.
        //
        if (data.payload.accepted && data.term === this.term) {
          this.votes.granted++;
        }

        //
        // Again, update our term if it's out sync.
        //
        if (data.term > this.term) this.change({ term: data.term });

        //
        // Check if we've received the minimal amount of votes required for this
        // current voting round to be considered valid
        //
        if (this.votes.granted >= this.quorum()) {
          this.change({
            leader: this.name,
            state: Node.LEADER
          });
        }
      break;

      case 'rpc':
      break;
    }
  });
};

/**
 * The minimum amount of votes we need to receive in order for a voting round to
 * be considered valid.
 *
 * @returns {Number}
 * @api private
 */
Node.prototype.quorum = function quorum() {
  return Math.ceil(this.nodes.length / 2) + 1;
};

/**
 * Process a change in the node.
 *
 * @param {Object} changed Data that is changed.
 * @returns {Node}
 * @api private
 */
Node.prototype.change = function change(changed) {
  var changes = ['term', 'leader', 'state']
    , i = 0;

  if (!changed) return this;

  for (; i < changes.length; i++) {
    if (changes[i] in changed && changed[changes[i]] !== this[changes[i]]) {
      this[changes[i]] = changed[changes[i]];
      this.emit(changes[i] +' change');
    }
  }

  return this;
};

/**
 * Start or update the heartbeat of the Node. If we detect that we've received
 * a heartbeat timeout we will promote our selfs to a candidate to take over the
 * leadership.
 *
 * @param {String|Number} duration Time it would take for the heartbeat to timeout.
 * @returns {Node}
 * @api public
 */
Node.prototype.heartbeat = function heartbeat(duration) {
  duration = duration || this.timeout('heartbeat');

  if (this.timers.active('heartbeat')) {
    this.timers.adjust('heartbeat', duration);
    return this;
  }

  this.timers.setTimeout('heartbeat', function () {
    if (Node.LEADER !== this.state) {
      this.emit('heartbeat timeout');
      return this.promote();
    }

    //
    // We're the LEADER so we should be broadcasting.
    //
    this.broadcast('heartbeat');
  }, duration);

  return this;
};

/**
 * Generate the various of timeouts.
 *
 * @param {String} which Type of timeout we want to generate.
 * @returns {Number}
 * @api public
 */
Node.prototype.timeout = function timeout(which) {
  var times = this[which];

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

/**
 * Node detected a failure in the cluster and wishes to be promoted to new
 * master and promotes it self to candidate.
 *
 * @returns {Node}
 * @api public
 */
Node.prototype.promote = function promote() {
  if (Node.CANDIDATE === this.state) return this;

  this.change({
    state: Node.CANDIDATE,  // We're now a candidate,
    term: this.term + 1,    // but only for this term.
    leader: ''              // We no longer have a leader.
  });

  //
  // Candidates are always biased and vote for them selfs first before sending
  // out a voting request to all other nodes in the cluster.
  //
  this.votes.for = this.name;
  this.votes.granted = 1;
  this.broadcast('vote');

  return this;
};

/**
 * While we don't really adapt the Stream interface here from node, we still
 * want to follow it's API signature. So we assume that the `write` method will
 * return a boolean indicating if the packet has been written.
 *
 * @param {Object} packet The data that needs to be written.
 * @returns {Boolean} Indication that the message was written.
 * @api public
 */
Node.prototype.write = function write(packet) {
  return false;
};

/**
 * Read and process an incoming data packet.
 *
 * @returns {Boolean} Did we read the message.
 * @api public
 */
Node.prototype.read = function read(packet) {
  return this.emit('data', packet);
};

/**
 * Broadcast a message.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Boolean} Successful write.
 * @api public
 */
Node.prototype.broadcast = function broadcast(type, data) {
  var packet = this.packet(type, data);
};

/**
 * Wrap the outgoing messages in an object with additional required data.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Object} Packet.
 * @api private
 */
Node.prototype.packet = function packet(type, data) {
  return {
    state: this.state,  // So you know if we're a leader, candidate or follower
    term:  this.term,   // Our current term so we can find mis matches
    name:  this.name,   // Name of the sender.
    data:  data,        // Custom data we send.
    type:  type         // Message type.
  };
};

/**
 * This Node needs to be shut down.
 *
 * @returns {Boolean} Successful destruction.
 * @api public
 */
Node.prototype.end = function end() {
  if (!this.state) return false;

  this.timers.end();
  this.removeAllListeners();

  this.timers = this.state = this.write = this.read = null;

  return true;
};

//
// Expose the module interface.
//
module.exports = Node;
<commit_msg>[minor] Adding more events<commit_after>'use strict';

var EventEmitter = require('eventemitter3')
  , Tick = require('tick-tock');

/**
 * Generate a somewhat unique UUID.
 *
 * @see stackoverflow.com/q/105034
 * @returns {String} UUID.
 * @api private
 */
function UUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function gen(c) {
    var random = Math.random() * 16 | 0
      , value = c !== 'x'
        ? (random & 0x3 | 0x8)
        : random;

    return value.toString(16);
  });
}

/**
 * Representation of a single node in the cluster.
 *
 * Options:
 *
 * - `id`: An unique id of this given node.
 * - `heartbeat min`: Minimum heartbeat timeout.
 * - `heartbeat max`: Maximum heartbeat timeout.
 * - `election min`: Minimum election timeout.
 * - `election max`: Maximum election timeout.
 * - `threshold`: Threshold when the heartbeat RTT is close to the election
 *   timeout.
 *
 * @constructor
 * @param {Object} options Node configuration.
 * @api public
 */
function Node(options) {
  if (!(this instanceof Node)) return new Node(options);

  options = options || {};

  this.election = {
    min: Tick.parse(options['election min'] || '150 ms'),
    max: Tick.parse(options['election max'] || '300 ms')
  };

  this.beat = {
    min: Tick.parse(options['heartbeat min'] || '50 ms'),
    max: Tick.parse(options['heartbeat max'] || '70 ms')
  };

  this.votes = {
    for: null,                // Who did we vote for in this current term.
    granted: 0                // How many votes we're granted to us.
  };

  this.threshold = options.threshold || 0.8;
  this.name = options.name || UUID();
  this.timers = new Tick(this);

  //
  // 5.2: When a server starts, it's always started as Follower and it will
  // remain in this state until receive a message from a Leader or Candidate.
  //
  this.state = Node.FOLLOWER; // Our current state.
  this.leader = null;         // Leader in our cluster.
  this.term = 0;              // Our current term.

  this.initialize();
}

//
// Add some sugar and spice and everything nice. Oh, and also inheritance.
//
Node.extend = require('extendable');
Node.prototype = new EventEmitter();
Node.prototype.emits = require('emits');
Node.prototype.constructor = Node;

/**
 * The different states that a node can have.
 *
 * @type {Number}
 * @private
 */
Node.LEADER    = 1;   // We're selected as leader process.
Node.CANDIDATE = 2;   // We want to be promoted to leader.
Node.FOLLOWER  = 3;   // We're just following a leader.
Node.STOPPED   = 4;   // Assume we're dead.

/**
 * Initialize the node.
 *
 * @api private
 */
Node.prototype.initialize = function initialize() {
  this.on('term change', function change() {
    //
    // Reset our vote as we're starting a new term. Votes only last one term.
    //
    this.votes.for = null;
    this.votes.granted = 0;
  });

  this.on('data', function incoming(data) {
    if ('object' !== typeof data) return; /* Invalid data structure, G.T.F.O. */

    //
    // We're waiting for votes to come in as we're promoted to a candidate but
    // a new node with a leadership role just send us a message. If his term is
    // greater then ours we will step down as candidate and acknowledge their
    // leadership.
    //
    if (
         Node.CANDIDATE === this.state
      && Node.LEADER === this.state
    ) {
      if (data.term >= this.term) {
        this.change({
          state: Node.FOLLOWER,
          term: data.term
        });
      }
      else return; /* We need to ignore the RPC as it's in an incorrect state */
    }

    switch (data.type) {
      case 'heartbeat':
        if (Node.LEADER === data.state) {
          this.heartbeat(data.data);
        }
      break;

      //
      // A node asked us to vote on them. We can only vote to them if they
      // represent a higher term (and last log term, last log index).
      //
      case 'vote':
        //
        // If the request is coming from an old term we should deny it.
        //
        if (data.term < this.term) {
          this.emit('vote', data, false);
          return this.write('vote', { accepted: false });
        }

        //
        // The term of the vote is bigger then ours so we need to update it. If
        // it's the same and we already voted, we need to deny the vote.
        //
        if (data.term > this.term) this.change({ term: data.term });
        else if (this.votes.for && this.votes.for !== data.name) {
          this.emit('vote', data, false);
          return this.write('vote', { accepted: false });
        }

        //
        // If we maintain a log, check if the candidates log is as up to date as
        // ours.
        //

        //
        // We've made our decision, we haven't voted for this term yet and this
        // candidate came in first so it gets our vote as all requirements are
        // met.
        //
        this.votes.for = data.name;
        this.emit('vote', data, true);
        this.write('vote', { accepted: true });
      break;

      //
      // A new incoming vote.
      //
      case 'voted':
        //
        // Only accepts votes while we're still in a CANDIDATE state.
        //
        if (Node.CANDIDATE !== this.state) return;

        //
        // Increment our received votes when our voting request has been
        // accepted by the node that received the data.
        //
        if (data.payload.accepted && data.term === this.term) {
          this.votes.granted++;
        }

        //
        // Again, update our term if it's out sync.
        //
        if (data.term > this.term) this.change({ term: data.term });

        //
        // Check if we've received the minimal amount of votes required for this
        // current voting round to be considered valid
        //
        if (this.votes.granted >= this.quorum()) {
          this.change({
            leader: this.name,
            state: Node.LEADER
          });
        }
      break;

      case 'rpc':
      break;
    }
  });
};

/**
 * The minimum amount of votes we need to receive in order for a voting round to
 * be considered valid.
 *
 * @returns {Number}
 * @api private
 */
Node.prototype.quorum = function quorum() {
  return Math.ceil(this.nodes.length / 2) + 1;
};

/**
 * Process a change in the node.
 *
 * @param {Object} changed Data that is changed.
 * @returns {Node}
 * @api private
 */
Node.prototype.change = function change(changed) {
  var changes = ['term', 'leader', 'state']
    , currently, previously
    , i = 0;

  if (!changed) return this;

  for (; i < changes.length; i++) {
    if (changes[i] in changed && changed[changes[i]] !== this[changes[i]]) {
      currently = changed[changes[i]];
      previously = this[changes[i]];

      this[changes[i]] = currently;
      this.emit(changes[i] +' change', currently, previously);
    }
  }

  return this;
};

/**
 * Start or update the heartbeat of the Node. If we detect that we've received
 * a heartbeat timeout we will promote our selfs to a candidate to take over the
 * leadership.
 *
 * @param {String|Number} duration Time it would take for the heartbeat to timeout.
 * @returns {Node}
 * @api public
 */
Node.prototype.heartbeat = function heartbeat(duration) {
  duration = duration || this.timeout('heartbeat');

  if (this.timers.active('heartbeat')) {
    this.timers.adjust('heartbeat', duration);
    return this;
  }

  this.timers.setTimeout('heartbeat', function () {
    if (Node.LEADER !== this.state) {
      this.emit('heartbeat timeout');
      return this.promote();
    }

    //
    // We're the LEADER so we should be broadcasting.
    //
    this.broadcast('heartbeat');
  }, duration);

  return this;
};

/**
 * Generate the various of timeouts.
 *
 * @param {String} which Type of timeout we want to generate.
 * @returns {Number}
 * @api public
 */
Node.prototype.timeout = function timeout(which) {
  var times = this[which];

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

/**
 * Node detected a failure in the cluster and wishes to be promoted to new
 * master and promotes it self to candidate.
 *
 * @returns {Node}
 * @api public
 */
Node.prototype.promote = function promote() {
  if (Node.CANDIDATE === this.state) return this;

  this.change({
    state: Node.CANDIDATE,  // We're now a candidate,
    term: this.term + 1,    // but only for this term.
    leader: ''              // We no longer have a leader.
  });

  //
  // Candidates are always biased and vote for them selfs first before sending
  // out a voting request to all other nodes in the cluster.
  //
  this.votes.for = this.name;
  this.votes.granted = 1;
  this.broadcast('vote');

  return this;
};

/**
 * While we don't really adapt the Stream interface here from node, we still
 * want to follow it's API signature. So we assume that the `write` method will
 * return a boolean indicating if the packet has been written.
 *
 * @param {Object} packet The data that needs to be written.
 * @returns {Boolean} Indication that the message was written.
 * @api public
 */
Node.prototype.write = function write(packet) {
  return false;
};

/**
 * Read and process an incoming data packet.
 *
 * @returns {Boolean} Did we read the message.
 * @api public
 */
Node.prototype.read = function read(packet) {
  return this.emit('data', packet);
};

/**
 * Broadcast a message.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Boolean} Successful write.
 * @api public
 */
Node.prototype.broadcast = function broadcast(type, data) {
  var packet = this.packet(type, data);
};

/**
 * Wrap the outgoing messages in an object with additional required data.
 *
 * @param {String} type Message type we're trying to send.
 * @param {Mixed} data Data to be transfered.
 * @returns {Object} Packet.
 * @api private
 */
Node.prototype.packet = function packet(type, data) {
  return {
    state: this.state,  // So you know if we're a leader, candidate or follower
    term:  this.term,   // Our current term so we can find mis matches
    name:  this.name,   // Name of the sender.
    data:  data,        // Custom data we send.
    type:  type         // Message type.
  };
};

/**
 * This Node needs to be shut down.
 *
 * @returns {Boolean} Successful destruction.
 * @api public
 */
Node.prototype.end = function end() {
  if (!this.state) return false;

  this.timers.end();
  this.removeAllListeners();

  this.timers = this.state = this.write = this.read = null;

  return true;
};

//
// Expose the module interface.
//
module.exports = Node;
<|endoftext|>


<commit_before>'use strict';

function *circularIterator(arr) {
  let index = 0;
  const elements = Array.isArray(arr) ? arr.slice() : [];
  const length = elements.length;

  while (elements.length) {
    yield elements[ index++ % length ];
  }
}

module.exports = circularIterator;
<commit_msg>use the const length<commit_after>'use strict';

function *circularIterator(arr) {
  let index = 0;
  const elements = Array.isArray(arr) ? arr.slice() : [];
  const length = elements.length;

  while (length) {
    yield elements[ index++ % length ];
  }
}

module.exports = circularIterator;
<|endoftext|>


<commit_before>'use strict'

const back = require('./lib/back')
const emitter = require('./lib/global_emitter')
const {
  activate,
  isActive,
  isDone,
  pendingMocks,
  activeMocks,
  removeInterceptor,
  disableNetConnect,
  enableNetConnect,
  removeAll,
  abortPendingRequests,
} = require('./lib/intercept')
const recorder = require('./lib/recorder')
const { Scope, load, loadDefs, define } = require('./lib/scope')

module.exports = (basePath, options) => new Scope(basePath, options)

Object.assign(module.exports, {
  activate,
  isActive,
  isDone,
  pendingMocks,
  activeMocks,
  removeInterceptor,
  disableNetConnect,
  enableNetConnect,
  // TODO-12.x Historically `nock.cleanAll()` has returned the nock global.
  // The other global methods do noto do this, so it's not clear this was
  // deliberate or is even helpful. This shim is included for backward
  // compatibility and shoulud be replaced with an alias to `removeAll()`.
  cleanAll() {
    removeAll()
    return module.exports
  },
  abortPendingRequests,
  load,
  loadDefs,
  define,
  emitter,
  recorder: {
    rec: recorder.record,
    clear: recorder.clear,
    play: recorder.outputs,
  },
  restore: recorder.restore,
  back,
})
<commit_msg>minor typo in index.js comment (#1842)<commit_after>'use strict'

const back = require('./lib/back')
const emitter = require('./lib/global_emitter')
const {
  activate,
  isActive,
  isDone,
  pendingMocks,
  activeMocks,
  removeInterceptor,
  disableNetConnect,
  enableNetConnect,
  removeAll,
  abortPendingRequests,
} = require('./lib/intercept')
const recorder = require('./lib/recorder')
const { Scope, load, loadDefs, define } = require('./lib/scope')

module.exports = (basePath, options) => new Scope(basePath, options)

Object.assign(module.exports, {
  activate,
  isActive,
  isDone,
  pendingMocks,
  activeMocks,
  removeInterceptor,
  disableNetConnect,
  enableNetConnect,
  // TODO-12.x Historically `nock.cleanAll()` has returned the nock global.
  // The other global methods do not do this, so it's not clear this was
  // deliberate or is even helpful. This shim is included for backward
  // compatibility and shoulud be replaced with an alias to `removeAll()`.
  cleanAll() {
    removeAll()
    return module.exports
  },
  abortPendingRequests,
  load,
  loadDefs,
  define,
  emitter,
  recorder: {
    rec: recorder.record,
    clear: recorder.clear,
    play: recorder.outputs,
  },
  restore: recorder.restore,
  back,
})
<|endoftext|>


<commit_before>'use strict'

module.exports = (pluginContext) => {
	const shell = pluginContext.shell;
	const clipboard = pluginContext.clipboard;
	//to access filesystem
	const fs = require('fs');

	//check if the file or folder exists
	//return 1:File 2:Folder -1,0:Invalid path
	function checkFileOrFolder(path) {
		try {
			var stat = fs.statSync(path);
			if(stat.isFile() == true){
				return 1;//file
			}else if(stat.isDirectory() == true){
				return 2;//folder
			}else{//unreachable
				return 0;//invalid
			}
		} catch(err) {
			if(err.code === 'ENOENT'){
				return -1;//invalid
			}
		}
	}

	//remove all specified characters from string
	//return string (removed characters).
	//arguments are not modified.
	function removeCharacters(targetString,removingCharacterArray){
		var copyOfTargetString = targetString;
		for(var index = 0 ; index < removingCharacterArray.length ; index++){
			var removingCharacter = removingCharacterArray[index];
			switch(removingCharacter){
				case "*":
				case "?":
				case "|":
					//add '\' to characters which need '\'
					removingCharacter = "\\" + removingCharacter;
				default:
					//do nothing.
					break;
			}
			copyOfTargetString =
				copyOfTargetString.replace(
					new RegExp(removingCharacter,"g")
					,""
				);
		}
		return copyOfTargetString;
	}

	function search (query, res) {
		//format query.
		//remove spaces attached on head and bottom.
		var trimmedQuery = query.trim();

		//remove unavailable characters ( * / ? " < > | ).
		var queryRemovedUnavailableCharacters =
			removeCharacters(trimmedQuery,['*','/','?',"\"","<",">","|","\t"]);

		//split by '\'.
		var splittedQuery = queryRemovedUnavailableCharacters.split('\\');

		//search available file/folder name. (considering needless space)

		//Check state of formatted path (File or Folder or not).
		//and set Description Message according to the state.
		var descriptionMessage = "";
		switch(checkFileOrFolder(queryRemovedUnavailableCharacters)){
			case -1://invalid
			case 0://invalid
				descriptionMessage = "Not File/Folder. Cannot open."
				break;
			case 1://file
				descriptionMessage = "Open this File."
				break;
			case 2://folder
				descriptionMessage = "Open this Folder."
				break;
		}

		//add to res.
		res.add(
			{
				id: queryRemovedUnavailableCharacters,
				payload: 'open',
				title: queryRemovedUnavailableCharacters,
				desc: descriptionMessage
			}
		);
	}

	function execute (id, payload) {
		//open file or folder.
		if (payload !== 'open') {
			return
		}
		shell.openItem(`${id}`);
	}

	return { search, execute };
}
<commit_msg>Add function to search file or path<commit_after>'use strict'

module.exports = (pluginContext) => {
	const shell = pluginContext.shell;
	const clipboard = pluginContext.clipboard;
	//to access filesystem
	const fs = require('fs');

	//check if the file or folder exists
	//return 1:File 2:Folder -1,0:Invalid path
	function checkFileOrFolder(path) {
		try {
			var stat = fs.statSync(path);
			if(stat.isFile() == true){
				return 1;//file
			}else if(stat.isDirectory() == true){
				return 2;//folder
			}else{//unreachable
				return 0;//invalid
			}
		} catch(err) {
			if(err.code === 'ENOENT'){
				return -1;//invalid
			}
		}
	}

	//remove all specified characters from string
	//return string (removed characters).
	//arguments are not modified.
	function removeCharacters(targetString,removingCharacterArray){
		var copyOfTargetString = targetString;
		for(var index = 0 ; index < removingCharacterArray.length ; index++){
			var removingCharacter = removingCharacterArray[index];
			switch(removingCharacter){
				case "*":
				case "?":
				case "|":
					//add '\' to characters which need '\'
					removingCharacter = "\\" + removingCharacter;
				default:
					//do nothing.
					break;
			}
			copyOfTargetString =
				copyOfTargetString.replace(
					new RegExp(removingCharacter,"g")
					,""
				);
		}
		return copyOfTargetString;
	}

	//search available path (considering unnecessary space)
	function searchAvailablePathConsideringUnnecessarySpace(
		availableFullPathes, availableCurrentPath , splittedRemainingPath
	){

	}

	//check the position of space(' ' or '　').
	//return array of positions.
	function checkPositionOfSpaces(targetString){
		var positionOfSpaces = [];
		for(var index = 0 , len = targetString.length ; index < len; index++){
			if((targetString[index] == ' ') || (targetString[index] == '　' )){
				positionOfSpaces.push(index);
			}
		}
		return positionOfSpaces;
	}

	function searchAvailablePathConsideringUnnecessarySpace(
		availableFullPathes, availableCurrentPath , splittedRemainingPath
	){
		searchAvailablePathConsideringUnnecessarySpaceWithDistance(
			availableFullPathes, availableCurrentPath , splittedRemainingPath , 0
		);
	}

	function searchAvailablePathConsideringUnnecessarySpaceWithDistance(
		availableFullPathes, availableCurrentPath , splittedRemainingPath , currentDistance
	){
		if(splittedRemainingPath.length > 0){
			var targetPath = splittedRemainingPath[0];
			var checkingPath = "";
			if(availableCurrentPath == ""){
				checkingPath = targetPath;
			}else{
				checkingPath = availableCurrentPath + "\\" + targetPath;
			}
			switch(checkFileOrFolder(checkingPath)){
				case -1:
				case 3:
					//do nothing
					break;
				case 1://Available File
				case 2://Available Folder
					var shiftedSplittedRemainingPath = splittedRemainingPath.slice();
					shiftedSplittedRemainingPath.shift();
					var nextAvailableCurrentPath = checkingPath;
					var nextDistance = currentDistance;
					searchAvailablePathConsideringUnnecessarySpaceWithDistance(
						availableFullPathes, nextAvailableCurrentPath,
						shiftedSplittedRemainingPath, nextDistance
					);
					break;
				default:
					//do nothing
					break;
			}

			//count the number of ' ' and '　'.
			var positionOfSpaces = checkPositionOfSpaces(targetPath);
			var numberOfSpaces = positionOfSpaces.length;
			if(numberOfSpaces > 0){
				//remove one of spaces and check the path.
				for(var index = 0; index < numberOfSpaces; index++){
					var nextSplittedRemainingPath = splittedRemainingPath;
					var firstHalfOfTargetPathRemovedSpace = targetPath;
					var latterHalfOfTargetPathRemovedSpace = targetPath;
					var targetPathRemovedSpace =
						firstHalfOfTargetPathRemovedSpace.slice(0,positionOfSpaces[index]) +
						latterHalfOfTargetPathRemovedSpace.slice(positionOfSpaces[index]+1);
					nextSplittedRemainingPath[0] = targetPathRemovedSpace;
					var nextDistance = currentDistance + 1;
					var nextAvailableCurrentPath = availableCurrentPath;
					searchAvailablePathConsideringUnnecessarySpaceWithDistance(
						availableFullPathes, nextAvailableCurrentPath,
						nextSplittedRemainingPath, nextDistance
					);
				}
			}
		}else{
			//check if the availableCurrentPath is already added.
			var alreadyExistFlag = false;
			for(var index = 0, len = availableFullPathes.length; index < len ; index++){
				if(availableFullPathes[index][0] == availableCurrentPath){
					alreadyExistFlag = true;
				}
			}
			if(alreadyExistFlag == false){
				availableFullPathes.push([availableCurrentPath , currentDistance]);
				console.log("Added : " + availableCurrentPath + " - Distance : " + currentDistance);
			}
		}
	}

	function search (query, res) {
		//format query.
		//remove spaces attached on head and bottom.
		var trimmedQuery = query.trim();

		//remove unavailable characters ( * / ? " < > | ).
		var queryRemovedUnavailableCharacters =
			removeCharacters(trimmedQuery,['*','/','?',"\"","<",">","|","\t"]);

		//split by '\'.
		var splittedQuery = queryRemovedUnavailableCharacters.split('\\');

		//search available file/folder name. (considering needless space)
		var availableFullPathes = [];
		searchAvailablePathConsideringUnnecessarySpace(availableFullPathes,"",splittedQuery);

		//Check state of formatted path (File or Folder or not).
		//and set Description Message according to the state.
		var descriptionMessage = "";
		switch(checkFileOrFolder(queryRemovedUnavailableCharacters)){
			case -1://invalid
			case 0://invalid
				descriptionMessage = "Not File/Folder. Cannot open."
				break;
			case 1://file
				descriptionMessage = "Open this File."
				break;
			case 2://folder
				descriptionMessage = "Open this Folder."
				break;
		}

		//add to res.
		res.add(
			{
				id: queryRemovedUnavailableCharacters,
				payload: 'open',
				title: queryRemovedUnavailableCharacters,
				desc: descriptionMessage
			}
		);
	}

	function execute (id, payload) {
		//open file or folder.
		if (payload !== 'open') {
			return
		}
		shell.openItem(`${id}`);
	}

	return { search, execute };
}
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var gitHub = require('octonode');

var tc = require('./team-city');
var Builds = require('./builds');

var app = express();

var client = gitHub.client(process.env.GITHUB_TOKEN);
var noop = function () {};

app.configure(function () {
  app.use(express.bodyParser());
});

app.post('/api/events', function (req, res) {
  Builds.add(req.body)
    .then(function (buildEvent) {
      var buildId = buildEvent.build.buildId;
      console.log('Build', buildId, 'saved');

      res.send(201, buildEvent);

      tc.getBuild(buildId)
        .then(function (build) {
          var revision = build.revisions.revision[0];

          tc.getVscRootInstance(revision['vcs-root-instance'].id)
            .then(function (vcsRootInstance) {
              var sha = revision.version;
              console.log('Updating status for:', sha);

              var state,
                description;

              switch (build.status) {
                case 'RUNNING':
                  state = 'pending';
                  description = 'Build ' + build.number + ' in progress';
                  break;

                case 'SUCCESS':
                  state = 'success';
                  description = 'Build ' + build.number + ' successful';
                  break;

                case 'FAIL': // TODO: Check?
                  state = 'fail';
                  description = 'Build ' + build.number + ' failed';
                  break;

                default:
                  state = 'error';
                  description = 'I don\'t know what happened?';
              }

              var url;
              vcsRootInstance.properties.property.forEach(function (p) {
                if (p.name === 'url') {
                  url = p.value;
                }
              });

              if (!url) {
                throw new Error('Could not find VCS root instance GitHub URL');
              }

              var repoUrl = url.match(/git@github.com:(.*).git/)[1];

              // Update GitHub commit status
              var repo = client.repo(repoUrl);
              repo.status(sha, {
                state: state,
                'target_url': build.webUrl,
                description: description
              }, noop);

              // Post to Flowdock
            });
        });

    }, function (err) {
      res.send(500, err);
    });
});

app.get('/api/events', function (req, res) {
  Builds.all()
    .then(function (builds) {
      res.send(builds);
    }, function (err) {
      res.send(500, err);
    });
});

var port = Number(process.env.PORT || 5000);
app.listen(port, function() {
  console.log('Listening on ' + port);
});
<commit_msg>Back to preferring event data<commit_after>'use strict';

var express = require('express');
var gitHub = require('octonode');

var tc = require('./team-city');
var Builds = require('./builds');

var app = express();

var client = gitHub.client(process.env.GITHUB_TOKEN);
var noop = function (a) { console.log('I nooped', a); };

app.configure(function () {
  app.use(express.bodyParser());
});

app.post('/api/events', function (req, res) {
  Builds.add(req.body)
    .then(function (buildEvent) {
      var buildId = buildEvent.build.buildId;
      console.log('Build', buildId, 'saved');

      res.send(201, buildEvent);

      var state,
        description;

      switch (buildEvent.build.buildResult.toLowerCase()) {
        case 'running':
          state = 'pending';
          description = 'Build #' + buildEvent.build.buildNumber + ' in progress';
          break;

        case 'success':
          state = 'success';
          description = 'Build #' + buildEvent.build.buildNumber + ' successful';
          break;

        case 'failure': // TODO: Check?
          state = 'failure';
          description = 'Build #' + buildEvent.build.buildNumber + ' failed: ' + buildEvent.build.buildStatus;
          break;

        default:
          state = 'error';
          description = 'I don\'t know what happened?';
      }

      tc.getBuild(buildId)
        .then(function (build) {
          var revision = build.revisions.revision[0];

          tc.getVscRootInstance(revision['vcs-root-instance'].id)
            .then(function (vcsRootInstance) {
              var url;
              vcsRootInstance.properties.property.forEach(function (p) {
                if (p.name === 'url') {
                  url = p.value;
                }
              });

              if (!url) {
                throw new Error('Could not find VCS root instance GitHub URL');
              }

              var repoUrl = url.match(/git@github.com:(.*).git/)[1];
              var sha = revision.version;

              console.log('Updating (' + repoUrl + '/' + sha + ')');
              console.log('Build', state);
              console.log(description);

              // Update GitHub commit status
              var repo = client.repo(repoUrl);
              repo.status(sha, {
                state: state,
                'target_url': buildEvent.build.buildStatusUrl,
                description: description
              }, noop);

              // Post to Flowdock
            });
        });

    }, function (err) {
      res.send(500, err);
    });
});

app.get('/api/events', function (req, res) {
  Builds.all()
    .then(function (builds) {
      res.send(builds);
    }, function (err) {
      res.send(500, err);
    });
});

var port = Number(process.env.PORT || 5000);
app.listen(port, function() {
  console.log('Listening on ' + port);
});
<|endoftext|>


<commit_before>// Defining helper functions
function info(message){
  console.log(message.blue);
}
function danger(message){
  console.log(message.red);
}
function warn(message){
  console.log(message.yellow.bold);
}
function success(message){
  console.log(message.green.bold);
}
function log(message){
  console.log(message);
}
function title(message){
  var title='';
  function getStars(messsage){
    var ret = '';
    for(var i=0; i<messsage.length+6; i++){
      ret+='*';
    }
    return ret;
  }
  title += getStars(message) + '\n';
  title += '** ' + message + ' **\n';
  title += getStars(message);
  return title;
}

// Requiring dependencies
require('colors');
var pkg = require('./package.json');
var express = require('express');
var cli = require('commander');
var open = require('open');
var fs = require('fs');
var jade = require('jade');

// Initializations
var app = express();
var tmp = '', stars = '', url='';
// Default options
var options = {
  port: process.env.PORT || 8080,
  dir: __dirname,
  browser: undefined
}

// Defining and parsing CLI options
cli.version(pkg.version)
.option('-d --dir <directory>','directory to serve (default: .)')
.option('-b --browser <browser name>','browser which open served directory')
.option('-p --port <port>','http port to serve to (default: 8080)')
.option('-r --remote','don\'t automatically lauch browser on  localhost (useful if running on _r_emote host)')
.option('-s --stopOnClose','automatically stop the server when user close the browser')
.parse(process.argv);

// Setting options
if (cli.port)       options.port = cli.port;
if (cli.dir)        options.dir = cli.dir;
if (cli.browser)    options.browser = cli.browser;
if (cli.remote)     options.remote = cli.remote;

// Logging CLI user friendly messages
info(title('autostatic-server v' + pkg.version))
info('* serving directory ' + options.dir);
info('* on port ' + options.port);
if(!options.remote) info('* via ' + (options.browser || 'your default') + ' browser');
info('**');

app.use(function(req,res,next){
  if (req.path==='/favicon.ico') log(req.path);
  else info(req.path);
  return next();
});
app.use(express.static(options.dir));

app.use(function(req,res,next){
  var filePath = __dirname + req.path;
  require('fs').exists(filePath, function(exists){
    if(!exists)  return res.status(404).send();

    fs.stat(filePath, function(err,stats){
      if (err) return next(err);
      if (stats.isDirectory()) {
        fs.readdir(filePath,function(err,files){
          if (err) return next('Unable to read directory '+filePath);

          var linkedFiles = [];
          for(i in files){
            var relPath = filePath.split(__dirname).join('');
            var href = (relPath.length>1) ? relPath + '/' + files[i] : files[i];

            linkedFiles.push({
              name: files[i],
              href: href
            });
          }

          var relPath = filePath.split(__dirname).join('');
          // res.status(200).jsonp(files);
          var html = jade.renderFile(__dirname + '/index.jade',{
            parentHref: '../',
            dirname: relPath,
            files: linkedFiles
          });

          res.status(200).send(html);
        });
      }
    });
  });
});
app.use(function(err,req,res,next){
  info(res.status());
  danger('Server Error');
  console.error(err.message);
  console.log(err);
  console.error(err.stack);
  return res.status(500).jsonp(err);
});

var server = app.listen(options.port,function(){
  if (!cli.remote){
    url = 'http://localhost:' + options.port;
    open(url,options.browser)
    .on('error',function(err){
      danger('Error');
      console.log(err);
    })
    .on('close',function(){
      warn('browser closed by client.');
      if(cli.stopOnClose){
        info('stopping server.');
        process.exit();
      }
    })
  } else {
    url = 'http://' + server.address().address + ':' + options.port;
  }
  success('Server running... \nAccess to served static files at '+ url);

});
<commit_msg>Add -s --stop-on-close option<commit_after>// Defining helper functions
function info(message){
  console.log(message.blue);
}
function danger(message){
  console.log(message.red);
}
function warn(message){
  console.log(message.yellow.bold);
}
function success(message){
  console.log(message.green.bold);
}
function log(message){
  console.log(message);
}
function title(message){
  var title='';
  function getStars(messsage){
    var ret = '';
    for(var i=0; i<messsage.length+6; i++){
      ret+='*';
    }
    return ret;
  }
  title += getStars(message) + '\n';
  title += '** ' + message + ' **\n';
  title += getStars(message);
  return title;
}

// Requiring dependencies
require('colors');
var pkg = require('./package.json');
var express = require('express');
var cli = require('commander');
var open = require('open');
var fs = require('fs');
var jade = require('jade');

// Initializations
var app = express();
var tmp = '', stars = '', url='';
// Default options
var options = {
  port: process.env.PORT || 8080,
  dir: __dirname,
  browser: undefined
}

// Defining and parsing CLI options
cli.version(pkg.version)
.option('-d --dir <directory>','directory to serve (default: .)')
.option('-b --browser <browser name>','browser which open served directory')
.option('-p --port <port>','http port to serve to (default: 8080)')
.option('-r --remote','don\'t automatically lauch browser on  localhost (useful if running on _r_emote host)')
.option('-s --stop-on-close','automatically stop the server when user close the browser')
.parse(process.argv);

// Setting options
if (cli.port)       options.port = cli.port;
if (cli.dir)        options.dir = cli.dir;
if (cli.browser)    options.browser = cli.browser;
if (cli.remote)     options.remote = cli.remote;

// Logging CLI user friendly messages
info(title('autostatic-server v' + pkg.version))
info('* serving directory ' + options.dir);
info('* on port ' + options.port);
if(!options.remote) info('* via ' + (options.browser || 'your default') + ' browser');
info('**');

app.use(function(req,res,next){
  if (req.path==='/favicon.ico') log(req.path);
  else info(req.path);
  return next();
});
app.use(express.static(options.dir));

app.use(function(req,res,next){
  var filePath = __dirname + req.path;
  require('fs').exists(filePath, function(exists){
    if(!exists)  return res.status(404).send();

    fs.stat(filePath, function(err,stats){
      if (err) return next(err);
      if (stats.isDirectory()) {
        fs.readdir(filePath,function(err,files){
          if (err) return next('Unable to read directory '+filePath);

          var linkedFiles = [];
          for(i in files){
            var relPath = filePath.split(__dirname).join('');
            var href = (relPath.length>1) ? relPath + '/' + files[i] : files[i];

            linkedFiles.push({
              name: files[i],
              href: href
            });
          }

          var relPath = filePath.split(__dirname).join('');
          // res.status(200).jsonp(files);
          var html = jade.renderFile(__dirname + '/index.jade',{
            parentHref: '../',
            dirname: relPath,
            files: linkedFiles
          });

          res.status(200).send(html);
        });
      }
    });
  });
});
app.use(function(err,req,res,next){
  info(res.status());
  danger('Server Error');
  console.error(err.message);
  console.log(err);
  console.error(err.stack);
  return res.status(500).jsonp(err);
});

var server = app.listen(options.port,function(){
  if (!cli.remote){
    url = 'http://localhost:' + options.port;
    open(url,options.browser)
    .on('error',function(err){
      danger('Error');
      console.log(err);
    })
    .on('close',function(){
      warn('browser closed by client.');
      if(cli.stopOnClose){
        info('stopping server.');
        process.exit();
      }
    })
  } else {
    url = 'http://' + server.address().address + ':' + options.port;
  }
  success('Server running... \nAccess to served static files at '+ url);

});
<|endoftext|>


<commit_before>
var worldCameraPosition = new THREE.Vector3(),
	offset = new THREE.Vector3(),
	cameraVector = new THREE.Vector3();

function updateCameraVector(camera, x, y) {
	//flip y, just cuz
	cameraVector.set( x, -y, 0.5 );
	cameraVector.unproject( camera );
	worldCameraPosition.copy(camera.position);
	camera.parent.localToWorld(worldCameraPosition);
	cameraVector.sub( worldCameraPosition ).normalize();
};

function updateCameraVectorOrtho(camera, x, y) {
	//flip y, just cuz
	cameraVector.set( x, -y, 0.5 );
	cameraVector.unproject( camera );
	worldCameraPosition.copy(camera.position);
	camera.parent.localToWorld(worldCameraPosition);
	cameraVector.sub( worldCameraPosition ).normalize();
};

function hitTest(x, y, camera, objects) {
	if(camera instanceof THREE.PerspectiveCamera) {
		updateCameraVector(camera, x, y);
		var raycaster = new THREE.Raycaster( worldCameraPosition, cameraVector );
		return raycaster.intersectObjects( objects );
	} else {
		cameraVector.set( x, -y, 0.5 );
		var ray = projector.pickingRay( cameraVector, camera );
		return ray.intersectObjects( objects );
	}
}
hitTest.testGrid = function(x, y, camera, objects, cols, rows) {
	cols = cols || 60;
	rows = rows || ~~(cols / window.innerWidth * window.innerHeight * .5);
	var range = {
		x: {
			min : -1,
			max : 1
		},
		y: {
			min : -1,
			max : 1
		}
	};
	range.x.size = range.x.max - range.x.min;
	range.y.size = range.y.max - range.y.min;
	var targetRow = ~~(rows * .5) + ~~(rows * .5 * (y / window.innerHeight * range.y.size + range.y.min));
	var targetCol = ~~(cols * .5) + ~~(cols * .5 * (x / window.innerWidth * range.x.size + range.x.min));
	var results = [];
	for (var iRow = 0; iRow < rows; iRow++) {
		var ratioY = iRow / rows;
		var resultsLine = "" + iRow;
		while(resultsLine.length < 3) resultsLine += " ";
		for (var iCol = 0; iCol < cols; iCol++) {
			var ratioX = iCol / cols;
			var x = ratioX * range.x.size + range.x.min;
			var y = ratioY * range.y.size + range.y.min;
			var hit = hitTest(x, y, camera, objects).length > 0;
			if(iCol == targetCol && iRow == targetRow) {
				resultsLine += hit ? '●' : '◌';
			} else {
				resultsLine += hit ? '▓' : '░';
			}
		};
		console.log(resultsLine);
		results.push(resultsLine);
	};
}

module.exports = hitTest;<commit_msg>adding orthographic fix, which requires newest ThreeJS and setFromCamera<commit_after>
var worldCameraPosition = new THREE.Vector3(),
	offset = new THREE.Vector3(),
	cameraVector = new THREE.Vector3();

function updateCameraVector(camera, x, y) {
	//flip y, just cuz
	cameraVector.set( x, -y, 0.5 );
	cameraVector.unproject( camera );
	worldCameraPosition.copy(camera.position);
	camera.parent.localToWorld(worldCameraPosition);
	cameraVector.sub( worldCameraPosition ).normalize();
};

function updateCameraVectorOrtho(camera, x, y) {
	//flip y, just cuz
	cameraVector.set( x, -y, 0.5 );
	cameraVector.unproject( camera );
	worldCameraPosition.copy(camera.position);
	camera.parent.localToWorld(worldCameraPosition);
	cameraVector.sub( worldCameraPosition ).normalize();
};

function hitTest(x, y, camera, objects) {
	if(camera instanceof THREE.PerspectiveCamera) {
		updateCameraVector(camera, x, y);
		var raycaster = new THREE.Raycaster( worldCameraPosition, cameraVector );
		return raycaster.intersectObjects( objects );
	} else {
		cameraVector.set( x, -y, 0.5 );
		var raycaster = new THREE.Raycaster();
		raycaster.setFromCamera(cameraVector, camera);
		return raycaster.intersectObjects( objects );
	}
}
hitTest.testGrid = function(x, y, camera, objects, cols, rows) {
	cols = cols || 60;
	rows = rows || ~~(cols / window.innerWidth * window.innerHeight * .5);
	var range = {
		x: {
			min : -1,
			max : 1
		},
		y: {
			min : -1,
			max : 1
		}
	};
	range.x.size = range.x.max - range.x.min;
	range.y.size = range.y.max - range.y.min;
	var targetRow = ~~(rows * .5) + ~~(rows * .5 * (y / window.innerHeight * range.y.size + range.y.min));
	var targetCol = ~~(cols * .5) + ~~(cols * .5 * (x / window.innerWidth * range.x.size + range.x.min));
	var results = [];
	for (var iRow = 0; iRow < rows; iRow++) {
		var ratioY = iRow / rows;
		var resultsLine = "" + iRow;
		while(resultsLine.length < 3) resultsLine += " ";
		for (var iCol = 0; iCol < cols; iCol++) {
			var ratioX = iCol / cols;
			var x = ratioX * range.x.size + range.x.min;
			var y = ratioY * range.y.size + range.y.min;
			var hit = hitTest(x, y, camera, objects).length > 0;
			if(iCol == targetCol && iRow == targetRow) {
				resultsLine += hit ? '●' : '◌';
			} else {
				resultsLine += hit ? '▓' : '░';
			}
		};
		console.log(resultsLine);
		results.push(resultsLine);
	};
}

module.exports = hitTest;<|endoftext|>


<commit_before>var	child = require('./child.js');

var defaults = {
	'viewportSize': {
		'width': 2880,
		'height': 1440
	},
	'paperSize': {
		'format': 'A4',
		'orientation': 'portrait',
		'margin': {
			'top': '1cm',
			'right': '1cm',
			'bottom': '1cm',
			'left': '1cm'
		}
	},
	'zoomFactor': 1,
	'args': '',
	'captureDelay': 400
};

//code from https://github.com/rxaviers/cldr
var merge = function() {
	var destination = {},
	sources = [].slice.call( arguments, 0 );
	sources.forEach(function( source ) {
		var prop;
		for ( prop in source ) {
			if ( prop in destination && Array.isArray( destination[ prop ] ) ) {
				// Concat Arrays
				destination[ prop ] = destination[ prop ].concat( source[ prop ] );
			} else if ( prop in destination && typeof destination[ prop ] === "object" ) {
				// Merge Objects
				destination[ prop ] = merge( destination[ prop ], source[ prop ] );
			} else {
				// Set new values
				destination[ prop ] = source[ prop ];
			}
		}
	});
	return destination;
};

module.exports = function(url, fileName, opts){
	var ps,
		readStream,
		self = this;

	this.url = url;
	this.fileName = fileName;
	this.filePath = process.env.PWD || process.cwd() || __dirname;

	this.options = merge(defaults, opts);
	this.evts = {};
	this.on = function(evt, callback) {
		this.evts[evt] = callback;
	};

	child.supports(function(support){
		if (!support)
			self.evts['error'].call(this, 'PhanomJS not installed');
	});

	ps = child.exec(this.url, this.fileName, this.options);

	readStream = function(stream) {
		if (stream.toString('utf-8').length === 2) {
			self.evts['done'].call(this, self.filePath+'/'+self.fileName);
			ps.kill();
		} else {
			self.evts['error'].call(this, 'There was a problem');
		};
	};

	ps.stdout.on('data', function(std){
		readStream(std);
	});

	ps.stderr.on('data', function(std){
		self.evts['error'].call(self, std);
	});

	return this;
};
<commit_msg>set a noop function for events per default so there's always a function which can be called. solves #12<commit_after>var	child = require('./child.js');

var defaults = {
	'viewportSize': {
		'width': 2880,
		'height': 1440
	},
	'paperSize': {
		'format': 'A4',
		'orientation': 'portrait',
		'margin': {
			'top': '1cm',
			'right': '1cm',
			'bottom': '1cm',
			'left': '1cm'
		}
	},
	'zoomFactor': 1,
	'args': '',
	'captureDelay': 400
};

//code from https://github.com/rxaviers/cldr
var merge = function() {
	var destination = {},
	sources = [].slice.call( arguments, 0 );
	sources.forEach(function( source ) {
		var prop;
		for ( prop in source ) {
			if ( prop in destination && Array.isArray( destination[ prop ] ) ) {
				// Concat Arrays
				destination[ prop ] = destination[ prop ].concat( source[ prop ] );
			} else if ( prop in destination && typeof destination[ prop ] === "object" ) {
				// Merge Objects
				destination[ prop ] = merge( destination[ prop ], source[ prop ] );
			} else {
				// Set new values
				destination[ prop ] = source[ prop ];
			}
		}
	});
	return destination;
};

module.exports = function(url, fileName, opts){
	var ps,
		readStream,
		self = this,
		NOOP = function() {};

	this.url = url;
	this.fileName = fileName;
	this.filePath = process.env.PWD || process.cwd() || __dirname;

	this.options = merge(defaults, opts);
	this.evts = {
		'error': NOOP,
		'done': NOOP
	};
	this.on = function(evt, callback) {
		this.evts[evt] = callback;
	};

	child.supports(function(support){
		if (!support) self.evts.error('PhantomJS not installed');
	});

	ps = child.exec(this.url, this.fileName, this.options);

	readStream = function(stream) {
		if (stream.toString('utf-8').length === 2) {
			self.evts.done(self.filePath+'/'+self.fileName);
			ps.kill();
		} else {
			self.evts.error('There was a problem');
		};
	};

	ps.stdout.on('data', function(std){
		readStream(std);
	});

	ps.stderr.on('data', function(std){
		self.evts.error(std);
	});

	return this;
};
<|endoftext|>


<commit_before>var request    = require('request')
  , sax        = require('sax')
  , _          = require('underscore');

// Public: Fetch the articles from the RSS or ATOM feed.
//
// url      - The String feed url, or an Array of urls.
// callback - Receives `(err, articles)`, where each article has properties:
//
//              * "title"
//              * "author"
//              * "link"
//              * "content"
//              * "published"
//              * "feed" - {name, source, link}
//
// Returns nothing.
var FeedRead = module.exports = function(feed_url, callback) {
  if (feed_url instanceof Array) {
    var feed_urls = feed_url
      , articles  = [];
    var next = function(i) {
      var feed_url = feed_urls[i];
      if (!feed_url) return callback(null, articles);
      FeedRead.get(feed_url, function(err, _articles) {
        if (err) return callback(err);
        articles = articles.concat(_articles);
        next(i + 1);
      });
    };
    next(0);
  } else {
    FeedRead.get(feed_url, callback);
  }
};

// Public: Check if the XML is RSS, ATOM, or neither.
//
// xml - A String of XML.
//
// Returns "atom", "rss", or false when it is neither.
FeedRead.identify = function(xml) {
  if (/<rss /i.test(xml)) {
    return "rss";
  } else if (/<feed /i.test(xml)) {
    return "atom";
  } else {
    return false;
  }
}

// Internal: Get a single feed.
//
// feed_url - String url.
// callback - Receives `(err, articles)`.
//
FeedRead.get = function(feed_url, callback) {
  request(feed_url, function(err, res, body) {
    if (err) return callback(err);
    var type = FeedRead.identify(body);
    if (type == "atom") {
      FeedRead.atom(body, feed_url, callback);
    } else if (type == "rss") {
      FeedRead.rss(body, feed_url, callback);
    } else {
      return callback(new Error( "Body is not RSS or ATOM"
                                , body.substr(0, 30), "..."));
    }
  });
};

// Public: Parse the articles from some ATOM.
//
// xml      - A XML String.
// source   - (optional)
// callback - Receives `(err, articles)`.
//
// Returns an Array of Articles.
FeedRead.atom = function(xml, source, callback) {
  if (!callback) return FeedRead.atom(xml, "", source);

  var parser   = new FeedParser()
    , articles = []
    // Info about the feed itself, not an article.
    , meta     = {source: source}
    // The current article.
    , article
    // The author for when no author is specified for the post.
    , default_author;

  parser.onopentag = function(tag) {
    if (tag.name == "entry") article = tag;
  };

  parser.onclosetag = function(tagname, current_tag) {
    if (tagname == "entry") {
      articles.push(article);
      article = null;
    } else if (tagname == "author" && !article) {
      default_author = child_data(current_tag, "name");
    } else if (tagname == "link" && current_tag.attributes.rel != "self") {
      meta.link || (meta.link = current_tag.attributes.href);
    } else if (tagname == "title" && !current_tag.parent.parent) {
      meta.name = current_tag.children[0];
    }
  };

  parser.onend = function() {
    callback(null, _.map(articles,
      function(art) {
        var author = child_by_name(art, "author");
        if (author) author = child_data(author, "name");

        var obj = {
            title:     child_data(art, "title")
          , content:   child_data(art, "description")
                    || child_data(art, "summary")
                    || child_data(art, "content")
          , published: child_data(art, "published")
                    || child_data(art, "updated")
          , author:    author || default_author
          , link:      child_by_name(art, "link").attributes.href
          , enclosure: child_attr(art, "enclosure", "url")
                    || child_attr(art, "media:content", "url")
          , enclosure_type: child_attr(art, "enclosure", "type")
                         || child_attr(art, "media:content", "medium")
          , enclosure_size: child_attr(art, "enclosure", "length")
          , enclosure_thumbnail: child_attr(art, "media:thumbnail", "url")
          , feed:      meta
          };
        if (obj.published) obj.published = new Date(obj.published);
        return obj;
      }
    ));
  };

  parser.write(xml);
};

// Public: Parse the articles from some RSS.
//
// xml      - A XML String.
// source   - (optional)
// callback - Receives `(err, articles)`.
//
// Returns an Array of Articles.
FeedRead.rss = function(xml, source, callback) {
  if (!callback) return FeedRead.rss(xml, "", source);

  var parser   = new FeedParser()
    , articles = []
    // Info about the feed itself, not an article.
    , meta     = {source: source}
    // The current article.
    , article;

  parser.onopentag = function(tag) {
    if (tag.name == "item") article = tag;
  };

  parser.onclosetag = function(tagname, current_tag) {
    if (tagname == "item") {
      articles.push(article);
      article = null;
    } else if (tagname == "channel") {
      meta.link || (meta.link = child_data(current_tag, "link"));
      meta.name = child_data(current_tag, "title");
    }
  };

  parser.onend = function() {
    callback(null, _.map(articles,
      function(art) {
        var obj = {
            title:     child_data(art, "title")
          , content:   scrub_html(child_data(art, "description"))
                    || scrub_html(child_data(art, "summary"))
                    || scrub_html(child_data(art, "content:encoded"))
          , published: child_data(art, "pubDate")
          , author:    child_data(art, "author")
                    || child_data(art, "dc:creator")
          , link:      child_data(art, "link")
          , enclosure: child_attr(art, "enclosure", "url")
                    || child_attr(art, "media:content", "url")
          , enclosure_type: child_attr(art, "enclosure", "type")
                         || child_attr(art, "media:content", "medium")
          , enclosure_size: child_attr(art, "enclosure", "length")
          , enclosure_thumbnail: child_attr(art, "media:thumbnail", "url")
          , feed:      meta
          };
        if (obj.published) obj.published = new Date(obj.published);
        return obj;
      }
    ));
  };

  parser.write(xml);
};

// Methods to override:
//
//   * onopentag
//   * onclosetag
//   * onend
//
var FeedParser = (function() {
  // Internal: Parse the XML.
  //
  // xml      - An XML String.
  // callback - Receives `(err, obj)`.
  //
  function FeedParser() {
    this.current_tag = null;
    var parser       = this.parser = sax.parser(true,
        { trim: true
        , normalize: true
        })
      , _this        = this;

    parser.onopentag  = function(tag) { _this.open(tag); };
    parser.onclosetag = function(tag) { _this.close(tag); };

    parser.ontext  = function(text) { _this.ontext(text); };
    parser.oncdata = function(text) { _this.ontext(text); };
    parser.onend   = function() { _this.onend(); };

    parser.onerror = console.error;
  }

  // Public: Parse the XML.
  FeedParser.prototype.write = function(xml) {
    this.parser.write(xml).close();
  };

  // Internal: Open a tag.
  FeedParser.prototype.open = function(tag) {
    tag.parent   = this.current_tag;
    tag.children = [];
    if (tag.parent) tag.parent.children.push(tag);
    this.current_tag = tag;
    this.onopentag(tag);
  };

  // Internal: CLose a tag.
  FeedParser.prototype.close = function(tagname) {
    this.onclosetag(tagname, this.current_tag);
    if (this.current_tag && this.current_tag.parent) {
      var p = this.current_tag.parent;
      delete this.current_tag.parent;
      this.current_tag = p;
    }
  };

  // Internal: Add the text as a child of the current tag.
  FeedParser.prototype.ontext = function(text) {
    if (this.current_tag) {
      this.current_tag.children.push(text);
    }
  };

  return FeedParser;
})();

// Internal: Remove <script> tags from the HTML.
//
// html     - An HTML String.
// callback - Receives `(err, html)`.
//
// TODO: Do actual HTML parsing!!
function scrub_html(html) {
  return html.replace(/<script.*<\/script>/gi, "");
}

// Internal: Find the first node from the parent node's children that has
// the given name.
//
// parent - An Array of node objects.
// name   - String node name.
//
// Returns a node Object or null.
function child_by_name(parent, name) {
  var children = parent.children || [];
  for (var i = 0; i < children.length; i++) {
    if (children[i].name == name) return children[i];
  }
  return null;
}

// Internal: Get the first child of `parent` with `name`,
// and return the text of its children.
function child_data(parent, name) {
  var node     = child_by_name(parent, name);
  if (!node) return "";
  var children = node.children;
  if (!children.length) return "";
  return children.join("");
}

function child_attr(parent, name, attr) {
  var node     = child_by_name(parent, name);
  if (!node || !node.attributes) return "";
  return node.attributes[attr] || "";
}
<commit_msg>Added support for PA wires<commit_after>var request    = require('request')
  , sax        = require('sax')
  , _          = require('underscore');

// Public: Fetch the articles from the RSS or ATOM feed.
//
// url      - The String feed url, or an Array of urls.
// callback - Receives `(err, articles)`, where each article has properties:
//
//              * "title"
//              * "author"
//              * "link"
//              * "content"
//              * "published"
//              * "feed" - {name, source, link}
//
// Returns nothing.
var FeedRead = module.exports = function(feed_url, callback) {
  if (feed_url instanceof Array) {
    var feed_urls = feed_url
      , articles  = [];
    var next = function(i) {
      var feed_url = feed_urls[i];
      if (!feed_url) return callback(null, articles);
      FeedRead.get(feed_url, function(err, _articles) {
        if (err) return callback(err);
        articles = articles.concat(_articles);
        next(i + 1);
      });
    };
    next(0);
  } else {
    FeedRead.get(feed_url, callback);
  }
};

// Public: Check if the XML is RSS, ATOM, or neither.
//
// xml - A String of XML.
//
// Returns "atom", "rss", or false when it is neither.
FeedRead.identify = function(xml) {
  if (/<rss /i.test(xml)) {
    return "rss";
  } else if (/<feed /i.test(xml)) {
    return "atom";
  } else {
    return false;
  }
}

// Internal: Get a single feed.
//
// feed_url - String url.
// callback - Receives `(err, articles)`.
//
FeedRead.get = function(feed_url, callback) {
  request(feed_url, function(err, res, body) {
    if (err) return callback(err);
    var type = FeedRead.identify(body);
    if (type == "atom") {
      FeedRead.atom(body, feed_url, callback);
    } else if (type == "rss") {
      FeedRead.rss(body, feed_url, callback);
    } else {
      return callback(new Error( "Body is not RSS or ATOM"
                                , body.substr(0, 30), "..."));
    }
  });
};

// Public: Parse the articles from some ATOM.
//
// xml      - A XML String.
// source   - (optional)
// callback - Receives `(err, articles)`.
//
// Returns an Array of Articles.
FeedRead.atom = function(xml, source, callback) {
  if (!callback) return FeedRead.atom(xml, "", source);

  var parser   = new FeedParser()
    , articles = []
    // Info about the feed itself, not an article.
    , meta     = {source: source}
    // The current article.
    , article
    // The author for when no author is specified for the post.
    , default_author;

  parser.onopentag = function(tag) {
    if (tag.name == "entry") article = tag;
  };

  parser.onclosetag = function(tagname, current_tag) {
    if (tagname == "entry") {
      articles.push(article);
      article = null;
    } else if (tagname == "author" && !article) {
      default_author = child_data(current_tag, "name");
    } else if (tagname == "link" && current_tag.attributes.rel != "self") {
      meta.link || (meta.link = current_tag.attributes.href);
    } else if (tagname == "title" && !current_tag.parent.parent) {
      meta.name = current_tag.children[0];
    }
  };

  parser.onend = function() {
    callback(null, _.map(articles,
      function(art) {
        var author = child_by_name(art, "author");
        if (author) author = child_data(author, "name");

        var obj = {
            title:     child_data(art, "title")
          , content:   child_data(art, "description")
                    || child_data(art, "summary")
                    || child_data(art, "content")
          , published: child_data(art, "published")
                    || child_data(art, "updated")
          , author:    author || default_author
          , link:      child_by_name(art, "link").attributes.href
          , enclosure: child_attr(art, "enclosure", "url")
                    || child_attr(art, "media:content", "url")
          , enclosure_type: child_attr(art, "enclosure", "type")
                         || child_attr(art, "media:content", "medium")
                         || child_attr(art, "media:content", "type")
          , enclosure_size: child_attr(art, "enclosure", "length")
          , enclosure_thumbnail: child_attr(art, "media:thumbnail", "url")
          , feed:      meta
          };
        if (obj.published) obj.published = new Date(obj.published);
        return obj;
      }
    ));
  };

  parser.write(xml);
};

// Public: Parse the articles from some RSS.
//
// xml      - A XML String.
// source   - (optional)
// callback - Receives `(err, articles)`.
//
// Returns an Array of Articles.
FeedRead.rss = function(xml, source, callback) {
  if (!callback) return FeedRead.rss(xml, "", source);

  var parser   = new FeedParser()
    , articles = []
    // Info about the feed itself, not an article.
    , meta     = {source: source}
    // The current article.
    , article;

  parser.onopentag = function(tag) {
    if (tag.name == "item") article = tag;
  };

  parser.onclosetag = function(tagname, current_tag) {
    if (tagname == "item") {
      articles.push(article);
      article = null;
    } else if (tagname == "channel") {
      meta.link || (meta.link = child_data(current_tag, "link"));
      meta.name = child_data(current_tag, "title");
    }
  };

  parser.onend = function() {
    callback(null, _.map(articles,
      function(art) {
        var obj = {
            title:     child_data(art, "title")
          , content:   scrub_html(child_data(art, "description"))
                    || scrub_html(child_data(art, "summary"))
                    || scrub_html(child_data(art, "content:encoded"))
          , published: child_data(art, "pubDate")
          , author:    child_data(art, "author")
                    || child_data(art, "dc:creator")
          , link:      child_data(art, "link")
          , enclosure: child_attr(art, "enclosure", "url")
                    || child_attr(art, "media:content", "url")
          , enclosure_type: child_attr(art, "enclosure", "type")
                         || child_attr(art, "media:content", "medium")
                         || child_attr(art, "media:content", "type")
          , enclosure_size: child_attr(art, "enclosure", "length")
          , enclosure_thumbnail: child_attr(art, "media:thumbnail", "url")
          , feed:      meta
          };
        if (obj.published) obj.published = new Date(obj.published);
        return obj;
      }
    ));
  };

  parser.write(xml);
};

// Methods to override:
//
//   * onopentag
//   * onclosetag
//   * onend
//
var FeedParser = (function() {
  // Internal: Parse the XML.
  //
  // xml      - An XML String.
  // callback - Receives `(err, obj)`.
  //
  function FeedParser() {
    this.current_tag = null;
    var parser       = this.parser = sax.parser(true,
        { trim: true
        , normalize: true
        })
      , _this        = this;

    parser.onopentag  = function(tag) { _this.open(tag); };
    parser.onclosetag = function(tag) { _this.close(tag); };

    parser.ontext  = function(text) { _this.ontext(text); };
    parser.oncdata = function(text) { _this.ontext(text); };
    parser.onend   = function() { _this.onend(); };

    parser.onerror = console.error;
  }

  // Public: Parse the XML.
  FeedParser.prototype.write = function(xml) {
    this.parser.write(xml).close();
  };

  // Internal: Open a tag.
  FeedParser.prototype.open = function(tag) {
    tag.parent   = this.current_tag;
    tag.children = [];
    if (tag.parent) tag.parent.children.push(tag);
    this.current_tag = tag;
    this.onopentag(tag);
  };

  // Internal: CLose a tag.
  FeedParser.prototype.close = function(tagname) {
    this.onclosetag(tagname, this.current_tag);
    if (this.current_tag && this.current_tag.parent) {
      var p = this.current_tag.parent;
      delete this.current_tag.parent;
      this.current_tag = p;
    }
  };

  // Internal: Add the text as a child of the current tag.
  FeedParser.prototype.ontext = function(text) {
    if (this.current_tag) {
      this.current_tag.children.push(text);
    }
  };

  return FeedParser;
})();

// Internal: Remove <script> tags from the HTML.
//
// html     - An HTML String.
// callback - Receives `(err, html)`.
//
// TODO: Do actual HTML parsing!!
function scrub_html(html) {
  return html.replace(/<script.*<\/script>/gi, "");
}

// Internal: Find the first node from the parent node's children that has
// the given name.
//
// parent - An Array of node objects.
// name   - String node name.
//
// Returns a node Object or null.
function child_by_name(parent, name) {
  var children = parent.children || [];
  for (var i = 0; i < children.length; i++) {
    if (children[i].name == name) return children[i];
  }
  return null;
}

// Internal: Get the first child of `parent` with `name`,
// and return the text of its children.
function child_data(parent, name) {
  var node     = child_by_name(parent, name);
  if (!node) return "";
  var children = node.children;
  if (!children.length) return "";
  return children.join("");
}

function child_attr(parent, name, attr) {
  var node     = child_by_name(parent, name);
  if (!node || !node.attributes) return "";
  return node.attributes[attr] || "";
}
<|endoftext|>


<commit_before>var infrared = require('ir-attx4');

// understanding the implementation:
// https://github.com/tessel/ir-attx4#api-infrared-on-data-callback-data-Emitted-when-an-infrared-signal-is-detected
// http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol
// http://en.wikipedia.org/wiki/Apple_Remote#Technical_details
// https://github.com/squeed/AppleRemoteSender/blob/master/AppleRemoteSender.cpp
// https://hifiduino.wordpress.com/apple-aluminum-remote/

// parse a Buffer|Array of 16 bit words into signed int durations
function durations_from_hex_buffer(buf) {
    // https://github.com/tessel/ir-attx4 sends off values through a two's complement system
    var durations = new Array(buf.length / 2);
    for (var i = 0; i < buf.length; i += 2) {
        durations[i / 2] = buf.readInt16BE(i);
    }
    return durations;
}

// validate the leader bit
function valid_leader(durations) {
    var on = durations[0];
    var off = durations[1];
    return !(on < 8900 || on > 9150 || off < -4600 || off > -4400);
}

function binary_from_durations(durations) {
    var binary = [];
    // skip the leader, ignore the stop bit
    for (var i = 2; i < durations.length - 1; i += 2) {
        var on = durations[i];
        var off = durations[i + 1];
        if (on >= 500 && on < 700) {
            if (off <= -500 && off >= -650) {
                binary.push(0);
            } else if (off < -1600 && off >= -1750) {
                binary.push(1);
            }
        }
    }

    return binary;
}

function valid_binary(binary) {
    return binary.length != 32;
}

function bytes_from_binary(binary) {
    var bytes = new Array(4);

    // parse backwards, the least significant bit comes first
    for (var i = binary.length; i > 0; i -= 8) {
        var byte = "";
        for (var j = 0; j < 7; j++) {
            byte += binary[i - j - 1];
        }
        bytes[(i / 8) - 1] = parseInt(byte, 2);
    }

    return bytes;
}

function valid_bytes(bytes) {
    return bytes.length == 4;
}

// validate the Apple-specific ID
function valid_codes(bytes) {
    return bytes[0] == 0x77 && bytes[1] == 0x43;
}

// using the byte array, return a string name
var commands = {
    1: "menu",
    2: "center",
    3: "right",
    4: "left",
    5: "up",
    6: "down",
    46: "center",
    47: "play"
}

// switch between first and second generation maps
function command_id_from_bytes(bytes) {
    if (!commands[bytes[2]]) return;
    return { command : commands[bytes[2]], id : bytes[3] };
}

// a small implementation of the whole flow
function command_id_from_buffer(data) {

    // var chopped = data.toString('hex').match(/.{2}/g);
    var durations = durations_from_hex_buffer(data);

    if (!valid_leader(durations)) return;

    var binary = binary_from_durations(durations);
    if (!valid_binary(durations)) return;

    var bytes = bytes_from_binary(binary);
    if (!valid_bytes(bytes)) return;
    if (!valid_codes(bytes)) return;

    return command_id_from_bytes(bytes);
}

// determine whether or not the buffer is a valid continuation code
function continue_from_buffer(data) {

    var durations = durations_from_hex_buffer(data);

    var on = durations[0];
    var off = durations[1];
    var stop = durations[2];

    return (on > 8900 && on < 9150) &&
        (off > -2350 && off < -2100) &&
        (stop > 500 && stop < 650);
}

module.exports = function(port) {

    var ir = infrared.use(port);

    // on each data packet received, process the whole flow
    var button, ids = {}, id;
    ir.on('data', function(data) {

        // don't do any processing if we're just getting interference
        if (data.length < 6) return;

        // continues are short, buttons long
        if (data.length == 6) {
            // we can't send a continue if we miss the first button press
            if (button && continue_from_buffer(data)) {
                ir.emit(button + ".long");
                ir.emit(id + "." + button + ".long");
            }
        } else if (data.length == 134) {
            command_id = command_id_from_buffer(data);
            if (command_id) {
                button = command_id.command;
                if (id != command_id.id) {
                    id = command_id.id;
                    if (!ids[id]) ir.emit('id', id);
                    ids[id] = true;
                }
                ir.emit(button);
                ir.emit(id + "." + button);
            }
        }

    });

    return ir;
}

// expose additional functionality to allow for easy testing
module.exports.durations_from_hex_buffer = durations_from_hex_buffer;
module.exports.valid_leader = valid_leader;
module.exports.binary_from_durations = binary_from_durations;
module.exports.valid_binary = valid_binary;
module.exports.bytes_from_binary = bytes_from_binary;
module.exports.valid_bytes = valid_bytes;
module.exports.command_id_from_bytes = command_id_from_bytes;
module.exports.command_id_from_buffer = command_id_from_buffer;
module.exports.continue_from_buffer = continue_from_buffer;<commit_msg>re:#11, more perf gains, optimizing for loops, shaved another 10ms<commit_after>var infrared = require('ir-attx4');

// understanding the implementation:
// https://github.com/tessel/ir-attx4#api-infrared-on-data-callback-data-Emitted-when-an-infrared-signal-is-detected
// http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol
// http://en.wikipedia.org/wiki/Apple_Remote#Technical_details
// https://github.com/squeed/AppleRemoteSender/blob/master/AppleRemoteSender.cpp
// https://hifiduino.wordpress.com/apple-aluminum-remote/

// parse a Buffer|Array of 16 bit words into signed int durations
function durations_from_hex_buffer(buf) {
    // https://github.com/tessel/ir-attx4 sends off values through a two's complement system
    var len = buf.length;
    var durations = new Array(len / 2);
    for (var i = 0; i < len; i += 2) {
        durations[i / 2] = buf.readInt16BE(i);
    }
    return durations;
}

// validate the leader bit
function valid_leader(durations) {
    var on = durations[0];
    var off = durations[1];
    return !(on < 8900 || on > 9150 || off < -4600 || off > -4400);
}

function binary_from_durations(durations) {
    var binary = []
    // skip the leader, ignore the stop bit
    var len = durations.length - 1;
    for (var i = 2; i < len; i += 2) {
        var on = durations[i];
        var off = durations[i + 1];
        if (on >= 500 && on < 700) {
            if (off <= -500 && off >= -650) {
                binary.push(0);
            } else if (off < -1600 && off >= -1750) {
                binary.push(1);
            }
        }
    }

    return binary;
}

function valid_binary(binary) {
    return binary.length != 32;
}

function bytes_from_binary(binary) {
    var bytes = new Array(4);

    // parse backwards, the least significant bit comes first
    var len = binary.length;
    for (var i = len; i > 0; i -= 8) {
        var byte = "";
        for (var j = 0; j < 7; j++) {
            byte += binary[i - j - 1];
        }
        bytes[(i / 8) - 1] = parseInt(byte, 2);
    }

    return bytes;
}

function valid_bytes(bytes) {
    return bytes.length == 4;
}

// validate the Apple-specific ID
function valid_codes(bytes) {
    return bytes[0] == 0x77 && bytes[1] == 0x43;
}

// using the byte array, return a string name
var commands = {
    1: "menu",
    2: "center",
    3: "right",
    4: "left",
    5: "up",
    6: "down",
    46: "center",
    47: "play"
}

// switch between first and second generation maps
function command_id_from_bytes(bytes) {
    if (!commands[bytes[2]]) return;
    return { command : commands[bytes[2]], id : bytes[3] };
}

// a small implementation of the whole flow
function command_id_from_buffer(data) {

    // var chopped = data.toString('hex').match(/.{2}/g);
    var durations = durations_from_hex_buffer(data);

    if (!valid_leader(durations)) return;

    var binary = binary_from_durations(durations);
    if (!valid_binary(durations)) return;

    var bytes = bytes_from_binary(binary);
    if (!valid_bytes(bytes)) return;
    if (!valid_codes(bytes)) return;

    return command_id_from_bytes(bytes);
}

// determine whether or not the buffer is a valid continuation code
function continue_from_buffer(data) {

    var durations = durations_from_hex_buffer(data);

    var on = durations[0];
    var off = durations[1];
    var stop = durations[2];

    return (on > 8900 && on < 9150) &&
        (off > -2350 && off < -2100) &&
        (stop > 500 && stop < 650);
}

module.exports = function(port) {

    var ir = infrared.use(port);

    // on each data packet received, process the whole flow
    var button, ids = {}, id;
    ir.on('data', function(data) {

        // don't do any processing if we're just getting interference
        if (data.length < 6) return;

        // continues are short, buttons long
        if (data.length == 6) {
            // we can't send a continue if we miss the first button press
            if (button && continue_from_buffer(data)) {
                ir.emit(button + ".long");
                ir.emit(id + "." + button + ".long");
            }
        } else if (data.length == 134) {
            command_id = command_id_from_buffer(data);
            if (command_id) {
                button = command_id.command;
                if (id != command_id.id) {
                    id = command_id.id;
                    if (!ids[id]) ir.emit('id', id);
                    ids[id] = true;
                }
                ir.emit(button);
                ir.emit(id + "." + button);
            }
        }

    });

    return ir;
}

// expose additional functionality to allow for easy testing
module.exports.durations_from_hex_buffer = durations_from_hex_buffer;
module.exports.valid_leader = valid_leader;
module.exports.binary_from_durations = binary_from_durations;
module.exports.valid_binary = valid_binary;
module.exports.bytes_from_binary = bytes_from_binary;
module.exports.valid_bytes = valid_bytes;
module.exports.command_id_from_bytes = command_id_from_bytes;
module.exports.command_id_from_buffer = command_id_from_buffer;
module.exports.continue_from_buffer = continue_from_buffer;<|endoftext|>


<commit_before>#!/usr/bin/env node
var config = require('commander')
var express = require('express')
var IssueTypeRouter = require('./routes/issuetype_router')
var IssueRouter = require('./routes/issue_router')
var BoardRouter = require('./routes/board_router')
var SprintRouter = require('./routes/sprint_router')
var app = express()

config
  .version(require('./package.json').version)
  .option('-u, --user [username]', 'The JIRA username ($JIRA_USER)', process.env.JIRA_USER)
  .option('--password [password]', 'The JIRA password ($JIRA_PASS)', process.env.JIRA_PASS)
  .option('-h, --host [host]', 'The JIRA hostname ($JIRA_HOST)', process.env.JIRA_HOST)
  .parse(process.argv)

function validateOpts (config) {
  var errors = 0
  if (!config.user) {
    console.error('ERROR: Username required. Use -u/--user, or set $JIRA_USER')
    errors++
  }
  if (!config.password) {
    console.error('ERROR: Password required. Set $JIRA_PASS (or use --password)')
    errors++
  }
  if (!config.host) {
    console.error('ERROR: JIRA hostname required. Use -h/--host, or set $JIRA_HOST')
    errors++
  }

  if (errors) {
    process.exit(errors)
  }
}

validateOpts(config)

var issuetype_router = new IssueTypeRouter(config, express.Router())
var issue_router = new IssueRouter(config, express.Router())
var board_router = new BoardRouter(config, express.Router())
var sprint_router = new SprintRouter(config, express.Router())

app.use('/issuetypes', issuetype_router.routes())
app.use('/issues', issue_router.routes())
app.use('/boards', board_router.routes())
app.use('/sprints', sprint_router.routes())

app.use(express.static('public'))

var port = process.env.PORT || 3000

if (process.env.NODE_ENV !== 'test') {
  var server = app.listen(port, function () {
    var host = server.address().address
    var port = server.address().port

    console.log('jiraprinter listening at http://%s:%s', host, port)
  })
}

module.exports = app
<commit_msg>Renaming variables to camelCase to satisfy Standard v7<commit_after>#!/usr/bin/env node
var config = require('commander')
var express = require('express')
var IssueTypeRouter = require('./routes/issuetype_router')
var IssueRouter = require('./routes/issue_router')
var BoardRouter = require('./routes/board_router')
var SprintRouter = require('./routes/sprint_router')
var app = express()

config
  .version(require('./package.json').version)
  .option('-u, --user [username]', 'The JIRA username ($JIRA_USER)', process.env.JIRA_USER)
  .option('--password [password]', 'The JIRA password ($JIRA_PASS)', process.env.JIRA_PASS)
  .option('-h, --host [host]', 'The JIRA hostname ($JIRA_HOST)', process.env.JIRA_HOST)
  .parse(process.argv)

function validateOpts (config) {
  var errors = 0
  if (!config.user) {
    console.error('ERROR: Username required. Use -u/--user, or set $JIRA_USER')
    errors++
  }
  if (!config.password) {
    console.error('ERROR: Password required. Set $JIRA_PASS (or use --password)')
    errors++
  }
  if (!config.host) {
    console.error('ERROR: JIRA hostname required. Use -h/--host, or set $JIRA_HOST')
    errors++
  }

  if (errors) {
    process.exit(errors)
  }
}

validateOpts(config)

var issuetypeRouter = new IssueTypeRouter(config, express.Router())
var issueRouter = new IssueRouter(config, express.Router())
var boardRouter = new BoardRouter(config, express.Router())
var sprintRouter = new SprintRouter(config, express.Router())

app.use('/issuetypes', issuetypeRouter.routes())
app.use('/issues', issueRouter.routes())
app.use('/boards', boardRouter.routes())
app.use('/sprints', sprintRouter.routes())

app.use(express.static('public'))

var port = process.env.PORT || 3000

if (process.env.NODE_ENV !== 'test') {
  var server = app.listen(port, function () {
    var host = server.address().address
    var port = server.address().port

    console.log('jiraprinter listening at http://%s:%s', host, port)
  })
}

module.exports = app
<|endoftext|>


<commit_before>var spsave = require('spsave'),
    gutil = require('gulp-util'),
    PluginError = gutil.PluginError,
    path = require("path"),
	through = require("through2");

var PLUGIN_NAME = 'gulp-spsave';

function gulpspsave(options) {
    if (!options) {
        throw new PluginError(PLUGIN_NAME, 'Missing options');
    }

    return through.obj(function (file, enc, cb) {
        if (file.isNull()) {
            return cb();
        }

        if (file.isStream()) {
            this.emit('error', new PluginError(PLUGIN_NAME, 'Streaming not supported'));
            return cb();
        }

        if (file.isBuffer()) {
            options.fileName = path.basename(file.path);
            options.fileContent = file.contents.toString(enc);

			spsave(options, function(err, data){
				if(err){
					console.log(err);
					this.emit('error', new PluginError(PLUGIN_NAME, err.message));
				}

				return cb();
			});
        }
    });
}

module.exports = gulpspsave;<commit_msg>Fixed formatting.<commit_after>var spsave = require('spsave'),
    gutil = require('gulp-util'),
    PluginError = gutil.PluginError,
    path = require("path"),
	through = require("through2");

var PLUGIN_NAME = 'gulp-spsave';

function gulpspsave(options) {
	if (!options) {
		throw new PluginError(PLUGIN_NAME, 'Missing options');
	}

	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			return cb();
		}

		if (file.isStream()) {
			this.emit('error', new PluginError(PLUGIN_NAME, 'Streaming not supported'));
			return cb();
		}

		if (file.isBuffer()) {
			options.fileName = path.basename(file.path);
			options.fileContent = file.contents.toString(enc);

			spsave(options, function (err, data) {
				if (err) {
					console.log(err);
					this.emit('error', new PluginError(PLUGIN_NAME, err.message));
				}

				return cb();
			});
		}
	});
}

module.exports = gulpspsave;<|endoftext|>