<commit_before>//  Grid Data Provider
//	===================
//
//	provides data to a lux.grid using websockets
define(['angular',
        'lux/grid',
        'lux/services/stream'], function (angular) {
    'use strict';

    angular.module('lux.grid.stream', ['lux.grid', 'lux.stream'])

        .run(['$lux', 'luxGridDataProviders', function ($lux, dataProvider) {

            dataProvider.register('websocket', gridDataProviderWebsocketFactory($lux, dataProvider));
        }]);

    function gridDataProviderWebsocketFactory ($lux, dataProvider) {

        function GridDataProviderWebsocket (grid) {
            this._grid = grid;
            this._websocketUrl = grid.options.target.url;
            this._channel = grid.options.target.channel;
        }

        GridDataProviderWebsocket.prototype.destroy = function() {
            this._grid = null;
        };

        GridDataProviderWebsocket.prototype.connect = function() {
            dataProvider.check(this);

            function onConnect () {
                this.getPage();
            }

            function onMessage (sock, msg) {
                var tasks;

                if (msg.data.event === 'record-update') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'records') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'columns-metadata') {
                    this._grid.onMetadataReceived(msg.data.data);
                }
            }

            this._stream = $lux.stream(this._websocketUrl);

            this._stream.addListener(this._channel, onMessage.bind(this));

            this._stream.connect(onConnect.bind(this));

        };

        GridDataProviderWebsocket.prototype.getPage = function (options) {
            this._stream.rpc(this._channel, options);
        };

        GridDataProviderWebsocket.prototype.deleteItem = function(identifier, onSuccess, onFailure) {
            var options = {id: identifier};
            this._stream.rpc(this._channel, options).then(onSuccess, onFailure);
        };

        return GridDataProviderWebsocket;
    }

});
<commit_msg>Websocket grid now using new rpm method to request metadata<commit_after>//  Grid Data Provider
//	===================
//
//	provides data to a lux.grid using websockets
define(['angular',
        'lux/grid',
        'lux/services/stream'], function (angular) {
    'use strict';

    angular.module('lux.grid.stream', ['lux.grid', 'lux.stream'])

        .run(['$lux', 'luxGridDataProviders', function ($lux, dataProvider) {

            dataProvider.register('websocket', gridDataProviderWebsocketFactory($lux, dataProvider));
        }]);

    function gridDataProviderWebsocketFactory ($lux, dataProvider) {

        function GridDataProviderWebsocket (grid) {
            this._grid = grid;
            this._websocketUrl = grid.options.target.url;
            this._channel = grid.options.target.channel;
            this._model = grid.options.target.model;
        }

        GridDataProviderWebsocket.prototype.destroy = function() {
            this._grid = null;
        };

        GridDataProviderWebsocket.prototype.connect = function() {
            dataProvider.check(this);

            function onConnect () {
                this.getPage();
            }

            function onMessage (sock, msg) {
                var tasks;

                if (msg.data.event === 'record-update') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'records') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'columns-metadata') {
                    this._grid.onMetadataReceived(msg.data.data);
                }
            }

            this._stream = $lux.stream(this._websocketUrl);

            this._stream.rpc(
                'model_metadata',
                { 'model': this._model },
                onMessage.bind(this),
                function() { console.log('rpc error', arguments); }
            );
        };

        GridDataProviderWebsocket.prototype.getPage = function (options) {
            this._stream.rpc(this._channel, options);
        };

        GridDataProviderWebsocket.prototype.deleteItem = function(identifier, onSuccess, onFailure) {
            var options = {id: identifier};
            this._stream.rpc(this._channel, options).then(onSuccess, onFailure);
        };

        return GridDataProviderWebsocket;
    }

});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react')

class Footer extends React.Component {
  docUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl
    const docsUrl = this.props.config.docsUrl
    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`
    const langPart = `${language ? `${language}/` : ''}`
    return `${baseUrl}${docsPart}${langPart}${doc}`
  }

  pageUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl
    return baseUrl + (language ? `${language}/` : '') + doc
  }

  render() {
    return (

            {this.props.config.footerIcon && (

            )}

Docs

              Getting Started

              Guides

            API Reference

Community

              Slack

              irc (#selenium)

              Google group

More

            <a href={`${this.props.config.baseUrl}blog`}>Blog
            GitHub

              Star

{this.props.config.copyright}

    )
  }
}

module.exports = Footer
<commit_msg>Fixed footer links to docs<commit_after>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react')

class Footer extends React.Component {
  docUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl
    const docsUrl = this.props.config.docsUrl
    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`
    const langPart = `${language ? `${language}/` : 'en/'}`
    return `${baseUrl}${docsPart}${langPart}${doc}`
  }

  pageUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl
    return baseUrl + (language ? `${language}/` : '') + doc
  }

  render() {
    return (

            {this.props.config.footerIcon && (

            )}

Docs

              Getting Started

            API Reference

              Build a Plugin

Community

              Slack

              irc (#selenium)

              Google group

More

            <a href={`${this.props.config.baseUrl}blog`}>Blog
            GitHub

              Star

{this.props.config.copyright}

    )
  }
}

module.exports = Footer
<|endoftext|>


<commit_before>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

/**
 * @constructor
 */

var Random = function () {
};

/**
 * Seedable random number generator
 *
 * @module Random
 * @class Random
 * @api
 */

Random.prototype = {

    /**
     * Sets initial seed
     *
     * @method initialSeed
     * @param {String|Number} seed Initial seed
     */

    initialSeed: function (seed) {
        this.i = 0;
        this.j = 0;
        if (typeof seed === 'number') {
            this.keystream = this._keystream(this._longToHex(seed));
        } else {
            this.keystream = this._keystream(seed);
        }
    },

    /**
     * Generates random number
     *
     * @method random
     * @return {Number} Number between 0 and 1
     */

    random: function () {
        if (!this.keystream) {
            this.initialSeed('seed');
        }
        return (this._randomByte() + this._randomByte() * 256 + this._randomByte() * 65536 +
                this._randomByte() * 16777216 + this._randomByte() * 4294967296 +
                this._randomByte() * 1099511627776 + this._randomByte() * 281474976710656 +
                this._randomByte() * 72057594037927940) / 18446744073709551616;
    },

//////////////////////////////// Private Random methods ////////////////////////////////

    /**
     * Converts 64-bit unsigned long to hexadecimal
     *
     * @method _longToHex
     * @param {Number} n 64-bit unsigned long
     * @return {String} Hexadecimal
     * @private
     */

    _longToHex: function (n) {
        var key = '';
        var hex = '0123456789ABCDEF';
        for (var i = 0; i < 8; i++) {
            var ch = n & 0xf;
            key = hex.charAt(ch) + key;
            n = (n - ch) / 16;
        }
        return key;
    },

    /**
     * The key-scheduling algorithm
     *
     * @method _keystream
     * @param {String} key Key
     * @return {Array} Keystream
     * @private
     */

    _keystream: function (key) {
        var S = [];
        var j = 0;
        for(var i = 0; i < 256; i++) {
            S[i] = i;
        }
        for(var k = 0; k < 256; k++) {
            var swap = S[k];
            j = (j + swap + key[k % key.length].charCodeAt(0)) % 256;
            S[k] = S[j];
            S[j] = swap;
        }
        return S;
    },

    /**
     * Generates random byte
     *
     * @method _randomByte
     * @return {Number} Random byte
     * @private
     */

    _randomByte: function () {
        var swap = this.keystream[this.i];
        this.i = (this.i + 1) % 256;
        this.j = (this.j + swap) % 256;
        this.keystream[this.i] = this.keystream[this.j];
        this.keystream[this.j] = swap;
        return this.keystream[(this.keystream[this.i] + this.keystream[this.j]) % 256];
    }
};

// export the module
module.exports = Random;
<commit_msg>Refactored version<commit_after>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

/**
 * @constructor
 */

var Random = function () {
};

/**
 * Seedable random number generator
 *
 * @module Random
 * @class Random
 * @api
 */

Random.prototype = {

    /**
     * Sets initial seed
     *
     * @method initialSeed
     * @param {String|Number} seed Initial seed
     */

    initialSeed: function (seed) {
        this.i = 0;
        this.j = 0;
        if (typeof seed === 'number') {
            this.keystream = this._keystream(this._longToHex(seed));
        } else {
            this.keystream = this._keystream(seed);
        }
    },

    /**
     * Generates random number
     *
     * @method random
     * @return {Number} Number between 0 and 1
     */

    random: function () {
        if (!this.keystream) {
            this.initialSeed('seed');
        }
        return (this._randomByte() + this._randomByte() * 256 + this._randomByte() * 65536 +
                this._randomByte() * 16777216 + this._randomByte() * 4294967296 +
                this._randomByte() * 1099511627776 + this._randomByte() * 281474976710656 +
                this._randomByte() * 72057594037927940) / 18446744073709551616;
    },

//////////////////////////////// Private Random methods ////////////////////////////////

    /**
     * Converts 64-bit unsigned long to hexadecimal
     *
     * @method _longToHex
     * @param {Number} n 64-bit unsigned long
     * @return {String} Hexadecimal
     * @private
     */

    _longToHex: function (n) {
        var key = '';
        var hex = '0123456789ABCDEF';
        for (var i = 0; i < 16; i++) {
            var ch = n & 0xf;
            key = hex.charAt(ch) + key;
            n = (n - ch) / 16;
        }
        return key;
    },

    /**
     * The key-scheduling algorithm
     *
     * @method _keystream
     * @param {String} key Key
     * @return {Array} Keystream
     * @private
     */

    _keystream: function (key) {
        var S = [];
        var j = 0;
        for(var i = 0; i < 256; i++) {
            S[i] = i;
        }
        for(var k = 0; k < 256; k++) {
            var swap = S[k];
            j = (j + swap + key[k % key.length].charCodeAt(0)) % 256;
            S[k] = S[j];
            S[j] = swap;
        }
        return S;
    },

    /**
     * Generates random byte
     *
     * @method _randomByte
     * @return {Number} Random byte
     * @private
     */

    _randomByte: function () {
        var swap = this.keystream[this.i];
        this.i = (this.i + 1) % 256;
        this.j = (this.j + swap) % 256;
        this.keystream[this.i] = this.keystream[this.j];
        this.keystream[this.j] = swap;
        return this.keystream[(this.keystream[this.i] + this.keystream[this.j]) % 256];
    }
};

