<commit_before>/*!
 * fullnode.js - full node for bcoin
 * Copyright (c) 2014-2015, Fedor Indutny (MIT License)
 * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
 * https://github.com/bcoin-org/bcoin
 */

'use strict';

var util = require('../utils/util');
var co = require('../utils/co');
var Node = require('./node');
var Chain = require('../blockchain/chain');
var Fees = require('../mempool/fees');
var Mempool = require('../mempool/mempool');
var Pool = require('../net/pool');
var Miner = require('../mining/miner');
var WalletDB = require('../wallet/walletdb');
var HTTPServer = require('../http/server');
var policy = require('../protocol/policy');

/**
 * Respresents a fullnode complete with a
 * chain, mempool, miner, wallet, etc.
 * @alias module:node.FullNode
 * @extends Node
 * @constructor
 * @param {Object?} options
 * @property {Chain} chain
 * @property {PolicyEstimator} fees
 * @property {Mempool} mempool
 * @property {Pool} pool
 * @property {Miner} miner
 * @property {WalletDB} walletdb
 * @property {HTTPServer} http
 * @emits FullNode#block
 * @emits FullNode#tx
 * @emits FullNode#connect
 * @emits FullNode#disconnect
 * @emits FullNode#reset
 * @emits FullNode#error
 */

function FullNode(options) {
  if (!(this instanceof FullNode))
    return new FullNode(options);

  Node.call(this, options);

  // Instantiate blockchain.
  this.chain = new Chain({
    network: this.network,
    logger: this.logger,
    db: this.options.db,
    location: this.location('chain'),
    maxFiles: this.options.maxFiles,
    cacheSize: this.options.cacheSize,
    forceWitness: this.options.forceWitness,
    prune: this.options.prune,
    checkpoints: this.options.checkpoints,
    coinCache: this.options.coinCache,
    indexTX: this.options.indexTX,
    indexAddress: this.options.indexAddress
  });

  // Fee estimation.
  this.fees = new Fees(this.network, this.logger);
  this.fees.init();

  // Mempool needs access to the chain.
  this.mempool = new Mempool({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    fees: this.fees,
    db: this.options.db,
    location: this.location('mempool'),
    persistent: this.options.persistentMempool,
    maxSize: this.options.mempoolSize,
    limitFree: this.options.limitFree,
    limitFreeRelay: this.options.limitFreeRelay,
    requireStandard: this.options.requireStandard,
    rejectInsaneFees: this.options.rejectInsaneFees,
    replaceByFee: this.options.replaceByFee,
    indexAddress: this.options.indexAddress
  });

  // Pool needs access to the chain and mempool.
  this.pool = new Pool({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    mempool: this.mempool,
    selfish: this.options.selfish,
    compact: this.options.compact,
    bip37: this.options.bip37,
    bip151: this.options.bip151,
    bip150: this.options.bip150,
    authPeers: this.options.authPeers,
    knownPeers: this.options.knownPeers,
    identityKey: this.options.identityKey,
    maxOutbound: this.options.maxOutbound,
    maxInbound: this.options.maxInbound,
    proxy: this.options.proxy,
    onion: this.options.onion,
    seeds: this.options.seeds,
    nodes: this.options.nodes,
    publicHost: this.options.publicHost,
    publicPort: this.options.publicPort,
    host: this.options.host,
    port: this.options.port,
    listen: this.options.listen
  });

  // Miner needs access to the chain and mempool.
  this.miner = new Miner({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    mempool: this.mempool,
    fees: this.fees,
    address: this.options.payoutAddress,
    coinbaseFlags: this.options.coinbaseFlags,
    maxWeight: this.options.maxBlockWeight,
    reservedWeight: this.options.reservedBlockWeight,
    reservedSigops: this.options.reservedBlockSigops
  });

  // Wallet database needs access to fees.
  this.walletdb = new WalletDB({
    network: this.network,
    logger: this.logger,
    client: this.client,
    db: this.options.db,
    location: this.location('walletdb'),
    maxFiles: this.options.walletMaxFiles,
    cacheSize: this.options.walletCacheSize,
    witness: false,
    checkpoints: this.options.checkpoints,
    startHeight: this.options.startHeight,
    wipeNoReally: this.options.wipeNoReally,
    verify: false
  });

  // HTTP needs access to the node.
  if (!HTTPServer.unsupported) {
    this.http = new HTTPServer({
      network: this.network,
      logger: this.logger,
      node: this,
      key: this.options.sslKey,
      cert: this.options.sslCert,
      port: this.options.httpPort,
      host: this.options.httpHost,
      apiKey: this.options.apiKey,
      serviceKey: this.options.serviceKey,
      walletAuth: this.options.walletAuth,
      noAuth: this.options.noAuth
    });
  }

  this._init();
}

util.inherits(FullNode, Node);

/**
 * Initialize the node.
 * @private
 */

FullNode.prototype._init = function _init() {
  var self = this;
  var onError = this.error.bind(this);

  // Bind to errors
  this.chain.on('error', onError);
  this.mempool.on('error', onError);
  this.pool.on('error', onError);
  this.miner.on('error', onError);
  this.walletdb.on('error', onError);

  if (this.http)
    this.http.on('error', onError);

  this.mempool.on('tx', function(tx) {
    self.miner.notifyEntry();
    self.emit('tx', tx);
  });

  this.chain.on('connect', co(function* (entry, block) {
    if (self.chain.synced) {
      try {
        yield self.mempool.addBlock(entry, block.txs);
      } catch (e) {
        self.error(e);
      }
    }
    self.emit('block', block);
    self.emit('connect', entry, block);
  }));

  this.chain.on('disconnect', co(function* (entry, block) {
    if (self.chain.synced) {
      try {
        yield self.mempool.removeBlock(entry, block.txs);
      } catch (e) {
        self.error(e);
      }
    }
    self.emit('disconnect', entry, block);
  }));

  this.chain.on('reset', co(function* (tip) {
    try {
      yield self.mempool.reset();
    } catch (e) {
      self.error(e);
    }
    self.emit('reset', tip);
  }));
};

/**
 * Open the node and all its child objects,
 * wait for the database to load.
 * @alias FullNode#open
 * @returns {Promise}
 */

FullNode.prototype._open = co(function* open() {
  yield this.chain.open();
  yield this.mempool.open();
  yield this.miner.open();
  yield this.pool.open();
  yield this.walletdb.open();

  // Ensure primary wallet.
  yield this.openWallet();

  if (this.http)
    yield this.http.open();

  this.logger.info('Node is loaded.');
});

/**
 * Close the node, wait for the database to close.
 * @alias FullNode#close
 * @returns {Promise}
 */

FullNode.prototype._close = co(function* close() {
  if (this.http)
    yield this.http.close();

  yield this.wallet.destroy();

  this.wallet = null;

  yield this.walletdb.close();
  yield this.pool.close();
  yield this.miner.close();
  yield this.mempool.close();
  yield this.chain.close();

  this.logger.info('Node is closed.');
});

/**
 * Rescan for any missed transactions.
 * @param {Number|Hash} start - Start block.
 * @param {Bloom} filter
 * @param {Function} iter - Iterator.
 * @returns {Promise}
 */

FullNode.prototype.scan = function scan(start, filter, iter) {
  return this.chain.scan(start, filter, iter);
};

/**
 * Broadcast a transaction (note that this will _not_ be verified
 * by the mempool - use with care, lest you get banned from
 * bitcoind nodes).
 * @param {TX|Block} item
 * @returns {Promise}
 */

FullNode.prototype.broadcast = co(function* broadcast(item) {
  try {
    yield this.pool.broadcast(item);
  } catch (e) {
    this.emit('error', e);
  }
});

/**
 * Add transaction to mempool, broadcast.
 * @param {TX} tx
 */

FullNode.prototype.sendTX = co(function* sendTX(tx) {
  var missing;

  try {
    missing = yield this.mempool.addTX(tx);
  } catch (err) {
    if (err.type === 'VerifyError' && err.score === 0) {
      this.error(err);
      this.logger.warning('Verification failed for tx: %s.', tx.txid());
      this.logger.warning('Attempting to broadcast anyway...');
      this.broadcast(tx);
      return;
    }
    throw err;
  }

  if (missing) {
    this.logger.warning('TX was orphaned in mempool: %s.', tx.txid());
    this.logger.warning('Attempting to broadcast anyway...');
    this.broadcast(tx);
    return;
  }

  // We need to announce by hand if
  // we're running in selfish mode.
  if (this.pool.options.selfish)
    this.pool.broadcast(tx);
});

/**
 * Add transaction to mempool, broadcast. Silence errors.
 * @param {TX} tx
 * @returns {Promise}
 */

FullNode.prototype.relay = co(function* relay(tx) {
  try {
    yield this.sendTX(tx);
  } catch (e) {
    this.error(e);
  }
});

/**
 * Connect to the network.
 * @returns {Promise}
 */

FullNode.prototype.connect = function connect() {
  return this.pool.connect();
};

/**
 * Disconnect from the network.
 * @returns {Promise}
 */

FullNode.prototype.disconnect = function disconnect() {
  return this.pool.disconnect();
};

/**
 * Start the blockchain sync.
 */

FullNode.prototype.startSync = function startSync() {
  return this.pool.startSync();
};

/**
 * Stop syncing the blockchain.
 */

FullNode.prototype.stopSync = function stopSync() {
  return this.pool.stopSync();
};

/**
 * Retrieve a block from the chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link Block}.
 */

FullNode.prototype.getBlock = function getBlock(hash) {
  return this.chain.db.getBlock(hash);
};

/**
 * Retrieve a coin from the mempool or chain database.
 * Takes into account spent coins in the mempool.
 * @param {Hash} hash
 * @param {Number} index
 * @returns {Promise} - Returns {@link Coin}.
 */

FullNode.prototype.getCoin = function getCoin(hash, index) {
  var coin = this.mempool.getCoin(hash, index);

  if (coin)
    return Promise.resolve(coin);

  if (this.mempool.isSpent(hash, index))
    return Promise.resolve();

  return this.chain.db.getCoin(hash, index);
};

/**
 * Get coins that pertain to an address from the mempool or chain database.
 * Takes into account spent coins in the mempool.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link Coin}[].
 */

FullNode.prototype.getCoinsByAddress = co(function* getCoinsByAddress(addresses) {
  var mempool = this.mempool.getCoinsByAddress(addresses);
  var chain = yield this.chain.db.getCoinsByAddress(addresses);
  var out = [];
  var i, coin, spent;

  for (i = 0; i < chain.length; i++) {
    coin = chain[i];
    spent = this.mempool.isSpent(coin.hash, coin.index);

    if (spent)
      continue;

    out.push(coin);
  }

  for (i = 0; i < mempool.length; i++) {
    coin = mempool[i];
    out.push(coin);
  }

  return out;
});

/**
 * Retrieve transactions pertaining to an
 * address from the mempool or chain database.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link TXMeta}[].
 */

FullNode.prototype.getMetaByAddress = co(function* getTXByAddress(addresses) {
  var mempool = this.mempool.getMetaByAddress(addresses);
  var chain = yield this.chain.db.getMetaByAddress(addresses);
  return chain.concat(mempool);
});

/**
 * Retrieve a transaction from the mempool or chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link TXMeta}.
 */

FullNode.prototype.getMeta = co(function* getMeta(hash) {
  var meta = this.mempool.getMeta(hash);

  if (meta)
    return meta;

  return yield this.chain.db.getMeta(hash);
});

/**
 * Retrieve transactions pertaining to an
 * address from the mempool or chain database.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link TX}[].
 */

FullNode.prototype.getTXByAddress = co(function* getTXByAddress(addresses) {
  var mtxs = yield this.getMetaByAddress(addresses);
  var out = [];
  var i, mtx;

  for (i = 0; i < mtxs.length; i++) {
    mtx = mtxs[i];
    out.push(mtx.tx);
  }

  return out;
});

/**
 * Retrieve a transaction from the mempool or chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link TX}.
 */

FullNode.prototype.getTX = co(function* getTX(hash) {
  var mtx = yield this.getMeta(hash);
  if (!mtx)
    return;
  return mtx.tx;
});

