<commit_before>var uuid = require('uuid');

var leaderboard = require('./leaderboard');

const MAX_LEADERBOARD_INCR = 10;
const TIME_UPDATE_PLAYTIME = 1000 * 60 * 5;  // 5 minutes

function now() {
    // Returns a UNIX timestamp.
    return Math.floor((new Date()).getTime() / 1000);
}

// This manages user state for a single connection.
function user(dataChannel) {
    this.authenticated = false;
    this.dataChannel = dataChannel;
    this.data = {};
}

user.prototype.set = function(key, value) {
    this.data[key] = value;
};

user.prototype.get = function(key) {
    return this.data[key] || null;
};

user.prototype.authenticate = function(email, callback) {
    var self = this;
    this.dataChannel.hget('users', email, function(err, userData) {
        if (err) {
            callback('error_fetching_user');
            return;
        }
        if (!userData) {
            userData = {
                username: email.split('@')[0],
                email: email,
                id: uuid.v4()
            };
            self.dataChannel.hset('users', email, JSON.stringify(userData));
            finishAuth(userData);
        } else {
            userData = JSON.parse(userData);
            self.dataChannel.hget('authenticated', userData.id, function(err, resp) {
                if (resp) {
                    callback('already_authenticated');
                    return;
                }
                finishAuth(userData);
            });
        }
    });

    function finishAuth(userData) {
        self.dataChannel.hset('authenticated', userData.id, 'y');
        self.set('username', userData.username);
        self.set('uid', userData.id);
        self.set('email', userData.email);
        self.authenticated = true;
        callback(null);
    }
    // TODO: There can be a race condition here. If the client doesn't
    // wait for the server to process an auth request before sending a
    // second request, their second request will be processed before
    // this callback executes. Someday, there should be a queue of
    // requests which can get processed in order when this callback
    // fires.
};

user.prototype.startPlaying = function(game) {
    var timeNow = now();
    var currentlyPlaying = this.get('currentlyPlaying');
    if (currentlyPlaying) {
        clearInterval(this.get('playTimer'));

        var startedPlaying = this.get('startedPlaying');
        this.incrPlaytime(currentlyPlaying, timeNow - startedPlaying);
    }
    // TODO: Validate that game is valid.
    // And validate that user can play/paid for game.
    this.set('startedPlaying', timeNow);
    this.set('currentlyPlaying', game);
    this.dataChannel.hset('currentlyPlaying', this.get('id'), game);
    this.dataChannel.sadd('userPlayed:' + this.get('id'), game);
    this.dataChannel.sadd('gamePlayed:' + game, this.get('id'));

    // Set up a timer to update this every few minutes so the data doesn't
    // get stale.
    var self = this;
    this.set('playTimer', setInterval(function() {
        self.incrPlaytime(game, TIME_UPDATE_PLAYTIME);
        self.set('startedPlaying', now());
    }, TIME_UPDATE_PLAYTIME));
};

user.prototype.incrPlaytime = function(game, amount) {
    if (!amount) {
        return;
    }
    this.dataChannel.hincrby(
        'playtime:' + this.get('currentlyPlaying'),
        this.get('id'),
        amount || 0
    );
};

user.prototype.donePlaying = function() {
    var currentlyPlaying = this.get('currentlyPlaying');
    if (!currentlyPlaying) {
        return
    }
    this.incrPlaytime(currentlyPlaying, now() - this.get('startedPlaying'));
    this.dataChannel.hdel('currentlyPlaying', this.get('id'));

    // Clean up the playtime updater.
    clearInterval(this.get('playTimer'));
};

user.prototype.updateLeaderboard = function(board, value) {
    // TODO: Throttle this function.

    var currentlyPlaying = this.get('currentlyPlaying');
    // Check that the user is playing a game.
    if (!currentlyPlaying) {
        return;
    }

    // Check that the board is being updated with a valid value.
    if (typeof value !== 'number' ||
        value === 0 ||
        value < -1 * MAX_LEADERBOARD_INCR ||
        value > MAX_LEADERBOARD_INCR) {
        return;
    }

    // Check that the board the user is trying to update exists.
    leaderboard.isLeaderboard(
        this.dataChannel,
        currentlyPlaying,
        board,
        function(exists) {
            if (!exists) return;

            leaderboard.updateLeaderboard(
                this.dataChannel,
                currentlyPlaying,
                board,
                this.get('id'),
                value
            );
        }
    );
};

user.prototype.finish = function() {
    if (this.authenticated) {
        this.dataChannel.hdel('authenticated', this.get('id'));
        this.authenticated = false;
    }
    this.donePlaying();
};

exports.User = user;
<commit_msg>Expose a stable way to access user data from email and ID<commit_after>var uuid = require('uuid');

var leaderboard = require('./leaderboard');

const MAX_LEADERBOARD_INCR = 10;
const TIME_UPDATE_PLAYTIME = 1000 * 60 * 5;  // 5 minutes

function now() {
    // Returns a UNIX timestamp.
    return Math.floor((new Date()).getTime() / 1000);
}

// This manages user state for a single connection.
function user(dataChannel) {
    this.authenticated = false;
    this.dataChannel = dataChannel;
    this.data = {};
}

user.prototype.set = function(key, value) {
    this.data[key] = value;
};

user.prototype.get = function(key) {
    return this.data[key] || null;
};

user.prototype.authenticate = function(email, callback) {
    var self = this;
    getUserFromEmail(this.dataChannel, email, function(err, userData) {
        if (err) {
            callback('error_fetching_user');
            return;
        }
        if (!userData) {
            userData = {
                username: email.split('@')[0],
                email: email,
                id: uuid.v4()
            };
            self.dataChannel.hset('users', userData.id, JSON.stringify(userData));
            self.dataChannel.hset('usersByEmail', email, userData.id);
            finishAuth(userData);
        } else {
            userData = JSON.parse(userData);
            self.dataChannel.hget('authenticated', userData.id, function(err, resp) {
                if (resp) {
                    callback('already_authenticated');
                    return;
                }
                finishAuth(userData);
            });
        }
    });

    function finishAuth(userData) {
        self.dataChannel.hset('authenticated', userData.id, 'y');
        self.set('username', userData.username);
        self.set('uid', userData.id);
        self.set('email', userData.email);
        self.authenticated = true;
        callback(null);
    }
    // TODO: There can be a race condition here. If the client doesn't
    // wait for the server to process an auth request before sending a
    // second request, their second request will be processed before
    // this callback executes. Someday, there should be a queue of
    // requests which can get processed in order when this callback
    // fires.
};

user.prototype.startPlaying = function(game) {
    var timeNow = now();
    var currentlyPlaying = this.get('currentlyPlaying');
    if (currentlyPlaying) {
        clearInterval(this.get('playTimer'));

        var startedPlaying = this.get('startedPlaying');
        this.incrPlaytime(currentlyPlaying, timeNow - startedPlaying);
    }
    // TODO: Validate that game is valid.
    // And validate that user can play/paid for game.
    this.set('startedPlaying', timeNow);
    this.set('currentlyPlaying', game);
    this.dataChannel.hset('currentlyPlaying', this.get('id'), game);
    this.dataChannel.sadd('userPlayed:' + this.get('id'), game);
    this.dataChannel.sadd('gamePlayed:' + game, this.get('id'));

    // Set up a timer to update this every few minutes so the data doesn't
    // get stale.
    var self = this;
    this.set('playTimer', setInterval(function() {
        self.incrPlaytime(game, TIME_UPDATE_PLAYTIME);
        self.set('startedPlaying', now());
    }, TIME_UPDATE_PLAYTIME));
};

user.prototype.incrPlaytime = function(game, amount) {
    if (!amount) {
        return;
    }
    this.dataChannel.hincrby(
        'playtime:' + this.get('currentlyPlaying'),
        this.get('id'),
        amount || 0
    );
};

user.prototype.donePlaying = function() {
    var currentlyPlaying = this.get('currentlyPlaying');
    if (!currentlyPlaying) {
        return
    }
    this.incrPlaytime(currentlyPlaying, now() - this.get('startedPlaying'));
    this.dataChannel.hdel('currentlyPlaying', this.get('id'));

    // Clean up the playtime updater.
    clearInterval(this.get('playTimer'));
};

user.prototype.updateLeaderboard = function(board, value) {
    // TODO: Throttle this function.

    var currentlyPlaying = this.get('currentlyPlaying');
    // Check that the user is playing a game.
    if (!currentlyPlaying) {
        return;
    }

    // Check that the board is being updated with a valid value.
    if (typeof value !== 'number' ||
        value === 0 ||
        value < -1 * MAX_LEADERBOARD_INCR ||
        value > MAX_LEADERBOARD_INCR) {
        return;
    }

    // Check that the board the user is trying to update exists.
    leaderboard.isLeaderboard(
        this.dataChannel,
        currentlyPlaying,
        board,
        function(exists) {
            if (!exists) return;

            leaderboard.updateLeaderboard(
                this.dataChannel,
                currentlyPlaying,
                board,
                this.get('id'),
                value
            );
        }
    );
};

user.prototype.finish = function() {
    if (this.authenticated) {
        this.dataChannel.hdel('authenticated', this.get('id'));
        this.authenticated = false;
    }
    this.donePlaying();
};

exports.User = user;

function getUserFromID(client, id, callback) {
    /*
    `callback` is called with an error parameter and a parameter
    containing a JSON blob of user data.
    */
    client.hget('users', id, function(err, resp) {
        if (err) {
            callback('db_error');
        } else if (!resp) {
            callback('no_such_user');
        } else {
            callback(null, JSON.parse(resp));
        }
    });
}
exports.getUserFromID = getUserFromID;