// export the module
module.exports = Random;
<|endoftext|>


<commit_before>var CryptoJS = require("crypto-js")
var Transaction = require('ethereumjs-tx')
var EC = require('elliptic').ec
var ec = new EC('secp256k1')
var Mnemonic = require('bitcore-mnemonic')
var bitcore = require('bitcore')

var KeyStore = function(mnemonic, password) {

    this.encSeed = undefined;
    this.encMasterPriv = undefined;
    this.pwHash = undefined;
    this.salt = undefined;
    this.hdIndex = 0;
    this.encPrivKeys = {};
    this.addresses = [];
    if ((typeof password !== 'undefined') && (typeof mnemonic !== 'undefined')){

      if (!Mnemonic.isValid(mnemonic, Mnemonic.Words.ENGLISH)){
        throw new Error("KeyStore: Invalid mnemonic");
      }
      this.salt = CryptoJS.lib.WordArray.random(128 / 8);
      this.pwHash = CryptoJS.PBKDF2(password, this.salt, {keysize: 512 / 32, iterations: 1000}).toString();

      this.encSeed = KeyStore._encryptString(mnemonic, password);
      var master = new Mnemonic(mnemonic).toHDPrivateKey().xprivkey;
      this.encMasterPriv = KeyStore._encryptString(master, password);
    }
}

KeyStore._encryptString = function (string, password) {
    var encObj = CryptoJS.AES.encrypt(string, password);
    var encString = { 'encStr': encObj.toString(),
                    'iv': encObj.iv.toString(),
                    'salt': encObj.salt.toString()}
    return encString
}

KeyStore._decryptString = function (encryptedStr, password) {
    var decryptedStr = CryptoJS.AES.decrypt(encryptedStr.encStr, password, {'iv': encryptedStr.iv, 'salt': encryptedStr.salt });
    return decryptedStr.toString(CryptoJS.enc.Latin1);
}

KeyStore._encryptKey = function (privKey, password) {
    var privKeyWordArray = CryptoJS.enc.Hex.parse(privKey)
    var encKey = CryptoJS.AES.encrypt(privKeyWordArray, password);
    var encKey = { 'key': encKey.toString(),
                    'iv': encKey.iv.toString(),
                    'salt': encKey.salt.toString()}
    return encKey
}

KeyStore._decryptKey = function (encryptedKey, password) {
    var decryptedKey = CryptoJS.AES.decrypt(encryptedKey.key, password, {'iv': encryptedKey.iv, 'salt': encryptedKey.salt });
    return decryptedKey.toString(CryptoJS.enc.Hex);
}

KeyStore._computeAddressFromPrivKey = function (privKey) {
    var keyPair = ec.genKeyPair()
    keyPair._importPrivate(privKey, 'hex')
    var compact = false
    var pubKey = keyPair.getPublic(compact, 'hex').slice(2)
    var pubKeyWordArray = CryptoJS.enc.Hex.parse(pubKey)
    var hash = CryptoJS.SHA3(pubKeyWordArray, { outputLength: 256 })
    var address = hash.toString(CryptoJS.enc.Hex).slice(24)

    return address
}

KeyStore.prototype._addKeyPair = function (privKey, address, password) {
    var encPrivKey = KeyStore._encryptKey(privKey, password)

    this.encPrivKeys[address] = encPrivKey
    this.addresses.push(address)
}

KeyStore.prototype._generatePrivKey = function(password) {
    if (!this.validatePw(password)){
        throw new Error("Keystore.generatePrivKey: Invalid Password");
    }
    var master = KeyStore._decryptString(this.encMasterPriv, password);
    var key = new bitcore.HDPrivateKey(master).derive(this.hdIndex++);

    return key.privateKey.toString()
}

// External static functions

KeyStore.generateRandomSeed = function() {
    var seed = new Mnemonic(Mnemonic.Words.ENGLISH)
    return seed.toString()
}

// Takes keystore serialized as string and returns an instance of KeyStore
KeyStore.deserialize = function (keystore) {
    jsonKS = JSON.parse(keystore)

    // Create keystore
    var keystore = new KeyStore()

    keystore.encSeed = jsonKS.encSeed
    keystore.encMasterPriv = jsonKS.encMasterPriv
    keystore.hdIndex = jsonKS.hdIndex
    keystore.encPrivKeys = jsonKS.encPrivKeys
    keystore.addresses = jsonKS.addresses

    return keystore
}

// External API functions

KeyStore.prototype.serialize = function () {
    var jsonKS = {"encSeed": this.encSeed,
                "encMasterPriv": this.encMasterPriv,
                "hdIndex": this.hdIndex,
                "encPrivKeys": this.encPrivKeys,
                "addresses": this.addresses}

    return JSON.stringify(jsonKS)
}

KeyStore.prototype.getAddresses = function () {
    return this.addresses;
}

KeyStore.prototype.getSeed = function (password) {
    var seed = KeyStore._decryptString(this.encSeed, password);
    if (!Mnemonic.isValid(seed, Mnemonic.Words.ENGLISH)){
        throw new Error("Invalid Password");
    }
    return seed;
}

KeyStore.prototype.exportPrivateKey = function (address, password) {
    if (this.encPrivKeys[address] === undefined) {
        throw new Error("KeyStore.exportPrivateKey: Address not found in KeyStore")
    }
    var encKey = this.encPrivKeys[address]
    var privKey = KeyStore._decryptKey(encKey, password)

    return privKey;
}

KeyStore.prototype.generateNewAddress = function(password) {
    if (!this.encSeed) {
        throw new Error("KeyStore.generateNewAddress: No seed set");
    }

    var privateKey = this._generatePrivKey(password)
    var address = KeyStore._computeAddressFromPrivKey(privateKey)
    this._addKeyPair(privateKey, address, password)

    return address
}

KeyStore.prototype.signTx = function (rawTx, password, signingAddress) {

    if (this.addresses.length === 0) {
        throw new Error("KeyStore.signTx: No private keys in KeyStore.")
    }

    var address = ''
    if (signingAddress === undefined) {
        address = this.addresses[0]
    }
    else {
        if (this.encPrivKeys[signingAddress] === undefined) {
            throw new Error("KeyStore.signTx: Address not found in KeyStore")
        }
        address = signingAddress
    }
    if (!this.validatePw(password)){
        throw new Error("Keystore.signTx: Invalid Password");
    }

    var txCopy = new Transaction(new Buffer(rawTx, 'hex'))
    var encPrivKey = this.encPrivKeys[address]
    var privKey = KeyStore._decryptKey(encPrivKey, password)
    var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
    if (addrFromPrivKey !== address) {
        throw new Error("KeyStore.signTx: Decrypting private key failed!")
    }
    txCopy.sign(new Buffer(privKey, 'hex'));
    privKey = ''

    return txCopy.serialize().toString('hex')
}

KeyStore.prototype.validatePw = function(password) {
    var hash = CryptoJS.PBKDF2(password, this.salt, {keysize: 512 / 32, iterations: 1000}).toString();
    return (hash === this.pwHash);
}

module.exports = KeyStore;
<commit_msg>Encryption keys generated using PBKDF2<commit_after>var CryptoJS = require("crypto-js")
var Transaction = require('ethereumjs-tx')
var EC = require('elliptic').ec
var ec = new EC('secp256k1')
var Mnemonic = require('bitcore-mnemonic')
var bitcore = require('bitcore')

var KeyStore = function(mnemonic, password) {

    this.encSeed = undefined;
    this.encMasterPriv = undefined;
    this.keyHash = undefined;
    this.salt = undefined;
    this.hdIndex = 0;
    this.encPrivKeys = {};
    this.addresses = [];
    if ((typeof password !== 'undefined') && (typeof mnemonic !== 'undefined')){

      if (!Mnemonic.isValid(mnemonic, Mnemonic.Words.ENGLISH)){
        throw new Error("KeyStore: Invalid mnemonic");
      }
      this.salt = CryptoJS.lib.WordArray.random(128 / 8);
      var masterKey = CryptoJS.PBKDF2(password, this.salt, {keysize: 512 / 32, iterations: 500}).toString();
      this.keyHash = CryptoJS.SHA3(masterKey).toString();

      this.encSeed = KeyStore._encryptString(mnemonic, masterKey);
      var master = new Mnemonic(mnemonic).toHDPrivateKey().xprivkey;
      this.encMasterPriv = KeyStore._encryptString(master, masterKey);
    }
}