/**
 * Test whether the mempool or chain contains a transaction.
 * @param {Hash} hash
 * @returns {Promise} - Returns Boolean.
 */

FullNode.prototype.hasTX = function hasTX(hash) {
  if (this.mempool.hasTX(hash))
    return Promise.resolve(true);

  return this.chain.db.hasTX(hash);
};

/*
 * Expose
 */

module.exports = FullNode;
<commit_msg>fullnode: minor.<commit_after>/*!
 * fullnode.js - full node for bcoin
 * Copyright (c) 2014-2015, Fedor Indutny (MIT License)
 * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
 * https://github.com/bcoin-org/bcoin
 */

'use strict';

var util = require('../utils/util');
var co = require('../utils/co');
var Node = require('./node');
var Chain = require('../blockchain/chain');
var Fees = require('../mempool/fees');
var Mempool = require('../mempool/mempool');
var Pool = require('../net/pool');
var Miner = require('../mining/miner');
var WalletDB = require('../wallet/walletdb');
var HTTPServer = require('../http/server');

/**
 * Respresents a fullnode complete with a
 * chain, mempool, miner, wallet, etc.
 * @alias module:node.FullNode
 * @extends Node
 * @constructor
 * @param {Object?} options
 * @property {Chain} chain
 * @property {PolicyEstimator} fees
 * @property {Mempool} mempool
 * @property {Pool} pool
 * @property {Miner} miner
 * @property {WalletDB} walletdb
 * @property {HTTPServer} http
 * @emits FullNode#block
 * @emits FullNode#tx
 * @emits FullNode#connect
 * @emits FullNode#disconnect
 * @emits FullNode#reset
 * @emits FullNode#error
 */

function FullNode(options) {
  if (!(this instanceof FullNode))
    return new FullNode(options);

  Node.call(this, options);

  // Instantiate blockchain.
  this.chain = new Chain({
    network: this.network,
    logger: this.logger,
    db: this.options.db,
    location: this.location('chain'),
    maxFiles: this.options.maxFiles,
    cacheSize: this.options.cacheSize,
    forceWitness: this.options.forceWitness,
    prune: this.options.prune,
    checkpoints: this.options.checkpoints,
    coinCache: this.options.coinCache,
    indexTX: this.options.indexTX,
    indexAddress: this.options.indexAddress
  });

  // Fee estimation.
  this.fees = new Fees(this.network, this.logger);
  this.fees.init();

  // Mempool needs access to the chain.
  this.mempool = new Mempool({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    fees: this.fees,
    db: this.options.db,
    location: this.location('mempool'),
    persistent: this.options.persistentMempool,
    maxSize: this.options.mempoolSize,
    limitFree: this.options.limitFree,
    limitFreeRelay: this.options.limitFreeRelay,
    requireStandard: this.options.requireStandard,
    rejectInsaneFees: this.options.rejectInsaneFees,
    replaceByFee: this.options.replaceByFee,
    indexAddress: this.options.indexAddress
  });

  // Pool needs access to the chain and mempool.
  this.pool = new Pool({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    mempool: this.mempool,
    selfish: this.options.selfish,
    compact: this.options.compact,
    bip37: this.options.bip37,
    bip151: this.options.bip151,
    bip150: this.options.bip150,
    authPeers: this.options.authPeers,
    knownPeers: this.options.knownPeers,
    identityKey: this.options.identityKey,
    maxOutbound: this.options.maxOutbound,
    maxInbound: this.options.maxInbound,
    proxy: this.options.proxy,
    onion: this.options.onion,
    seeds: this.options.seeds,
    nodes: this.options.nodes,
    publicHost: this.options.publicHost,
    publicPort: this.options.publicPort,
    host: this.options.host,
    port: this.options.port,
    listen: this.options.listen
  });

  // Miner needs access to the chain and mempool.
  this.miner = new Miner({
    network: this.network,
    logger: this.logger,
    chain: this.chain,
    mempool: this.mempool,
    fees: this.fees,
    address: this.options.payoutAddress,
    coinbaseFlags: this.options.coinbaseFlags,
    maxWeight: this.options.maxBlockWeight,
    reservedWeight: this.options.reservedBlockWeight,
    reservedSigops: this.options.reservedBlockSigops
  });

  // Wallet database needs access to fees.
  this.walletdb = new WalletDB({
    network: this.network,
    logger: this.logger,
    client: this.client,
    db: this.options.db,
    location: this.location('walletdb'),
    maxFiles: this.options.walletMaxFiles,
    cacheSize: this.options.walletCacheSize,
    witness: false,
    checkpoints: this.options.checkpoints,
    startHeight: this.options.startHeight,
    wipeNoReally: this.options.wipeNoReally,
    verify: false
  });

  // HTTP needs access to the node.
  if (!HTTPServer.unsupported) {
    this.http = new HTTPServer({
      network: this.network,
      logger: this.logger,
      node: this,
      key: this.options.sslKey,
      cert: this.options.sslCert,
      port: this.options.httpPort,
      host: this.options.httpHost,
      apiKey: this.options.apiKey,
      serviceKey: this.options.serviceKey,
      walletAuth: this.options.walletAuth,
      noAuth: this.options.noAuth
    });
  }

  this._init();
}

util.inherits(FullNode, Node);

/**
 * Initialize the node.
 * @private
 */

FullNode.prototype._init = function _init() {
  var self = this;
  var onError = this.error.bind(this);

  // Bind to errors
  this.chain.on('error', onError);
  this.mempool.on('error', onError);
  this.pool.on('error', onError);
  this.miner.on('error', onError);
  this.walletdb.on('error', onError);

  if (this.http)
    this.http.on('error', onError);

  this.mempool.on('tx', function(tx) {
    self.miner.notifyEntry();
    self.emit('tx', tx);
  });

  this.chain.on('connect', co(function* (entry, block) {
    if (self.chain.synced) {
      try {
        yield self.mempool.addBlock(entry, block.txs);
      } catch (e) {
        self.error(e);
      }
    }
    self.emit('block', block);
    self.emit('connect', entry, block);
  }));

  this.chain.on('disconnect', co(function* (entry, block) {
    if (self.chain.synced) {
      try {
        yield self.mempool.removeBlock(entry, block.txs);
      } catch (e) {
        self.error(e);
      }
    }
    self.emit('disconnect', entry, block);
  }));

  this.chain.on('reset', co(function* (tip) {
    try {
      yield self.mempool.reset();
    } catch (e) {
      self.error(e);
    }
    self.emit('reset', tip);
  }));
};

/**
 * Open the node and all its child objects,
 * wait for the database to load.
 * @alias FullNode#open
 * @returns {Promise}
 */

FullNode.prototype._open = co(function* open() {
  yield this.chain.open();
  yield this.mempool.open();
  yield this.miner.open();
  yield this.pool.open();
  yield this.walletdb.open();

  // Ensure primary wallet.
  yield this.openWallet();

  if (this.http)
    yield this.http.open();

  this.logger.info('Node is loaded.');
});

/**
 * Close the node, wait for the database to close.
 * @alias FullNode#close
 * @returns {Promise}
 */

FullNode.prototype._close = co(function* close() {
  if (this.http)
    yield this.http.close();

  yield this.wallet.destroy();

  this.wallet = null;

  yield this.walletdb.close();
  yield this.pool.close();
  yield this.miner.close();
  yield this.mempool.close();
  yield this.chain.close();

  this.logger.info('Node is closed.');
});

/**
 * Rescan for any missed transactions.
 * @param {Number|Hash} start - Start block.
 * @param {Bloom} filter
 * @param {Function} iter - Iterator.
 * @returns {Promise}
 */

FullNode.prototype.scan = function scan(start, filter, iter) {
  return this.chain.scan(start, filter, iter);
};

/**
 * Broadcast a transaction (note that this will _not_ be verified
 * by the mempool - use with care, lest you get banned from
 * bitcoind nodes).
 * @param {TX|Block} item
 * @returns {Promise}
 */

FullNode.prototype.broadcast = co(function* broadcast(item) {
  try {
    yield this.pool.broadcast(item);
  } catch (e) {
    this.emit('error', e);
  }
});

/**
 * Add transaction to mempool, broadcast.
 * @param {TX} tx
 */

FullNode.prototype.sendTX = co(function* sendTX(tx) {
  var missing;

  try {
    missing = yield this.mempool.addTX(tx);
  } catch (err) {
    if (err.type === 'VerifyError' && err.score === 0) {
      this.error(err);
      this.logger.warning('Verification failed for tx: %s.', tx.txid());
      this.logger.warning('Attempting to broadcast anyway...');
      this.broadcast(tx);
      return;
    }
    throw err;
  }

  if (missing) {
    this.logger.warning('TX was orphaned in mempool: %s.', tx.txid());
    this.logger.warning('Attempting to broadcast anyway...');
    this.broadcast(tx);
    return;
  }

  // We need to announce by hand if
  // we're running in selfish mode.
  if (this.pool.options.selfish)
    this.pool.broadcast(tx);
});

/**
 * Add transaction to mempool, broadcast. Silence errors.
 * @param {TX} tx
 * @returns {Promise}
 */

FullNode.prototype.relay = co(function* relay(tx) {
  try {
    yield this.sendTX(tx);
  } catch (e) {
    this.error(e);
  }
});

/**
 * Connect to the network.
 * @returns {Promise}
 */

FullNode.prototype.connect = function connect() {
  return this.pool.connect();
};

/**
 * Disconnect from the network.
 * @returns {Promise}
 */

FullNode.prototype.disconnect = function disconnect() {
  return this.pool.disconnect();
};

/**
 * Start the blockchain sync.
 */

FullNode.prototype.startSync = function startSync() {
  return this.pool.startSync();
};

/**
 * Stop syncing the blockchain.
 */

FullNode.prototype.stopSync = function stopSync() {
  return this.pool.stopSync();
};

/**
 * Retrieve a block from the chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link Block}.
 */

FullNode.prototype.getBlock = function getBlock(hash) {
  return this.chain.db.getBlock(hash);
};

/**
 * Retrieve a coin from the mempool or chain database.
 * Takes into account spent coins in the mempool.
 * @param {Hash} hash
 * @param {Number} index
 * @returns {Promise} - Returns {@link Coin}.
 */

FullNode.prototype.getCoin = function getCoin(hash, index) {
  var coin = this.mempool.getCoin(hash, index);

  if (coin)
    return Promise.resolve(coin);

  if (this.mempool.isSpent(hash, index))
    return Promise.resolve();

  return this.chain.db.getCoin(hash, index);
};

/**
 * Get coins that pertain to an address from the mempool or chain database.
 * Takes into account spent coins in the mempool.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link Coin}[].
 */

FullNode.prototype.getCoinsByAddress = co(function* getCoinsByAddress(addresses) {
  var mempool = this.mempool.getCoinsByAddress(addresses);
  var chain = yield this.chain.db.getCoinsByAddress(addresses);
  var out = [];
  var i, coin, spent;

  for (i = 0; i < chain.length; i++) {
    coin = chain[i];
    spent = this.mempool.isSpent(coin.hash, coin.index);

    if (spent)
      continue;

    out.push(coin);
  }

  for (i = 0; i < mempool.length; i++) {
    coin = mempool[i];
    out.push(coin);
  }

  return out;
});

/**
 * Retrieve transactions pertaining to an
 * address from the mempool or chain database.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link TXMeta}[].
 */

FullNode.prototype.getMetaByAddress = co(function* getTXByAddress(addresses) {
  var mempool = this.mempool.getMetaByAddress(addresses);
  var chain = yield this.chain.db.getMetaByAddress(addresses);
  return chain.concat(mempool);
});

/**
 * Retrieve a transaction from the mempool or chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link TXMeta}.
 */

FullNode.prototype.getMeta = co(function* getMeta(hash) {
  var meta = this.mempool.getMeta(hash);

  if (meta)
    return meta;

  return yield this.chain.db.getMeta(hash);
});

/**
 * Retrieve transactions pertaining to an
 * address from the mempool or chain database.
 * @param {Address} addresses
 * @returns {Promise} - Returns {@link TX}[].
 */