function getUserFromEmail(client, email, callback) {
    client.hget('usersByEmail', email, function(err, resp) {
        if (err) {
            callback('db_error');
        } else if (!resp) {
            callback('no_such_user');
        } else {
            // `resp` is the user ID.
            getUserFromID(client, resp, callback);
        }
    });
}
exports.getUserFromEmail = getUserFromEmail;
<|endoftext|>


<commit_before>require('buffertools');
var crypto = require('crypto');
var bignum = require('bignum');
var Binary = require('./binary');
var logger = require('./logger');

// Native extensions
try {
  var ccmodule = require('../native.node');
} catch (e) {
  var bpath = require('path').resolve(__dirname, '..');
  logger.error((e.stack ? e.stack : e.toString()) + "\n");
  logger.error("Unable to load native module, try recompiling it:");
  logger.error("  cd "+bpath+"; node-waf build configure");
  process.exit(1);
}
exports.ccmodule = ccmodule;

exports.BitcoinKey = ccmodule.BitcoinKey;

var sha256 = exports.sha256 = function (data) {
  return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary');
};

var ripe160 = exports.ripe160 = function (data) {
  return new Buffer(crypto.createHash('rmd160').update(data).digest('binary'), 'binary');
};

var sha1 = exports.sha1 = function (data) {
  return new Buffer(crypto.createHash('sha').update(data).digest('binary'), 'binary');
};

var twoSha256 = exports.twoSha256 = function (data) {
  return sha256(sha256(data));
};

var sha256ripe160 = exports.sha256ripe160 = function (data) {
  return ripe160(sha256(data));
};

var sha256midstate = exports.sha256midstate = ccmodule.sha256_midstate;

var encodeHex = exports.encodeHex = function (buffer) {
  return buffer.slice(0).toHex().toString('ascii');
};

var decodeHex = exports.decodeHex = function (hex) {
  // Note that we copy (slice) at the end to convert from SlowBuffer to Buffer
  return new Buffer(hex, 'ascii').fromHex().slice(0);
};

var encodeBase58 = exports.encodeBase58 = ccmodule.base58_encode;

var decodeBase58 = exports.decodeBase58 = ccmodule.base58_decode;

// DEPRECATED, use BitcoinKey
var verifySig = exports.verifySig = function (sig, pubkey, hash) {
  var key = new ccmodule.BitcoinKey();
  key.public = pubkey;
  return key.verifySignatureSync(hash, sig);
};

/**
 * Format a block hash like the official client does.
 */
var formatHash = exports.formatHash = function (hash) {
  // Make a copy, because reverse() and toHex() are destructive.
  var hashEnd = new Buffer(10);
  hash.copy(hashEnd, 0, 22, 32);
  return hashEnd.reverse().toHex();
};

/**
 * Display the whole hash, as hex, in correct endian order.
 */
var formatHashFull = exports.formatHashFull = function (hash) {
  // Make a copy, because reverse() and toHex() are destructive.
  var copy = new Buffer(hash.length);
  hash.copy(copy);
  var hex = copy.reverse().toHex();
  return hex;
};

/**
 * Format a block hash like Block Explorer does.
 *
 * Formats a block hash by removing leading zeros and truncating to 10 characters.
 */
var formatHashAlt = exports.formatHashAlt = function (hash) {
  var hex = formatHashFull(hash);
  hex = hex.replace(/^0*/, '');
  return hex.substr(0, 10);
};

var formatBuffer = exports.formatBuffer = function (buffer, maxLen) {
  // Calculate amount of bytes to display
  if (maxLen === null) {
    maxLen = 10;
  }
  if (maxLen > buffer.length || maxLen === 0) {
    maxLen = buffer.length;
  }

  // Copy those bytes into a temporary buffer
  var temp = new Buffer(maxLen);
  buffer.copy(temp, 0, 0, maxLen);

  // Format as string
  var output = temp.toHex();
  if (temp.length < buffer.length) {
    output += "...";
  }
  return output;
};

var valueToBigInt = exports.valueToBigInt = function (valueBuffer) {
  if (Buffer.isBuffer(valueBuffer)) {
    return bignum.fromBuffer(valueBuffer, {endian: 'little', size: 8});
  } else {
    return valueBuffer;
  }
};

var bigIntToValue = exports.bigIntToValue = function (valueBigInt) {
  if (Buffer.isBuffer(valueBigInt)) {
    return valueBigInt;
  } else {
    return valueBigInt.toBuffer({endian: 'little', size: 8});
  }
};

var formatValue = exports.formatValue = function (valueBuffer) {
  var value = valueToBigInt(valueBuffer).toString();
  var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0';
  var decimalPart = value.length > 8 ? value.substr(value.length-8) : value;
  while (decimalPart.length < 8) {
    decimalPart = "0"+decimalPart;
  }
  decimalPart = decimalPart.replace(/0*$/, '');
  while (decimalPart.length < 2) {
    decimalPart += "0";
  }
  return integerPart+"."+decimalPart;
};

var pubKeyHashToAddress = exports.pubKeyHashToAddress = function (pubKeyHash) {
  if (!pubKeyHash) {
    return "";
  }

  var put = Binary.put();
  // Version
  put.word8le(0);
  // Hash
  put.put(pubKeyHash);
  // Checksum (four bytes)
  put.put(twoSha256(put.buffer()).slice(0,4));
  return encodeBase58(put.buffer());
};

var addressToPubKeyHash = exports.addressToPubKeyHash = function (address) {
  // Trim
  address = String(address).replace(/\s/g, '');

  // Check sanity
  if (!address.match(/^[1-9A-HJ-NP-Za-km-z]{27,35}$/)) {
    logger.warn("Not a valid Bitcoin address");
    return null;
  }

  // Decode
  var buffer = decodeBase58(address);

  // Parse
  var parser = Binary.parse(buffer);
  parser.word8('version');
  parser.buffer('hash', 20);
  parser.buffer('checksum', 4);

  // Check checksum
  var checksum = twoSha256(buffer.slice(0, 21)).slice(0, 4);
  if (checksum.compare(parser.vars.checksum) !== 0) {
    logger.warn("Checksum comparison failed");
    return null;
  }

  return parser.vars.hash;
};

// Utility that synchronizes function calls based on a key
var createSynchrotron = exports.createSynchrotron = function (fn) {
  var table = {};
  return function (key) {
    var args = Array.prototype.slice.call(arguments);
    var run = function () {
      // Function fn() will call when it finishes
      args[0] = function next() {
        if (table[key]) {
          if (table[key].length) {
            table[key].shift()();
          } else {
            delete table[key];
          }
        }
      };

      fn.apply(null, args);
    };

    if (!table[key]) {
      table[key] = [];
      run();
    } else {
      table[key].push(run);
    }
  };
};

/**
 * Generate a random 64-bit number.
 *
 * With ideas from node-uuid:
 * Copyright (c) 2010 Robert Kieffer
 * https://github.com/broofa/node-uuid/
 *
 * @returns Buffer random nonce
 */
var generateNonce = exports.generateNonce = function () {
  var b32 = 0x100000000, ff = 0xff;
  var b = new Buffer(8), i = 0;

  // Generate eight random bytes
  r = Math.random()*b32;
  b[i++] = r & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  r = Math.random()*b32;
  b[i++] = r & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;

  return b;
};

/**
 * Decode difficulty bits.
 *
 * This function calculates the difficulty target given the difficulty bits.
 */
var decodeDiffBits = exports.decodeDiffBits = function (diffBits, asBigInt) {
  diffBits = +diffBits;
  var target = bignum(diffBits & 0xffffff);
  target = target.shiftLeft(8*((diffBits >>> 24) - 3));

  if (asBigInt) {
    return target;
  }

  // Convert to buffer
  var diffBuf = target.toBuffer();
  var targetBuf = new Buffer(32).clear();
  diffBuf.copy(targetBuf, 32-diffBuf.length);
  return targetBuf;
};

/**
 * Encode difficulty bits.
 *
 * This function calculates the compact difficulty, given a difficulty target.
 */
var encodeDiffBits = exports.encodeDiffBits = function encodeDiffBits(target) {
  if (Buffer.isBuffer(target)) {
    target = bignum.fromBuffer(target);
  } else if ("function" === typeof target.toBuffer) { // duck-typing bignum
    // Nothing to do
  } else {
    throw new Error("Incorrect variable type for difficulty");
  }

  var mpiBuf = target.toBuffer("mpint");
  var size = mpiBuf.length - 4;

  var compact = size << 24;
  if (size >= 1) compact |= mpiBuf[4] << 16;
  if (size >= 2) compact |= mpiBuf[5] <<  8;
  if (size >= 3) compact |= mpiBuf[6]      ;

  return compact;
};

/**
 * Calculate "difficulty".
 *
 * This function calculates the maximum difficulty target divided by the given
 * difficulty target.
 */
var calcDifficulty = exports.calcDifficulty = function (target) {
  if (!Buffer.isBuffer(target)) {
    target = decodeDiffBits(target);
  }
  var targetBigint = bignum.fromBuffer(target, {order: 'forward'});
  var maxBigint = bignum.fromBuffer(MAX_TARGET, {order: 'forward'});
  return maxBigint.div(targetBigint).toNumber();
};

var reverseBytes32 = exports.reverseBytes32 = function (data) {
  if (data.length % 4) {
    throw new Error("Util.reverseBytes32(): Data length must be multiple of 4");
  }
  var put = Binary.put();
  var parser = Binary.parse(data);
  while (!parser.eof()) {
    var word = parser.word32le('word').vars.word;
    put.word32be(word);
  }
  return put.buffer();
};

var getVarIntSize = exports.getVarIntSize = function getVarIntSize(i) {

  if (i < 0xFD) {
    // unsigned char
    return 1;
  } else if (i <= 1<<16) {
    // unsigned short (LE)
    return 3;
  } else if (i <= 1<<32) {
    // unsigned int (LE)
    return 5;
  } else {
    // unsigned long long (LE)
    return 9;
  }
};