KeyStore._encryptString = function (string, password) {
    var encObj = CryptoJS.AES.encrypt(string, password);
    var encString = { 'encStr': encObj.toString(),
                    'iv': encObj.iv.toString(),
                    'salt': encObj.salt.toString()}
    return encString
}

KeyStore._decryptString = function (encryptedStr, password) {
    var decryptedStr = CryptoJS.AES.decrypt(encryptedStr.encStr, password, {'iv': encryptedStr.iv, 'salt': encryptedStr.salt });
    return decryptedStr.toString(CryptoJS.enc.Latin1);
}

KeyStore._encryptKey = function (privKey, password) {
    var privKeyWordArray = CryptoJS.enc.Hex.parse(privKey)
    var encKey = CryptoJS.AES.encrypt(privKeyWordArray, password);
    var encKey = { 'key': encKey.toString(),
                    'iv': encKey.iv.toString(),
                    'salt': encKey.salt.toString()}
    return encKey
}

KeyStore._decryptKey = function (encryptedKey, password) {
    var decryptedKey = CryptoJS.AES.decrypt(encryptedKey.key, password, {'iv': encryptedKey.iv, 'salt': encryptedKey.salt });
    return decryptedKey.toString(CryptoJS.enc.Hex);
}

KeyStore._computeAddressFromPrivKey = function (privKey) {
    var keyPair = ec.genKeyPair()
    keyPair._importPrivate(privKey, 'hex')
    var compact = false
    var pubKey = keyPair.getPublic(compact, 'hex').slice(2)
    var pubKeyWordArray = CryptoJS.enc.Hex.parse(pubKey)
    var hash = CryptoJS.SHA3(pubKeyWordArray, { outputLength: 256 })
    var address = hash.toString(CryptoJS.enc.Hex).slice(24)

    return address
}

KeyStore.prototype._addKeyPair = function (privKey, address, password) {
    var masterKey = this.generateMKey(password)
    var encPrivKey = KeyStore._encryptKey(privKey, masterKey)

    this.encPrivKeys[address] = encPrivKey
    this.addresses.push(address)
}

KeyStore.prototype._generatePrivKey = function(password) {
    var masterKey = this.generateMKey(password)
    var master = KeyStore._decryptString(this.encMasterPriv, masterKey);
    var key = new bitcore.HDPrivateKey(master).derive(this.hdIndex++);

    return key.privateKey.toString()
}

// External static functions

KeyStore.generateRandomSeed = function() {
    var seed = new Mnemonic(Mnemonic.Words.ENGLISH)
    return seed.toString()
}

// Takes keystore serialized as string and returns an instance of KeyStore
KeyStore.deserialize = function (keystore) {
    jsonKS = JSON.parse(keystore)

    // Create keystore
    var keystore = new KeyStore()

    keystore.encSeed = jsonKS.encSeed
    keystore.encMasterPriv = jsonKS.encMasterPriv
    keystore.hdIndex = jsonKS.hdIndex
    keystore.encPrivKeys = jsonKS.encPrivKeys
    keystore.addresses = jsonKS.addresses
    keystore.salt = jsonKS.salt
    keystore.keyHash = jsonKS.keyHash
    return keystore
}

// External API functions

KeyStore.prototype.serialize = function () {
    var jsonKS = {"encSeed": this.encSeed,
                "encMasterPriv": this.encMasterPriv,
                "hdIndex": this.hdIndex,
                "encPrivKeys": this.encPrivKeys,
                "addresses": this.addresses,
                "salt": this.salt,
                "keyHash": this.keyHash}

    return JSON.stringify(jsonKS)
}

KeyStore.prototype.getAddresses = function () {
    return this.addresses;
}

KeyStore.prototype.getSeed = function (password) {
    var masterKey = this.generateMKey(password)
    var seed = KeyStore._decryptString(this.encSeed, masterKey);
    return seed;
}

KeyStore.prototype.exportPrivateKey = function (address, password) {
    if (this.encPrivKeys[address] === undefined) {
        throw new Error("KeyStore.exportPrivateKey: Address not found in KeyStore")
    }
    var encKey = this.encPrivKeys[address]
    var masterKey = this.generateMKey(password)

    var privKey = KeyStore._decryptKey(encKey, masterKey)

    return privKey;
}

KeyStore.prototype.generateNewAddress = function(password) {
    if (!this.encSeed) {
        throw new Error("KeyStore.generateNewAddress: No seed set");
    }

    var privateKey = this._generatePrivKey(password)
    var address = KeyStore._computeAddressFromPrivKey(privateKey)
    this._addKeyPair(privateKey, address, password)

    return address
}

KeyStore.prototype.signTx = function (rawTx, password, signingAddress) {

    if (this.addresses.length === 0) {
        throw new Error("KeyStore.signTx: No private keys in KeyStore.")
    }

    var address = ''
    if (signingAddress === undefined) {
        address = this.addresses[0]
    }
    else {
        if (this.encPrivKeys[signingAddress] === undefined) {
            throw new Error("KeyStore.signTx: Address not found in KeyStore")
        }
        address = signingAddress
    }

    var txCopy = new Transaction(new Buffer(rawTx, 'hex'))
    var encPrivKey = this.encPrivKeys[address]
    var masterKey = this.generateMKey(password)

    var privKey = KeyStore._decryptKey(encPrivKey, masterKey)
    var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
    if (addrFromPrivKey !== address) {
        throw new Error("KeyStore.signTx: Decrypting private key failed!")
    }
    txCopy.sign(new Buffer(privKey, 'hex'));
    privKey = ''

    return txCopy.serialize().toString('hex')
}

KeyStore.prototype.generateMKey = function(password) {
    var masterKey = CryptoJS.PBKDF2(password, this.salt, {keysize: 512 / 32, iterations: 500}).toString();
    if (CryptoJS.SHA3(masterKey).toString() !== this.keyHash){
      throw new Error('Invalid Password');
    }
    return masterKey
}

module.exports = KeyStore;
<|endoftext|>


<commit_before>// Load modules

// Declare internals

var internals = {};

exports.errors = {
    root: 'value',
    any: {
        unknown: 'is not allowed',
        invalid: 'contains an invalid value',
        empty: 'is not allowed to be empty',
        required: 'is required',
        allowOnly: 'must be one of {{valids}}'
    },
    alternatives: {
        base: 'not matching any of the allowed alternatives'
    },
    array: {
        base: 'must be an array',
        includes: 'position {{pos}} does not match any of the allowed types',
        includesOne: 'position {{pos}} fails because {{reason}}',
        excludes: 'position {{pos}} contains an excluded value',
        min: 'must contain at least {{limit}} items',
        max: 'must contain less than or equal to {{limit}} items',
        length: 'must contain {{limit}} items'
    },
    boolean: {
        base: 'must be a boolean'
    },
    binary: {
        base: 'must be a buffer or a string',
        min: 'must be at least {{limit}} bytes',
        max: 'must be less than or equal to {{limit}} bytes',
        length: 'must be {{limit}} bytes'
    },
    date: {
        base: 'must be a number of milliseconds or valid date string',
        min: 'must be larger than or equal to {{limit}}',
        max: 'must be less than or equal to {{limit}}'
    },
    function: {
        base: 'must be a Function'
    },
    object: {
        base: 'must be an object',
        min: 'must have at least {{limit}} children',
        max: 'must have less than or equal to {{limit}} children',
        length: 'must have {{limit}} children',
        allowUnknown: 'is not allowed',
        with: 'missing required peer {{peer}}',
        without: 'conflict with forbidden peer {{peer}}',
        missing: 'must contain at least one of {{peers}}',
        xor: 'contains a conflict between exclusive peers {{peers}}',
        or: 'must contain at least one of {{peers}}',
        and: 'contains {{present}} without its required peers {{missing}}',
        assert: 'validation failed because {{ref}} failed to {{message}}',
        rename: {
            multiple: 'cannot rename child {{from}} because multiple renames are disabled and another key was already renamed to {{to}}',
            override: 'cannot rename child {{from}} because override is disabled and target {{to}} exists'
        }
    },
    number: {
        base: 'must be a number',
        min: 'must be larger than or equal to {{limit}}',
        max: 'must be less than or equal to {{limit}}',
        float: 'must be a float or double',
        integer: 'must be an integer',
        negative: 'must be a negative number',
        positive: 'must be a positive number',
        precision: 'must have no more then {{limit}} decimal places'
    },
    string: {
        base: 'must be a string',
        min: 'length must be at least {{limit}} characters long',
        max: 'length must be less than or equal to {{limit}} characters long',
        length: 'length must be {{limit}} characters long',
        alphanum: 'must only contain alpha-numeric characters',
        token: 'must only contain alpha-numeric and underscore characters',
        regex: 'fails to match the required pattern',
        email: 'must be a valid email',
        isoDate: 'must be a valid ISO 8601 date',
        guid: 'must be a valid GUID',
        hostname: 'must be a valid hostname',
        lowercase: 'must only contain lowercase characters',
        uppercase: 'must only contain uppercase characters',
        trim: 'must not have leading or trailing whitespace'
    }
};
<commit_msg>Fix typo.<commit_after>// Load modules

// Declare internals

var internals = {};