FullNode.prototype.getTXByAddress = co(function* getTXByAddress(addresses) {
  var mtxs = yield this.getMetaByAddress(addresses);
  var out = [];
  var i, mtx;

  for (i = 0; i < mtxs.length; i++) {
    mtx = mtxs[i];
    out.push(mtx.tx);
  }

  return out;
});

/**
 * Retrieve a transaction from the mempool or chain database.
 * @param {Hash} hash
 * @returns {Promise} - Returns {@link TX}.
 */

FullNode.prototype.getTX = co(function* getTX(hash) {
  var mtx = yield this.getMeta(hash);
  if (!mtx)
    return;
  return mtx.tx;
});

/**
 * Test whether the mempool or chain contains a transaction.
 * @param {Hash} hash
 * @returns {Promise} - Returns Boolean.
 */

FullNode.prototype.hasTX = function hasTX(hash) {
  if (this.mempool.hasTX(hash))
    return Promise.resolve(true);

  return this.chain.db.hasTX(hash);
};

/*
 * Expose
 */

module.exports = FullNode;
<|endoftext|>


<commit_before>var basic = require('./basic');
var prime = exports;

/**
 * Determine if number is prime.  This is far from high performance.
 *
 * @param {Number} number to evaluate
 * @return {Boolean} return true if value is prime. false otherwise.
 */
prime.simple = function (val) {
  if (val === 1) return false;
  else if (val === 2) return true;
  else if (val !== undefined) {
    var start = 1;
    var valSqrt = Math.ceil(Math.sqrt(val));
    while (++start <= valSqrt) {
      if (val % start === 0) {
        return false;
      }
    }
    return true;
  }
};

/**
 * Using trial method, evaluate the prime factorization of a value.
 *
 * Note: incredibly slow.
 *
 * @param {Number} number to evaluate
 * @param {Number} Max number of attempts
 * @return {Array|Boolean} array of prime factors for value; false if no set was found.
 */
prime.factorization = function (num, max) {
  if (num === 1) return [1];
  if (prime.simple(num)) return [num];

  var primes = [],
      result = [],
      temp   = [1],
      quant;

  for (var i = 0 ; i < num; i++) {
    if (prime.simple(i)) primes.push(i);
  }

  while(basic.product(temp) !== num && max > 0) {
    max--;
    quant = Math.ceil(Math.random() * (primes.length-1));
    temp = basic.random(primes, quant, true);
  }

  return (max > 0 || basic.product(temp) === num) ? temp : false;
};
<commit_msg>Optimized `prime.factorization()`<commit_after>var basic = require('./basic');
var prime = exports;

/**
 * Determine if number is prime.  This is far from high performance.
 *
 * @param {Number} number to evaluate
 * @return {Boolean} return true if value is prime. false otherwise.
 */
prime.simple = function (val) {
  if (val === 1) return false;
  else if (val === 2) return true;
  else if (val !== undefined) {
    var start = 1;
    var valSqrt = Math.ceil(Math.sqrt(val));
    while (++start <= valSqrt) {
      if (val % start === 0) {
        return false;
      }
    }
    return true;
  }
};

/**
 * Returns the prime factors of a number. <br/>
 * More info (http://bateru.com/news/2012/05/code-of-the-day-javascript-prime-factors-of-a-number/)
 * Taken from https://github.com/LarryBattle/Ratio.js
 *
 * @param {Number} num
 * @return {Array} an array of numbers
 * @example
prime.factorization(20).join(',') === "2,2,5"
 **/
prime.factorization = function (num) {
  num = Math.floor(num);
	var root,
	factors = [],
	x,
	sqrt = Math.sqrt,
	doLoop = 1 < num && isFinite(num);
	while (doLoop) {
		root = sqrt(num);
		x = 2;
		if (num % x) {
			x = 3;
			while ((num % x) && ((x += 2) < root)) {}
		}
		x = (root < x) ? num : x;
		factors.push(x);
		doLoop = (x !== num);
		num /= x;
	}
	return factors;
};
<|endoftext|>


<commit_before>/**
 * @license
 * js-sorting <http://github.com/Tyriar/js-sorting>
 * Copyright 2014 Daniel Imms <http://www.growingwiththeweb.com>
 * Released under the MIT license <http://github.com/Tyriar/js-sorting/blob/master/LICENSE>
 */
'use strict';

var attachObserver = require('./common/attach-observer');
var defaultCompare = require('./common/default-compare');
var defaultSwap = require('./common/default-swap');

/**
 * Compares every second element of an array with its following element and
 * swaps it if not in order using a compare function.
 * @param {function} compare The compare function.
 * @param {function} swap A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
function innerSort(array, i, compare, swap) {
  var sorted = true;
  for (; i < array.length - 1; i += 2) {
    if (compare(array[i], array[i + 1]) > 0) {
      swap(array, i, i + 1);
      sorted = false;
    }
  }
  return sorted;
}

/**
 * Sorts an array using odd even sort.
 * @param {Array} array The array to sort.
 * @param {function} compare The compare function.
 * @param {function} swap A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
function sort(array, compare, swap) {
  var sorted = false;
  while (!sorted) {
    sorted = innerSort(array, 1, compare, swap);
    sorted = sorted && innerSort(array, 0, compare, swap);
  }
  return array;
}

/**
 * Sorts an array using odd even sort.
 * @param {Array} array The array to sort.
 * @param {function} customCompare A custom compare function.
 * @param {function} swapObserver A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
module.exports = function (array, customCompare, swapObserver) {
  var compare = customCompare || defaultCompare;
  var swap = attachObserver(defaultSwap, swapObserver);
  return sort(array, compare, swap);
};
<commit_msg>Add missing jsdoc argument<commit_after>/**
 * @license
 * js-sorting <http://github.com/Tyriar/js-sorting>
 * Copyright 2014 Daniel Imms <http://www.growingwiththeweb.com>
 * Released under the MIT license <http://github.com/Tyriar/js-sorting/blob/master/LICENSE>
 */
'use strict';

var attachObserver = require('./common/attach-observer');
var defaultCompare = require('./common/default-compare');
var defaultSwap = require('./common/default-swap');

/**
 * Compares every second element of an array with its following element and
 * swaps it if not in order using a compare function.
 * @param {Array} array The array to sort.
 * @param {number} i The index to start at, should be either 0 or 1.
 * @param {function} compare The compare function.
 * @param {function} swap A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
function innerSort(array, i, compare, swap) {
  var sorted = true;
  for (; i < array.length - 1; i += 2) {
    if (compare(array[i], array[i + 1]) > 0) {
      swap(array, i, i + 1);
      sorted = false;
    }
  }
  return sorted;
}

/**
 * Sorts an array using odd even sort.
 * @param {Array} array The array to sort.
 * @param {function} compare The compare function.
 * @param {function} swap A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
function sort(array, compare, swap) {
  var sorted = false;
  while (!sorted) {
    sorted = innerSort(array, 1, compare, swap);
    sorted = sorted && innerSort(array, 0, compare, swap);
  }
  return array;
}

/**
 * Sorts an array using odd even sort.
 * @param {Array} array The array to sort.
 * @param {function} customCompare A custom compare function.
 * @param {function} swapObserver A function to call when the swap operation is
 * performed. This can be used to listen in on internals of the algorithm.
 * @returns The sorted array.
 */
module.exports = function (array, customCompare, swapObserver) {
  var compare = customCompare || defaultCompare;
  var swap = attachObserver(defaultSwap, swapObserver);
  return sort(array, compare, swap);
};
<|endoftext|>


<commit_before>'use strict';

var remove        = require('es5-ext/array/#/remove')
  , isBoolean     = require('es5-ext/boolean/is-boolean')
  , copyDeep      = require('es5-ext/object/copy-deep')
  , forEach       = require('es5-ext/object/for-each')
  , contains      = require('es5-ext/string/#/contains')
  , hyphenToCamel = require('es5-ext/string/#/hyphen-to-camel')
  , startsWith    = require('es5-ext/string/#/starts-with')
  , resolve       = require('path').resolve
  , toList        = require('./to-list')

  , isArray = Array.isArray, push = Array.prototype.push
  , call = Function.prototype.call, trim = call.bind(String.prototype.trim)

  , nameRe = /^(!?)([a-z](?:-?[a-z0-9:._]+)*)([+\-]?)(?:\s+|$)/
  , newFileStartRe = /^\.[\\\/]/
  , addPath, extendOption;

addPath = function (conf, path, opts) {
	if (!conf.hasOwnProperty(path)) {
		conf[path] = opts;
		return;
	}
	forEach(opts, function (value, name) {
		extendOption(conf[path], name, value);
	});
};

extendOption = function (conf, name, value) {
	if (!conf.hasOwnProperty(name) || !value.mod || !isArray(conf[name])) {
		conf[name] = value;
		return;
	}
	if (conf[name].mod) {
		push.apply(conf[name], value);
		return;
	}
	value.forEach(function (data) {
		if (data.action === 'add') push.apply(this, data.value);
		else remove.apply(this, data.value);
	}, conf[name]);
};