// Initializations
try {
  var NULL_HASH = exports.NULL_HASH = new Buffer(32).clear();
  var EMPTY_BUFFER = exports.EMPTY_BUFFER = new Buffer(0);
  var ZERO_VALUE = exports.ZERO_VALUE = new Buffer(8).clear();
  var INT64_MAX = exports.INT64_MAX = decodeHex("ffffffffffffffff");

  // How much of Bitcoin's internal integer coin representation
  // makes 1 BTC
  var COIN = exports.COIN = 100000000;

  var MAX_TARGET = exports.MAX_TARGET = decodeHex('00000000FFFF0000000000000000000000000000000000000000000000000000');
} catch (e) {
  logger.error("Error while generating utility constants:\n" +
         (e.stack ? e.stack : e.toString()));
  process.exit(1);
}
<commit_msg>Fix SHA1 opcode.<commit_after>require('buffertools');
var crypto = require('crypto');
var bignum = require('bignum');
var Binary = require('./binary');
var logger = require('./logger');

// Native extensions
try {
  var ccmodule = require('../native.node');
} catch (e) {
  var bpath = require('path').resolve(__dirname, '..');
  logger.error((e.stack ? e.stack : e.toString()) + "\n");
  logger.error("Unable to load native module, try recompiling it:");
  logger.error("  cd "+bpath+"; node-waf build configure");
  process.exit(1);
}
exports.ccmodule = ccmodule;

exports.BitcoinKey = ccmodule.BitcoinKey;

var sha256 = exports.sha256 = function (data) {
  return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary');
};

var ripe160 = exports.ripe160 = function (data) {
  return new Buffer(crypto.createHash('rmd160').update(data).digest('binary'), 'binary');
};

var sha1 = exports.sha1 = function (data) {
  return new Buffer(crypto.createHash('sha1').update(data).digest('binary'), 'binary');
};

var twoSha256 = exports.twoSha256 = function (data) {
  return sha256(sha256(data));
};

var sha256ripe160 = exports.sha256ripe160 = function (data) {
  return ripe160(sha256(data));
};

var sha256midstate = exports.sha256midstate = ccmodule.sha256_midstate;

var encodeHex = exports.encodeHex = function (buffer) {
  return buffer.slice(0).toHex().toString('ascii');
};

var decodeHex = exports.decodeHex = function (hex) {
  // Note that we copy (slice) at the end to convert from SlowBuffer to Buffer
  return new Buffer(hex, 'ascii').fromHex().slice(0);
};

var encodeBase58 = exports.encodeBase58 = ccmodule.base58_encode;

var decodeBase58 = exports.decodeBase58 = ccmodule.base58_decode;

// DEPRECATED, use BitcoinKey
var verifySig = exports.verifySig = function (sig, pubkey, hash) {
  var key = new ccmodule.BitcoinKey();
  key.public = pubkey;
  return key.verifySignatureSync(hash, sig);
};

/**
 * Format a block hash like the official client does.
 */
var formatHash = exports.formatHash = function (hash) {
  // Make a copy, because reverse() and toHex() are destructive.
  var hashEnd = new Buffer(10);
  hash.copy(hashEnd, 0, 22, 32);
  return hashEnd.reverse().toHex();
};

/**
 * Display the whole hash, as hex, in correct endian order.
 */
var formatHashFull = exports.formatHashFull = function (hash) {
  // Make a copy, because reverse() and toHex() are destructive.
  var copy = new Buffer(hash.length);
  hash.copy(copy);
  var hex = copy.reverse().toHex();
  return hex;
};

/**
 * Format a block hash like Block Explorer does.
 *
 * Formats a block hash by removing leading zeros and truncating to 10 characters.
 */
var formatHashAlt = exports.formatHashAlt = function (hash) {
  var hex = formatHashFull(hash);
  hex = hex.replace(/^0*/, '');
  return hex.substr(0, 10);
};

var formatBuffer = exports.formatBuffer = function (buffer, maxLen) {
  // Calculate amount of bytes to display
  if (maxLen === null) {
    maxLen = 10;
  }
  if (maxLen > buffer.length || maxLen === 0) {
    maxLen = buffer.length;
  }

  // Copy those bytes into a temporary buffer
  var temp = new Buffer(maxLen);
  buffer.copy(temp, 0, 0, maxLen);

  // Format as string
  var output = temp.toHex();
  if (temp.length < buffer.length) {
    output += "...";
  }
  return output;
};

var valueToBigInt = exports.valueToBigInt = function (valueBuffer) {
  if (Buffer.isBuffer(valueBuffer)) {
    return bignum.fromBuffer(valueBuffer, {endian: 'little', size: 8});
  } else {
    return valueBuffer;
  }
};

var bigIntToValue = exports.bigIntToValue = function (valueBigInt) {
  if (Buffer.isBuffer(valueBigInt)) {
    return valueBigInt;
  } else {
    return valueBigInt.toBuffer({endian: 'little', size: 8});
  }
};

var formatValue = exports.formatValue = function (valueBuffer) {
  var value = valueToBigInt(valueBuffer).toString();
  var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0';
  var decimalPart = value.length > 8 ? value.substr(value.length-8) : value;
  while (decimalPart.length < 8) {
    decimalPart = "0"+decimalPart;
  }
  decimalPart = decimalPart.replace(/0*$/, '');
  while (decimalPart.length < 2) {
    decimalPart += "0";
  }
  return integerPart+"."+decimalPart;
};

var pubKeyHashToAddress = exports.pubKeyHashToAddress = function (pubKeyHash) {
  if (!pubKeyHash) {
    return "";
  }

  var put = Binary.put();
  // Version
  put.word8le(0);
  // Hash
  put.put(pubKeyHash);
  // Checksum (four bytes)
  put.put(twoSha256(put.buffer()).slice(0,4));
  return encodeBase58(put.buffer());
};

var addressToPubKeyHash = exports.addressToPubKeyHash = function (address) {
  // Trim
  address = String(address).replace(/\s/g, '');

  // Check sanity
  if (!address.match(/^[1-9A-HJ-NP-Za-km-z]{27,35}$/)) {
    logger.warn("Not a valid Bitcoin address");
    return null;
  }

  // Decode
  var buffer = decodeBase58(address);

  // Parse
  var parser = Binary.parse(buffer);
  parser.word8('version');
  parser.buffer('hash', 20);
  parser.buffer('checksum', 4);

  // Check checksum
  var checksum = twoSha256(buffer.slice(0, 21)).slice(0, 4);
  if (checksum.compare(parser.vars.checksum) !== 0) {
    logger.warn("Checksum comparison failed");
    return null;
  }

  return parser.vars.hash;
};

// Utility that synchronizes function calls based on a key
var createSynchrotron = exports.createSynchrotron = function (fn) {
  var table = {};
  return function (key) {
    var args = Array.prototype.slice.call(arguments);
    var run = function () {
      // Function fn() will call when it finishes
      args[0] = function next() {
        if (table[key]) {
          if (table[key].length) {
            table[key].shift()();
          } else {
            delete table[key];
          }
        }
      };

      fn.apply(null, args);
    };

    if (!table[key]) {
      table[key] = [];
      run();
    } else {
      table[key].push(run);
    }
  };
};

/**
 * Generate a random 64-bit number.
 *
 * With ideas from node-uuid:
 * Copyright (c) 2010 Robert Kieffer
 * https://github.com/broofa/node-uuid/
 *
 * @returns Buffer random nonce
 */
var generateNonce = exports.generateNonce = function () {
  var b32 = 0x100000000, ff = 0xff;
  var b = new Buffer(8), i = 0;

  // Generate eight random bytes
  r = Math.random()*b32;
  b[i++] = r & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  r = Math.random()*b32;
  b[i++] = r & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;
  b[i++] = (r=r>>>8) & ff;

  return b;
};

/**
 * Decode difficulty bits.
 *
 * This function calculates the difficulty target given the difficulty bits.
 */
var decodeDiffBits = exports.decodeDiffBits = function (diffBits, asBigInt) {
  diffBits = +diffBits;
  var target = bignum(diffBits & 0xffffff);
  target = target.shiftLeft(8*((diffBits >>> 24) - 3));

  if (asBigInt) {
    return target;
  }

  // Convert to buffer
  var diffBuf = target.toBuffer();
  var targetBuf = new Buffer(32).clear();
  diffBuf.copy(targetBuf, 32-diffBuf.length);
  return targetBuf;
};

/**
 * Encode difficulty bits.
 *
 * This function calculates the compact difficulty, given a difficulty target.
 */
var encodeDiffBits = exports.encodeDiffBits = function encodeDiffBits(target) {
  if (Buffer.isBuffer(target)) {
    target = bignum.fromBuffer(target);
  } else if ("function" === typeof target.toBuffer) { // duck-typing bignum
    // Nothing to do
  } else {
    throw new Error("Incorrect variable type for difficulty");
  }

  var mpiBuf = target.toBuffer("mpint");
  var size = mpiBuf.length - 4;

  var compact = size << 24;
  if (size >= 1) compact |= mpiBuf[4] << 16;
  if (size >= 2) compact |= mpiBuf[5] <<  8;
  if (size >= 3) compact |= mpiBuf[6]      ;

  return compact;
};

/**
 * Calculate "difficulty".
 *
 * This function calculates the maximum difficulty target divided by the given
 * difficulty target.
 */
var calcDifficulty = exports.calcDifficulty = function (target) {
  if (!Buffer.isBuffer(target)) {
    target = decodeDiffBits(target);
  }
  var targetBigint = bignum.fromBuffer(target, {order: 'forward'});
  var maxBigint = bignum.fromBuffer(MAX_TARGET, {order: 'forward'});
  return maxBigint.div(targetBigint).toNumber();
};