exports.errors = {
    root: 'value',
    any: {
        unknown: 'is not allowed',
        invalid: 'contains an invalid value',
        empty: 'is not allowed to be empty',
        required: 'is required',
        allowOnly: 'must be one of {{valids}}'
    },
    alternatives: {
        base: 'not matching any of the allowed alternatives'
    },
    array: {
        base: 'must be an array',
        includes: 'position {{pos}} does not match any of the allowed types',
        includesOne: 'position {{pos}} fails because {{reason}}',
        excludes: 'position {{pos}} contains an excluded value',
        min: 'must contain at least {{limit}} items',
        max: 'must contain less than or equal to {{limit}} items',
        length: 'must contain {{limit}} items'
    },
    boolean: {
        base: 'must be a boolean'
    },
    binary: {
        base: 'must be a buffer or a string',
        min: 'must be at least {{limit}} bytes',
        max: 'must be less than or equal to {{limit}} bytes',
        length: 'must be {{limit}} bytes'
    },
    date: {
        base: 'must be a number of milliseconds or valid date string',
        min: 'must be larger than or equal to {{limit}}',
        max: 'must be less than or equal to {{limit}}'
    },
    function: {
        base: 'must be a Function'
    },
    object: {
        base: 'must be an object',
        min: 'must have at least {{limit}} children',
        max: 'must have less than or equal to {{limit}} children',
        length: 'must have {{limit}} children',
        allowUnknown: 'is not allowed',
        with: 'missing required peer {{peer}}',
        without: 'conflict with forbidden peer {{peer}}',
        missing: 'must contain at least one of {{peers}}',
        xor: 'contains a conflict between exclusive peers {{peers}}',
        or: 'must contain at least one of {{peers}}',
        and: 'contains {{present}} without its required peers {{missing}}',
        assert: 'validation failed because {{ref}} failed to {{message}}',
        rename: {
            multiple: 'cannot rename child {{from}} because multiple renames are disabled and another key was already renamed to {{to}}',
            override: 'cannot rename child {{from}} because override is disabled and target {{to}} exists'
        }
    },
    number: {
        base: 'must be a number',
        min: 'must be larger than or equal to {{limit}}',
        max: 'must be less than or equal to {{limit}}',
        float: 'must be a float or double',
        integer: 'must be an integer',
        negative: 'must be a negative number',
        positive: 'must be a positive number',
        precision: 'must have no more than {{limit}} decimal places'
    },
    string: {
        base: 'must be a string',
        min: 'length must be at least {{limit}} characters long',
        max: 'length must be less than or equal to {{limit}} characters long',
        length: 'length must be {{limit}} characters long',
        alphanum: 'must only contain alpha-numeric characters',
        token: 'must only contain alpha-numeric and underscore characters',
        regex: 'fails to match the required pattern',
        email: 'must be a valid email',
        isoDate: 'must be a valid ISO 8601 date',
        guid: 'must be a valid GUID',
        hostname: 'must be a valid hostname',
        lowercase: 'must only contain lowercase characters',
        uppercase: 'must only contain uppercase characters',
        trim: 'must not have leading or trailing whitespace'
    }
};
<|endoftext|>


<commit_before>import child_process from 'child_process';
import dateformat from 'dateformat';
import waitOn from 'wait-on';

// container name
const NAME = `sel-standalone-${dateformat('yymmddhhMMss')}`;
const DEFAULT_IMG = 'selenium/standalone-chrome:3.4.0';

class SeleniumLauncher {
    constructor () {
        this.enabled = undefined;
    }

    onPrepare (config) {
        const dockerizedSeleniumArgs = config.dockerizedSeleniumArgs || {};
        const imageName = dockerizedSeleniumArgs.imageName || DEFAULT_IMG;
        this.enabled = dockerizedSeleniumArgs.enabled || true;

        if (!this.enabled) {
            return;
        }

        child_process.execSync(`docker run -d -p 0:4444 -p 0:5900 -v /dev/shm:/dev/shm --name ${NAME} ${imageName}`);
        try {
            // check if we are running in docker
            child_process.execSync(`awk -F/ '$2 == "docker"' /proc/self/cgroup | read`, {stdio: []});
            // we are running in docker
            config.host = child_process.execSync(
                `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${NAME}`).toString();
        } catch (err) {
            // we are not running in docker
            const port = child_process.execSync(
                `docker inspect -f '{{ (index (index .NetworkSettings.Ports "4444/tcp") 0).HostPort }}' ${NAME}`).toString();
            config.port = parseInt(port);
        }

        console.info(`Started dockerized selenium container ${NAME} at ${config.host}:${config.port}`)
        const statusUrl = `http-get://${config.host}:${config.port}/wd/hub/status`;
        const opts = {
            resources: [statusUrl],
            delay: 1000,
            timeout: 10000,
            followAllRedirects: true,
            followRedirect: true
        };
        return new Promise((resolve, reject) => waitOn(opts, (err) => {
            if (err) {
                console.error('Failed during wait for port');
                return reject(err)
            }

            resolve()
        }));
    }

    onComplete () {
        if (!this.enabled) {
            return;
        }
        child_process.execSync(`docker rm -f ${NAME}`);
        console.log(`Removed docker container ${NAME}`);
    }
}

export default SeleniumLauncher;<commit_msg>fix enabled flag<commit_after>import child_process from 'child_process';
import dateformat from 'dateformat';
import waitOn from 'wait-on';

// container name
const NAME = `sel-standalone-${dateformat('yymmddhhMMss')}`;
const DEFAULT_IMG = 'selenium/standalone-chrome:3.4.0';

class SeleniumLauncher {
    constructor () {
        this.enabled = undefined;
    }

    onPrepare (config) {
        const dockerizedSeleniumArgs = config.dockerizedSeleniumArgs || {};
        const imageName = dockerizedSeleniumArgs.imageName || DEFAULT_IMG;
        this.enabled = dockerizedSeleniumArgs.enabled === undefined ? true : dockerizedSeleniumArgs.enabled;

        if (!this.enabled) {
            return;
        }

        child_process.execSync(`docker run -d -p 0:4444 -p 0:5900 -v /dev/shm:/dev/shm --name ${NAME} ${imageName}`);
        try {
            // check if we are running in docker
            child_process.execSync(`awk -F/ '$2 == "docker"' /proc/self/cgroup | read`, {stdio: []});
            // we are running in docker
            config.host = child_process.execSync(
                `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${NAME}`).toString();
        } catch (err) {
            // we are not running in docker
            const port = child_process.execSync(
                `docker inspect -f '{{ (index (index .NetworkSettings.Ports "4444/tcp") 0).HostPort }}' ${NAME}`).toString();
            config.port = parseInt(port);
        }

        console.info(`Started dockerized selenium container ${NAME} at ${config.host}:${config.port}`)
        const statusUrl = `http-get://${config.host}:${config.port}/wd/hub/status`;
        const opts = {
            resources: [statusUrl],
            delay: 1000,
            timeout: 10000,
            followAllRedirects: true,
            followRedirect: true
        };
        return new Promise((resolve, reject) => waitOn(opts, (err) => {
            if (err) {
                console.error('Failed during wait for port');
                return reject(err)
            }

            resolve()
        }));
    }

    onComplete () {
        if (!this.enabled) {
            return;
        }
        child_process.execSync(`docker rm -f ${NAME}`);
        console.log(`Removed docker container ${NAME}`);
    }
}

export default SeleniumLauncher;<|endoftext|>


<commit_before>'use strict';

/**
 * nodecached loadtesting client.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var token = require('./token.js');
var server = require('./server.js');
var Client = require('./client.js').Client;
var MemcachedClient = require('./client.js').MemcachedClient;
var Log = require('log');
var testing = require('testing');

// globals
var log = new Log('notice');

// constants
var DEFAULT_PORT = 11211;

/**
 * Run load tests on a memcached server. Options is an object which may have:
 *	- host: to test.
 *	- port: to connect to.
 *	- concurrency: number of simultaneous connections to make.
 *	- maxRequests: number of requests to send.
 *	- maxSeconds: time to spend sending requests.
 *	- key: the key to use.
 *	- memcached: use the memcached driver.
 *	- noResponse: ignore the server response.
 * An optional callback is called after tests have run.
 */
exports.run = function(options, callback)
{
	if (options.info)
	{
		log = new Log('info');
	}
	if (options.debug)
	{
		log = new Log('debug');
	}
	var operation = new Operation(options);
	operation.start(callback);
};

/**
 * A load test operation. Options are the same as for exports.run.
 */