module.exports = function (data, path) {
	var opts = {}, ignore, lastPathLine, workingPath, currentPath, optsList = []
	  , currentOpts;

	data = String(data);
	if (!data) return opts;

	data = data.trim().split('\n').map(trim).map(function (line) {
		return line.replace(/#[\0-\uffff]*$/, '').trim();
	});

	while (!data[0]) data.shift();

	if (data[0] === '@root') {
		opts.root = true;
		data.shift();
	}

	workingPath = path;
	data.forEach(function (line) {
		var name, value, match, nuPath;

		if (newFileStartRe.test(line)) {
			nuPath = resolve(path, line);
			if (!startsWith.call(nuPath, path)) {
				console.error("Cannot set options for outer path: '" + line + "' in " +
					resolve(path, '.lint') + " (section ignored)");
				ignore = true;
			} else {
				ignore = false;
			}
			if (lastPathLine) workingPath += '\x08' + nuPath;
			else workingPath = nuPath;
			lastPathLine = true;
			return;
		}

		lastPathLine = false;
		if (!line || ignore) return;

		match = line.match(nameRe);
		if (!match) {
			console.error("Unrecognized option: '" + line + "' in " +
				resolve(path, '.lint') + " (rule ignored)");
			return;
		}

		name = match[2];
		value = line.slice(match[0].length).trim() || true;

		if (match[1]) {
			if (value !== true) {
				console.error("Negation of not boolean option: '" + name + "' in " +
					resolve(path, '.lint') + " (rule ignored)");
				return;
			}
			value = false;
		}

		if (match[3] && isBoolean(value)) {
			console.error("+/- instruction for non list option: '" + name +
				"' in " + resolve(path, '.lint') + " (rule ignored)");
			return;
		}

		if (workingPath !== currentPath) {
			optsList.push({ path: workingPath, opts: currentOpts = {} });
			currentPath = workingPath;
		}

		if (match[3]) {
			value = toList(value);
			value = [{ action: (match[3] === '+') ? 'add' : 'remove', value: value }];
			value.mod = true;
		} else if (contains.call(value, ',')) {
			value = toList(value);
		}
		extendOption(currentOpts, hyphenToCamel.call(name), value);
	});

	optsList.forEach(function (data) {
		var index = data.path.indexOf('\x08');
		if (index === -1) {
			addPath(opts, data.path, data.opts);
			return;
		}
		data.path.split('\x08').forEach(function (path) {
			addPath(opts, path, copyDeep(data.opts));
		});
	});

	return opts;
};
<commit_msg>Assure no data override<commit_after>'use strict';

var aFrom         = require('es5-ext/array/from')
  , remove        = require('es5-ext/array/#/remove')
  , isBoolean     = require('es5-ext/boolean/is-boolean')
  , copy          = require('es5-ext/object/copy')
  , forEach       = require('es5-ext/object/for-each')
  , contains      = require('es5-ext/string/#/contains')
  , hyphenToCamel = require('es5-ext/string/#/hyphen-to-camel')
  , startsWith    = require('es5-ext/string/#/starts-with')
  , resolve       = require('path').resolve
  , toList        = require('./to-list')

  , isArray = Array.isArray, push = Array.prototype.push
  , call = Function.prototype.call, trim = call.bind(String.prototype.trim)

  , nameRe = /^(!?)([a-z](?:-?[a-z0-9:._]+)*)([+\-]?)(?:\s+|$)/
  , newFileStartRe = /^\.[\\\/]/
  , addPath, extendOption;

addPath = function (conf, path, opts) {
	if (!conf.hasOwnProperty(path)) {
		conf[path] = copy(opts);
		return;
	}
	forEach(opts, function (value, name) {
		extendOption(conf[path], name, value);
	});
};

extendOption = function (conf, name, value) {
	if (!conf.hasOwnProperty(name) || !value.mod || !isArray(conf[name])) {
		conf[name] = value;
		return;
	}
	if (conf[name].mod) {
		conf[name] = conf[name].concat(value);
		conf[name].mod = true;
		return;
	}
	conf[name] = aFrom(conf[name]);
	value.forEach(function (data) {
		if (data.action === 'add') push.apply(this, data.value);
		else remove.apply(this, data.value);
	}, conf[name]);
};

module.exports = function (data, path) {
	var opts = {}, ignore, lastPathLine, workingPath, currentPath, optsList = []
	  , currentOpts;

	data = String(data);
	if (!data) return opts;

	data = data.trim().split('\n').map(trim).map(function (line) {
		return line.replace(/#[\0-\uffff]*$/, '').trim();
	});

	while (!data[0]) data.shift();

	if (data[0] === '@root') {
		opts.root = true;
		data.shift();
	}

	workingPath = path;
	data.forEach(function (line) {
		var name, value, match, nuPath;

		if (newFileStartRe.test(line)) {
			nuPath = resolve(path, line);
			if (!startsWith.call(nuPath, path)) {
				console.error("Cannot set options for outer path: '" + line + "' in " +
					resolve(path, '.lint') + " (section ignored)");
				ignore = true;
			} else {
				ignore = false;
			}
			if (lastPathLine) workingPath += '\x08' + nuPath;
			else workingPath = nuPath;
			lastPathLine = true;
			return;
		}

		lastPathLine = false;
		if (!line || ignore) return;

		match = line.match(nameRe);
		if (!match) {
			console.error("Unrecognized option: '" + line + "' in " +
				resolve(path, '.lint') + " (rule ignored)");
			return;
		}

		name = match[2];
		value = line.slice(match[0].length).trim() || true;

		if (match[1]) {
			if (value !== true) {
				console.error("Negation of not boolean option: '" + name + "' in " +
					resolve(path, '.lint') + " (rule ignored)");
				return;
			}
			value = false;
		}

		if (match[3] && isBoolean(value)) {
			console.error("+/- instruction for non list option: '" + name +
				"' in " + resolve(path, '.lint') + " (rule ignored)");
			return;
		}

		if (workingPath !== currentPath) {
			optsList.push({ path: workingPath, opts: currentOpts = {} });
			currentPath = workingPath;
		}

		if (match[3]) {
			value = toList(value);
			value = [{ action: (match[3] === '+') ? 'add' : 'remove', value: value }];
			value.mod = true;
		} else if (contains.call(value, ',')) {
			value = toList(value);
		}
		extendOption(currentOpts, hyphenToCamel.call(name), value);
	});

	optsList.forEach(function (data) {
		var index = data.path.indexOf('\x08');
		if (index === -1) {
			addPath(opts, data.path, data.opts);
			return;
		}
		data.path.split('\x08').forEach(function (path) {
			addPath(opts, path, data.opts);
		});
	});

	return opts;
};
<|endoftext|>


<commit_before>'use strict';

var Promise = require('bluebird');

var parsers = {
  npm: {
    name: 'NPM',
    type: 'manifest',
    parser: require('./npm'),
    filter: path => path.match(/^package\.json$/)
  },
  cpanMetaYML: {
    name: 'CPAN',
    type: 'manifest',
    parser: require('./cpan-meta-yml'),
    filter: path => path.match(/^META\.yml$/)
  },
  cpanMetaJSON: {
    name: 'CPAN',
    type: 'manifest',
    parser: require('./cpan-meta-json'),
    filter: path => path.match(/^META\.json$/)
  },
  cran: {
    name: 'CRAN',
    type: 'manifest',
    parser: require('./cran'),
    filter: path => path.match(/^DESCRIPTION$/)
  },
  npmshrinkwrap: {
    name: 'NPM',
    type: 'lockfile',
    parser: require('./npm-shrinkwrap'),
    filter: path => path.match(/^npm-shrinkwrap\.json$/)
  },
  rubygems: {
    name: 'Rubygems',
    type: 'manifest',
    parser: require('./rubygems'),
    filter: path => path.match(/^Gemfile$|^gems\.rb$/)
  },
  rubygemslockfile: {
    name: 'Rubygems',
    type: 'lockfile',
    parser: require('./rubygems-lockfile'),
    filter: path => path.match(/^Gemfile\.lock$|^gems\.locked$/)
  },
  gemspec: {
    name: 'Rubygems',
    type: 'gemspec',
    parser: require('./gemspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.gemspec$/)
  },
  podspec: {
    name: 'Cocoapods',
    type: 'podspec',
    parser: require('./podspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.podspec$/)
  },
  podspecJson: {
    name: 'Cocoapods',
    type: 'podspec',
    parser: require('./podspec-json'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.podspec.json$/)
  },
  packagist: {
    name: 'Packagist',
    type: 'manifest',
    parser: require('./packagist'),
    filter: path => path.match(/^composer\.json$/)
  },
  packagistlockfile: {
    name: 'Packagist',
    type: 'lockfile',
    parser: require('./packagist-lockfile'),
    filter: path => path.match(/^composer\.lock$/)
  },
  cargo: {
    name: 'Cargo',
    type: 'manifest',
    parser: require('./cargo'),
    filter: path => path.match(/^Cargo\.toml$/)
  },
  cargolockfile: {
    name: 'Cargo',
    type: 'lockfile',
    parser: require('./cargo-lock'),
    filter: path => path.match(/^Cargo\.lock$/)
  },
  elm: {
    name: 'Elm',
    type: 'manifest',
    parser: require('./elm'),
    filter: path => path.match(/^elm-package\.json$|^elm_dependencies\.json$/)
  },
  elmExact: {
    name: 'Elm',
    type: 'lockfile',
    parser: require('./elm-exact'),
    filter: path => path.match(/^elm-stuff\/exact-dependencies\.json$/)
  },
  bower: {
    name: 'Bower',
    type: 'manifest',
    parser: require('./bower'),
    filter: path => path.match(/^bower\.json$/)
  },
  dub:{
    name: 'Dub',
    type: 'manifest',
    parser: require('./dub'),
    filter: path => path.match(/^dub\.json$/)
  },
  dubSdl:{
    name: 'Dub',
    type: 'manifest',
    parser: require('./dub-sdl'),
    filter: path => path.match(/^dub\.sdl$/)
  },
  pub: {
    name: 'Pub',
    type: 'manifest',
    parser: require('./pub'),
    filter: path => path.match(/^pubspec\.yaml$/)
  },
  publock: {
    name: 'Pub',
    type: 'lockfile',
    parser: require('./publock'),
    filter: path => path.match(/^pubspec\.lock$/)
  },
  clojars: {
    name: 'Clojars',
    type: 'manifest',
    parser: require('./clojars'),
    filter: path => path.match(/^project\.clj$/)
  },
  hex: {
    name: 'Hex',
    type: 'manifest',
    parser: require('./hex'),
    filter: path => path.match(/^mix\.exs$/)
  },
  hexLock: {
    name: 'Hex',
    type: 'lockfile',
    parser: require('./hex-lock'),
    filter: path => path.match(/^mix\.lock$/)
  },
  pypi: {
    name: 'PyPI',
    type: 'manifest',
    parser: require('./pypi'),
    filter: path =>
      path.match(/require.*\.(txt|pip)$/) && !path.match(/^node_modules/)
  },
  pypiSetup: {
    name: 'PyPI',
    type: 'manifest',
    parser: require('./pypi-setup'),
    filter: path => path.match(/^setup\.py$/)
  },
  cocoapods: {
    name: 'CocoaPods',
    type: 'manifest',
    parser: require('./cocoapods'),
    filter: path => path.match(/^Podfile$/)
  },
  cocoapodsLockfile: {
    name: 'CocoaPods',
    type: 'lockfile',
    parser: require('./cocoapods-lockfile'),
    filter: path => path.match(/^Podfile\.lock$/)
  },
  nuget: {
    name: 'NuGet',
    type: 'manifest',
    parser: require('./nuget'),
    filter: path => path.match(/Project\.json$/)
  },
  nugetLockfile: {
    name: 'NuGet',
    type: 'lockfile',
    parser: require('./nuget-lockfile'),
    filter: path => path.match(/Project\.lock\.json$/)
  },
  nugetPackages: {
    name: 'NuGet',
    type: 'manifest',
    parser: require('./nuget-packages'),
    filter: path => path.match(/packages\.config$/)
  },
  nuspec: {
    name: 'Nuspec',
    type: 'manifest',
    parser: require('./nuspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.nuspec$/)
  },
  julia: {
    parser: require('./julia'),
    filter: path => path.match(/^REQUIRE$/)
  },
  meteor: {
    parser: require('./meteor'),
    filter: path => path.match(/^versions\.json$/)
  },
  go: {
    name: 'Go',
    type: 'manifest',
    parser: require('./godeps'),
    filter: path => path.match(/^Godeps\/Godeps\.json$/)
  },
  glide: {
    name: 'Go',
    type: 'manifest',
    parser: require('./glide'),
    filter: path => path.match(/^glide\.yaml$/)
  },
  glidelockfile: {
    name: 'Go',
    type: 'lockfile',
    parser: require('./glidelockfile'),
    filter: path => path.match(/^glide\.lock$/)
  },
  cartfile: {
    name: 'Carthage',
    type: 'manifest',
    parser: require('./cartfile'),
    filter: path => path.match(/^Cartfile$/)
  },
  cartfileprivate: {
    name: 'Carthage',
    type: 'manifest',
    parser: require('./cartfileprivate'),
    filter: path => path.match(/^Cartfile\.private$/)
  },
  cartfileresolved: {
    name: 'Carthage',
    type: 'lockfile',
    parser: require('./cartfileresolved'),
    filter: path => path.match(/^Cartfile\.resolved$/)
  },
  maven: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./maven'),
    filter: path => path.match(/pom\.xml$/i)
  },
  ivy: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./ivy'),
    filter: path => path.match(/ivy\.xml$/i)
  },
  gradle: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./gradle'),
    filter: path => path.match(/build\.gradle$/i)
  },
  shard: {
    name: 'Shards',
    type: 'manifest',
    parser: require('./shard'),
    filter: path => path.match(/shard\.yml$/i)
  },
  shardLockfile: {
    name: 'Shards',
    type: 'lockfile',
    parser: require('./shard-lockfile'),
    filter: path => path.match(/^shard\.lock$/i)
  },
  swift: {
    name: 'Swift',
    type: 'manifest',
    parser: require('./swift'),
    filter: path => path.match(/^Package\.swift$/i)
  }
};

var parse = function(platformName, str) {
  var platform = parsers[platformName];
  if (!platform) return Promise.reject('Invalid platform');

  return Promise.resolve(platform.parser(str));
};

var findPlatform = function(filepath) {
  var pm;
  Object.keys(parsers).some( (_pm) => {
    pm = parsers[_pm];
    pm.parserName = _pm;

    if (pm.filter(filepath)) { return true; } else { pm = null; }
  });
  return pm;
};

module.exports = {
  parse: parse,
  findPlatform: findPlatform,
  parsers: parsers
};
<commit_msg>fixed nuspec name<commit_after>'use strict';

var Promise = require('bluebird');

var parsers = {
  npm: {
    name: 'NPM',
    type: 'manifest',
    parser: require('./npm'),
    filter: path => path.match(/^package\.json$/)
  },
  cpanMetaYML: {
    name: 'CPAN',
    type: 'manifest',
    parser: require('./cpan-meta-yml'),
    filter: path => path.match(/^META\.yml$/)
  },
  cpanMetaJSON: {
    name: 'CPAN',
    type: 'manifest',
    parser: require('./cpan-meta-json'),
    filter: path => path.match(/^META\.json$/)
  },
  cran: {
    name: 'CRAN',
    type: 'manifest',
    parser: require('./cran'),
    filter: path => path.match(/^DESCRIPTION$/)
  },
  npmshrinkwrap: {
    name: 'NPM',
    type: 'lockfile',
    parser: require('./npm-shrinkwrap'),
    filter: path => path.match(/^npm-shrinkwrap\.json$/)
  },
  rubygems: {
    name: 'Rubygems',
    type: 'manifest',
    parser: require('./rubygems'),
    filter: path => path.match(/^Gemfile$|^gems\.rb$/)
  },
  rubygemslockfile: {
    name: 'Rubygems',
    type: 'lockfile',
    parser: require('./rubygems-lockfile'),
    filter: path => path.match(/^Gemfile\.lock$|^gems\.locked$/)
  },
  gemspec: {
    name: 'Rubygems',
    type: 'gemspec',
    parser: require('./gemspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.gemspec$/)
  },
  podspec: {
    name: 'Cocoapods',
    type: 'podspec',
    parser: require('./podspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.podspec$/)
  },
  podspecJson: {
    name: 'Cocoapods',
    type: 'podspec',
    parser: require('./podspec-json'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.podspec.json$/)
  },
  packagist: {
    name: 'Packagist',
    type: 'manifest',
    parser: require('./packagist'),
    filter: path => path.match(/^composer\.json$/)
  },
  packagistlockfile: {
    name: 'Packagist',
    type: 'lockfile',
    parser: require('./packagist-lockfile'),
    filter: path => path.match(/^composer\.lock$/)
  },
  cargo: {
    name: 'Cargo',
    type: 'manifest',
    parser: require('./cargo'),
    filter: path => path.match(/^Cargo\.toml$/)
  },
  cargolockfile: {
    name: 'Cargo',
    type: 'lockfile',
    parser: require('./cargo-lock'),
    filter: path => path.match(/^Cargo\.lock$/)
  },
  elm: {
    name: 'Elm',
    type: 'manifest',
    parser: require('./elm'),
    filter: path => path.match(/^elm-package\.json$|^elm_dependencies\.json$/)
  },
  elmExact: {
    name: 'Elm',
    type: 'lockfile',
    parser: require('./elm-exact'),
    filter: path => path.match(/^elm-stuff\/exact-dependencies\.json$/)
  },
  bower: {
    name: 'Bower',
    type: 'manifest',
    parser: require('./bower'),
    filter: path => path.match(/^bower\.json$/)
  },
  dub:{
    name: 'Dub',
    type: 'manifest',
    parser: require('./dub'),
    filter: path => path.match(/^dub\.json$/)
  },
  dubSdl:{
    name: 'Dub',
    type: 'manifest',
    parser: require('./dub-sdl'),
    filter: path => path.match(/^dub\.sdl$/)
  },
  pub: {
    name: 'Pub',
    type: 'manifest',
    parser: require('./pub'),
    filter: path => path.match(/^pubspec\.yaml$/)
  },
  publock: {
    name: 'Pub',
    type: 'lockfile',
    parser: require('./publock'),
    filter: path => path.match(/^pubspec\.lock$/)
  },
  clojars: {
    name: 'Clojars',
    type: 'manifest',
    parser: require('./clojars'),
    filter: path => path.match(/^project\.clj$/)
  },
  hex: {
    name: 'Hex',
    type: 'manifest',
    parser: require('./hex'),
    filter: path => path.match(/^mix\.exs$/)
  },
  hexLock: {
    name: 'Hex',
    type: 'lockfile',
    parser: require('./hex-lock'),
    filter: path => path.match(/^mix\.lock$/)
  },
  pypi: {
    name: 'PyPI',
    type: 'manifest',
    parser: require('./pypi'),
    filter: path =>
      path.match(/require.*\.(txt|pip)$/) && !path.match(/^node_modules/)
  },
  pypiSetup: {
    name: 'PyPI',
    type: 'manifest',
    parser: require('./pypi-setup'),
    filter: path => path.match(/^setup\.py$/)
  },
  cocoapods: {
    name: 'CocoaPods',
    type: 'manifest',
    parser: require('./cocoapods'),
    filter: path => path.match(/^Podfile$/)
  },
  cocoapodsLockfile: {
    name: 'CocoaPods',
    type: 'lockfile',
    parser: require('./cocoapods-lockfile'),
    filter: path => path.match(/^Podfile\.lock$/)
  },
  nuget: {
    name: 'NuGet',
    type: 'manifest',
    parser: require('./nuget'),
    filter: path => path.match(/Project\.json$/)
  },
  nugetLockfile: {
    name: 'NuGet',
    type: 'lockfile',
    parser: require('./nuget-lockfile'),
    filter: path => path.match(/Project\.lock\.json$/)
  },
  nugetPackages: {
    name: 'NuGet',
    type: 'manifest',
    parser: require('./nuget-packages'),
    filter: path => path.match(/packages\.config$/)
  },
  nuspec: {
    name: 'NuGet',
    type: 'manifest',
    parser: require('./nuspec'),
    filter: path => path.match(/^[A-Za-z0-9_-]+\.nuspec$/)
  },
  julia: {
    parser: require('./julia'),
    filter: path => path.match(/^REQUIRE$/)
  },
  meteor: {
    parser: require('./meteor'),
    filter: path => path.match(/^versions\.json$/)
  },
  go: {
    name: 'Go',
    type: 'manifest',
    parser: require('./godeps'),
    filter: path => path.match(/^Godeps\/Godeps\.json$/)
  },
  glide: {
    name: 'Go',
    type: 'manifest',
    parser: require('./glide'),
    filter: path => path.match(/^glide\.yaml$/)
  },
  glidelockfile: {
    name: 'Go',
    type: 'lockfile',
    parser: require('./glidelockfile'),
    filter: path => path.match(/^glide\.lock$/)
  },
  cartfile: {
    name: 'Carthage',
    type: 'manifest',
    parser: require('./cartfile'),
    filter: path => path.match(/^Cartfile$/)
  },
  cartfileprivate: {
    name: 'Carthage',
    type: 'manifest',
    parser: require('./cartfileprivate'),
    filter: path => path.match(/^Cartfile\.private$/)
  },
  cartfileresolved: {
    name: 'Carthage',
    type: 'lockfile',
    parser: require('./cartfileresolved'),
    filter: path => path.match(/^Cartfile\.resolved$/)
  },
  maven: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./maven'),
    filter: path => path.match(/pom\.xml$/i)
  },
  ivy: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./ivy'),
    filter: path => path.match(/ivy\.xml$/i)
  },
  gradle: {
    name: 'Maven',
    type: 'manifest',
    parser: require('./gradle'),
    filter: path => path.match(/build\.gradle$/i)
  },
  shard: {
    name: 'Shards',
    type: 'manifest',
    parser: require('./shard'),
    filter: path => path.match(/shard\.yml$/i)
  },
  shardLockfile: {
    name: 'Shards',
    type: 'lockfile',
    parser: require('./shard-lockfile'),
    filter: path => path.match(/^shard\.lock$/i)
  },
  swift: {
    name: 'Swift',
    type: 'manifest',
    parser: require('./swift'),
    filter: path => path.match(/^Package\.swift$/i)
  }
};

var parse = function(platformName, str) {
  var platform = parsers[platformName];
  if (!platform) return Promise.reject('Invalid platform');

  return Promise.resolve(platform.parser(str));
};

var findPlatform = function(filepath) {
  var pm;
  Object.keys(parsers).some( (_pm) => {
    pm = parsers[_pm];
    pm.parserName = _pm;

    if (pm.filter(filepath)) { return true; } else { pm = null; }
  });
  return pm;
};

module.exports = {
  parse: parse,
  findPlatform: findPlatform,
  parsers: parsers
};
<|endoftext|>


<commit_before>'use strict';

var expectFile = require('gulp-expect-file');
var streamSync = require('./stream-sync');
var through = require('through2').obj;

module.exports = function (gulp, gutil) {

  function allDirTreePaths(paths) {
    var newPaths = [];
    for (var i = 0; i < paths.length; i++) {
      var dirs = paths[i].split('/');
      var path = '';
      for (var j = 0; j < dirs.length; j++) {
        path = path + (path.length === 0 ? '' : '/') + dirs[j];
        if (newPaths.indexOf(path) === -1) {
          newPaths.push(path);
        }
      }
    }
    return newPaths;
  }

  var RULES = [
    // expected files
    {
      pattern: ['**/*'],
      options: {
        reportMissing: false,
        reportUnexpected: true,
        errorOnFailure: true,
        testFiles: true
      },
      expectations: [
        'res/lang/text.{en,en-gb}.properties',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8).properties',
        'res/lang/text.{en,en-gb}/*.text',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8)/*.text',
        'res/lang/feature/*/text.*.properties',
        'res/lang/feature/*/text.*.properties.json',
        'res/quilts/*.quilt.xml',
        'res/quilts/custom/*.quilt.xml',
        'res/components/*.ftl',
        'res/skins/**/css/*.css',
        'res/skins/**/sass/**/*.{scss,sass}',
        'res/skins/**/sass/**/*.{scss,sass}.ftl',
        'res/skins/**/components/*.ftl',
        'res/skins/**/images/*.{png,gif,jpg,jpeg,svg}',
        'res/skins/**/skin.properties',
        'res/js/angularjs/**/*.js',
        'res/js/angularjs/metadata/dependencies.json',
        'res/editors/tinymce/**/*.js',
        'res/editors/tinymce/instances/**/*.json',
        'res/editors/tinymce/plugins/**/img/*.{png,gif,jpg,jpeg,svg}',
        '{res,web}/**/README.md',
        '{res,web}/**/*.example',
        'web/html/**/*.*',
        'web/html/**/version'
      ]
    },
    // expected directories
    {
      pattern: ['**/*'],
      options: {
        reportMissing: false,
        reportUnexpected: true,
        errorOnFailure: true,
        testDirectories: true
      },
      expectations: allDirTreePaths([
        'res/editors/tinymce/**',
        'res/lang',
        'res/lang/text.{en,en-gb}',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8)',
        'res/lang/feature/*',
        'res/quilts',
        'res/quilts/custom',
        'res/components',
        'res/skins/**',
        'res/js/angularjs/**',
        'res/js/angularjs/metadata',
        'web/html/ng-app/status/version',
        'web/html/assets/**'
      ])
    },
    // mandatory files
    // (no files mandatory, uncomment block to add mandatory files)
      // {
      //   pattern: '**/*.*',
      //   options: {
      //     reportMissing: true,
      //     reportUnexpected: false,
      //     errorOnFailure: true,
      //     testFiles: true
      //   },
      //   expectations: [
      //   ]
      // },
    // mandatory directories
    {
      pattern: '**/*',
      options: {
        reportMissing: true,
        reportUnexpected: false,
        errorOnFailure: true,
        testDirectories: true
      },
      expectations: allDirTreePaths([
        'res/**'
      ])
    }
  ];

  return {
    verify: function () {
      return streamSync(
        {
          collateErrors: true
        },
        RULES.map(function (rule) {
          return function () {
            return gulp.src(rule.pattern, { cwd: 'plugin' })
              .pipe(through(function (file, enc, cb) {
                if (file.isStream()) {
                  cb(new gutil.PluginError('plugin-verify', 'Streaming not supported'));
                  return;
                }
                if (file.isNull() && file.stat && file.stat.isDirectory && file.stat.isDirectory()) {
                  if (rule.options.testDirectories) {
                    this.push(file);
                  }
                } else {
                  if (rule.options.testFiles) {
                    this.push(file);
                  }
                }
                cb();
              }))
              .pipe(expectFile(rule.options, rule.expectations));
          };
        })
      );
    }
  };
};
<commit_msg>Updating plugin rules<commit_after>'use strict';