var reverseBytes32 = exports.reverseBytes32 = function (data) {
  if (data.length % 4) {
    throw new Error("Util.reverseBytes32(): Data length must be multiple of 4");
  }
  var put = Binary.put();
  var parser = Binary.parse(data);
  while (!parser.eof()) {
    var word = parser.word32le('word').vars.word;
    put.word32be(word);
  }
  return put.buffer();
};

var getVarIntSize = exports.getVarIntSize = function getVarIntSize(i) {

  if (i < 0xFD) {
    // unsigned char
    return 1;
  } else if (i <= 1<<16) {
    // unsigned short (LE)
    return 3;
  } else if (i <= 1<<32) {
    // unsigned int (LE)
    return 5;
  } else {
    // unsigned long long (LE)
    return 9;
  }
};

// Initializations
try {
  var NULL_HASH = exports.NULL_HASH = new Buffer(32).clear();
  var EMPTY_BUFFER = exports.EMPTY_BUFFER = new Buffer(0);
  var ZERO_VALUE = exports.ZERO_VALUE = new Buffer(8).clear();
  var INT64_MAX = exports.INT64_MAX = decodeHex("ffffffffffffffff");

  // How much of Bitcoin's internal integer coin representation
  // makes 1 BTC
  var COIN = exports.COIN = 100000000;

  var MAX_TARGET = exports.MAX_TARGET = decodeHex('00000000FFFF0000000000000000000000000000000000000000000000000000');
} catch (e) {
  logger.error("Error while generating utility constants:\n" +
         (e.stack ? e.stack : e.toString()));
  process.exit(1);
}
<|endoftext|>


<commit_before>(function(tree) {

tree.LayerXML = function(obj, styles) {
    var dsoptions = [];
    for (var i in obj.Datasource) {
        dsoptions.push('<Parameter name="' + i + '"><![CDATA[' +
            obj.Datasource[i] + ']]></Parameter>');
    }

    var prop_string = '';
    for (var prop in obj.properties) {
        prop_string += '  ' + prop + '="' + obj.properties[prop] + '"\n';
    }

    return '<Layer' +
        ' name="' + obj.name + '"\n' +
        prop_string +
        ((typeof obj.status === 'undefined') ? '' : '  status="' + obj.status + '"\n') +
        '  srs="' + obj.srs + '">\n    ' +
        styles.reverse().map(function(s) {
            return '<StyleName>' + s + '</StyleName>';
        }).join('\n    ') +
        '\n    <Datasource>\n       ' +
        dsoptions.join('\n       ') +
        '\n    </Datasource>\n' +
        '  </Layer>\n';
};

})(require('../tree'));
<commit_msg>Convert minzoom/maxzoom parameters on Layer properties.<commit_after>(function(tree) {

tree.LayerXML = function(obj, styles) {
    var dsoptions = [];
    for (var i in obj.Datasource) {
        dsoptions.push('<Parameter name="' + i + '"><![CDATA[' +
            obj.Datasource[i] + ']]></Parameter>');
    }

    var prop_string = '';
    for (var prop in obj.properties) {
        if (prop === 'minzoom') {
            prop_string += '  maxzoom="' + tree.Zoom.ranges[obj.properties[prop]] + '"\n';
        } else if (prop === 'maxzoom') {
            prop_string += '  minzoom="' + tree.Zoom.ranges[obj.properties[prop]+1] + '"\n';
        } else {
            prop_string += '  ' + prop + '="' + obj.properties[prop] + '"\n';
        }
    }

    return '<Layer' +
        ' name="' + obj.name + '"\n' +
        prop_string +
        ((typeof obj.status === 'undefined') ? '' : '  status="' + obj.status + '"\n') +
        '  srs="' + obj.srs + '">\n    ' +
        styles.reverse().map(function(s) {
            return '<StyleName>' + s + '</StyleName>';
        }).join('\n    ') +
        '\n    <Datasource>\n       ' +
        dsoptions.join('\n       ') +
        '\n    </Datasource>\n' +
        '  </Layer>\n';
};

})(require('../tree'));
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2013 LevelUP contributors
 * See list at <https://github.com/rvagg/node-levelup#contributing>
 * MIT +no-false-attribs License
 * <https://github.com/rvagg/node-levelup/blob/master/LICENSE>
 */

var encodings = [
        'hex'
      , 'utf8'
      , 'utf-8'
      , 'ascii'
      , 'binary'
      , 'base64'
      , 'ucs2'
      , 'ucs-2'
      , 'utf16le'
      , 'utf-16le'
    ]

  , toSlice = (function () {
      var slicers = {}
        , isBuffer = function (data) {
            return data === undefined || data === null || Buffer.isBuffer(data)
          }
      slicers.json = JSON.stringify.bind(JSON)
      slicers.utf8 = function (data) {
        return isBuffer(data) ? data : String(data)
      }
      encodings.forEach(function (enc) {
        if (slicers[enc]) return
        slicers[enc] = function (data) {
          return isBuffer(data) ? data : new Buffer(data, enc)
        }
      })
      return slicers
    }())

  , toEncoding = (function () {
      var encoders = {}
      encoders.json = function (str) { return JSON.parse(str) }
      encoders.utf8 = function (str) { return str }
      encoders.binary = function (buffer) { return buffer }
      encodings.forEach(function (enc) {
        if (encoders[enc]) return
        encoders[enc] = function (buffer) { return buffer.toString(enc) }
      })
      return encoders
    }())

  , copy = function (srcdb, dstdb, callback) {
      srcdb.readStream()
        .pipe(dstdb.writeStream({ useBatch: false }))
        .on('close', callback ? callback : function () {})
        .on('error', callback ? callback : function (err) { throw err })
    }

  , setImmediate = global.setImmediate || process.nextTick

  , encodingOpts = (function () {
      var eo = {}
      encodings.forEach(function (e) { eo[e] = { encoding: e } })
      return eo
    }())

module.exports = {
    toSlice      : toSlice
  , toEncoding   : toEncoding
  , copy         : copy
  , setImmediate : setImmediate
  , encodingOpts : encodingOpts
}<commit_msg>remove useBatch in copy<commit_after>/* Copyright (c) 2012-2013 LevelUP contributors
 * See list at <https://github.com/rvagg/node-levelup#contributing>
 * MIT +no-false-attribs License
 * <https://github.com/rvagg/node-levelup/blob/master/LICENSE>
 */

var encodings = [
        'hex'
      , 'utf8'
      , 'utf-8'
      , 'ascii'
      , 'binary'
      , 'base64'
      , 'ucs2'
      , 'ucs-2'
      , 'utf16le'
      , 'utf-16le'
    ]

  , toSlice = (function () {
      var slicers = {}
        , isBuffer = function (data) {
            return data === undefined || data === null || Buffer.isBuffer(data)
          }
      slicers.json = JSON.stringify.bind(JSON)
      slicers.utf8 = function (data) {
        return isBuffer(data) ? data : String(data)
      }
      encodings.forEach(function (enc) {
        if (slicers[enc]) return
        slicers[enc] = function (data) {
          return isBuffer(data) ? data : new Buffer(data, enc)
        }
      })
      return slicers
    }())

  , toEncoding = (function () {
      var encoders = {}
      encoders.json = function (str) { return JSON.parse(str) }
      encoders.utf8 = function (str) { return str }
      encoders.binary = function (buffer) { return buffer }
      encodings.forEach(function (enc) {
        if (encoders[enc]) return
        encoders[enc] = function (buffer) { return buffer.toString(enc) }
      })
      return encoders
    }())

  , copy = function (srcdb, dstdb, callback) {
      srcdb.readStream()
        .pipe(dstdb.writeStream())
        .on('close', callback ? callback : function () {})
        .on('error', callback ? callback : function (err) { throw err })
    }

  , setImmediate = global.setImmediate || process.nextTick

  , encodingOpts = (function () {
      var eo = {}
      encodings.forEach(function (e) { eo[e] = { encoding: e } })
      return eo
    }())

module.exports = {
    toSlice      : toSlice
  , toEncoding   : toEncoding
  , copy         : copy
  , setImmediate : setImmediate
  , encodingOpts : encodingOpts
}<|endoftext|>


<commit_before>'use strict';
// ==================================================================================
// utils.js
// ----------------------------------------------------------------------------------
// Description:   System Information - library
//                for Node.js
// Copyright:     (c) 2014 - 2019
// Author:        Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License:       MIT
// ==================================================================================
// 0. helper functions
// ----------------------------------------------------------------------------------

const os = require('os');
const fs = require('fs');
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;

let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
// const _sunos = (_platform === 'sunos');

let _cores = 0;
let wmic = '';
let codepage = '';

const execOptsWin = {
  windowsHide: true,
  maxBuffer: 1024 * 2000,
  encoding: 'UTF-8'
};

function isFunction(functionToCheck) {
  let getType = {};
  return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}

function unique(obj) {
  let uniques = [];
  let stringify = {};
  for (let i = 0; i < obj.length; i++) {
    let keys = Object.keys(obj[i]);
    keys.sort(function (a, b) { return a - b; });
    let str = '';
    for (let j = 0; j < keys.length; j++) {
      str += JSON.stringify(keys[j]);
      str += JSON.stringify(obj[i][keys[j]]);
    }
    if (!stringify.hasOwnProperty(str)) {
      uniques.push(obj[i]);
      stringify[str] = true;
    }
  }
  return uniques;
}

function sortByKey(array, keys) {
  return array.sort(function (a, b) {
    let x = '';
    let y = '';
    keys.forEach(function (key) {
      x = x + a[key]; y = y + b[key];
    });
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  });
}

function cores() {
  if (_cores === 0) {
    _cores = os.cpus().length;
  }
  return _cores;
}