function Operation(options)
{
	// self-reference
	var self = this;

	// attributes
	var freeClients = {};
	var busyClients = {};
	var totalRequests = 0;
	var totalResponses = 0;
	var totalErrors = 0;
	var start = Date.now();
	var key = options.key || 'test' + token.create();
	var concurrency = options.concurrency || 1;
	var callback;

	// init
	init();

	/**
	 * Init the operation.
	 */
	function init()
	{
		options.port = options.port || DEFAULT_PORT;
		if (!options.maxRequests && !options.maxSeconds)
		{
			options.maxRequests = 1;
		}
		var ClientConstructor = Client;
		if (options.memcached)
		{
			ClientConstructor = MemcachedClient;
		}
		for (var i = 0; i < concurrency; i++)
		{
			freeClients[i] = new ClientConstructor(options, getBusier(i));
		}
	}

	/**
	 * Start the operation.
	 * An optional callback will be called after tests finish.
	 */
	self.start = function(hook)
	{
		callback = hook;
	};

	/**
	 * Get a function to make a client busy.
	 */
	function getBusier(index)
	{
		return function(error)
		{
			if (error)
			{
				log.error('Could not connect client %s: %s', index, error);
				return;
			}
			makeBusy(index);
		};
	}

	/**
	 * Make a client busy.
	 */
	function makeBusy(index)
	{
		if (options.maxRequests && totalRequests >= options.maxRequests)
		{
			return;
		}
		log.debug('Sending using %s: %s / %s', index, totalRequests, options.maxRequests);
		var client = freeClients[index];
		if (!client)
		{
			log.error('Client %s not free', index);
			return;
		}
		totalRequests += 1;
		delete freeClients[index];
		busyClients[index] = client;
		client.get(key, getReceiver(index, client));
	}

	/**
	 * Get a function to receive a response.
	 */
	function getReceiver(index)
	{
		return function(error, result)
		{
			log.debug('Receiving using %s', index);
			log.debug('Received response: %s', result);
			if (error)
			{
				log.error('Received error: %s', error);
				totalErrors += 1;
			}
			else
			{
				totalResponses += 1;
			}
			var client = busyClients[index];
			if (!client)
			{
				log.error('Client %s is not busy', index);
				return;
			}
			delete busyClients[index];
			freeClients[index] = client;
			if (isFinished())
			{
				return finish();
			}
			makeBusy(index);
		};
	}

	function isFinished()
	{
		if (options.maxRequests && totalResponses >= options.maxRequests)
		{
			return true;
		}
		if (options.maxSeconds)
		{
			var elapsed = (Date.now() - start) / 1000;
			if (elapsed >= options.maxSeconds)
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * Finish the load test.
	 */
	function finish()
	{
		freeClients.overwriteWith(busyClients);
		for (var index in freeClients)
		{
			freeClients[index].stop();
		}
		var elapsedSeconds = (Date.now() - start) / 1000;
		var rps = Math.round(totalRequests / elapsedSeconds);
		var meanTimeMs = 1000 * elapsedSeconds / totalRequests;
		if (callback)
		{
			callback({
				totalRequests: totalRequests,
				totalResponses: totalResponses,
				totalErrors: totalErrors,
				totalTimeSeconds: elapsedSeconds,
				rps: rps,
				meanTimeMs: meanTimeMs,
			});
		}
		else
		{
			log.notice('Concurrency Level:      %s', concurrency);
			log.notice('Time taken for tests:   %s seconds', elapsedSeconds);
			log.notice('Complete requests:      %s', totalResponses);
			log.notice('Failed requests:        %s', totalErrors);
			//log.notice('Total transferred:      x bytes');
			log.notice('Requests per second:    %s [#/sec] (mean)', rps);
			log.notice('Time per request:       %s [ms] (mean)', meanTimeMs);
			log.notice('Time per request:       %s [ms] (mean, across all concurrent requests)', meanTimeMs / concurrency);
			//log.notice('Transfer rate:          x [Kbytes/sec] received');
		}
	}
}

/**
 * Test loadtest.
 */
function testLoadTest(callback)
{
	var options = {
		port: 11237,
		maxRequests: 10000,
		key: 'test' + token.create(),
	};
	server.start(options, function(error, nodecached)
	{
		var client = new Client(options, function(error)
		{
			testing.check(error, 'Could not create test client', callback);
			client.set(options.key, 10, {b: 'c'}, function(error, result)
			{
				client.stop();
				testing.check(error, 'Could not set test', callback);
				testing.assert(result, 'Could not set test', callback);
				exports.run(options, function(results)
				{
					testing.assertEquals(results.totalResponses, options.maxRequests, 'Invalid number of responses', callback);
					server.stop(nodecached, function(error)
					{
						testing.check(error, 'Could not stop server', callback);
						testing.success(results, callback);
					});
				});
			});
		});
	});
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	log.debug('Running tests');
	testing.run({
		loadTest: testLoadTest,
	}, 5000, callback);
};

// run tests if invoked directly
if (__filename == process.argv[1])
{
	return exports.test(testing.show);
}

<commit_msg>Minor optimizations.<commit_after>'use strict';

/**
 * nodecached loadtesting client.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var token = require('./token.js');
var server = require('./server.js');
var Client = require('./client.js').Client;
var MemcachedClient = require('./client.js').MemcachedClient;
var Log = require('log');
var testing = require('testing');

// globals
var log = new Log('notice');

// constants
var DEFAULT_PORT = 11211;

/**
 * Run load tests on a memcached server. Options is an object which may have:
 *	- host: to test.
 *	- port: to connect to.
 *	- concurrency: number of simultaneous connections to make.
 *	- maxRequests: number of requests to send.
 *	- maxSeconds: time to spend sending requests.
 *	- key: the key to use.
 *	- memcached: use the memcached driver.
 *	- noResponse: ignore the server response.
 * An optional callback is called after tests have run.
 */
exports.run = function(options, callback)
{
	if (options.info)
	{
		log = new Log('info');
	}
	if (options.debug)
	{
		log = new Log('debug');
	}
	var operation = new Operation(options);
	operation.start(callback);
};

/**
 * A load test operation. Options are the same as for exports.run.
 */
function Operation(options)
{
	// self-reference
	var self = this;

	// attributes
	var freeClients = {};
	var busyClients = {};
	var totalRequests = 0;
	var totalResponses = 0;
	var totalErrors = 0;
	var start = Date.now();
	var key = options.key || 'test' + token.create();
	var concurrency = options.concurrency || 1;
	var callback;

	// init
	init();

	/**
	 * Init the operation.
	 */
	function init()
	{
		options.port = options.port || DEFAULT_PORT;
		if (!options.maxRequests && !options.maxSeconds)
		{
			options.maxRequests = 1;
		}
		var ClientConstructor = Client;
		if (options.memcached)
		{
			ClientConstructor = MemcachedClient;
		}
		for (var i = 0; i < concurrency; i++)
		{
			freeClients[i] = new ClientConstructor(options, getBusier(i));
		}
	}

	/**
	 * Start the operation.
	 * An optional callback will be called after tests finish.
	 */
	self.start = function(hook)
	{
		callback = hook;
	};

	/**
	 * Get a function to make a client busy.
	 */
	function getBusier(index)
	{
		return function(error)
		{
			if (error)
			{
				log.error('Could not connect client %s: %s', index, error);
				return;
			}
			makeBusy(index);
		};
	}

	/**
	 * Make a client busy.
	 */
	function makeBusy(index)
	{
		if (options.maxRequests && totalRequests >= options.maxRequests)
		{
			return;
		}
		log.debug('Sending using %s: %s / %s', index, totalRequests, options.maxRequests);
		var client = freeClients[index];
		if (!client)
		{
			log.error('Client %s not free', index);
			return;
		}
		totalRequests += 1;
		delete freeClients[index];
		busyClients[index] = client;
		client.get(key, getReceiver(index));
	}

	/**
	 * Get a function to receive a response.
	 */
	function getReceiver(index)
	{
		return function(error)
		{
			log.debug('Receiving using %s', index);
			if (error)
			{
				log.error('Received error: %s', error);
				totalErrors += 1;
			}
			else
			{
				totalResponses += 1;
			}
			var client = busyClients[index];
			if (!client)
			{
				log.error('Client %s is not busy', index);
				return;
			}
			delete busyClients[index];
			freeClients[index] = client;
			if (isFinished())
			{
				return finish();
			}
			makeBusy(index);
		};
	}

	function isFinished()
	{
		if (options.maxRequests && totalResponses >= options.maxRequests)
		{
			return true;
		}
		if (options.maxSeconds)
		{
			var elapsed = (Date.now() - start) / 1000;
			if (elapsed >= options.maxSeconds)
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * Finish the load test.
	 */
	function finish()
	{
		freeClients.overwriteWith(busyClients);
		for (var index in freeClients)
		{
			freeClients[index].stop();
		}
		var elapsedSeconds = (Date.now() - start) / 1000;
		var rps = Math.round(totalRequests / elapsedSeconds);
		var meanTimeMs = 1000 * elapsedSeconds / totalRequests;
		if (callback)
		{
			callback({
				totalRequests: totalRequests,
				totalResponses: totalResponses,
				totalErrors: totalErrors,
				totalTimeSeconds: elapsedSeconds,
				rps: rps,
				meanTimeMs: meanTimeMs,
			});
		}
		else
		{
			log.notice('Concurrency Level:      %s', concurrency);
			log.notice('Time taken for tests:   %s seconds', elapsedSeconds);
			log.notice('Complete requests:      %s', totalResponses);
			log.notice('Failed requests:        %s', totalErrors);
			//log.notice('Total transferred:      x bytes');
			log.notice('Requests per second:    %s [#/sec] (mean)', rps);
			log.notice('Time per request:       %s [ms] (mean)', meanTimeMs);
			log.notice('Time per request:       %s [ms] (mean, across all concurrent requests)', meanTimeMs / concurrency);
			//log.notice('Transfer rate:          x [Kbytes/sec] received');
		}
	}
}

/**
 * Test loadtest.
 */
function testLoadTest(callback)
{
	var options = {
		port: 11237,
		maxRequests: 10000,
		key: 'test' + token.create(),
	};
	server.start(options, function(error, nodecached)
	{
		var client = new Client(options, function(error)
		{
			testing.check(error, 'Could not create test client', callback);
			client.set(options.key, 10, {b: 'c'}, function(error, result)
			{
				client.stop();
				testing.check(error, 'Could not set test', callback);
				testing.assert(result, 'Could not set test', callback);
				exports.run(options, function(results)
				{
					testing.assertEquals(results.totalResponses, options.maxRequests, 'Invalid number of responses', callback);
					server.stop(nodecached, function(error)
					{
						testing.check(error, 'Could not stop server', callback);
						testing.success(results, callback);
					});
				});
			});
		});
	});
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	log.debug('Running tests');
	testing.run({
		loadTest: testLoadTest,
	}, 5000, callback);
};

// run tests if invoked directly
if (__filename == process.argv[1])
{
	return exports.test(testing.show);
}

<|endoftext|>


<commit_before>Minionette.Region = function(options) {
	options = options || {};
    // Setup a unique id for this region.
    // Not really necessary, but it doesn't hurt.
    this.cid = options.name || _.uniqueId('region');

    // Make sure we have a view.
    this._ensureView(options);
};

function getParentViewContext(view) {
    return _.result(view._parent, '$el') || Backbone.$();
}

// Allow Regions to be extended.
// Backbone's extend is generic, just copy it over.
Minionette.Region.extend = Backbone.View.extend;

_.extend(Minionette.Region.prototype, Backbone.Events, {
    // Ensures the region has a view.
    _ensureView: function(options) {
        var viewOpts = {
            // Grab the el from options.
            // This will override the following if it exists.
            el: options.el,
            // If not, set it to a span so when it's
            // empty it's collapsed on the DOM.
            tagName: 'span',
            // Use the data-cid attribute as a unique
            // attribute. Used for reattaching a detached view.
            attributes: function() {
                return {'data-cid': this.cid};
            }
        };

        this._view = new Backbone.View(viewOpts);
        this._view.$el.selector = this._view.$el.selector ||
            '[data-cid=' + this._view.cid + ']';

        this.view = options.view || this._view;

        // And set our view's _parent to this region.
        this._assignParent(this.view);
    },

    _ensureElement: function(view) {
        var $context = getParentViewContext(this),
            viewSelector = view.$el.selector;
        view.setElement($context.find(viewSelector));
    },

    // Resets the region's view to placeholder view.
    // Optionally takes a boolean, in which case the
    // oldView will just be detached.
    reset: function(detach) {
        this.attach(this._view, detach);
    },

    // A proxy method to the view's render().
    render: function() {
        return this.view.render();
    },

    // Attaches newView. This sets newView#$el
    // at the same index (inside the parent element)
    // as the old view, and removes the old view.
    attach: function(newView, detach) {
        var oldView = this.view;

        // Remove the old _detachedView, if it exists
        attempt(this._detachedView, 'remove');
        delete this._detachedView;

        this._assignParent(newView);

        if (oldView.$el.parent().length) {
            // Places newView after the current view.
            oldView.$el.after(newView.$el);
            // And detaches the view.
            oldView.$el.detach();
        }

        this.view = newView;

        // Remove the view, unless we are only detaching.
        if (!detach) { oldView.remove(); }

        return newView;
    },

    // Removes this region, and it's view.
    remove: function() {
        this.trigger('remove', this);
        this._removeViews();
        this._removeFromParent();
        this.stopListening();
    },

    _removeViews: function() {
        this.view.remove();
        this._view.remove();
        // Remove the _detachedView, if it exists
        attempt(this._detachedView, 'remove');
    },

    _removeFromParent: function() {
        // Remove this region from its parent, if it exists
        attempt(this._parent, '_removeRegion', this);
        this._parent = null;
    },

    // Detaches the current view, replacing it with
    // the placeholder. Convenient for detaching
    // during rendering.
    detach: function() {
        var view = this.view;
        if (view !== this._view) {
            this.reset(true);

            // Store the current view for later reattaching.
            this._detachedView = view;
        }

        return this;
    },

    // Reattaches the detached view.
    reattach: function() {
        // Make sure our `_view` has it's el.
        // It may not depending on whether the region was
        // created with a selector and the parent view hadn't
        // rendered yet.
        if (!this._view.el) { this._ensureElement(this._view); }

        // $context is a scoped context in which to search
        // for the current view's element in.
        var $context = getParentViewContext(this),
            viewSelector = this.view.$el.selector,
            newView = this._detachedView || this._view;

        // We then replace the current view with the detached view.
        $context.find(viewSelector).replaceWith(newView.$el);

        delete this._detachedView;
        this.view = newView;

        return newView;
    },

    // A hook method that is called during
    // a view#remove(). Allows a view to be removed,
    // replacing it with the placeholder.
    _removeView: function(view) {
        if (this.view === view) {
            this.reset(true);
        }
    },

    // Sets view#_parent to this region.
    // So view#remove() can hook into our
    // _removeView().
    _assignParent: function(view) {
        view._parent = this;
    }
});
<commit_msg>Prevent a Region's view from becoming detached<commit_after>Minionette.Region = function(options) {
	options = options || {};
    // Setup a unique id for this region.
    // Not really necessary, but it doesn't hurt.
    this.cid = options.name || _.uniqueId('region');

    // Make sure we have a view.
    this._ensureView(options);
};

function getParentViewContext(view) {
    return _.result(view._parent, '$el') || Backbone.$();
}

// Allow Regions to be extended.
// Backbone's extend is generic, just copy it over.
Minionette.Region.extend = Backbone.View.extend;

_.extend(Minionette.Region.prototype, Backbone.Events, {
    // Ensures the region has a view.
    _ensureView: function(options) {
        var viewOpts = {
            // Grab the el from options.
            // This will override the following if it exists.
            el: options.el,
            // If not, set it to a span so when it's
            // empty it's collapsed on the DOM.
            tagName: 'span',
            // Use the data-cid attribute as a unique
            // attribute. Used for reattaching a detached view.
            attributes: function() {
                return {'data-cid': this.cid};
            }
        };

        this._view = new Backbone.View(viewOpts);
        this._view.$el.selector = this._view.$el.selector ||
            '[data-cid=' + this._view.cid + ']';

        this.view = options.view || this._view;

        // And set our view's _parent to this region.
        this._assignParent(this.view);
    },

    _ensureElement: function(view) {
        var $context = getParentViewContext(this),
            viewSelector = view.$el.selector;
        view.setElement($context.find(viewSelector));
    },

    // Resets the region's view to placeholder view.
    // Optionally takes a boolean, in which case the
    // oldView will just be detached.
    reset: function(detach) {
        this.attach(this._view, detach);
    },

    // A proxy method to the view's render().
    render: function() {
        return this.view.render();
    },

    // Attaches newView. This sets newView#$el
    // at the same index (inside the parent element)
    // as the old view, and removes the old view.
    attach: function(newView, detach) {
        var oldView = this.view;

        if (newView === oldView) { return; }

        // Remove the old _detachedView, if it exists
        attempt(this._detachedView, 'remove');
        delete this._detachedView;

        this._assignParent(newView);

        if (oldView.$el.parent().length) {
            // Places newView after the current view.
            oldView.$el.after(newView.$el);
            // And detaches the view.
            oldView.$el.detach();
        }

        this.view = newView;

        // Remove the view, unless we are only detaching.
        if (!detach) { oldView.remove(); }

        return newView;
    },

    // Removes this region, and it's view.
    remove: function() {
        this.trigger('remove', this);
        this._removeViews();
        this._removeFromParent();
        this.stopListening();
    },

    _removeViews: function() {
        this.view.remove();
        this._view.remove();
        // Remove the _detachedView, if it exists
        attempt(this._detachedView, 'remove');
    },

    _removeFromParent: function() {
        // Remove this region from its parent, if it exists
        attempt(this._parent, '_removeRegion', this);
        this._parent = null;
    },

    // Detaches the current view, replacing it with
    // the placeholder. Convenient for detaching
    // during rendering.
    detach: function() {
        var view = this.view;
        if (view !== this._view) {
            this.reset(true);

            // Store the current view for later reattaching.
            this._detachedView = view;
        }

        return this;
    },

    // Reattaches the detached view.
    reattach: function() {
        // Make sure our `_view` has it's el.
        // It may not depending on whether the region was
        // created with a selector and the parent view hadn't
        // rendered yet.
        if (!this._view.el) { this._ensureElement(this._view); }
        if (!this._detachedView) { return; }

        // $context is a scoped context in which to search
        // for the current view's element in.
        var $context = getParentViewContext(this),
            viewSelector = this.view.$el.selector,
            newView = this._detachedView;

        // We then replace the current view with the detached view.
        $context.find(viewSelector).replaceWith(newView.$el);

        delete this._detachedView;
        this.view = newView;

        return newView;
    },

    // A hook method that is called during
    // a view#remove(). Allows a view to be removed,
    // replacing it with the placeholder.
    _removeView: function(view) {
        if (this.view === view) {
            this.reset(true);
        }
    },

    // Sets view#_parent to this region.
    // So view#remove() can hook into our
    // _removeView().
    _assignParent: function(view) {
        view._parent = this;
    }
});
<|endoftext|>


<commit_before>const remove = (array, fn) => {
if(array === null || array === undefined){ return undefined}
  let result = []
  for(let index = 0; index < array.length; index++){
    let item = array[index]
    if (fn(item)){
    result.push(item)
    }
  }
  return result
}

export {remove}<commit_msg>Update remove.js<commit_after>const remove = (array, fn) => {
if(array === null || array === undefined){
  return undefined
}
let result = []
 for(let index = 0; index < array.length; index++){
    let item = array[index]
    if (fn(item)){
    result.push(item)
    }
  }
  return result
}

export {remove}
<|endoftext|>


<commit_before>let Merge = require("merge");
let Style = require("./style.js");
let Format = require("./format.js");
let Render = {};

/**
 * Converts arrays of data into arrays of cell strings
 */
Render.stringifyData = function(config,data){
  let sections = {
        header : [],
        body : [],
        footer : []
      };
  let marginLeft = Array(config.marginLeft + 1).join('\ ');
  let borderStyle = config.borderCharacters[config.borderStyle];
  let borders = [];

  //because automattic/cli-table syntax infers table type based on
  //how rows are passed (array of arrays, objects, etc)
  config.rowFormat = Render.getRowFormat(data[0] || [],config);

  //now translate them
  data = Render.transformRows(config,data);

  //when streaming values to tty-table, we don't want column widths to change
  //from one data set to the next, so we save the first set of widths and reuse
  if(!global.columnWidths){
    global.columnWidths = {};
  }

  if(global.columnWidths[config.tableId]){
     config.table.columnWidths = global.columnWidths[config.tableId];
  }
  else{
     global.columnWidths[config.tableId] = config.table.columnWidths = Format.getColumnWidths(config,data);
  }

  //stringify header cells
  if(!config.headerEmpty){
    sections.header = config.table.header.map(function(row){
      return buildRow(config,row,'header');
    });
  }
  else{
    sections.header = [];
  }

  //stringify body cells
  sections.body = data.map(function(row){
    return buildRow(config,row,'body');
  });

  //stringify footer cells
  sections.footer = (config.table.footer instanceof Array && config.table.footer.length > 0) ? [config.table.footer] : [];

  sections.footer = sections.footer.map(function(row){
    return buildRow(config,row,'footer');
  });

  //add borders
  //0=header, 1=body, 2=footer
  for(let a=0; a<3; a++){
    borders.push('');
    config.table.columnWidths.forEach(function(w,i,arr){
      borders[a] += Array(w).join(borderStyle[a].h) +
        ((i+1 !== arr.length) ? borderStyle[a].j : borderStyle[a].r);
    });
    borders[a] = borderStyle[a].l + borders[a];
    borders[a] = borders[a].split('');
    borders[a][borders[a].length1] = borderStyle[a].r;
    borders[a] = borders[a].join('');
    //no trailing space on footer
    borders[a] = (a<2) ? marginLeft + borders[a] + '\n' : marginLeft + borders[a];
  }

  //top horizontal border
  let output = '';
  output += borders[0];

  //for each section (header,body,footer)
  Object.keys(sections).forEach(function(p,i){

    //for each row in the section
    while(sections[p].length){

      let row = sections[p].shift();

      //if(row.length === 0) {break}

      row.forEach(function(line){
        //vertical row borders
        output = output
          + marginLeft
          //left vertical border
          + borderStyle[1].v
          //join cells on vertical border
          +  line.join(borderStyle[1].v)
          //right vertical border
          + borderStyle[1].v
          //end of line
          + '\n';
      });

      //bottom horizontal row border
      switch(true){
        //skip if end of body and no footer
        case(sections[p].length === 0
             && i === 1
             && sections.footer.length === 0):
          break;
        //skip if end of footer
        case(sections[p].length === 0
             && i === 2):
          break;
        //skip if compact
        case(config.compact && p === 'body' && !row.empty):
          break;
        default:
          output += borders[1];
      }
    }
  });

  //bottom horizontal border
  output += borders[2];

  let finalOutput = Array(config.marginTop + 1).join('\n') + output;

  //record the height of the output
  config.height = finalOutput.split(/\r\n|\r|\n/).length;
  return finalOutput;
};

const buildRow = function(config,row,rowType){

  let minRowHeight = 0;

  //tag row as empty if empty
  //(used) for compact tables
  if(row.length === 0 && config.compact){
    row.empty = true;
    return row;
  }

  //force row to have correct number of columns
  let difL = config.table.columnWidths.length - row.length;
  if(difL > 0){
    //add empty element to array
    row = row.concat(Array.apply(null, new Array(difL))
                          .map(function(){return null}));
  }
  else if(difL < 0){
    //truncate array
    row.length = config.table.columnWidths.length;
  }

  //get row as array of cell arrays
  //can't use es5 row functions (map, forEach because i.e.
  //[1,,3] will only iterate 1,3
  let cArrs = [];
  let rowLength = row.length;
  for(let index=0; index<rowLength; index++){

    let c = Render.buildCell(config,row[index],index,rowType);
    let cellArr = c.cellArr;

    if(rowType === 'header'){
      config.table.columnInnerWidths.push(c.width);
    }

    minRowHeight = (minRowHeight < cellArr.length) ?
      cellArr.length : minRowHeight;

    cArrs.push(cellArr);
  }

  //adjust minRowHeight to reflect vertical row padding
  minRowHeight = (rowType === 'header') ? minRowHeight :
    minRowHeight + (config.paddingBottom + config.paddingTop);

  //convert array of cell arrays to array of lines
  let lines = Array.apply(null,{length:minRowHeight})
                   .map(Function.call,function(){return []});
  cArrs.forEach(function(cellArr,a){
    let whiteline = Array(config.table.columnWidths[a]).join('\ ');

    if(rowType ==='body'){
      //add whitespace for top padding
      for(let i=0; i<config.paddingTop; i++){
        cellArr.unshift(whiteline);
      }

      //add whitespace for bottom padding
      for(let i=0; i<config.paddingBottom; i++){
        cellArr.push(whiteline);
      }
    }
    for(let b=0; b<minRowHeight; b++){
      lines[b].push((typeof cellArr[b] !== 'undefined') ?
                    cellArr[b] : whiteline);
    }
  });

  return lines;
}

Render.buildCell = function(config,cell,columnIndex,rowType){

  let cellValue;
  let cellOptions = Merge(true,{},config,
                          (rowType === 'body') ?
                          config.columnSettings[columnIndex] : {}, //ignore columnSettings for footer
                          cell);

  if(rowType === 'header'){
    config.table.columns.push(cellOptions);
    cellValue = cellOptions.alias || cellOptions.value || '';
  }
  else{
    //set cellValue
    switch(true){
      case(typeof cell === 'undefined' || cell === null):
        //replace undefined/null cell values with placeholder
        cellValue = (config.errorOnNull) ? config.defaultErrorValue : config.defaultValue;
        break;
      case(typeof cell === 'object' && typeof cell.value !== 'undefined'):
        cellValue = cell.value;
        break;
      default:
        //cell is assumed to be a scalar
        cellValue = cell;
    }

    //run formatter
    if(typeof cellOptions.formatter === 'function'){
      cellValue = cellOptions.formatter(cellValue);
    }
  }

  //colorize cellValue
  cellValue = Style.colorizeCell(cellValue,cellOptions,rowType);

  //textwrap cellValue
  let WrapObj  = Format.wrapCellContent(config, cellValue, columnIndex, cellOptions, rowType);
  //cellValue = WrapObj.output.join('\n');

  //return as array of lines
  return {
    cellArr : WrapObj.output,
    width : WrapObj.width
  };
};

Render.getRowFormat = function(row,config){
  let type;

  //rows passed as an object
  if(typeof row === 'object' && !(row instanceof Array)){
    let keys = Object.keys(row);
    if(config.adapter === 'automattic'){
      //detected cross table
      let key = keys[0];
      if(row[key] instanceof Array){
        type = 'automattic-cross';
      }
      //detected vertical table
      else{
        type = 'automattic-vertical';
      }
    }
    else {
      //detected horizontal table
      type = 'o-horizontal';
    }
  }
  //rows passed as an array
  else{
    type = 'a-horizontal';
  }

  return type;
};

//@todo For rotating horizontal data into a vertical table
//assumes all rows are same length
Render.verticalizeMatrix = function(config,inputArray){

  //grow to # arrays equal to number of columns in input array
  let outputArray = [];
  let headers = config.table.columns;

  //create a row for each heading, and prepend the row
  //with the heading name
  headers.forEach(function(name){
    outputArray.push([name]);
  });

  inputArray.forEach(function(row){
    row.forEach(function(element,index){
      outputArray[index].push(element);
    });
  });

  return outputArray;
}

/**
 * Transforms input data arrays to base rendering structure.
 */
Render.transformRows = function(config,rows){

  let output = [];
  switch(config.rowFormat){
    case('automattic-cross'):
      //assign header styles to first column
      config.columnSettings[0] = config.columnSettings[0] || {};
      config.columnSettings[0].color = config.headerColor;

      output = rows.map(function(obj){
        let arr = [];
        let key = Object.keys(obj)[0];
        arr.push(key);
        return arr.concat(obj[key]);
      });
      break;
    case('automattic-vertical'):
      //assign header styles to first column
      config.columnSettings[0] = config.columnSettings[0] || {};
      config.columnSettings[0].color = config.headerColor;

      output = rows.map(function(value){
        let key = Object.keys(value)[0];
        return [key,value[key]];
      });
      break;
    case('o-horizontal'):
      output = rows.map(function(row){
        //requires that column names are specified in header
        return config.table.header[0].map(function(object){
          return row[object.value] || null;
        });
      });
      break;
    case('a-horizontal'):
      output = rows;
      break;
    default:
  }

  return output;
}

module.exports = Render;
<commit_msg>render: use Object.assign when available<commit_after>let Merge = require("merge");
let Style = require("./style.js");
let Format = require("./format.js");
let Render = {};

/**
 * Converts arrays of data into arrays of cell strings
 */
Render.stringifyData = function(config,data){
  let sections = {
        header : [],
        body : [],
        footer : []
      };
  let marginLeft = Array(config.marginLeft + 1).join('\ ');
  let borderStyle = config.borderCharacters[config.borderStyle];
  let borders = [];

  //because automattic/cli-table syntax infers table type based on
  //how rows are passed (array of arrays, objects, etc)
  config.rowFormat = Render.getRowFormat(data[0] || [],config);

  //now translate them
  data = Render.transformRows(config,data);

  //when streaming values to tty-table, we don't want column widths to change
  //from one data set to the next, so we save the first set of widths and reuse
  if(!global.columnWidths){
    global.columnWidths = {};
  }

  if(global.columnWidths[config.tableId]){
     config.table.columnWidths = global.columnWidths[config.tableId];
  }
  else{
     global.columnWidths[config.tableId] = config.table.columnWidths = Format.getColumnWidths(config,data);
  }

  //stringify header cells
  if(!config.headerEmpty){
    sections.header = config.table.header.map(function(row){
      return buildRow(config,row,'header');
    });
  }
  else{
    sections.header = [];
  }

  //stringify body cells
  sections.body = data.map(function(row){
    return buildRow(config,row,'body');
  });

  //stringify footer cells
  sections.footer = (config.table.footer instanceof Array && config.table.footer.length > 0) ? [config.table.footer] : [];

  sections.footer = sections.footer.map(function(row){
    return buildRow(config,row,'footer');
  });

  //add borders
  //0=header, 1=body, 2=footer
  for(let a=0; a<3; a++){
    borders.push('');
    config.table.columnWidths.forEach(function(w,i,arr){
      borders[a] += Array(w).join(borderStyle[a].h) +
        ((i+1 !== arr.length) ? borderStyle[a].j : borderStyle[a].r);
    });
    borders[a] = borderStyle[a].l + borders[a];
    borders[a] = borders[a].split('');
    borders[a][borders[a].length1] = borderStyle[a].r;
    borders[a] = borders[a].join('');
    //no trailing space on footer
    borders[a] = (a<2) ? marginLeft + borders[a] + '\n' : marginLeft + borders[a];
  }

  //top horizontal border
  let output = '';
  output += borders[0];

  //for each section (header,body,footer)
  Object.keys(sections).forEach(function(p,i){

    //for each row in the section
    while(sections[p].length){

      let row = sections[p].shift();

      //if(row.length === 0) {break}

      row.forEach(function(line){
        //vertical row borders
        output = output
          + marginLeft
          //left vertical border
          + borderStyle[1].v
          //join cells on vertical border
          +  line.join(borderStyle[1].v)
          //right vertical border
          + borderStyle[1].v
          //end of line
          + '\n';
      });

      //bottom horizontal row border
      switch(true){
        //skip if end of body and no footer
        case(sections[p].length === 0
             && i === 1
             && sections.footer.length === 0):
          break;
        //skip if end of footer
        case(sections[p].length === 0
             && i === 2):
          break;
        //skip if compact
        case(config.compact && p === 'body' && !row.empty):
          break;
        default:
          output += borders[1];
      }
    }
  });

  //bottom horizontal border
  output += borders[2];

  let finalOutput = Array(config.marginTop + 1).join('\n') + output;

  //record the height of the output
  config.height = finalOutput.split(/\r\n|\r|\n/).length;
  return finalOutput;
};

const buildRow = function(config,row,rowType){

  let minRowHeight = 0;

  //tag row as empty if empty
  //(used) for compact tables
  if(row.length === 0 && config.compact){
    row.empty = true;
    return row;
  }

  //force row to have correct number of columns
  let difL = config.table.columnWidths.length - row.length;
  if(difL > 0){
    //add empty element to array
    row = row.concat(Array.apply(null, new Array(difL))
                          .map(function(){return null}));
  }
  else if(difL < 0){
    //truncate array
    row.length = config.table.columnWidths.length;
  }

  //get row as array of cell arrays
  //can't use es5 row functions (map, forEach because i.e.
  //[1,,3] will only iterate 1,3
  let cArrs = [];
  let rowLength = row.length;
  for(let index=0; index<rowLength; index++){

    let c = Render.buildCell(config,row[index],index,rowType);
    let cellArr = c.cellArr;

    if(rowType === 'header'){
      config.table.columnInnerWidths.push(c.width);
    }

    minRowHeight = (minRowHeight < cellArr.length) ?
      cellArr.length : minRowHeight;

    cArrs.push(cellArr);
  }

  //adjust minRowHeight to reflect vertical row padding
  minRowHeight = (rowType === 'header') ? minRowHeight :
    minRowHeight + (config.paddingBottom + config.paddingTop);

  //convert array of cell arrays to array of lines
  let lines = Array.apply(null,{length:minRowHeight})
                   .map(Function.call,function(){return []});
  cArrs.forEach(function(cellArr,a){
    let whiteline = Array(config.table.columnWidths[a]).join('\ ');

    if(rowType ==='body'){
      //add whitespace for top padding
      for(let i=0; i<config.paddingTop; i++){
        cellArr.unshift(whiteline);
      }

      //add whitespace for bottom padding
      for(let i=0; i<config.paddingBottom; i++){
        cellArr.push(whiteline);
      }
    }
    for(let b=0; b<minRowHeight; b++){
      lines[b].push((typeof cellArr[b] !== 'undefined') ?
                    cellArr[b] : whiteline);
    }
  });

  return lines;
}

Render.buildCell = function(config,cell,columnIndex,rowType){

  let cellValue;
  let merge = typeof Object.assign === 'function' ? Object.assign : Merge
  let cellOptions = merge(true,{},config,
                          (rowType === 'body') ?
                          config.columnSettings[columnIndex] : {}, //ignore columnSettings for footer
                          cell);

  if(rowType === 'header'){
    config.table.columns.push(cellOptions);
    cellValue = cellOptions.alias || cellOptions.value || '';
  }
  else{
    //set cellValue
    switch(true){
      case(typeof cell === 'undefined' || cell === null):
        //replace undefined/null cell values with placeholder
        cellValue = (config.errorOnNull) ? config.defaultErrorValue : config.defaultValue;
        break;
      case(typeof cell === 'object' && typeof cell.value !== 'undefined'):
        cellValue = cell.value;
        break;
      default:
        //cell is assumed to be a scalar
        cellValue = cell;
    }

    //run formatter
    if(typeof cellOptions.formatter === 'function'){
      cellValue = cellOptions.formatter(cellValue);
    }
  }

  //colorize cellValue
  cellValue = Style.colorizeCell(cellValue,cellOptions,rowType);

  //textwrap cellValue
  let WrapObj  = Format.wrapCellContent(config, cellValue, columnIndex, cellOptions, rowType);
  //cellValue = WrapObj.output.join('\n');

  //return as array of lines
  return {
    cellArr : WrapObj.output,
    width : WrapObj.width
  };
};

Render.getRowFormat = function(row,config){
  let type;

  //rows passed as an object
  if(typeof row === 'object' && !(row instanceof Array)){
    let keys = Object.keys(row);
    if(config.adapter === 'automattic'){
      //detected cross table
      let key = keys[0];
      if(row[key] instanceof Array){
        type = 'automattic-cross';
      }
      //detected vertical table
      else{
        type = 'automattic-vertical';
      }
    }
    else {
      //detected horizontal table
      type = 'o-horizontal';
    }
  }
  //rows passed as an array
  else{
    type = 'a-horizontal';
  }

  return type;
};

//@todo For rotating horizontal data into a vertical table
//assumes all rows are same length
Render.verticalizeMatrix = function(config,inputArray){

  //grow to # arrays equal to number of columns in input array
  let outputArray = [];
  let headers = config.table.columns;

  //create a row for each heading, and prepend the row
  //with the heading name
  headers.forEach(function(name){
    outputArray.push([name]);
  });

  inputArray.forEach(function(row){
    row.forEach(function(element,index){
      outputArray[index].push(element);
    });
  });

  return outputArray;
}

/**
 * Transforms input data arrays to base rendering structure.
 */
Render.transformRows = function(config,rows){

  let output = [];
  switch(config.rowFormat){
    case('automattic-cross'):
      //assign header styles to first column
      config.columnSettings[0] = config.columnSettings[0] || {};
      config.columnSettings[0].color = config.headerColor;

      output = rows.map(function(obj){
        let arr = [];
        let key = Object.keys(obj)[0];
        arr.push(key);
        return arr.concat(obj[key]);
      });
      break;
    case('automattic-vertical'):
      //assign header styles to first column
      config.columnSettings[0] = config.columnSettings[0] || {};
      config.columnSettings[0].color = config.headerColor;

      output = rows.map(function(value){
        let key = Object.keys(value)[0];
        return [key,value[key]];
      });
      break;
    case('o-horizontal'):
      output = rows.map(function(row){
        //requires that column names are specified in header
        return config.table.header[0].map(function(object){
          return row[object.value] || null;
        });
      });
      break;
    case('a-horizontal'):
      output = rows;
      break;
    default:
  }

  return output;
}

module.exports = Render;
<|endoftext|>