var expectFile = require('gulp-expect-file');
var streamSync = require('./stream-sync');
var through = require('through2').obj;

module.exports = function (gulp, gutil) {

  function allDirTreePaths(paths) {
    var newPaths = [];
    for (var i = 0; i < paths.length; i++) {
      var dirs = paths[i].split('/');
      var path = '';
      for (var j = 0; j < dirs.length; j++) {
        path = path + (path.length === 0 ? '' : '/') + dirs[j];
        if (newPaths.indexOf(path) === -1) {
          newPaths.push(path);
        }
      }
    }
    return newPaths;
  }

  var RULES = [
    // expected files
    {
      pattern: ['**/*'],
      options: {
        reportMissing: false,
        reportUnexpected: true,
        errorOnFailure: true,
        testFiles: true
      },
      expectations: [
        'res/lang/text.{en,en-gb}.properties',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8).properties',
        'res/lang/text.{en,en-gb}/*.text',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8)/*.text',
        'res/lang/feature/*/text.*.properties',
        'res/lang/feature/*/text.*.properties.json',
        'res/quilts/*.quilt.xml',
        'res/quilts/custom/*.quilt.xml',
        'res/components/*.ftl',
        'res/skins/**/css/*.css',
        'res/skins/**/sass/**/*.{scss,sass}',
        'res/skins/**/sass/**/*.{scss,sass}.ftl',
        'res/skins/**/components/*.ftl',
        'res/skins/**/images/*.{png,gif,jpg,jpeg,svg}',
        'res/skins/**/skin.properties',
        'res/js/angularjs/**/*.js',
        'res/js/angularjs/metadata/dependencies.json',
        'res/editors/tinymce/**/*.js',
        'res/editors/tinymce/instances/**/*.json',
        'res/editors/tinymce/plugins/**/img/*.{png,gif,jpg,jpeg,svg}',
        'res/feature/*/*/res/editors/tinymce/**/*.js',
        'res/feature/*/*/res/editors/tinymce/instances/**/*.json',
        'res/feature/*/*/res/editors/tinymce/plugins/**/img/*.{png,gif,jpg,jpeg,svg}',
        '{res,web}/**/README.md',
        '{res,web}/**/*.example',
        'web/html/**/*.*',
        'web/html/**/version'
      ]
    },
    // expected directories
    {
      pattern: ['**/*'],
      options: {
        reportMissing: false,
        reportUnexpected: true,
        errorOnFailure: true,
        testDirectories: true
      },
      expectations: allDirTreePaths([
        'res/editors/tinymce/**',
        'res/feature/*/*/res/editors/tinymce/**',
        'res/lang',
        'res/lang/text.{en,en-gb}',
        'res/lang/text.{ar,bg,ca,cs,da,de,el,es,es-mx,fi,fr,hr,hu,in,it,iw,ja,ko,ms,nl,no,pl,pt,pt-br,ro,ru,sk,sq,' +
          'sv,th,tr,uk,vi,zn-cn,zn-tw}.(UTF-8)',
        'res/lang/feature/*',
        'res/quilts',
        'res/quilts/custom',
        'res/components',
        'res/skins/**',
        'res/js/angularjs/**',
        'res/js/angularjs/metadata',
        'web/html/ng-app/status/version',
        'web/html/assets/**'
      ])
    },
    // mandatory files
    // (no files mandatory, uncomment block to add mandatory files)
      // {
      //   pattern: '**/*.*',
      //   options: {
      //     reportMissing: true,
      //     reportUnexpected: false,
      //     errorOnFailure: true,
      //     testFiles: true
      //   },
      //   expectations: [
      //   ]
      // },
    // mandatory directories
    {
      pattern: '**/*',
      options: {
        reportMissing: true,
        reportUnexpected: false,
        errorOnFailure: true,
        testDirectories: true
      },
      expectations: allDirTreePaths([
        'res/**'
      ])
    }
  ];

  return {
    verify: function () {
      return streamSync(
        {
          collateErrors: true
        },
        RULES.map(function (rule) {
          return function () {
            return gulp.src(rule.pattern, { cwd: 'plugin' })
              .pipe(through(function (file, enc, cb) {
                if (file.isStream()) {
                  cb(new gutil.PluginError('plugin-verify', 'Streaming not supported'));
                  return;
                }
                if (file.isNull() && file.stat && file.stat.isDirectory && file.stat.isDirectory()) {
                  if (rule.options.testDirectories) {
                    this.push(file);
                  }
                } else {
                  if (rule.options.testFiles) {
                    this.push(file);
                  }
                }
                cb();
              }))
              .pipe(expectFile(rule.options, rule.expectations));
          };
        })
      );
    }
  };
};
<|endoftext|>


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