function getValue(lines, property, separator, trimmed) {
  separator = separator || ':';
  property = property.toLowerCase();
  trimmed = trimmed || false;
  for (let i = 0; i < lines.length; i++) {
    let line = lines[i].toLowerCase().replace(/\t/g, '');
    if (trimmed) {
      line = line.trim();
    }
    if (line.startsWith(property)) {
      const parts = lines[i].split(separator);
      if (parts.length >= 2) {
        parts.shift();
        return parts.join(separator).trim();
      } else {
        return '';
      }
    }
  }
  return '';
}

function decodeEscapeSequence(str, base) {
  base = base || 16;
  return str.replace(/\\x([0-9A-Fa-f]{2})/g, function () {
    return String.fromCharCode(parseInt(arguments[1], base));
  });
}

function parseDateTime(dt) {
  const result = {
    date: '',
    time: ''
  };
  const parts = dt.split(' ');
  if (parts[0]) {
    if (parts[0].indexOf('/') >= 0) {
      // Dateformat: mm/dd/yyyy
      const dtparts = parts[0].split('/');
      if (dtparts.length === 3) {
        result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
      }
    }
    if (parts[0].indexOf('.') >= 0) {
      // Dateformat: dd.mm.yyyy
      const dtparts = parts[0].split('.');
      if (dtparts.length === 3) {
        result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
      }
    }
    if (parts[0].indexOf('-') >= 0) {
      // Dateformat: yyyy-mm-dd
      const dtparts = parts[0].split('-');
      if (dtparts.length === 3) {
        result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
      }
    }
  }
  if (parts[1]) {
    result.time = parts[1];
  }
  return result;
}

function parseHead(head, rights) {
  let space = (rights > 0);
  let count = 1;
  let from = 0;
  let to = 0;
  let result = [];
  for (let i = 0; i < head.length; i++) {
    if (count <= rights) {
      // if (head[i] === ' ' && !space) {
      if (/\s/.test(head[i]) && !space) {
        to = i - 1;
        result.push({
          from: from,
          to: to + 1,
          cap: head.substring(from, to + 1)
        });
        from = to + 2;
        count++;
      }
      space = head[i] === ' ';
    } else {
      if (!/\s/.test(head[i]) && space) {
        to = i - 1;
        if (from < to) {
          result.push({
            from: from,
            to: to,
            cap: head.substring(from, to)
          });
        }
        from = to + 1;
        count++;
      }
      space = head[i] === ' ';
    }
  }
  to = 1000;
  result.push({
    from: from,
    to: to,
    cap: head.substring(from, to)
  });
  let len = result.length;
  for (var i = 0; i < len; i++) {
    if (result[i].cap.replace(/\s/g, '').length === 0) {
      if (i + 1 < len) {
        result[i].to = result[i + 1].to;
        result[i].cap = result[i].cap + result[i + 1].cap;
        result.splice(i + 1, 1);
        len = len - 1;
      }
    }
  }
  return result;
}

function findObjectByKey(array, key, value) {
  for (let i = 0; i < array.length; i++) {
    if (array[i][key] === value) {
      return i;
    }
  }
  return -1;
}

function getWmic() {
  if (os.type() === 'Windows_NT' && !wmic) {
    if (fs.existsSync(process.env.WINDIR + '\\system32\\wbem\\wmic.exe')) {
      wmic = process.env.WINDIR + '\\system32\\wbem\\wmic.exe';
    } else wmic = 'wmic';
  }
  return wmic;
}

function powerShell(cmd) {
  return new Promise((resolve, reject) => {
    process.nextTick(() => {

      let result = '';
      const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], {
        stdio: 'pipe'
      });

      if (child) {
        child.stdout.on('data', function (data) {
          result = result + data.toString('utf8');
        });
        child.stderr.on('data', function (data) {
          child.kill();
          reject(data);
        });
        child.on('close', function () {
          child.kill();
          resolve(result);
        });
        child.on('error', function () {
          child.kill();
          resolve(result);
        });

        try {
          child.stdin.write(cmd + '\n');
          child.stdin.end();
        } catch (e) {
          reject(result)
        }
      } else {
        reject(result);
      }
    });
  });
}

function getCodepage() {
  if (_windows) {
    if (!codepage) {
      try {
        const stdout = execSync('chcp');
        const lines = stdout.toString().split('\r\n');
        const parts = lines[0].split(':');
        codepage = parts.length > 1 ? parts[1].replace('.', '') : '';
      } catch (err) {
        codepage = '437';
      }
    }
    return codepage;
  }
  if (_linux || _darwin || _freebsd || _openbsd) {
    if (!codepage) {
      try {
        const stdout = execSync('echo $LANG');
        const lines = stdout.toString().split('\r\n');
        const parts = lines[0].split('.');
        codepage = parts.length > 1 ? parts[1].trim() : '';
        if (!codepage) {
          codepage = 'UTF-8';
        }
      } catch (err) {
        codepage = 'UTF-8';
      }
    }
    return codepage;
  }
}

function isRaspberry() {
  const PI_MODEL_NO = [
    'BCM2708',
    'BCM2709',
    'BCM2710',
    'BCM2835',
    'BCM2837B0'
  ];
  let cpuinfo = [];
  try {
    cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).split('\n');
  } catch (e) {
    return false;
  }
  const hardware = getValue(cpuinfo, 'hardware');
  return (hardware && PI_MODEL_NO.indexOf(hardware) > -1);
}

function isRaspbian() {
  let osrelease = [];
  try {
    osrelease = fs.readFileSync('/etc/os-release', { encoding: 'utf8' }).split('\n');
  } catch (e) {
    return false;
  }
  const id = getValue(osrelease, 'id');
  return (id && id.indexOf('raspbian') > -1);
}

function execWin(cmd, opts, callback) {
  if (!callback) {
    callback = opts;
    opts = execOptsWin;
  }
  let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
  exec(newCmd, opts, function (error, stdout) {
    callback(error, stdout);
  });
}

function nanoSeconds() {
  const time = process.hrtime();
  if (!Array.isArray(time) || time.length !== 2) {
    return 0;
  }
  return +time[0] * 1e9 + +time[1];
}

function countUniqueLines(lines, startingWith) {
  startingWith = startingWith || '';
  const uniqueLines = [];
  lines.forEach(line => {
    if (line.indexOf(startingWith) === 0) {
      if (uniqueLines.indexOf(line) === -1) {
        uniqueLines.push(line);
      }
    }
  });
  return uniqueLines.length;
}
function noop() { }

exports.execOptsWin = execOptsWin;
exports.getCodepage = getCodepage;
exports.execWin = execWin;
exports.isFunction = isFunction;
exports.unique = unique;
exports.sortByKey = sortByKey;
exports.cores = cores;
exports.getValue = getValue;
exports.decodeEscapeSequence = decodeEscapeSequence;
exports.parseDateTime = parseDateTime;
exports.parseHead = parseHead;
exports.findObjectByKey = findObjectByKey;
exports.getWmic = getWmic;
exports.powerShell = powerShell;
exports.nanoSeconds = nanoSeconds;
exports.countUniqueLines = countUniqueLines;
exports.noop = noop;
exports.isRaspberry = isRaspberry;
exports.isRaspbian = isRaspbian;
<commit_msg>powerShell optimizatio error handling<commit_after>'use strict';
// ==================================================================================
// utils.js
// ----------------------------------------------------------------------------------
// Description:   System Information - library
//                for Node.js
// Copyright:     (c) 2014 - 2019
// Author:        Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License:       MIT
// ==================================================================================
// 0. helper functions
// ----------------------------------------------------------------------------------

const os = require('os');
const fs = require('fs');
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;

let _platform = process.platform;
const _linux = (_platform === 'linux');
const _darwin = (_platform === 'darwin');
const _windows = (_platform === 'win32');
const _freebsd = (_platform === 'freebsd');
const _openbsd = (_platform === 'openbsd');
// const _sunos = (_platform === 'sunos');

let _cores = 0;
let wmic = '';
let codepage = '';

const execOptsWin = {
  windowsHide: true,
  maxBuffer: 1024 * 2000,
  encoding: 'UTF-8'
};

function isFunction(functionToCheck) {
  let getType = {};
  return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}

function unique(obj) {
  let uniques = [];
  let stringify = {};
  for (let i = 0; i < obj.length; i++) {
    let keys = Object.keys(obj[i]);
    keys.sort(function (a, b) { return a - b; });
    let str = '';
    for (let j = 0; j < keys.length; j++) {
      str += JSON.stringify(keys[j]);
      str += JSON.stringify(obj[i][keys[j]]);
    }
    if (!stringify.hasOwnProperty(str)) {
      uniques.push(obj[i]);
      stringify[str] = true;
    }
  }
  return uniques;
}

function sortByKey(array, keys) {
  return array.sort(function (a, b) {
    let x = '';
    let y = '';
    keys.forEach(function (key) {
      x = x + a[key]; y = y + b[key];
    });
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  });
}

function cores() {
  if (_cores === 0) {
    _cores = os.cpus().length;
  }
  return _cores;
}

function getValue(lines, property, separator, trimmed) {
  separator = separator || ':';
  property = property.toLowerCase();
  trimmed = trimmed || false;
  for (let i = 0; i < lines.length; i++) {
    let line = lines[i].toLowerCase().replace(/\t/g, '');
    if (trimmed) {
      line = line.trim();
    }
    if (line.startsWith(property)) {
      const parts = lines[i].split(separator);
      if (parts.length >= 2) {
        parts.shift();
        return parts.join(separator).trim();
      } else {
        return '';
      }
    }
  }
  return '';
}

function decodeEscapeSequence(str, base) {
  base = base || 16;
  return str.replace(/\\x([0-9A-Fa-f]{2})/g, function () {
    return String.fromCharCode(parseInt(arguments[1], base));
  });
}