var debug = require('debug')('slate-irc:whois');
var utils = require('../utils');

/**
 * WHOIS plugin to query for whois info and\or emit "whois" events
 *
 *    client.whois('cmilhench');
 *
 *    client.whois('irc.host.com', 'cmilhench');
 *
 *    client.on('whois', function(err, data){ ... });
 *
 *    client.whois('cmilhench', function(err, data){
 *      console.log(names);
 *    });
 *
 *    client.whois('irc.host.com', 'cmilhench', function(err, data){
 *      console.log(names);
 *    });
 *
 * @return {Function}
 * @api public
 */

module.exports = function() {
  return function(irc){
    var map = {}
    irc.whois = whois;
    irc.whoisCallbacks = {};

    irc.on('data', function(msg){
      switch (msg.command) {
        case 'RPL_WHOISUSER':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target] = map[target] || {};
          map[target].username = params[2];
          map[target].hostname = params[3];
          map[target].realname = msg.trailing;
          map[target].channels = [];
          map[target].oper = false;
          break;
        case 'RPL_WHOISCHANNELS':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var channels = params.slice(2);
          map[target].channels = map[target].channels.concat(channels);
          break;
        case 'RPL_WHOISSERVER':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].server = params[2];
          break;
        case 'RPL_AWAY':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          if (!map[target]) { return; }
          map[target].away = msg.trailing;
        case 'RPL_WHOISOPERATOR':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].oper = true;
        case 'RPL_WHOISIDLE':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].idle = params[2]; // new Date(now - (n * 1000))
          map[target].sign = params[3]; // new Date(n * 1000)
          break;
        case 'RPL_ENDOFWHOIS':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var cb = irc.whoisCallbacks[target];
          var err = map[target].err;
          if (err) { delete map[target]; }
          if (cb) cb(err, map[target]);
          else irc.emit('whois', err, map[target]);
          break;
        case 'ERR_NEEDMOREPARAMS':
          var err = 'Not enough parameters';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          if (target !== 'whois') { return; }
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, null);
          else irc.emit('whois', err, null);
          break;
        case 'ERR_NOSUCHSERVER':
          var err = 'No such server';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, null);
          else irc.emit('whois', err, null);
          break;
        case 'ERR_NOSUCHNICK':
          var err = 'No such nick/channel';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target] = map[target] || {};
          map[target].err = err;
          break;
      }
    });
  }
}

/**
 * Fetch whois data and invoke `fn(err, data)`.
 *
 * @param {String} target
 * @param {String} mask
 * @param {Function} fn
 * @api public
 */

function whois(target, mask, fn) {
  var self = this;
  target = target.toLowerCase();
  if ('function' == typeof mask) {
    fn = mask;
    mask = '';
  }

  if (fn) {
    this.whoisCallbacks[target] = function(err, data){
      delete self.whoisCallbacks[target];
      fn(err, data);
    };
  }
  this.write(['WHOIS', target, mask].filter(Boolean).join(' '));
}<commit_msg>update error handeling in whois to be consistant<commit_after>
/**
 * Module dependencies.
 */

var debug = require('debug')('slate-irc:whois');
var utils = require('../utils');

/**
 * WHOIS plugin to query for whois info and\or emit "whois" events
 *
 *    client.whois('cmilhench');
 *
 *    client.whois('irc.host.com', 'cmilhench');
 *
 *    client.on('whois', function(err, data){ ... });
 *
 *    client.whois('cmilhench', function(err, data){
 *      console.log(names);
 *    });
 *
 *    client.whois('irc.host.com', 'cmilhench', function(err, data){
 *      console.log(names);
 *    });
 *
 * @return {Function}
 * @api public
 */

module.exports = function() {
  return function(irc){
    var map = {}
    irc.whois = whois;
    irc.whoisCallbacks = {};

    irc.on('data', function(msg){
      switch (msg.command) {
        case 'RPL_WHOISUSER':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target] = map[target] || {};
          map[target].username = params[2];
          map[target].hostname = params[3];
          map[target].realname = msg.trailing;
          map[target].channels = [];
          map[target].oper = false;
          break;
        case 'RPL_WHOISCHANNELS':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var channels = params.slice(2);
          map[target].channels = map[target].channels.concat(channels);
          break;
        case 'RPL_WHOISSERVER':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].server = params[2];
          break;
        case 'RPL_AWAY':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          if (!map[target]) { return; }
          map[target].away = msg.trailing;
        case 'RPL_WHOISOPERATOR':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].oper = true;
        case 'RPL_WHOISIDLE':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          map[target].idle = params[2]; // new Date(now - (n * 1000))
          map[target].sign = params[3]; // new Date(n * 1000)
          break;
        case 'RPL_ENDOFWHOIS':
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          if (!map[target]) { return; }
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, map[target]);
          else irc.emit('whois', null, map[target]);
          break;
        case 'ERR_NEEDMOREPARAMS':
          var err = 'Not enough parameters';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          if (target !== 'whois') { return; }
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, null);
          else irc.emit('whois', err, null);
          break;
        case 'ERR_NOSUCHSERVER':
          var err = 'No such server';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, null);
          else irc.emit('whois', err, null);
          break;
        case 'ERR_NOSUCHNICK':
          var err = 'No such nick/channel';
          var params = msg.params.split(' ');
          var target = params[1].toLowerCase();
          var cb = irc.whoisCallbacks[target];
          if (cb) cb(err, null);
          else irc.emit('whois', err, null);
          break;
      }
    });
  }
}

/**
 * Fetch whois data and invoke `fn(err, data)`.
 *
 * @param {String} target
 * @param {String} mask
 * @param {Function} fn
 * @api public
 */

function whois(target, mask, fn) {
  var self = this;
  target = target.toLowerCase();
  if ('function' == typeof mask) {
    fn = mask;
    mask = '';
  }

  if (fn) {
    this.whoisCallbacks[target] = function(err, data){
      delete self.whoisCallbacks[target];
      fn(err, data);
    };
  }
  this.write(['WHOIS', target, mask].filter(Boolean).join(' '));
}<|endoftext|>


<commit_before>
var basal = require('./basal');
var targets = require('./targets');
var carbs = require('./carbs');
var isf = require('./isf');

function defaults ( ) {
    var profile = {
        , max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have
        // , dia: pumpsettings_data.insulin_action_curve
        , type: "current"
    };
    return profile;
}

function generate (inputs, opts) {
  var profile = opts && opts.type ? opts : defaults( );

  if (inputs.settings.insulin_action_curve) {
    profile.dia =  pumpsettings_data.insulin_action_curve;
  }

  if (inputs.max_iob) {
    profile.max_iob = inputs.max_iob;
  }

  profile.current_basal = basal.basalLookup(inputs.basals);
  profile.max_daily_basal = basal.maxDailyBasal(inputs);
  profile.max_basal = basal.maxBasalLookup(inputs);

  var range = targets.bgTargetsLookup(inputs);
  profile.min_bg = range.min_bg;
  profile.max_bg = range.max_bg;
  profile.carbratio = carbs.carbRatioLookup(inputs);
  profile.sens = isf.isfLookup(inputs);

  return profile;
}

generate.defaults = defaults;
exports = module.exports = generate;

<commit_msg>fix syntax error<commit_after>
var basal = require('./basal');
var targets = require('./targets');
var carbs = require('./carbs');
var isf = require('./isf');

function defaults ( ) {
    var profile = {
          max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have
        // , dia: pumpsettings_data.insulin_action_curve
        , type: "current"
    };
    return profile;
}