function parseDateTime(dt) {
  const result = {
    date: '',
    time: ''
  };
  const parts = dt.split(' ');
  if (parts[0]) {
    if (parts[0].indexOf('/') >= 0) {
      // Dateformat: mm/dd/yyyy
      const dtparts = parts[0].split('/');
      if (dtparts.length === 3) {
        result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
      }
    }
    if (parts[0].indexOf('.') >= 0) {
      // Dateformat: dd.mm.yyyy
      const dtparts = parts[0].split('.');
      if (dtparts.length === 3) {
        result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
      }
    }
    if (parts[0].indexOf('-') >= 0) {
      // Dateformat: yyyy-mm-dd
      const dtparts = parts[0].split('-');
      if (dtparts.length === 3) {
        result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
      }
    }
  }
  if (parts[1]) {
    result.time = parts[1];
  }
  return result;
}

function parseHead(head, rights) {
  let space = (rights > 0);
  let count = 1;
  let from = 0;
  let to = 0;
  let result = [];
  for (let i = 0; i < head.length; i++) {
    if (count <= rights) {
      // if (head[i] === ' ' && !space) {
      if (/\s/.test(head[i]) && !space) {
        to = i - 1;
        result.push({
          from: from,
          to: to + 1,
          cap: head.substring(from, to + 1)
        });
        from = to + 2;
        count++;
      }
      space = head[i] === ' ';
    } else {
      if (!/\s/.test(head[i]) && space) {
        to = i - 1;
        if (from < to) {
          result.push({
            from: from,
            to: to,
            cap: head.substring(from, to)
          });
        }
        from = to + 1;
        count++;
      }
      space = head[i] === ' ';
    }
  }
  to = 1000;
  result.push({
    from: from,
    to: to,
    cap: head.substring(from, to)
  });
  let len = result.length;
  for (var i = 0; i < len; i++) {
    if (result[i].cap.replace(/\s/g, '').length === 0) {
      if (i + 1 < len) {
        result[i].to = result[i + 1].to;
        result[i].cap = result[i].cap + result[i + 1].cap;
        result.splice(i + 1, 1);
        len = len - 1;
      }
    }
  }
  return result;
}

function findObjectByKey(array, key, value) {
  for (let i = 0; i < array.length; i++) {
    if (array[i][key] === value) {
      return i;
    }
  }
  return -1;
}

function getWmic() {
  if (os.type() === 'Windows_NT' && !wmic) {
    if (fs.existsSync(process.env.WINDIR + '\\system32\\wbem\\wmic.exe')) {
      wmic = process.env.WINDIR + '\\system32\\wbem\\wmic.exe';
    } else wmic = 'wmic';
  }
  return wmic;
}

function powerShell(cmd) {

  // helper function
  function dispose(child) {
    return new Promise((resolve, reject) => {
      child.stdin.write('exit' + os.EOL);
      process.nextTick(() => {
        child.stdin.end()
        child.kill();
        resolve();
      });
    })
  }

  let result = '';

  return new Promise((resolve, reject) => {

    process.nextTick(() => {

      try {
        const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], {
          stdio: 'pipe'
        });

        if (child && child.pid) {
          child.stdout.on('data', function (data) {
            result = result + data.toString('utf8');
          });
          child.stderr.on('data', function (data) {
            dispose(child).then(resolve(result));
          });
          child.on('close', function () {
            dispose(child).then(resolve(result));
            ;
          });
          child.on('error', function () {
            dispose(child).then(resolve(result));
          });

          try {
            child.stdin.write(cmd + os.EOL);
          } catch (e) {
            dispose(child).then(resolve(result));
          }
        } else {
          resolve(result);
        }
      } catch (e) {
        resolve(result);
      }
    });
  });
}

function getCodepage() {
  if (_windows) {
    if (!codepage) {
      try {
        const stdout = execSync('chcp');
        const lines = stdout.toString().split('\r\n');
        const parts = lines[0].split(':');
        codepage = parts.length > 1 ? parts[1].replace('.', '') : '';
      } catch (err) {
        codepage = '437';
      }
    }
    return codepage;
  }
  if (_linux || _darwin || _freebsd || _openbsd) {
    if (!codepage) {
      try {
        const stdout = execSync('echo $LANG');
        const lines = stdout.toString().split('\r\n');
        const parts = lines[0].split('.');
        codepage = parts.length > 1 ? parts[1].trim() : '';
        if (!codepage) {
          codepage = 'UTF-8';
        }
      } catch (err) {
        codepage = 'UTF-8';
      }
    }
    return codepage;
  }
}

function isRaspberry() {
  const PI_MODEL_NO = [
    'BCM2708',
    'BCM2709',
    'BCM2710',
    'BCM2835',
    'BCM2837B0'
  ];
  let cpuinfo = [];
  try {
    cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).split('\n');
  } catch (e) {
    return false;
  }
  const hardware = getValue(cpuinfo, 'hardware');
  return (hardware && PI_MODEL_NO.indexOf(hardware) > -1);
}

function isRaspbian() {
  let osrelease = [];
  try {
    osrelease = fs.readFileSync('/etc/os-release', { encoding: 'utf8' }).split('\n');
  } catch (e) {
    return false;
  }
  const id = getValue(osrelease, 'id');
  return (id && id.indexOf('raspbian') > -1);
}

function execWin(cmd, opts, callback) {
  if (!callback) {
    callback = opts;
    opts = execOptsWin;
  }
  let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
  exec(newCmd, opts, function (error, stdout) {
    callback(error, stdout);
  });
}

function nanoSeconds() {
  const time = process.hrtime();
  if (!Array.isArray(time) || time.length !== 2) {
    return 0;
  }
  return +time[0] * 1e9 + +time[1];
}

function countUniqueLines(lines, startingWith) {
  startingWith = startingWith || '';
  const uniqueLines = [];
  lines.forEach(line => {
    if (line.indexOf(startingWith) === 0) {
      if (uniqueLines.indexOf(line) === -1) {
        uniqueLines.push(line);
      }
    }
  });
  return uniqueLines.length;
}
function noop() { }

exports.execOptsWin = execOptsWin;
exports.getCodepage = getCodepage;
exports.execWin = execWin;
exports.isFunction = isFunction;
exports.unique = unique;
exports.sortByKey = sortByKey;
exports.cores = cores;
exports.getValue = getValue;
exports.decodeEscapeSequence = decodeEscapeSequence;
exports.parseDateTime = parseDateTime;
exports.parseHead = parseHead;
exports.findObjectByKey = findObjectByKey;
exports.getWmic = getWmic;
exports.powerShell = powerShell;
exports.nanoSeconds = nanoSeconds;
exports.countUniqueLines = countUniqueLines;
exports.noop = noop;
exports.isRaspberry = isRaspberry;
exports.isRaspbian = isRaspbian;
<|endoftext|>


<commit_before>var fs = require('fs'),
    url = require('url'),

    _ = require('lodash'),
    prettyms = require('pretty-ms'),
    filesize = require('filesize'),
    request = require('postman-request'),
    parseJson = require('parse-json'),

    util,
    version = require('../package.json').version,

    SEP = ' / ',

    /**
     * The auxiliary character used to prettify file sizes from raw byte counts.
     *
     * @type {Object}
     */
    FILESIZE_OPTIONS = { spacer: '' },

    PRO_API_HOST = 'api.getpostman.com',
    USER_AGENT_VALUE = 'Newman/' + version,

    UID_REGEX = /^[0-9A-Z]+-[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;

util = {

    /**
     * The raw newman version, taken from package.json in the root directory
     *
     * @type {String}
     */
    version: version,

    /**
     * The user agent that this newman identifies as.
     *
     * @type {String}
     */
    userAgent: USER_AGENT_VALUE,

    /**
     * A utility helper method that prettifies and returns raw millisecond counts.
     *
     * @param {Number} ms - The raw millisecond count, usually from response times.
     * @returns {String} - The prettified time, scaled to units of time, depending on the input value.
     */
    prettyms: function (ms) {
        return (ms < 1998) ? `${parseInt(ms, 10)}ms` : prettyms(ms || 0);
    },

    /**
     * A utility helper method to prettify byte counts into human readable strings.
     *
     * @param {Number} bytes - The raw byte count, usually from computed response sizes.
     * @returns {String} - The prettified size, suffixed with scaled units, depending on the actual value provided.
     */
    filesize: function (bytes) {
        return filesize(bytes || 0, FILESIZE_OPTIONS);
    },

    /**
     * Resolves the fully qualified name for the provided item
     *
     * @param {PostmanItem|PostmanItemGroup} item The item for which to resolve the full name
     * @param {?String} [separator=SEP] The separator symbol to join path name entries with
     * @returns {String} The full name of the provided item, including prepended parent item names
     * @private
     */
    getFullName: function (item, separator) {
        if (_.isEmpty(item) || !_.isFunction(item.parent) || !_.isFunction(item.forEachParent)) { return; }

        var chain = [];

        item.forEachParent(function (parent) { chain.unshift(parent.name || parent.id); });

        item.parent() && chain.push(item.name || item.id); // Add the current item only if it is not the collection

        return chain.join(_.isString(separator) ? separator : SEP);
    },

    /**
     * Loads JSON data from the given location.
     *
     * @param {String} type - The type of data to load.
     * @param {String} location - Can be an HTTP URL or a local file path.
     * @param {Object=} options - A set of options for JSON data loading.
     * @param {Object} options.postmanApiKey - API Key used to load the resources via UID from the Postman Cloud.
     * @param {Function} callback - The function whose invocation marks the end of the JSON fetch routine.
     * @returns {*}
     */

    fetchJson: function (type, location, options, callback) {
        !callback && _.isFunction(options) && (callback = options, options = {});

        var postmanApiKey = _.get(options, 'postmanApiKey'),
            headers = { 'User-Agent': USER_AGENT_VALUE };

        // build API URL if `location` is a valid UID and api key is provided.
        // Fetch from file in case a file with valid UID name is present.
        if (UID_REGEX.test(location) && !fs.existsSync(location) && postmanApiKey) {
            location = `https://${PRO_API_HOST}/${type === 'collection' ? 'collections' : 'environments'}/${location}`;
            headers['X-Api-Key'] = postmanApiKey;
        }

        return (/^https?:\/\/.*/).test(location) ?
            // Load from URL
            request.get({
                url: location,
                json: true,
                headers: headers
            }, (err, response, body) => {
                if (err) {
                    return callback(_.set(err, 'help', `unable to fetch data from url "${location}"`));
                }

                try {
                    _.isString(body) && (body = parseJson(body.trim()));
                }
                catch (e) {
                    return callback(_.set(e, 'help', `the url "${location}" did not provide valid JSON data`));
                }

                var error,
                    urlObj,
                    resource = 'resource';

                if (response.statusCode !== 200) {
                    urlObj = url.parse(location);

                    (urlObj.hostname === PRO_API_HOST) &&
                        (resource = _(urlObj.path).split('/').get(1).slice(0, -1) || resource);

                    error = new Error(_.get(body, 'error.message',
                        `Error fetching ${resource}, the provided URL returned status code: ${response.statusCode}`));

                    return callback(_.assign(error, {
                        name: _.get(body, 'error.name', _.capitalize(resource) + 'FetchError'),
                        help: `Error fetching the ${resource} from the provided URL. Ensure that the URL is valid.`
                    }));
                }

                return callback(null, body);
            }) :
            fs.readFile(location, function (err, value) {
                if (err) {
                    return callback(_.set(err, 'help', `unable to read data from file "${location}"`));
                }

                try {
                    value = parseJson(value.toString());
                }
                catch (e) {
                    return callback(_.set(e, 'help', `the file at ${location} does not contain valid JSON data`));
                }

                return callback(null, value);
            });
    },

    /**
     * Loads raw data from a location, useful for working with non JSON data such as CSV files.
     *
     * @param {String} location - The relative path / URL to the raw data file.
     * @param {Object=} options - A set of load options for the raw data file.
     * @param {Function} callback - The callback function whose invocation marks the end of the fetch routine.
     * @returns {*}
     */
    fetch: function (location, options, callback) {
        !callback && _.isFunction(options) && (callback = options, options = {});

        return (/^https?:\/\/.*/).test(location) ?
            // Load from URL
            request.get({ url: location }, (err, response, body) => {
                if (err) {
                    return callback(err);
                }

                return callback(null, body);
            }) :
            fs.readFile(location, function (err, value) {
                if (err) {
                    return callback(err);
                }

                return callback(null, value.toString());
            });
    },

    /**
     * Helper function to test if a given string is an integer.
     * Reference: [node-csv-parse]: https://github.com/adaltas/node-csv-parse/blob/v2.5.0/lib/index.js#L207
     *
     * @param {String} value - The string to test for.
     * @returns {Boolean}
     */
    isInt: function (value) {
        return (/^(-|\+)?([1-9]+[0-9]*)$/).test(value);
    },

    /**
     * Helper function to test if a given string is a float.
     * Reference: [node-csv-parse]: https://github.com/adaltas/node-csv-parse/blob/v2.5.0/lib/index.js#L210
     *
     * @param {String} value - The string to test for.
     * @returns {Boolean}
     */
    isFloat: function (value) {
        return (value - parseFloat(value) + 1) >= 0;
    }
};

module.exports = util;
<commit_msg>Minor: Update condition<commit_after>var fs = require('fs'),
    url = require('url'),

    _ = require('lodash'),
    prettyms = require('pretty-ms'),
    filesize = require('filesize'),
    request = require('postman-request'),
    parseJson = require('parse-json'),

    util,
    version = require('../package.json').version,

    SEP = ' / ',

    /**
     * The auxiliary character used to prettify file sizes from raw byte counts.
     *
     * @type {Object}
     */
    FILESIZE_OPTIONS = { spacer: '' },

    PRO_API_HOST = 'api.getpostman.com',
    USER_AGENT_VALUE = 'Newman/' + version,

    UID_REGEX = /^[0-9A-Z]+-[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;

util = {

    /**
     * The raw newman version, taken from package.json in the root directory
     *
     * @type {String}
     */
    version: version,

    /**
     * The user agent that this newman identifies as.
     *
     * @type {String}
     */
    userAgent: USER_AGENT_VALUE,

    /**
     * A utility helper method that prettifies and returns raw millisecond counts.
     *
     * @param {Number} ms - The raw millisecond count, usually from response times.
     * @returns {String} - The prettified time, scaled to units of time, depending on the input value.
     */
    prettyms: function (ms) {
        return (ms < 1998) ? `${parseInt(ms, 10)}ms` : prettyms(ms || 0);
    },

    /**
     * A utility helper method to prettify byte counts into human readable strings.
     *
     * @param {Number} bytes - The raw byte count, usually from computed response sizes.
     * @returns {String} - The prettified size, suffixed with scaled units, depending on the actual value provided.
     */
    filesize: function (bytes) {
        return filesize(bytes || 0, FILESIZE_OPTIONS);
    },

    /**
     * Resolves the fully qualified name for the provided item
     *
     * @param {PostmanItem|PostmanItemGroup} item The item for which to resolve the full name
     * @param {?String} [separator=SEP] The separator symbol to join path name entries with
     * @returns {String} The full name of the provided item, including prepended parent item names
     * @private
     */
    getFullName: function (item, separator) {
        if (_.isEmpty(item) || !_.isFunction(item.parent) || !_.isFunction(item.forEachParent)) { return; }

        var chain = [];

        item.forEachParent(function (parent) { chain.unshift(parent.name || parent.id); });

        item.parent() && chain.push(item.name || item.id); // Add the current item only if it is not the collection

        return chain.join(_.isString(separator) ? separator : SEP);
    },

    /**
     * Loads JSON data from the given location.
     *
     * @param {String} type - The type of data to load.
     * @param {String} location - Can be an HTTP URL, a local file path or an UID.
     * @param {Object=} options - A set of options for JSON data loading.
     * @param {Object} options.postmanApiKey - API Key used to load the resources via UID from the Postman Cloud.
     * @param {Function} callback - The function whose invocation marks the end of the JSON fetch routine.
     * @returns {*}
     */

    fetchJson: function (type, location, options, callback) {
        !callback && _.isFunction(options) && (callback = options, options = {});

        var postmanApiKey = _.get(options, 'postmanApiKey'),
            headers = { 'User-Agent': USER_AGENT_VALUE },
            endpoint;

        // build API URL if `location` is a valid UID and api key is provided.
        // Fetch from file in case a file with valid UID name is present.
        if (postmanApiKey && UID_REGEX.test(location) && !fs.existsSync(location)) {
            endpoint = (type === 'collection' ? 'collections' : 'environments') + '/' + location;
            location = `https://${PRO_API_HOST}/${endpoint}`;
            headers['X-Api-Key'] = postmanApiKey;
        }

        return (/^https?:\/\/.*/).test(location) ?
            // Load from URL
            request.get({
                url: location,
                json: true,
                headers: headers
            }, (err, response, body) => {
                if (err) {
                    return callback(_.set(err, 'help', `unable to fetch data from url "${location}"`));
                }

                try {
                    _.isString(body) && (body = parseJson(body.trim()));
                }
                catch (e) {
                    return callback(_.set(e, 'help', `the url "${location}" did not provide valid JSON data`));
                }

                var error,
                    urlObj,
                    resource = 'resource';

                if (response.statusCode !== 200) {
                    urlObj = url.parse(location);

                    (urlObj.hostname === PRO_API_HOST) &&
                        (resource = _(urlObj.path).split('/').get(1).slice(0, -1) || resource);

                    error = new Error(_.get(body, 'error.message',
                        `Error fetching ${resource}, the provided URL returned status code: ${response.statusCode}`));

                    return callback(_.assign(error, {
                        name: _.get(body, 'error.name', _.capitalize(resource) + 'FetchError'),
                        help: `Error fetching the ${resource} from the provided URL. Ensure that the URL is valid.`
                    }));
                }

                return callback(null, body);
            }) :
            fs.readFile(location, function (err, value) {
                if (err) {
                    return callback(_.set(err, 'help', `unable to read data from file "${location}"`));
                }

                try {
                    value = parseJson(value.toString());
                }
                catch (e) {
                    return callback(_.set(e, 'help', `the file at ${location} does not contain valid JSON data`));
                }

                return callback(null, value);
            });
    },

    /**
     * Loads raw data from a location, useful for working with non JSON data such as CSV files.
     *
     * @param {String} location - The relative path / URL to the raw data file.
     * @param {Object=} options - A set of load options for the raw data file.
     * @param {Function} callback - The callback function whose invocation marks the end of the fetch routine.
     * @returns {*}
     */
    fetch: function (location, options, callback) {
        !callback && _.isFunction(options) && (callback = options, options = {});

        return (/^https?:\/\/.*/).test(location) ?
            // Load from URL
            request.get({ url: location }, (err, response, body) => {
                if (err) {
                    return callback(err);
                }

                return callback(null, body);
            }) :
            fs.readFile(location, function (err, value) {
                if (err) {
                    return callback(err);
                }

                return callback(null, value.toString());
            });
    },

    /**
     * Helper function to test if a given string is an integer.
     * Reference: [node-csv-parse]: https://github.com/adaltas/node-csv-parse/blob/v2.5.0/lib/index.js#L207
     *
     * @param {String} value - The string to test for.
     * @returns {Boolean}
     */
    isInt: function (value) {
        return (/^(-|\+)?([1-9]+[0-9]*)$/).test(value);
    },

    /**
     * Helper function to test if a given string is a float.
     * Reference: [node-csv-parse]: https://github.com/adaltas/node-csv-parse/blob/v2.5.0/lib/index.js#L210
     *
     * @param {String} value - The string to test for.
     * @returns {Boolean}
     */
    isFloat: function (value) {
        return (value - parseFloat(value) + 1) >= 0;
    }
};

module.exports = util;
<|endoftext|>


<commit_before>/**
 * The Reciprocal class
 *
 * @constructor
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 */
const Reciprocal = Function.inherits('Alchemy.Base', 'Alchemy.Reciprocal', function Reciprocal(link, identifier) {

	// Reciprocal identifier
	this.identifier = identifier;

	// The requests we're waiting on an answer for
	this.requests = new Map();

	// The request counter
	this.counter = 0;

	// The actual link
	this.link = link;

	// Listen for messages
	this.init();
});

/**
 * Initialize the listeners
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 */
Reciprocal.setMethod(function init() {

	const that = this;

	this.link.on('message', function onMessage(message) {

		if (!message.reciprocal || message.reciprocal != that.identifier) {
			that.emit('message', message);
			return;
		}

		if (message.method == 'send') {
			that.emit(message.type, message.data, null);
		} else if (message.method == 'ask') {
			that.emitAsk(message);
		} else if (message.method == 'response') {

			// Get the pledge
			let pledge = that.requests.get(message.response_to);

			if (!pledge) {
				throw new Error('Received Reciprocal response to unknown request');
			}

			// Delete the pledge
			that.requests.delete(message.response_to);

			if (message.error) {
				pledge.reject(message.error);
			} else {
				pledge.resolve(message.data);
			}
		}
	});
});

/**
 * Actually submit some data
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 */
Reciprocal.setMethod(function _submit(data) {
	this.link.send(data);
});

/**
 * Emit an ask message
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {Object}   message
 */
Reciprocal.setMethod(function emitAsk(message) {

	const that = this;

	this.emit(message.type, message.data, callback, null);

	function callback(err, response) {

		var id = ++that.counter;

		that._submit({
			id          : id,
			reciprocal  : that.identifier,
			method      : 'response',
			response_to : message.id,
			error       : err,
			data        : response
		});
	}
});

/**
 * Send a message to the other side without waiting for an answer
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {String}   type
 * @param    {Object}   data
 */
Reciprocal.setMethod(function send(type, data) {

	var id = ++this.counter;

	this._submit({
		id         : id,
		reciprocal : this.identifier,
		method     : 'send',
		type       : type,
		data       : data
	});
});

/**
 * Send a message to the other side and wait for an answer
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {String}   type
 * @param    {Object}   data
 *
 * @return   {Pledge}
 */
Reciprocal.setMethod(function ask(type, data) {

	var pledge = new Blast.Classes.Pledge(),
	    id = ++this.counter;

	this.requests.set(id, pledge);

	this._submit({
		id         : id,
		reciprocal : this.identifier,
		method     : 'ask',
		type       : type,
		data       : data
	});

	return pledge;
});<commit_msg>Add Reciprocal comments<commit_after>/**
 * A Reciprocal instance creates a named channel on an IPC link.
 *
 * This link instance has to implement the `message` event and the `send` method,
 * this will most probably be a ChildProcess but can also be used for socket.io
 *
 * @constructor
 *
 * @author   Jelle De Loecker   <jelle@elevenways.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {ChildProcess}   link
 * @param    {string}         identifier
 */
const Reciprocal = Function.inherits('Alchemy.Base', 'Alchemy.Reciprocal', function Reciprocal(link, identifier) {

	// Reciprocal identifier
	this.identifier = identifier;

	// The requests we're waiting on an answer for
	this.requests = new Map();

	// The request counter
	this.counter = 0;

	// The actual link
	this.link = link;

	// Listen for messages
	this.init();
});

/**
 * Initialize the listeners
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 */
Reciprocal.setMethod(function init() {

	const that = this;

	this.link.on('message', function onMessage(message) {

		if (!message.reciprocal || message.reciprocal != that.identifier) {
			that.emit('message', message);
			return;
		}

		if (message.method == 'send') {
			that.emit(message.type, message.data, null);
		} else if (message.method == 'ask') {
			that.emitAsk(message);
		} else if (message.method == 'response') {

			// Get the pledge
			let pledge = that.requests.get(message.response_to);

			if (!pledge) {
				throw new Error('Received Reciprocal response to unknown request');
			}

			// Delete the pledge
			that.requests.delete(message.response_to);

			if (message.error) {
				pledge.reject(message.error);
			} else {
				pledge.resolve(message.data);
			}
		}
	});
});

/**
 * Actually submit some data
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 */
Reciprocal.setMethod(function _submit(data) {
	this.link.send(data);
});

/**
 * Emit an ask message
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {Object}   message
 */
Reciprocal.setMethod(function emitAsk(message) {

	const that = this;

	this.emit(message.type, message.data, callback, null);

	function callback(err, response) {

		var id = ++that.counter;

		that._submit({
			id          : id,
			reciprocal  : that.identifier,
			method      : 'response',
			response_to : message.id,
			error       : err,
			data        : response
		});
	}
});

/**
 * Send a message to the other side without waiting for an answer
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {String}   type
 * @param    {Object}   data
 */
Reciprocal.setMethod(function send(type, data) {

	var id = ++this.counter;

	this._submit({
		id         : id,
		reciprocal : this.identifier,
		method     : 'send',
		type       : type,
		data       : data
	});
});

/**
 * Send a message to the other side and wait for an answer
 *
 * @author   Jelle De Loecker   <jelle@develry.be>
 * @since    1.1.0
 * @version  1.1.0
 *
 * @param    {String}   type
 * @param    {Object}   data
 *
 * @return   {Pledge}
 */
Reciprocal.setMethod(function ask(type, data) {

	var pledge = new Blast.Classes.Pledge(),
	    id = ++this.counter;

	this.requests.set(id, pledge);

	this._submit({
		id         : id,
		reciprocal : this.identifier,
		method     : 'ask',
		type       : type,
		data       : data
	});

	return pledge;
});<|endoftext|>


<commit_before>import program from 'commander';
import chalk from 'chalk';
import pkg from '../package.json';
import initiate from '../lib/initiate';
import yarnSpawnSync from '../lib/yarn_spawn_sync';
import { codeLog } from '../lib/helpers';

const logger = console;

if (process.argv[1].includes('getstorybook')) {
  logger.log(chalk.yellow('WARNING: getstorybook is deprecated.'));
  logger.log(chalk.yellow('The official command to install Storybook from now on is:\n'));
  codeLog(['storybook init']);
  logger.log();
  initiate({ force: true }, pkg).then(() => process.exit(0));
} else {
  program
    .command('init')
    .description('Initialize Storybook into your project.')
    .option('-f --force', 'Forcely add storybook')
    .option('-s --skip-install', 'Skip installing deps')
    .option('-N --use-npm', 'Use npm to install deps')
    .option('-p --parser <babel | babylon | flow>', 'jscodeshift parser')
    .option('-h --html', 'Add storybook for HTML')
    .action(options => initiate(options, pkg));

  program
    .command('start')
    .description('Start the local Storybook server')
    .option('-N --use-npm', 'Use NPM to start the Storybook server')
    .action(options => yarnSpawnSync(options, ['run', 'storybook']));

  program
    .command('build')
    .description('Build the Storybook static application')
    .option('-N --use-npm', 'Use NPM to build the Storybook server')
    .action(options => yarnSpawnSync(options, ['build', 'storybook']));

  program.command('*', { noHelp: true }).action(cmd => {
    logger.error('Invalid command: %s.\nSee --help for a list of available commands.', cmd);
    process.exit(1);
  });

  program.version(pkg.version).parse(process.argv);

  if (!program.args.length) {
    program.help();
  }
}
<commit_msg>Remove debugging flag<commit_after>import program from 'commander';
import chalk from 'chalk';
import pkg from '../package.json';
import initiate from '../lib/initiate';
import yarnSpawnSync from '../lib/yarn_spawn_sync';
import { codeLog } from '../lib/helpers';

const logger = console;

if (process.argv[1].includes('getstorybook')) {
  logger.log(chalk.yellow('WARNING: getstorybook is deprecated.'));
  logger.log(chalk.yellow('The official command to install Storybook from now on is:\n'));
  codeLog(['storybook init']);
  logger.log();
  initiate({}, pkg).then(() => process.exit(0));
} else {
  program
    .command('init')
    .description('Initialize Storybook into your project.')
    .option('-f --force', 'Forcely add storybook')
    .option('-s --skip-install', 'Skip installing deps')
    .option('-N --use-npm', 'Use npm to install deps')
    .option('-p --parser <babel | babylon | flow>', 'jscodeshift parser')
    .option('-h --html', 'Add storybook for HTML')
    .action(options => initiate(options, pkg));

  program
    .command('start')
    .description('Start the local Storybook server')
    .option('-N --use-npm', 'Use NPM to start the Storybook server')
    .action(options => yarnSpawnSync(options, ['run', 'storybook']));

  program
    .command('build')
    .description('Build the Storybook static application')
    .option('-N --use-npm', 'Use NPM to build the Storybook server')
    .action(options => yarnSpawnSync(options, ['build', 'storybook']));

  program.command('*', { noHelp: true }).action(cmd => {
    logger.error('Invalid command: %s.\nSee --help for a list of available commands.', cmd);
    process.exit(1);
  });

  program.version(pkg.version).parse(process.argv);

  if (!program.args.length) {
    program.help();
  }
}
<|endoftext|>