function generate (inputs, opts) {
  var profile = opts && opts.type ? opts : defaults( );

  if (inputs.settings.insulin_action_curve) {
    profile.dia =  pumpsettings_data.insulin_action_curve;
  }

  if (inputs.max_iob) {
    profile.max_iob = inputs.max_iob;
  }

  profile.current_basal = basal.basalLookup(inputs.basals);
  profile.max_daily_basal = basal.maxDailyBasal(inputs);
  profile.max_basal = basal.maxBasalLookup(inputs);

  var range = targets.bgTargetsLookup(inputs);
  profile.min_bg = range.min_bg;
  profile.max_bg = range.max_bg;
  profile.carbratio = carbs.carbRatioLookup(inputs);
  profile.sens = isf.isfLookup(inputs);

  return profile;
}

generate.defaults = defaults;
exports = module.exports = generate;

<|endoftext|>


<commit_before>"use strict";

var Property = require('./')

exports.$flags = {
  /**
   * Use $text to specify a text to an element
   * @type {string}
   * @memberOf Property
   *
   * @example
   * var a = new Element({
   *   $text: {
   *     $val: "some text"
   *   }
   * })
   *
   */

  $text: new Property({
    $on: {
      $change: function( event ) {
        var element = this.$parent
        var v = this.$val || ''
        console.log(' ????')
        if(element){
          console.log('  - - - -',this)
          // element.$forEachInstance(function(){
            var node = element.$node
            var nodes = node.childNodes

            if (/text/.test(node.type)) {
              node.value = v
              return
            }

            if (nodes) {
              for (var i = 0, l = nodes.length; i < l; i++) {
                node = nodes[i]
                if (node.nodeType === 3) {
                  node.nodeValue = v
                  return;
                }
              }
            }

            node.appendChild(document.createTextNode(v))
          // })
        }
      }
    }
  }).$Constructor
}<commit_msg>added 0 exception for textinput<commit_after>"use strict";

var Property = require('./')

exports.$flags = {
  /**
   * Use $text to specify a text to an element
   * @type {string}
   * @memberOf Property
   *
   * @example
   * var a = new Element({
   *   $text: {
   *     $val: "some text"
   *   }
   * })
   *
   */

  $text: new Property({
    $on: {
      $change: function( event ) {
        var element = this.$parent
        var v = this.$val
        if(!v && v !== 0){ val = '' }
        console.log(' ????')
        if(element){
          console.log('  - - - -',this)
          // element.$forEachInstance(function(){
            var node = element.$node
            var nodes = node.childNodes

            if (/text/.test(node.type)) {
              node.value = v
              return
            }

            if (nodes) {
              for (var i = 0, l = nodes.length; i < l; i++) {
                node = nodes[i]
                if (node.nodeType === 3) {
                  node.nodeValue = v
                  return;
                }
              }
            }

            node.appendChild(document.createTextNode(v))
          // })
        }
      }
    }
  }).$Constructor
}
<|endoftext|>


<commit_before>'use babel'

const e = require('estree-builder');

import { parse } from './acorn'
import { searchByLocationAndType } from './node-ops'

import { genJsList } from './js-gen'
import {
  buildImportStmts,
  buildClass,
  raw,
  fnArgs,
  dot,
  assign
} from './tree-builders'

export const generate = (inputText, point) => {
  const tree = parse(inputText)
  const selected = searchByLocationAndType(
    tree,
    // Note difference between Point and Position
    { line: point.row + 1, column: point.column },
    'JSXOpeningElement')
  console.dir(selected)

  const componentName = selected.name.name

  const importStmts = generateImports(componentName)
  const declarationStmts = generateComponents(selected)

  return {
    content: genJsList(importStmts.concat(declarationStmts)),
    componentName
  }
}

export const generateImports = (componentName) => {
  const namedImports = {
    react: ['Component']
  }
  const defaultImports = {
    react: 'React',
    'prop-types': 'PropTypes'
  }
  defaultImports[`./${componentName}.scss`] = 'styles'

  return buildImportStmts([namedImports], [defaultImports])
}

export const generateComponents = (jsxNode) => {
  const className = jsxNode.name.name

  const classDecl = buildClass(className, 'Component', {
    render: generateRender(className, jsxNode.attributes)
  })

  const defProps = generateProps(className, jsxNode.attributes)

  const defExport = raw(`export default ${className}`)
  return [classDecl, defProps, defExport]
}

const generateRender = (className, attributeNodes) => {
  const propVars = attributeNodes.map(a => {
    return e.id(a.name.name)
  })
  const objPattern = e('obj-pattern', propVars)
  const thisDotProps = dot(e.this(), 'props')
  return fnArgs(
    [],
    e.var(objPattern, thisDotProps),
    e.return(e.id(`(

        Here is a '${className}'

    )`))
  )
}

const generateProps = (className, attributeNodes) => {
  const propObject = {}
  attributeNodes.forEach(a => {
    propObject[a.name.name] = dot(dot(e.id('PropTypes'), 'object'), 'isRequired')
  })
  return assign(dot(e.id(className), 'propTypes'), e.object(propObject))
}
<commit_msg>Fix context sensitivity when trying to generate a component<commit_after>'use babel'

const e = require('estree-builder');

import { parse } from './acorn'
import { searchByLocationAndType } from './node-ops'

import { genJsList } from './js-gen'
import {
  buildImportStmts,
  buildClass,
  raw,
  fnArgs,
  dot,
  assign
} from './tree-builders'

export const generate = (inputText, point) => {
  const tree = parse(inputText)
  const jsxBlock = searchByLocationAndType(
    tree,
    // Note difference between Point and Position
    { line: point.row + 1, column: point.column },
    'JSXElement')
  //console.dir(selected)
  const jsxOpening = jsxBlock.openingElement

  const componentName = jsxOpening.name.name

  const importStmts = generateImports(componentName)
  const declarationStmts = generateComponents(jsxOpening)

  return {
    content: genJsList(importStmts.concat(declarationStmts)),
    componentName
  }
}

export const generateImports = (componentName) => {
  const namedImports = {
    react: ['Component']
  }
  const defaultImports = {
    react: 'React',
    'prop-types': 'PropTypes'
  }
  defaultImports[`./${componentName}.scss`] = 'styles'

  return buildImportStmts([namedImports], [defaultImports])
}

export const generateComponents = (jsxNode) => {
  const className = jsxNode.name.name

  const classDecl = buildClass(className, 'Component', {
    render: generateRender(className, jsxNode.attributes)
  })

  const defProps = generateProps(className, jsxNode.attributes)

  const defExport = raw(`export default ${className}`)
  return [classDecl, defProps, defExport]
}

const generateRender = (className, attributeNodes) => {
  const propVars = attributeNodes.map(a => {
    return e.id(a.name.name)
  })
  const objPattern = e('obj-pattern', propVars)
  const thisDotProps = dot(e.this(), 'props')
  return fnArgs(
    [],
    e.var(objPattern, thisDotProps),
    e.return(e.id(`(

        Here is a '${className}'

    )`))
  )
}

const generateProps = (className, attributeNodes) => {
  const propObject = {}
  attributeNodes.forEach(a => {
    propObject[a.name.name] = dot(dot(e.id('PropTypes'), 'object'), 'isRequired')
  })
  return assign(dot(e.id(className), 'propTypes'), e.object(propObject))
}
<|endoftext|>


<commit_before>const {basename, resolve: resolvePath} = require('path')
const chalk = require('chalk')
const {readFile} = require('fs-promise')
const {parse: parseDockerfile} = require('docker-file-parser')

const listPackage = {
  scripts: {
    start: 'serve ./content'
  },
  dependencies: {
    serve: '3.2.7'
  }
}

module.exports = readMetaData

async function readMetaData(path, {
  deploymentType = 'npm',
  deploymentName,
  quiet = false,
  strict = true,
  isStatic = false
}) {
  let pkg = {}
  let nowConfig = null
  let hasNowJson = false

  let name
  let description

  try {
    nowConfig = JSON.parse(await readFile(resolvePath(path, 'now.json')))
    hasNowJson = true
  } catch (err) {
    // if the file doesn't exist then that's fine; any other error bubbles up
    if (err.code !== 'ENOENT') {
      const e = Error(`Failed to read JSON in "${path}/now.json"`)
      e.userError = true
      throw e
    }
  }

  if (hasNowJson) {
    // user can specify the type of deployment explicitly in the `now.json` file
    // when both a package.json and Dockerfile exist
    if (nowConfig.type) {
      deploymentType = nowConfig.type
    }
    if (nowConfig.name) {
      deploymentName = nowConfig.name
    }
  }

  if (deploymentType === 'static') {
    isStatic = true
  }

  if (deploymentType === 'npm') {
    if (isStatic) {
      pkg = listPackage
    } else {
      try {
        pkg = JSON.parse(await readFile(resolvePath(path, 'package.json')))
      } catch (err) {
        const e = Error(`Failed to read JSON in "${path}/package.json"`)
        e.userError = true
        throw e
      }
    }

    if (strict && (!pkg.scripts || (!pkg.scripts.start && !pkg.scripts['now-start']))) {
      const e = Error('Missing `start` (or `now-start`) script in `package.json`. ' +
        'See: https://docs.npmjs.com/cli/start.')
      e.userError = true
      throw e
    }

    if (!deploymentName) {
      if (typeof pkg.name === 'string') {
        name = pkg.name
      } else {
        name = basename(path)

        if (!quiet && !isStatic) {
          console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`)
        }
      }
    }

    description = pkg.description
  } else if (deploymentType === 'docker') {
    let docker
    try {
      const dockerfile = await readFile(resolvePath(path, 'Dockerfile'), 'utf8')
      docker = parseDockerfile(dockerfile, {includeComments: true})
    } catch (err) {
      const e = Error(`Failed to parse "${path}/Dockerfile"`)
      e.userError = true
      throw e
    }

    if (strict && docker.length <= 0) {
      const e = Error('No commands found in `Dockerfile`')
      e.userError = true
      throw e
    }

    const labels = {}
    docker
    .filter(cmd => cmd.name === 'LABEL')
    .forEach(({args}) => {
      for (const key in args) {
        if (!{}.hasOwnProperty.call(args, key)) {
          continue
        }

        // unescape and convert into string
        try {
          labels[key] = JSON.parse(args[key])
        } catch (err) {
          const e = Error(`Error parsing value for LABEL ${key} in \`Dockerfile\``)
          e.userError = true
          throw e
        }
      }
    })

    if (!deploymentName) {
      if (labels.name) {
        name = labels.name
      } else {
        name = basename(path)

        if (!quiet) {
          if (hasNowJson) {
            console.log(`> No \`name\` LABEL in \`Dockerfile\` or \`name\` field in \`now.json\`, using ${chalk.bold(name)}`)
          } else {
            console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
          }
        }
      }
    }

    description = labels.description
  } else {
    throw new TypeError(`Unsupported "deploymentType": ${deploymentType}`)
  }

  if (deploymentName) {
    name = deploymentName
  }

  if (pkg.now) {
    // if the project has both a `now.json` and `now` Object in the `package.json`
    // file, then fail hard and let the user know that they need to pick one or the
    // other
    if (hasNowJson) {
      const e = new Error('You have a `now` configuration field' +
      'inside `package.json`, but configuration is also present' +
      'in `now.json`! Please ensure there\'s a single source of configuration by removing one')
      e.userError = true
      throw e
    } else {
      nowConfig = pkg.now
    }
  }

  return {
    name,
    description,
    deploymentType,
    pkg,
    nowConfig,
    hasNowJson
  }
}
<commit_msg>Make static deployments definable<commit_after>const {basename, resolve: resolvePath} = require('path')
const chalk = require('chalk')
const {readFile} = require('fs-promise')
const {parse: parseDockerfile} = require('docker-file-parser')

const listPackage = {
  scripts: {
    start: 'serve ./content'
  },
  dependencies: {
    serve: '3.2.7'
  }
}

module.exports = readMetaData

async function readMetaData(path, {
  deploymentType = 'npm',
  deploymentName,
  quiet = false,
  strict = true,
  isStatic = false
}) {
  let pkg = {}
  let nowConfig = null
  let hasNowJson = false

  let name
  let description

  try {
    nowConfig = JSON.parse(await readFile(resolvePath(path, 'now.json')))
    hasNowJson = true
  } catch (err) {
    // if the file doesn't exist then that's fine; any other error bubbles up
    if (err.code !== 'ENOENT') {
      const e = Error(`Failed to read JSON in "${path}/now.json"`)
      e.userError = true
      throw e
    }
  }

  if (hasNowJson) {
    // user can specify the type of deployment explicitly in the `now.json` file
    // when both a package.json and Dockerfile exist
    if (nowConfig.type) {
      deploymentType = nowConfig.type
    }
    if (nowConfig.name) {
      deploymentName = nowConfig.name
    }
  }

  if (deploymentType === 'static') {
    isStatic = true
    deploymentType = 'npm'
  }

  if (deploymentType === 'npm') {
    if (isStatic) {
      pkg = listPackage
    } else {
      try {
        pkg = JSON.parse(await readFile(resolvePath(path, 'package.json')))
      } catch (err) {
        const e = Error(`Failed to read JSON in "${path}/package.json"`)
        e.userError = true
        throw e
      }
    }

    if (strict && (!pkg.scripts || (!pkg.scripts.start && !pkg.scripts['now-start']))) {
      const e = Error('Missing `start` (or `now-start`) script in `package.json`. ' +
        'See: https://docs.npmjs.com/cli/start.')
      e.userError = true
      throw e
    }

    if (!deploymentName) {
      if (typeof pkg.name === 'string') {
        name = pkg.name
      } else {
        name = basename(path)

        if (!quiet && !isStatic) {
          console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`)
        }
      }
    }

    description = pkg.description
  } else if (deploymentType === 'docker') {
    let docker
    try {
      const dockerfile = await readFile(resolvePath(path, 'Dockerfile'), 'utf8')
      docker = parseDockerfile(dockerfile, {includeComments: true})
    } catch (err) {
      const e = Error(`Failed to parse "${path}/Dockerfile"`)
      e.userError = true
      throw e
    }

    if (strict && docker.length <= 0) {
      const e = Error('No commands found in `Dockerfile`')
      e.userError = true
      throw e
    }

    const labels = {}
    docker
    .filter(cmd => cmd.name === 'LABEL')
    .forEach(({args}) => {
      for (const key in args) {
        if (!{}.hasOwnProperty.call(args, key)) {
          continue
        }

        // unescape and convert into string
        try {
          labels[key] = JSON.parse(args[key])
        } catch (err) {
          const e = Error(`Error parsing value for LABEL ${key} in \`Dockerfile\``)
          e.userError = true
          throw e
        }
      }
    })

    if (!deploymentName) {
      if (labels.name) {
        name = labels.name
      } else {
        name = basename(path)

        if (!quiet) {
          if (hasNowJson) {
            console.log(`> No \`name\` LABEL in \`Dockerfile\` or \`name\` field in \`now.json\`, using ${chalk.bold(name)}`)
          } else {
            console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
          }
        }
      }
    }

    description = labels.description
  } else {
    throw new TypeError(`Unsupported "deploymentType": ${deploymentType}`)
  }

  if (deploymentName) {
    name = deploymentName
  }

  if (pkg.now) {
    // if the project has both a `now.json` and `now` Object in the `package.json`
    // file, then fail hard and let the user know that they need to pick one or the
    // other
    if (hasNowJson) {
      const e = new Error('You have a `now` configuration field' +
      'inside `package.json`, but configuration is also present' +
      'in `now.json`! Please ensure there\'s a single source of configuration by removing one')
      e.userError = true
      throw e
    } else {
      nowConfig = pkg.now
    }
  }

  return {
    name,
    description,
    deploymentType,
    pkg,
    nowConfig,
    hasNowJson
  }
}
<|endoftext|>


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

function getFileName(header) {
  var m = header.match(/filename="(.*?)"($|; )/i)
  if (!m) return;

  var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
  filename = filename.replace(/%22/g, '"');
  filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
    return String.fromCharCode(code);
  });
  return filename;
}

function parseRangeHeader(req) {
  var info = {};
  if(req.headers && req.headers['content-range']) {
    var ranges = req.headers['content-range'].match(/bytes\s(\*|\d+)-?(\d+)?\/(\d+)/i);
    if(ranges && ranges[1] && ranges[3] && !ranges[2]) {
      info.type = "info";
      info.size = Number(ranges[3]);
      info.stop = Number(ranges[2]);
    } else if(ranges && ranges[1] && ranges[2] && ranges[3]) {
      info.type = "data";
      info.start = Number(ranges[1]);
      info.stop = Number(ranges[2]);
      info.size = Number(ranges[3]);
    } else {
      return null;
    }
  } else {
    return null;
  }
  return info;
}

var ResumeRequest = module.exports = function(req, res, next, options) {
  this.req = req;
  this.res = res;
  this.options = options;
  this.range = parseRangeHeader(req);
  this.size = 0;
  this.next = next;
  this.mongodb = options.mongodb;
  this.mongo = options.mongo;
  this.requestSize = Number(req.headers['content-length']);
  this.received = 0;
  this.directory = options.directory || "/tmp/uploads";
  this.filename = getFileName(req.headers['content-disposition'] || req.headers['x-content-disposition']);
  var m;
  if (m = (req.headers['content-disposition'] || req.headers['x-content-disposition']).match(/name="([^"]+)"/i)) {
    this.name = m[1];
  }
  this.id = req.headers['etag'];
  req.pause();
}

ResumeRequest.prototype.info = function(callback) {
  var self = this;
  console.log("Statting",this.directory + '/' +this.id);
  fs.stat(this.directory + '/' +this.id, function(err, stats) {
    if(err || !stats) {
      return callback(err, stats)
    }
    self.size = stats.size;
    return callback(err, stats);
  });
}

ResumeRequest.prototype.execute = function() {
  // is this the last chunk?
  var self = this, stream, outputStream;
  stream = this.req;
  var at = 0;
  stream.pause();
  this.info(function(err, stats) {
    if(!err && stats) {
      console.log("exists",stats);
      self.received = stats.size;
      outputStream = self.writeStream = fs.createWriteStream(self.directory+'/'+self.id,{flags:'a'});
    } else {
      console.log("new",stats);
      outputStream = self.writeStream = fs.createWriteStream(self.directory+'/'+self.id);
    }
    stream.on('data', function(d) {
      var drain = outputStream.write(d);
      if(!drain) {
        stream.pause();
      }
    });

    outputStream.on('drain', function() {
      stream.resume();
    });

    stream.on('end', function() {
      outputStream.end();
      self.received = outputStream.bytesWritten;
      console.log("Wrote ",self.received," bytes to ",self.directory+'/'+self.filename);
      self.size += self.received;
      if(self.range.stop+1 >= self.range.size) {
        console.log("Last chunk, lets assemble.");
        self.respond();
      } else {
        self.respond();
      }
    });
    stream.resume();
  });

};

ResumeRequest.prototype.respond = function() {
  var self = this;
  if(this.range.stop+1>=this.range.size) {
    console.log("continuing to video route.");
    this.req.files = this.req.files || {};
    var file = this.req.files[this.name] = {};
    this.info(function(err, stats) {
      if(err) {
        return this.next(err);
      }
      file.size = stats.size;
      file.path = self.directory + '/' + self.id;
      file.name = self.id;
      file._writeStream = this.writeStream;
      console.log("File completed: ",file);
      return self.next();
    });
  } else if(this.received == this.requestSize && this.received < this.range.size) {
    console.log("asking more data with",'0-'+(this.range.start+this.received));
    this.res.set('Range','0-'+(this.range.start+this.received));
    this.res.set('Set-Cookie','upload_id='+this.id);
    this.res.writeHead(308, 'Resume incomplete');
    this.res.end();
  }
}<commit_msg>Workaround offset by 1 issue in older ios clients.<commit_after>
var fs = require('fs')
  , path = require('path');

function getFileName(header) {
  var m = header.match(/filename="(.*?)"($|; )/i)
  if (!m) return;

  var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
  filename = filename.replace(/%22/g, '"');
  filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
    return String.fromCharCode(code);
  });
  return filename;
}

function parseRangeHeader(req) {
  var info = {};
  if(req.headers && req.headers['content-range']) {
    var ranges = req.headers['content-range'].match(/bytes\s(\*|\d+)-?(\d+)?\/(\d+)/i);
    if(ranges && ranges[1] && ranges[3] && !ranges[2]) {
      info.type = "info";
      info.size = Number(ranges[3]);
      info.stop = Number(ranges[2]);
    } else if(ranges && ranges[1] && ranges[2] && ranges[3]) {
      info.type = "data";
      info.start = Number(ranges[1]);
      info.stop = Number(ranges[2]);
      info.size = Number(ranges[3]);
    } else {
      return null;
    }
  } else {
    return null;
  }
  return info;
}

var ResumeRequest = module.exports = function(req, res, next, options) {
  this.req = req;
  this.res = res;
  this.options = options;
  this.range = parseRangeHeader(req);
  this.size = 0;
  this.next = next;
  this.mongodb = options.mongodb;
  this.mongo = options.mongo;
  this.requestSize = Number(req.headers['content-length']);
  this.received = 0;
  this.directory = options.directory || "/tmp/uploads";
  this.filename = getFileName(req.headers['content-disposition'] || req.headers['x-content-disposition']);
  var m;
  if (m = (req.headers['content-disposition'] || req.headers['x-content-disposition']).match(/name="([^"]+)"/i)) {
    this.name = m[1];
  }
  this.id = req.headers['etag'];
  req.pause();
}

ResumeRequest.prototype.info = function(callback) {
  var self = this;
  console.log("Statting",this.directory + '/' +this.id);
  fs.stat(this.directory + '/' +this.id, function(err, stats) {
    if(err || !stats) {
      return callback(err, stats)
    }
    self.size = stats.size;
    return callback(err, stats);
  });
}

ResumeRequest.prototype.execute = function() {
  // is this the last chunk?
  var self = this, stream, outputStream;
  stream = this.req;
  var at = 0;
  stream.pause();
  this.info(function(err, stats) {
    if(!err && stats) {
      console.log("exists",stats);
      self.received = stats.size;
      var start = self.received;
      if(self.req && self.req.query) {
        // Workaround for old ios builds <= 5
        // EveryplayUpload.m:390: bytesCompleted = [bytes integerValue];
        // fixed in build6 to:
        // EveryplayUpload.m:390: bytesCompleted = [bytes integerValue] + 1;
        if(!self.req.query.build || Number(self.req.query.build) <= 5) {
          start -= 1;
          console.log("Working around build lte 5 issues with offset by 1 in stream seeking.");
        }
      }
      outputStream = self.writeStream = fs.createWriteStream(self.directory+'/'+self.id,{flags:'a',start:start});
    } else {
      console.log("new",stats);
      outputStream = self.writeStream = fs.createWriteStream(self.directory+'/'+self.id);
    }
    stream.on('data', function(d) {
      var drain = outputStream.write(d);
      if(!drain) {
        stream.pause();
      }
    });

    outputStream.on('drain', function() {
      stream.resume();
    });

    stream.on('end', function() {
      outputStream.end();
      self.received = outputStream.bytesWritten;
      console.log("Wrote ",self.received," bytes to ",self.directory+'/'+self.filename);
      self.size += self.received;
      if(self.range.stop+1 >= self.range.size) {
        console.log("Last chunk, lets assemble.");
        self.respond();
      } else {
        self.respond();
      }
    });
    stream.resume();
  });

};

ResumeRequest.prototype.respond = function() {
  var self = this;
  if(this.range.stop+1>=this.range.size) {
    console.log("continuing to video route.");
    this.req.files = this.req.files || {};
    var file = this.req.files[this.name] = {};
    this.info(function(err, stats) {
      if(err) {
        return this.next(err);
      }
      file.size = stats.size;
      file.path = self.directory + '/' + self.id;
      file.name = self.id;
      file._writeStream = this.writeStream;
      console.log("File completed: ",file);
      return self.next();
    });
  } else if(this.received == this.requestSize && this.received < this.range.size) {
    console.log("asking more data with",'0-'+(this.range.start+this.received));
    this.res.set('Range','0-'+(this.range.start+this.received));
    this.res.set('Set-Cookie','upload_id='+this.id);
    this.res.writeHead(308, 'Resume incomplete');
    this.res.end();
  }
}<|endoftext|>