<commit_before>/**
 * Main controller of test environment in Core. Is automatically used
 * by {core.test.Suite} instances for self registration. The controller
 * joins together the flow and results of the individual suites. It also
 * supports the Testem (https://github.com/airportyh/testem/) test runner
 * for automating multi browser tests.
 */
core.Module("core.test.Controller",
{
  /** {=core.test.Suite[]} List of suite instances */
  __suites : [],

  /** Whether the test suites are being executed right now */
  __isRunning : false,

  /** Whether the test suites are finished with execution */
  __isFinished : false,

  /** Current suite (by index) to execute */
  __currentIndex : 0,

  /** {=Object} Socket object used to transfer status to testem test runner */
  __testemSocket : null,

  /**
   * Registers the given @suite {core.test.Suite} to the controller.
   */
  registerSuite : function(suite) {
    this.__suites.push(suite);
  },

  /**
   * {Boolean} Whether the suites have been executed successfully
   */
  wasSuccessful : function()
  {
    var suites = this.__suites;
    for (var i=0, l=suites.length; i<l; i++)
    {
      if (!suites[i].wasSuccessful()) {
        return false;
      }
    }

    return true;
  },

  /**
   * {Boolean} Whether the test suites are being executed right now
   */
  isRunning : function() {
    return this.__isRunning;
  },

  /**
   * {Boolean} Whether the test suites are finished with execution
   */
  isFinished : function() {
    return this.__isFinished;
  },

  /**
   * {Array} Exports the internal suite data into a list of test results.
   */
  export : function()
  {
    var suites = this.__suites;
    return Array.prototype.concat.apply([], this.__suites.map(function(suite) {
      return suite.export();
    }));
  },

  __initReporter : function()
  {
    if (this.__reporter) {
      return;
    }

    var suites = this.__suites;

    if (jasy.Env.isSet("runtime", "browser") && typeof callPhantom != "function") {
      this.__reporter = new core.test.reporter.Html(suites);
    } else if (typeof console !== "undefined") {
      this.__reporter = new core.test.reporter.Console(suites);
    } else {
      this.__reporter = null;
    }
  },

  /**
   * Executes all tests of all registered test suites.
   */
  run : function()
  {
    if (this.__isRunning) {
      return;
    }

    this.__isRunning = true;

    var suites = this.__suites;

    // Sort suites by caption
    suites.sort(function(a, b) {
      return a.getCaption() > b.getCaption() ? 1 : -1;
    });

    // Initialize view
    this.__initReporter(suites);

    // Integration with Testem Runner
    if (jasy.Env.isSet("runtime", "browser") && location.hash == "#testem")
    {
      var self = this;

      core.io.Script.load("/testem.js", function()
      {
        Testem.useCustomAdapter(function(socket)
        {
          self.__testemSocket = socket;
          socket.emit("tests-start");

          self.__reporter.start(suites);
          self.__runNextSuite();
        });
      });
    }
    else
    {
      this.__reporter.start(suites);
      this.__runNextSuite();
    }
  },

  /**
   * Internal helper to execute the next suite in the list.
   */
  __runNextSuite : function()
  {
    var previousSuite = this.__suites[this.__currentIndex];
    var currentSuite = this.__suites[++this.__currentIndex];

    if (previousSuite) {
      this.__reporter.suiteFinished(previousSuite);
    }

    if (currentSuite)
    {
      this.__reporter.suiteStarted(currentSuite);

      var allComplete = core.util.Function.bind(this.__runNextSuite, this);
      var testStarted = core.util.Function.bind(this.__testStarted, this);
      var testFinished = core.util.Function.bind(this.__testFinished, this);

      currentSuite.run(allComplete, testStarted, testFinished, true);
    }
    else if (this.__isRunning)
    {
      this.__reporter.finished();

      this.__isRunning = false;
      this.__isFinished = true;

      if (jasy.Env.isSet("runtime", "browser"))
      {
        if (typeof callPhantom == "function")
        {
          callPhantom({
            action : "finished",
            status : this.isSuccessful()
          });
        }

        if (this.__testemSocket != null)
        {
          // Report back all test results and the fact that
          // we are done running them.
          this.__testemSocket.emit("all-test-results", this.export());
        }
      }
    }
  },

  /**
   * Callback which is being executed every time a @test {core.test.Test} was started.
   */
  __testStarted : function(test) {
    this.__reporter.testStarted(test);
  },

  /**
   * Callback which is being executed every time a @test {core.test.Test} was finished.
   */
  __testFinished : function(test)
  {
    this.__reporter.testFinished(test);

    var socket = this.__testemSocket;
    if (socket != null) {
      socket.emit("test-result", test.export());
    }
  }
});
<commit_msg>Minor fix<commit_after>/**
 * Main controller of test environment in Core. Is automatically used
 * by {core.test.Suite} instances for self registration. The controller
 * joins together the flow and results of the individual suites. It also
 * supports the Testem (https://github.com/airportyh/testem/) test runner
 * for automating multi browser tests.
 */
core.Module("core.test.Controller",
{
  /** {=core.test.Suite[]} List of suite instances */
  __suites : [],

  /** Whether the test suites are being executed right now */
  __isRunning : false,

  /** Whether the test suites are finished with execution */
  __isFinished : false,

  /** Current suite (by index) to execute */
  __currentIndex : 0,

  /** {=Object} Socket object used to transfer status to testem test runner */
  __testemSocket : null,

  /**
   * Registers the given @suite {core.test.Suite} to the controller.
   */
  registerSuite : function(suite) {
    this.__suites.push(suite);
  },

  /**
   * {Boolean} Whether the suites have been executed successfully
   */
  wasSuccessful : function()
  {
    var suites = this.__suites;
    for (var i=0, l=suites.length; i<l; i++)
    {
      if (!suites[i].wasSuccessful()) {
        return false;
      }
    }

    return true;
  },

  /**
   * {Boolean} Whether the test suites are being executed right now
   */
  isRunning : function() {
    return this.__isRunning;
  },

  /**
   * {Boolean} Whether the test suites are finished with execution
   */
  isFinished : function() {
    return this.__isFinished;
  },

  /**
   * {Array} Exports the internal suite data into a list of test results.
   */
  export : function()
  {
    var suites = this.__suites;
    return Array.prototype.concat.apply([], this.__suites.map(function(suite) {
      return suite.export();
    }));
  },

  __initReporter : function()
  {
    if (this.__reporter) {
      return;
    }

    var suites = this.__suites;

    if (jasy.Env.isSet("runtime", "browser") && typeof callPhantom != "function") {
      this.__reporter = new core.test.reporter.Html(suites);
    } else if (typeof console !== "undefined") {
      this.__reporter = new core.test.reporter.Console(suites);
    } else {
      this.__reporter = null;
    }
  },

  /**
   * Executes all tests of all registered test suites.
   */
  run : function()
  {
    if (this.__isRunning) {
      return;
    }

    this.__isRunning = true;

    var suites = this.__suites;

    // Sort suites by caption
    suites.sort(function(a, b) {
      return a.getCaption() > b.getCaption() ? 1 : -1;
    });

    // Initialize view
    this.__initReporter(suites);

    // Integration with Testem Runner
    if (jasy.Env.isSet("runtime", "browser") && location.hash == "#testem")
    {
      var self = this;

      core.io.Script.load("/testem.js", function()
      {
        Testem.useCustomAdapter(function(socket)
        {
          self.__testemSocket = socket;
          socket.emit("tests-start");

          self.__reporter.start(suites);
          self.__runNextSuite();
        });
      });
    }
    else
    {
      this.__reporter.start(suites);
      this.__runNextSuite();
    }
  },

  /**
   * Internal helper to execute the next suite in the list.
   */
  __runNextSuite : function()
  {
    var previousSuite = this.__suites[this.__currentIndex];
    var currentSuite = this.__suites[++this.__currentIndex];

    if (previousSuite) {
      this.__reporter.suiteFinished(previousSuite);
    }

    if (currentSuite)
    {
      this.__reporter.suiteStarted(currentSuite);

      var allComplete = core.util.Function.bind(this.__runNextSuite, this);
      var testStarted = core.util.Function.bind(this.__testStarted, this);
      var testFinished = core.util.Function.bind(this.__testFinished, this);

      currentSuite.run(allComplete, testStarted, testFinished, true);
    }
    else if (this.__isRunning)
    {
      this.__reporter.finished();

      this.__isRunning = false;
      this.__isFinished = true;

      if (jasy.Env.isSet("runtime", "browser"))
      {
        if (typeof callPhantom == "function")
        {
          callPhantom({
            action : "finished",
            status : this.wasSuccessful()
          });
        }

        if (this.__testemSocket != null)
        {
          // Report back all test results and the fact that
          // we are done running them.
          this.__testemSocket.emit("all-test-results", this.export());
        }
      }
    }
  },

  /**
   * Callback which is being executed every time a @test {core.test.Test} was started.
   */
  __testStarted : function(test) {
    this.__reporter.testStarted(test);
  },

  /**
   * Callback which is being executed every time a @test {core.test.Test} was finished.
   */
  __testFinished : function(test)
  {
    this.__reporter.testFinished(test);

    var socket = this.__testemSocket;
    if (socket != null) {
      socket.emit("test-result", test.export());
    }
  }
});
<|endoftext|>


<commit_before>var Orvibo = require('node-orvibo');
var o = new Orvibo();

var timer1 // This timer is used for discovering devices
var timer2 = [] // This timer is used to subscribe to a device
var timer3 = [] // This timer is used to resubscribe a device

// We've listened, and now we're ready to go.
o.on("ready", function() {
    timer1 = setInterval(function() { // Set up a timer to search for sockets every second until found

        o.discover();

    }, 1000)
});

// A device has been found and added to our list of devices
o.on("deviceadded", function(device) {

    clearInterval(timer1); // Clear our first timer, as we've found at least one socket
    o.discover(); // Ask around again, just in case we missed something
    timer2[device.macAddress] = setInterval(function() { // Set up a new timer for subscribing to this device. Repeat until we get confirmation of subscription

        o.subscribe(device);

    }, 1000);
})

// We've asked to subscribe (control) a device, and now we've had a response.
// Next, we will query the device for its name and such
o.on("subscribed", function(device) {

    clearInterval(timer2[device.macAddress]) // Stop the second subscribe timer for this device
    timer3[device.macAddress] = setInterval(function() { // Set up another timer, this time for querying

        o.subscribe(device)

    }, 120000);
});

o.listen();

module.exports = function(RED) {
    function node (config) {

        RED.nodes.createNode(this, config);
        var node = this;

        this.on('input', function(msg) {

            var device = msg.payload;

            o.setState({
                device: device,
                state: device.state
            });
        });
    };

    RED.nodes.registerType("Orvibo",node);
}<commit_msg>removed third timer<commit_after>var Orvibo = require('node-orvibo');
var o = new Orvibo();

var timer1 // This timer is used for discovering devices
var timer2 = [] // This timer is used to subscribe to a device

// We've listened, and now we're ready to go.
o.on("ready", function() {
    timer1 = setInterval(function() { // Set up a timer to search for sockets every second until found

        o.discover();

    }, 1000)
});

// A device has been found and added to our list of devices
o.on("deviceadded", function(device) {

    clearInterval(timer1); // Clear our first timer, as we've found at least one socket
    o.discover(); // Ask around again, just in case we missed something
    timer2[device.macAddress] = setInterval(function() { // Set up a new timer for subscribing to this device. Repeat until we get confirmation of subscription

        o.subscribe(device);

    }, 1000);
})

// We've asked to subscribe (control) a device, and now we've had a response.
// Next, we will query the device for its name and such
o.on("subscribed", function(device) {

    clearInterval(timer2[device.macAddress]) // Stop the second subscribe timer for this device
    timer2[device.macAddress] = setInterval(function() { // Set up another timer, this time for querying

        o.subscribe(device)

    }, 120000);
});

o.listen();

module.exports = function(RED) {
    function node (config) {

        RED.nodes.createNode(this, config);
        var node = this;

        this.on('input', function(msg) {

            var device = msg.payload;

            o.setState({
                device: device,
                state: device.state
            });
        });
    };

    RED.nodes.registerType("Orvibo",node);
}<|endoftext|>


<commit_before>import KeyPair from './keyPair';
import convert from '../utils/convert';
import Address from '../model/address';
import nacl from '../external/nacl-fast';
import Network from '../model/network';
import CryptoJS from 'crypto-js';
import Helpers from '../utils/helpers';

/**
 * Encrypt a private key for mobile apps (AES_PBKF2)
 *
 * @param {string} password - A wallet password
 * @param {string} privateKey - An account private key
 *
 * @return {object} - The encrypted data
 */
let toMobileKey = function(password, privateKey) {
    // Errors
    if (!password || !privateKey) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(privateKey)) throw new Error('Private key is not valid !');
    // Processing
    let salt = CryptoJS.lib.WordArray.random(256 / 8);
    let key = CryptoJS.PBKDF2(password, salt, {
        keySize: 256 / 32,
        iterations: 2000
    });
    let iv = nacl.randomBytes(16)
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(privateKey), key, encIv);
    // Result
    return {
        encrypted: convert.ua2hex(iv) + encrypted.ciphertext,
        salt:  salt.toString()
    }
};

/**
 * Derive a private key from a password using count iterations of SHA3-256
 *
 * @param {string} password - A wallet password
 * @param {number} count - A number of iterations above 0
 *
 * @return {object} - The derived private key
 */
let derivePassSha = function(password, count) {
    // Errors
    if(!password) throw new Error('Missing argument !');
    if(!count || count <= 0) throw new Error('Please provide a count number above 0');
    // Processing
    let data = password;
    console.time('sha3^n generation time');
    for (let i = 0; i < count; ++i) {
        data = CryptoJS.SHA3(data, {
            outputLength: 256
        });
    }
    console.timeEnd('sha3^n generation time');
    // Result
    return {
        'priv': CryptoJS.enc.Hex.stringify(data)
    };
};

/**
 * Reveal the private key of an account or derive it from the wallet password
 *
 * @param {object} common- An object containing password and privateKey field
 * @param {object} walletAccount - A wallet account object
 * @param {string} algo - A wallet algorithm
 *
 * @return {object|boolean} - The account private key in and object or false
 */
let passwordToPrivatekey = function(common, walletAccount, algo) {
    // Errors
    if(!common || !common.password || !walletAccount || !algo) throw new Error('Missing argument !');
    // Processing
    let r = undefined;
    if (algo === "pass:6k") { // Brain wallets
        if (!walletAccount.encrypted && !walletAccount.iv) {
            // Account private key is generated simply using a passphrase so it has no encrypted and iv
            r = derivePassSha(common.password, 6000);
        } else if (!walletAccount.encrypted || !walletAccount.iv) {
            // Else if one is missing there is a problem
            //console.log("Account might be compromised, missing encrypted or iv");
            return false;
        } else {
            // Else child accounts have encrypted and iv so we decrypt
            let pass = derivePassSha(common.password, 20);
            let obj = {
                ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
                iv: convert.hex2ua(walletAccount.iv),
                key: convert.hex2ua(pass.priv)
            };
            let d = decrypt(obj);
            r = {
                'priv': d
            };
        }
    } else if (algo === "pass:bip32") { // Wallets from PRNG
        let pass = derivePassSha(common.password, 20);
        let obj = {
            ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
            iv: convert.hex2ua(walletAccount.iv),
            key: convert.hex2ua(pass.priv)
        };
        let d = decrypt(obj);
        r = {
            'priv': d
        };
    } else if (algo === "pass:enc") { // Private Key wallets
        let pass = derivePassSha(common.password, 20);
        let obj = {
            ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
            iv: convert.hex2ua(walletAccount.iv),
            key: convert.hex2ua(pass.priv)
        };
        let d = decrypt(obj);
        r = {
            'priv': d
        };
    } else {
        //console.log("Unknown wallet encryption method");
        return false;
    }
    // Result
    common.privateKey = r.priv;
    return true;
}

/**
 * Check if a private key correspond to an account address
 *
 * @param {string} priv - An account private key
 * @param {number} network - A network id
 * @param {string} _expectedAddress - The expected NEM address
 *
 * @return {boolean} - True if valid, false otherwise
 */
let checkAddress = function(priv, network, _expectedAddress) {
    // Errors
    if (!priv || !network || !_expectedAddress) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(priv)) throw new Error('Private key is not valid !');
    //Processing
    let expectedAddress = _expectedAddress.toUpperCase().replace(/-/g, '');
    let kp = KeyPair.create(priv);
    let address = Address.toAddress(kp.publicKey.toString(), network);
    // Result
    return address === expectedAddress;
};

function hashfunc(dest, data, dataLength) {
    let convertedData = convert.ua2words(data, dataLength);
    let hash = CryptoJS.SHA3(convertedData, {
        outputLength: 512
    });
    convert.words2ua(dest, hash);
}

function key_derive(shared, salt, sk, pk) {
    nacl.lowlevel.crypto_shared_key_hash(shared, pk, sk, hashfunc);
    for (let i = 0; i < salt.length; i++) {
        shared[i] ^= salt[i];
    }
    let hash = CryptoJS.SHA3(convert.ua2words(shared, 32), {
        outputLength: 256
    });
    return hash;
}

/**
 * Generate a random key
 *
 * @return {Uint8Array} - A random key
 */
let randomKey = function() {
    let rkey = nacl.randomBytes(32)
    return rkey;
};

/**
 * Encrypt hex data using a key
 *
 * @param {string} data - An hex string
 * @param {Uint8Array} key - An Uint8Array key
 *
 * @return {object} - The encrypted data
 */
let encrypt = function(data, key) {
    // Errors
    if (!data || !key) throw new Error('Missing argument !');
    // Processing
    let iv = nacl.randomBytes(16)
    let encKey = convert.ua2words(key, 32);
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(data), encKey, encIv);
    // Result
    return {
        ciphertext: encrypted.ciphertext,
        iv: iv,
        key: key
    };
};

/**
 * Decrypt data
 *
 * @param {object} data - An encrypted data object
 *
 * @return {string} - The decrypted hex string
 */
let decrypt = function(data) {
    // Errors
    if (!data) throw new Error('Missing argument !');
    // Processing
    let encKey = convert.ua2words(data.key, 32);
    let encIv = {
        iv: convert.ua2words(data.iv, 16)
    };
    // Result
    return CryptoJS.enc.Hex.stringify(CryptoJS.AES.decrypt(data, encKey, encIv));
};

/**
 * Encode a private key using a password
 *
 * @param {string} privateKey - An hex private key
 * @param {string} password - A password
 *
 * @return {object} - The encoded data
 */
let encodePrivKey = function(privateKey, password) {
    // Errors
    if (!privateKey || !password) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(privateKey)) throw new Error('Private key is not valid !');
    // Processing
    let pass = derivePassSha(password, 20);
    let r = encrypt(privateKey, convert.hex2ua(pass.priv));
    // Result
    return {
        ciphertext: CryptoJS.enc.Hex.stringify(r.ciphertext),
        iv: convert.ua2hex(r.iv)
    };
};

/***
 * Encode a message, separated from encode() to help testing
 *
 * @param {string} senderPriv - A sender private key
 * @param {string} recipientPub - A recipient public key
 * @param {string} msg - A text message
 * @param {Uint8Array} iv - An initialization vector
 * @param {Uint8Array} salt - A salt
 *
 * @return {string} - The encoded message
 */
let _encode = function(senderPriv, recipientPub, msg, iv, salt) {
    // Errors
    if (!senderPriv || !recipientPub || !msg || !iv || !salt) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(senderPriv)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(recipientPub)) throw new Error('Public key is not valid !');
    // Processing
    let sk = convert.hex2ua_reversed(senderPriv);
    let pk = convert.hex2ua(recipientPub);
    let shared = new Uint8Array(32);
    let r = key_derive(shared, salt, sk, pk);
    let encKey = r;
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(convert.utf8ToHex(msg)), encKey, encIv);
    // Result
    let result = convert.ua2hex(salt) + convert.ua2hex(iv) + CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
    return result;
};

/**
 * Encode a message
 *
 * @param {string} senderPriv - A sender private key
 * @param {string} recipientPub - A recipient public key
 * @param {string} msg - A text message
 *
 * @return {string} - The encoded message
 */
let encode = function(senderPriv, recipientPub, msg) {
    // Errors
    if (!senderPriv || !recipientPub || !msg) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(senderPriv)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(recipientPub)) throw new Error('Public key is not valid !');
    // Processing
    let iv = nacl.randomBytes(16)
    //console.log("IV:", convert.ua2hex(iv));
    let salt = nacl.randomBytes(32)
    let encoded = _encode(senderPriv, recipientPub, msg, iv, salt);
    // Result
    return encoded;
};

/**
 * Decode an encrypted message payload
 *
 * @param {string} recipientPrivate - A recipient private key
 * @param {string} senderPublic - A sender public key
 * @param {string} _payload - An encrypted message payload
 *
 * @return {string} - The decoded payload as hex
 */
let decode = function(recipientPrivate, senderPublic, _payload) {
    // Errors
    if(!recipientPrivate || !senderPublic || !_payload) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(recipientPrivate)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(senderPublic)) throw new Error('Public key is not valid !');
    // Processing
    let binPayload = convert.hex2ua(_payload);
    let salt = new Uint8Array(binPayload.buffer, 0, 32);
    let iv = new Uint8Array(binPayload.buffer, 32, 16);
    let payload = new Uint8Array(binPayload.buffer, 48);
    let sk = convert.hex2ua_reversed(recipientPrivate);
    let pk = convert.hex2ua(senderPublic);
    let shared = new Uint8Array(32);
    let r = key_derive(shared, salt, sk, pk);
    let encKey = r;
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = {
        'ciphertext': convert.ua2words(payload, payload.length)
    };
    let plain = CryptoJS.AES.decrypt(encrypted, encKey, encIv);
    // Result
    let hexplain = CryptoJS.enc.Hex.stringify(plain);
    return hexplain;
};

module.exports = {
    toMobileKey,
    derivePassSha,
    passwordToPrivatekey,
    checkAddress,
    randomKey,
    decrypt,
    encrypt,
    encodePrivKey,
    _encode,
    encode,
    decode
}
<commit_msg>Add trezor wallet type to passwordToPrivateKey<commit_after>import KeyPair from './keyPair';
import convert from '../utils/convert';
import Address from '../model/address';
import nacl from '../external/nacl-fast';
import Network from '../model/network';
import CryptoJS from 'crypto-js';
import Helpers from '../utils/helpers';

/**
 * Encrypt a private key for mobile apps (AES_PBKF2)
 *
 * @param {string} password - A wallet password
 * @param {string} privateKey - An account private key
 *
 * @return {object} - The encrypted data
 */
let toMobileKey = function(password, privateKey) {
    // Errors
    if (!password || !privateKey) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(privateKey)) throw new Error('Private key is not valid !');
    // Processing
    let salt = CryptoJS.lib.WordArray.random(256 / 8);
    let key = CryptoJS.PBKDF2(password, salt, {
        keySize: 256 / 32,
        iterations: 2000
    });
    let iv = nacl.randomBytes(16)
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(privateKey), key, encIv);
    // Result
    return {
        encrypted: convert.ua2hex(iv) + encrypted.ciphertext,
        salt:  salt.toString()
    }
};

/**
 * Derive a private key from a password using count iterations of SHA3-256
 *
 * @param {string} password - A wallet password
 * @param {number} count - A number of iterations above 0
 *
 * @return {object} - The derived private key
 */
let derivePassSha = function(password, count) {
    // Errors
    if(!password) throw new Error('Missing argument !');
    if(!count || count <= 0) throw new Error('Please provide a count number above 0');
    // Processing
    let data = password;
    console.time('sha3^n generation time');
    for (let i = 0; i < count; ++i) {
        data = CryptoJS.SHA3(data, {
            outputLength: 256
        });
    }
    console.timeEnd('sha3^n generation time');
    // Result
    return {
        'priv': CryptoJS.enc.Hex.stringify(data)
    };
};

/**
 * Reveal the private key of an account or derive it from the wallet password
 *
 * @param {object} common- An object containing password and privateKey field
 * @param {object} walletAccount - A wallet account object
 * @param {string} algo - A wallet algorithm
 *
 * @return {object|boolean} - The account private key in and object or false
 */
let passwordToPrivatekey = function(common, walletAccount, algo) {
    // Errors
    if(!common || !common.password || !walletAccount || !algo) throw new Error('Missing argument !');
    // Processing
    let r = undefined;
    if (algo === "pass:6k") { // Brain wallets
        if (!walletAccount.encrypted && !walletAccount.iv) {
            // Account private key is generated simply using a passphrase so it has no encrypted and iv
            r = derivePassSha(common.password, 6000);
        } else if (!walletAccount.encrypted || !walletAccount.iv) {
            // Else if one is missing there is a problem
            //console.log("Account might be compromised, missing encrypted or iv");
            return false;
        } else {
            // Else child accounts have encrypted and iv so we decrypt
            let pass = derivePassSha(common.password, 20);
            let obj = {
                ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
                iv: convert.hex2ua(walletAccount.iv),
                key: convert.hex2ua(pass.priv)
            };
            let d = decrypt(obj);
            r = { 'priv': d };
        }
    } else if (algo === "pass:bip32") { // Wallets from PRNG
        let pass = derivePassSha(common.password, 20);
        let obj = {
            ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
            iv: convert.hex2ua(walletAccount.iv),
            key: convert.hex2ua(pass.priv)
        };
        let d = decrypt(obj);
        r = { 'priv': d };
    } else if (algo === "pass:enc") { // Private Key wallets
        let pass = derivePassSha(common.password, 20);
        let obj = {
            ciphertext: CryptoJS.enc.Hex.parse(walletAccount.encrypted),
            iv: convert.hex2ua(walletAccount.iv),
            key: convert.hex2ua(pass.priv)
        };
        let d = decrypt(obj);
        r = { 'priv': d };
    } else if (algo === "trezor") { // HW wallet
        r = { 'priv': '' };
        common.isHW = true;
    } else {
        //console.log("Unknown wallet encryption method");
        return false;
    }
    // Result
    common.privateKey = r.priv;
    return true;
}

/**
 * Check if a private key correspond to an account address
 *
 * @param {string} priv - An account private key
 * @param {number} network - A network id
 * @param {string} _expectedAddress - The expected NEM address
 *
 * @return {boolean} - True if valid, false otherwise
 */
let checkAddress = function(priv, network, _expectedAddress) {
    // Errors
    if (!priv || !network || !_expectedAddress) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(priv)) throw new Error('Private key is not valid !');
    //Processing
    let expectedAddress = _expectedAddress.toUpperCase().replace(/-/g, '');
    let kp = KeyPair.create(priv);
    let address = Address.toAddress(kp.publicKey.toString(), network);
    // Result
    return address === expectedAddress;
};

function hashfunc(dest, data, dataLength) {
    let convertedData = convert.ua2words(data, dataLength);
    let hash = CryptoJS.SHA3(convertedData, {
        outputLength: 512
    });
    convert.words2ua(dest, hash);
}

function key_derive(shared, salt, sk, pk) {
    nacl.lowlevel.crypto_shared_key_hash(shared, pk, sk, hashfunc);
    for (let i = 0; i < salt.length; i++) {
        shared[i] ^= salt[i];
    }
    let hash = CryptoJS.SHA3(convert.ua2words(shared, 32), {
        outputLength: 256
    });
    return hash;
}

/**
 * Generate a random key
 *
 * @return {Uint8Array} - A random key
 */
let randomKey = function() {
    let rkey = nacl.randomBytes(32)
    return rkey;
};

/**
 * Encrypt hex data using a key
 *
 * @param {string} data - An hex string
 * @param {Uint8Array} key - An Uint8Array key
 *
 * @return {object} - The encrypted data
 */
let encrypt = function(data, key) {
    // Errors
    if (!data || !key) throw new Error('Missing argument !');
    // Processing
    let iv = nacl.randomBytes(16)
    let encKey = convert.ua2words(key, 32);
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(data), encKey, encIv);
    // Result
    return {
        ciphertext: encrypted.ciphertext,
        iv: iv,
        key: key
    };
};

/**
 * Decrypt data
 *
 * @param {object} data - An encrypted data object
 *
 * @return {string} - The decrypted hex string
 */
let decrypt = function(data) {
    // Errors
    if (!data) throw new Error('Missing argument !');
    // Processing
    let encKey = convert.ua2words(data.key, 32);
    let encIv = {
        iv: convert.ua2words(data.iv, 16)
    };
    // Result
    return CryptoJS.enc.Hex.stringify(CryptoJS.AES.decrypt(data, encKey, encIv));
};

/**
 * Encode a private key using a password
 *
 * @param {string} privateKey - An hex private key
 * @param {string} password - A password
 *
 * @return {object} - The encoded data
 */
let encodePrivKey = function(privateKey, password) {
    // Errors
    if (!privateKey || !password) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(privateKey)) throw new Error('Private key is not valid !');
    // Processing
    let pass = derivePassSha(password, 20);
    let r = encrypt(privateKey, convert.hex2ua(pass.priv));
    // Result
    return {
        ciphertext: CryptoJS.enc.Hex.stringify(r.ciphertext),
        iv: convert.ua2hex(r.iv)
    };
};

/***
 * Encode a message, separated from encode() to help testing
 *
 * @param {string} senderPriv - A sender private key
 * @param {string} recipientPub - A recipient public key
 * @param {string} msg - A text message
 * @param {Uint8Array} iv - An initialization vector
 * @param {Uint8Array} salt - A salt
 *
 * @return {string} - The encoded message
 */
let _encode = function(senderPriv, recipientPub, msg, iv, salt) {
    // Errors
    if (!senderPriv || !recipientPub || !msg || !iv || !salt) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(senderPriv)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(recipientPub)) throw new Error('Public key is not valid !');
    // Processing
    let sk = convert.hex2ua_reversed(senderPriv);
    let pk = convert.hex2ua(recipientPub);
    let shared = new Uint8Array(32);
    let r = key_derive(shared, salt, sk, pk);
    let encKey = r;
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(convert.utf8ToHex(msg)), encKey, encIv);
    // Result
    let result = convert.ua2hex(salt) + convert.ua2hex(iv) + CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
    return result;
};

/**
 * Encode a message
 *
 * @param {string} senderPriv - A sender private key
 * @param {string} recipientPub - A recipient public key
 * @param {string} msg - A text message
 *
 * @return {string} - The encoded message
 */
let encode = function(senderPriv, recipientPub, msg) {
    // Errors
    if (!senderPriv || !recipientPub || !msg) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(senderPriv)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(recipientPub)) throw new Error('Public key is not valid !');
    // Processing
    let iv = nacl.randomBytes(16)
    //console.log("IV:", convert.ua2hex(iv));
    let salt = nacl.randomBytes(32)
    let encoded = _encode(senderPriv, recipientPub, msg, iv, salt);
    // Result
    return encoded;
};

/**
 * Decode an encrypted message payload
 *
 * @param {string} recipientPrivate - A recipient private key
 * @param {string} senderPublic - A sender public key
 * @param {string} _payload - An encrypted message payload
 *
 * @return {string} - The decoded payload as hex
 */
let decode = function(recipientPrivate, senderPublic, _payload) {
    // Errors
    if(!recipientPrivate || !senderPublic || !_payload) throw new Error('Missing argument !');
    if (!Helpers.isPrivateKeyValid(recipientPrivate)) throw new Error('Private key is not valid !');
    if (!Helpers.isPublicKeyValid(senderPublic)) throw new Error('Public key is not valid !');
    // Processing
    let binPayload = convert.hex2ua(_payload);
    let salt = new Uint8Array(binPayload.buffer, 0, 32);
    let iv = new Uint8Array(binPayload.buffer, 32, 16);
    let payload = new Uint8Array(binPayload.buffer, 48);
    let sk = convert.hex2ua_reversed(recipientPrivate);
    let pk = convert.hex2ua(senderPublic);
    let shared = new Uint8Array(32);
    let r = key_derive(shared, salt, sk, pk);
    let encKey = r;
    let encIv = {
        iv: convert.ua2words(iv, 16)
    };
    let encrypted = {
        'ciphertext': convert.ua2words(payload, payload.length)
    };
    let plain = CryptoJS.AES.decrypt(encrypted, encKey, encIv);
    // Result
    let hexplain = CryptoJS.enc.Hex.stringify(plain);
    return hexplain;
};

module.exports = {
    toMobileKey,
    derivePassSha,
    passwordToPrivatekey,
    checkAddress,
    randomKey,
    decrypt,
    encrypt,
    encodePrivKey,
    _encode,
    encode,
    decode
}
<|endoftext|>


<commit_before>import React from 'react'
import Relay from 'react-relay'
import {
  LeftNav,
  Styles,
  Divider,
  FloatingActionButton,
  RaisedButton,
  FlatButton,
  Card,
  CardTitle,
  CardText,
  CardActions,
  FontIcon,
  List,
  ListItem,
  Checkbox
} from 'material-ui'
import Subheader from 'material-ui/lib/Subheader'
import GCForm from './forms/GCForm'
import Form from 'react-formal'
import yup from 'yup'
import moment from 'moment'
import {BernieTheme} from './styles/bernie-theme'
import {BernieText, BernieColors} from './styles/bernie-css'
import stripScripts from '../helpers/stripScripts'
import SideBarLayout from './SideBarLayout'
import humps from 'humps'
import Papa from 'papaparse'
import downloadCSV from '../helpers/downloadCSV'
import flattenJSON from '../helpers/flattenJSON'

const publicEventsRootUrl = 'https://secure.berniesanders.com/page/event'

class LinkButton extends React.Component {
  static propTypes = {
    label: React.PropTypes.string.isRequired,
    href: React.PropTypes.string.isRequired
  }

  render() {
    return (
      <FlatButton
        label={this.props.label}
        linkButton={true}
        href={this.props.href}
        target='_blank'
        style={{textAlign: 'center'}}
      />
    )
  }
}

class EventsDashboard extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight
    }

    window.addEventListener('resize', this._handleResize)
  }

  _handleResize = (e) => {
    this.setState({
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight
    })
  }

  styles = () => {
    return {
      sideBar: {
        width: '20%',
        border: 'none',
        zIndex: 10
      },
      container: {
        borderBottom: 'none',
        border: 'none'
      },
      content: {
        height: this.state.windowHeight - 56,
        width: '80%',
        padding: 5, top: 56,
        position: 'absolute',
        overflow: 'scroll',
        boxSizing: 'border-box'
      }
    }
  }

  renderEvents() {
    const events = this.props.currentUser.relatedPerson ? this.props.currentUser.relatedPerson.hostedEvents : []
    if (events.length === 0)
      return

No Events

You haven't signed up to host any events yet! Click here to create your first event.

    return events.map((event) => {
      const utcOffset = event.localUTCOffset || 0
      const timezone = event.localTimezone || 'UTC'
      const offsetDate = moment(event.startDate).utcOffset(utcOffset)
      const formattedDate = offsetDate.format('l LT')
      return (

          <Card>
            <CardTitle
              title={{event.name}}
              subtitle={{formattedDate}}
              actAsExpander={true}
              showExpandableButton={true}
            />
            <CardText expandable={true}>

            </CardText>
            <CardActions expandable={true}>
              <LinkButton
                label='View'
                href={`${publicEventsRootUrl}/detail/${event.eventIdObfuscated}`}
              />
              <LinkButton
                label='Edit'
                href={`${publicEventsRootUrl}/edit_details?event_id=${event.eventIdUnObfuscated}`}
              />
              <LinkButton
                label='Delete'
                href={`${publicEventsRootUrl}/delete/${event.eventIdObfuscated}`}
              />
              <FlatButton
                label="Send Turnout Email"
                onTouchTap={() => this.props.history.push(`/events/${event.eventIdObfuscated}/request-email`)}
              />
              <FlatButton
                label="Download RSVPs"
                disabled={(event.attendees.length === 0)}
                onTouchTap={() => {
                  const attendees = event.attendees.map((attendee) => flattenJSON(attendee, {ignoreProps: ['__dataID__']}))
                  const data = Papa.unparse(humps.decamelizeKeys(attendees))
                  downloadCSV(data, `${event.eventIdObfuscated}.rsvps.csv`)
                }}
              />
            </CardActions>
          </Card>

      )
    })
  }

  renderContent() {
    return (

        {this.renderEvents()}
        <FloatingActionButton style={{marginRight: 20, position: 'fixed', bottom: 20, right: 10}} linkButton={true} href='/events/create' >
          <FontIcon className="material-icons">add</FontIcon>
        </FloatingActionButton>

    )
  }

  render() {
    const sideBar = (
      <LeftNav
        docked={true}
        open={true}
        width={this.styles().sideBar.width}
      >
        <List style={{marginTop: 56}}>
          <Subheader>General</Subheader>
          <ListItem
            primaryText="Hosting"
            secondaryText="Events you are hosting"
          />
          <ListItem
            primaryText="Attending"
            secondaryText="Events you are attending"
          />
        </List>
        <Divider />
        <List>
          <Subheader>View Settings</Subheader>
          <ListItem
            leftCheckbox={<Checkbox />}
            primaryText="Show All Events"
            secondaryText="View all past and upcoming events"
          />
          <ListItem
            leftCheckbox={<Checkbox />}
            primaryText="Use Calendar View"
            secondaryText="View as a calendar instead of list"
          />
        </List>
      </LeftNav>
    )

    return (
      <SideBarLayout
        sideBar={sideBar}
        sideBarStyle={this.styles().sideBar}
        content={this.renderContent()}
        contentViewStyle={this.styles().container}
      />
    )
  }
}

export default Relay.createContainer(EventsDashboard, {
  fragments: {
    currentUser: () => Relay.QL`
      fragment on User {
        id
        email
        relatedPerson {
          hostedEvents {
            name
            id
            host {
              id
              firstName
              lastName
              email
            }
            eventType {
              id
              name
            }
            eventIdUnObfuscated
            eventIdObfuscated
            flagApproval
            isOfficial
            description
            venueName
            latitude
            longitude
            venueZip
            venueCity
            venueState
            venueAddr1
            venueAddr2
            venueCountry
            venueDirections
            createDate
            startDate
            localTimezone
            localUTCOffset
            duration
            capacity
            attendeeVolunteerShow
            attendeeVolunteerMessage
            isSearchable
            publicPhone
            contactPhone
            hostReceiveRsvpEmails
            rsvpUseReminderEmail
            rsvpEmailReminderHours
            attendeesCount
            attendees {
              firstName
              lastName
              phone
              email
              address {
                city
                state
                zip
              }
            }
          }
        }
      }
    `
  }
})<commit_msg>Use width state<commit_after>import React from 'react'
import Relay from 'react-relay'
import {
  LeftNav,
  Styles,
  Divider,
  FloatingActionButton,
  RaisedButton,
  FlatButton,
  Card,
  CardTitle,
  CardText,
  CardActions,
  FontIcon,
  List,
  ListItem,
  Checkbox
} from 'material-ui'
import Subheader from 'material-ui/lib/Subheader'
import GCForm from './forms/GCForm'
import Form from 'react-formal'
import yup from 'yup'
import moment from 'moment'
import {BernieTheme} from './styles/bernie-theme'
import {BernieText, BernieColors} from './styles/bernie-css'
import stripScripts from '../helpers/stripScripts'
import SideBarLayout from './SideBarLayout'
import humps from 'humps'
import Papa from 'papaparse'
import downloadCSV from '../helpers/downloadCSV'
import flattenJSON from '../helpers/flattenJSON'

const publicEventsRootUrl = 'https://secure.berniesanders.com/page/event'

class LinkButton extends React.Component {
  static propTypes = {
    label: React.PropTypes.string.isRequired,
    href: React.PropTypes.string.isRequired
  }

  render() {
    return (
      <FlatButton
        label={this.props.label}
        linkButton={true}
        href={this.props.href}
        target='_blank'
        style={{textAlign: 'center'}}
      />
    )
  }
}

class EventsDashboard extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight
    }

    window.addEventListener('resize', this._handleResize)
  }

  _handleResize = (e) => {
    this.setState({
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight
    })
  }

  styles = () => {
    return {
      sideBar: {
        width: this.state.windowWidth * 0.2,
        border: 'none',
        zIndex: 10
      },
      container: {
        borderBottom: 'none',
        border: 'none'
      },
      content: {
        height: this.state.windowHeight - 56,
        width: this.state.windowWidth * 0.8,
        padding: 5, top: 56,
        position: 'absolute',
        overflow: 'scroll',
        boxSizing: 'border-box'
      }
    }
  }

  renderEvents() {
    const events = this.props.currentUser.relatedPerson ? this.props.currentUser.relatedPerson.hostedEvents : []
    if (events.length === 0)
      return

No Events

You haven't signed up to host any events yet! Click here to create your first event.

    return events.map((event) => {
      const utcOffset = event.localUTCOffset || 0
      const timezone = event.localTimezone || 'UTC'
      const offsetDate = moment(event.startDate).utcOffset(utcOffset)
      const formattedDate = offsetDate.format('l LT')
      return (

          <Card>
            <CardTitle
              title={{event.name}}
              subtitle={{formattedDate}}
              actAsExpander={true}
              showExpandableButton={true}
            />
            <CardText expandable={true}>

            </CardText>
            <CardActions expandable={true}>
              <LinkButton
                label='View'
                href={`${publicEventsRootUrl}/detail/${event.eventIdObfuscated}`}
              />
              <LinkButton
                label='Edit'
                href={`${publicEventsRootUrl}/edit_details?event_id=${event.eventIdUnObfuscated}`}
              />
              <LinkButton
                label='Delete'
                href={`${publicEventsRootUrl}/delete/${event.eventIdObfuscated}`}
              />
              <FlatButton
                label="Send Turnout Email"
                onTouchTap={() => this.props.history.push(`/events/${event.eventIdObfuscated}/request-email`)}
              />
              <FlatButton
                label="Download RSVPs"
                disabled={(event.attendees.length === 0)}
                onTouchTap={() => {
                  const attendees = event.attendees.map((attendee) => flattenJSON(attendee, {ignoreProps: ['__dataID__']}))
                  const data = Papa.unparse(humps.decamelizeKeys(attendees))
                  downloadCSV(data, `${event.eventIdObfuscated}.rsvps.csv`)
                }}
              />
            </CardActions>
          </Card>

      )
    })
  }

  renderContent() {
    return (

        {this.renderEvents()}
        <FloatingActionButton style={{marginRight: 20, position: 'fixed', bottom: 20, right: 10}} linkButton={true} href='/events/create' >
          <FontIcon className="material-icons">add</FontIcon>
        </FloatingActionButton>

    )
  }

  render() {
    const sideBar = (
      <LeftNav
        docked={true}
        open={true}
        width={this.styles().sideBar.width}
      >
        <List style={{marginTop: 56}}>
          <Subheader>General</Subheader>
          <ListItem
            primaryText="Hosting"
            secondaryText="Events you are hosting"
          />
          <ListItem
            primaryText="Attending"
            secondaryText="Events you are attending"
          />
        </List>
        <Divider />
        <List>
          <Subheader>View Settings</Subheader>
          <ListItem
            leftCheckbox={<Checkbox />}
            primaryText="Show All Events"
            secondaryText="View all past and upcoming events"
          />
          <ListItem
            leftCheckbox={<Checkbox />}
            primaryText="Use Calendar View"
            secondaryText="View as a calendar instead of list"
          />
        </List>
      </LeftNav>
    )

    return (
      <SideBarLayout
        sideBar={sideBar}
        sideBarStyle={this.styles().sideBar}
        content={this.renderContent()}
        contentViewStyle={this.styles().container}
      />
    )
  }
}

export default Relay.createContainer(EventsDashboard, {
  fragments: {
    currentUser: () => Relay.QL`
      fragment on User {
        id
        email
        relatedPerson {
          hostedEvents {
            name
            id
            host {
              id
              firstName
              lastName
              email
            }
            eventType {
              id
              name
            }
            eventIdUnObfuscated
            eventIdObfuscated
            flagApproval
            isOfficial
            description
            venueName
            latitude
            longitude
            venueZip
            venueCity
            venueState
            venueAddr1
            venueAddr2
            venueCountry
            venueDirections
            createDate
            startDate
            localTimezone
            localUTCOffset
            duration
            capacity
            attendeeVolunteerShow
            attendeeVolunteerMessage
            isSearchable
            publicPhone
            contactPhone
            hostReceiveRsvpEmails
            rsvpUseReminderEmail
            rsvpEmailReminderHours
            attendeesCount
            attendees {
              firstName
              lastName
              phone
              email
              address {
                city
                state
                zip
              }
            }
          }
        }
      }
    `
  }
})<|endoftext|>


<commit_before>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

// Generate calls to SpiderMonkey "testing functions" for:
// * testing that they do not cause assertions/crashes
// * testing that they do not alter visible results (compare_jit with and without the call)

function fuzzTestingFunctionsCtor(browser, fGlobal, fObject)
{
  var prefix = browser ? "fuzzPriv." : "";

  function numberOfInstructions() { return Math.floor(Random.ludOneTo(10000)); }
  function numberOfAllocs() { return Math.floor(Random.ludOneTo(500)); }
  function gcSliceSize() { return Math.floor(Random.ludOneTo(0x100000000)); }
  function maybeCommaShrinking() { return rnd(5) ? "" : ", 'shrinking'"; }

  function enableGCZeal()
  {
    // As of m-c 405243:02aa9c921aed 2018-02-26
    // https://hg.mozilla.org/mozilla-central/file/02aa9c921aed/js/src/gc/GC.cpp#l1000
    max_level = 18;
    max_level++;  // rnd function starts from zero
    var level = final_level = rnd(max_level - 3); // 3 levels disabled below

    // Generate the second level.
    // ref https://hg.mozilla.org/mozilla-central/file/02aa9c921aed/js/src/gc/GC.cpp#l1001
    var level_two = rnd(max_level - 3); // 3 levels disabled below
    if (level_two >= 3) ++level_two; // gczeal 3 does not exist, so repurpose it
    if (level_two >= 5) ++level_two; // gczeal 5 does not exist, so repurpose it
    if (level_two >= 6) ++level_two; // gczeal 6 does not exist, so repurpose it

    if (level >= 3) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 3 does not exist, so repurpose it
    if (level >= 5) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 5 does not exist, so repurpose it
    if (level >= 6) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 6 does not exist, so repurpose it

    var period = numberOfAllocs();
    return prefix + "gczeal" + "(" + final_level + ", " + period + ");";
  }

  function callSetGCCallback() {
    // https://dxr.mozilla.org/mozilla-central/source/js/src/shell/js.cpp - SetGCCallback
    var phases = Random.index(["both", "begin", "end"]);
    var actionAndOptions = rnd(2) ? 'action: "majorGC", depth: ' + rnd(17) : 'action: "minorGC"';
    var arg = "{ " + actionAndOptions + ", phases: \"" + phases + "\" }";
    return prefix + "setGCCallback(" + arg + ");";
  }

  function tryCatch(statement)
  {
    return "try { " + statement + " } catch(e) { }";
  }

  function setGcparam() {
    switch(rnd(2)) {
      case 0:  return _set("sliceTimeBudget", rnd(100));
      default: return _set("markStackLimit", rnd(2) ? (1 + rnd(30)) : 4294967295); // Artificially trigger delayed marking
    }

    function _set(name, value) {
      // try..catch because gcparam sets may throw, depending on GC state (see bug 973571)
      return tryCatch(prefix + "gcparam" + "('" + name + "', " + value + ");");
    }
  }

  // Functions shared between the SpiderMonkey shell and Firefox browser
  // https://mxr.mozilla.org/mozilla-central/source/js/src/builtin/TestingFunctions.cpp
  var sharedTestingFunctions = [
    // Force garbage collection (global or specific compartment)
    { w: 10, v: function(d, b) { return "void " + prefix + "gc" + "("                                            + ");"; } },
    { w: 10, v: function(d, b) { return "void " + prefix + "gc" + "(" + "'compartment'" + maybeCommaShrinking() + ");"; } },
    { w: 5,  v: function(d, b) { return "void " + prefix + "gc" + "(" + fGlobal(d, b)   + maybeCommaShrinking() + ");"; } },

    // Run a minor garbage collection on the nursery.
    { w: 20, v: function(d, b) { return prefix + "minorgc" + "(false);"; } },
    { w: 20, v: function(d, b) { return prefix + "minorgc" + "(true);"; } },

    // Start, continue, or abort incremental garbage collection.
    // startgc can throw: "Incremental GC already in progress"
    { w: 20, v: function(d, b) { return tryCatch(prefix + "startgc" + "(" + gcSliceSize() + maybeCommaShrinking() + ");"); } },
    { w: 20, v: function(d, b) { return prefix + "gcslice" + "(" + gcSliceSize() + ");"; } },
    { w: 10, v: function(d, b) { return prefix + "abortgc" + "(" + ");"; } },

    // Schedule the given objects to be marked in the next GC slice.
    { w: 10, v: function(d, b) { return prefix + "selectforgc" + "(" + fObject(d, b) + ");"; } },

    // Add a compartment to the next garbage collection.
    { w: 10, v: function(d, b) { return "void " + prefix + "schedulegc" + "(" + fGlobal(d, b) + ");"; } },

    // Schedule a GC for after N allocations.
    { w: 10, v: function(d, b) { return "void " + prefix + "schedulegc" + "(" + numberOfAllocs() + ");"; } },

    // Change a GC parameter.
    { w: 10, v: setGcparam },

    // Verify write barriers. This functions is effective in pairs.
    // The first call sets up the start barrier, the second call sets up the end barrier.
    // Nothing happens when there is only one call.
    { w: 10, v: function(d, b) { return prefix + "verifyprebarriers" + "();"; } },

    // hasChild(parent, child): Return true if |child| is a child of |parent|, as determined by a call to TraceChildren.
    // We ignore the return value because hasChild can be used to see which WeakMap entries have been GCed.
    { w: 1,  v: function(d, b) { return "void " + prefix + "hasChild(" + fObject(d, b) + ", " + fObject(d, b) + ");"; } },

    // Various validation functions (toggles)
    { w: 5,  v: function(d, b) { return prefix + "fullcompartmentchecks" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "fullcompartmentchecks" + "(true);"; } },
    { w: 5,  v: function(d, b) { return prefix + "setIonCheckGraphCoherency" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "setIonCheckGraphCoherency" + "(true);"; } },
    { w: 1,  v: function(d, b) { return prefix + "enableOsiPointRegisterChecks" + "();"; } },

    // Various validation functions (immediate)
    { w: 1,  v: function(d, b) { return prefix + "assertJitStackInvariants" + "();"; } },

    // Run-time equivalents to --baseline-eager, --baseline-warmup-threshold, --ion-eager, --ion-warmup-threshold
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('baseline.warmup.trigger', " + rnd(20) + ");"; } },
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('ion.warmup.trigger', " + rnd(40) + ");"; } },

    // Test the baseline compiler
    { w: 10,  v: function(d, b) { return prefix + "baselineCompile" + "();"; } },

    // Force inline cache.
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('ion.forceinlineCaches\', " + rnd(2) + ");"; } },

    // Run-time equivalents to --no-ion, --no-baseline
    // These can throw: "Can't turn off JITs with JIT code on the stack."
    { w: 1,  v: function(d, b) { return tryCatch(prefix + "setJitCompilerOption" + "('ion.enable', " + rnd(2) + ");"); } },
    { w: 1,  v: function(d, b) { return tryCatch(prefix + "setJitCompilerOption" + "('baseline.enable', " + rnd(2) + ");"); } },

    // Test the built-in profiler.
    { w: 1,  v: function(d, b) { return prefix + "enableGeckoProfiling" + "();"; } },
    { w: 1,  v: function(d, b) { return prefix + "enableGeckoProfilingWithSlowAssertions" + "();"; } },
    { w: 5,  v: function(d, b) { return prefix + "disableGeckoProfiling" + "();"; } },
    { w: 1,  v: function(d, b) { return "void " + prefix + "readGeckoProfilingStack" + "();"; } },

    // I'm not sure what this does in the shell.
    { w: 5,  v: function(d, b) { return prefix + "deterministicgc" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "deterministicgc" + "(true);"; } },

    // Causes JIT code to always be preserved by GCs afterwards (see https://bugzilla.mozilla.org/show_bug.cgi?id=750834)
    { w: 5,  v: function(d, b) { return prefix + "gcPreserveCode" + "();"; } },

    // Generate an LCOV trace (but throw away the returned string)
    { w: 1,  v: function(d, b) { return "void " + prefix + "getLcovInfo" + "();"; } },
    { w: 1,  v: function(d, b) { return "void " + prefix + "getLcovInfo" + "(" + fGlobal(d, b) + ");"; } },

    // JIT bailout
    { w: 5,  v: function(d, b) { return prefix + "bailout" + "();"; } },
    { w: 10, v: function(d, b) { return prefix + "bailAfter" + "(" + numberOfInstructions() + ");"; } },
  ];

  // Functions only in the SpiderMonkey shell
  // https://mxr.mozilla.org/mozilla-central/source/js/src/shell/js.cpp
  var shellOnlyTestingFunctions = [
    // ARM simulator settings
    // These throw when not in the ARM simulator.
    { w: 1,  v: function(d, b) { return tryCatch("(void" + prefix + "disableSingleStepProfiling" + "()" + ")"); } },
    { w: 1,  v: function(d, b) { return tryCatch("(" + prefix + "enableSingleStepProfiling" + "()" + ")"); } },

    // Force garbage collection with function relazification
    { w: 10, v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "();"; } },
    { w: 10, v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "('compartment');"; } },
    { w: 5,  v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "(" + fGlobal(d, b) + ");"; } },

    // [TestingFunctions.cpp, but debug-only and CRASHY]
    // After N js_malloc memory allocations, fail every following allocation
    { w: 1,  v: function(d, b) { return (typeof oomAfterAllocations == "function" && rnd(1000) === 0) ? prefix + "oomAfterAllocations" + "(" + (numberOfAllocs() - 1) + ");" : "void 0;"; } },
    // After N js_malloc memory allocations, fail one allocation
    { w: 1,  v: function(d, b) { return (typeof oomAtAllocation == "function" && rnd(100) === 0) ? prefix + "oomAtAllocation" + "(" + (numberOfAllocs() - 1) + ");" : "void 0;"; } },
    // Reset either of the above
    { w: 1,  v: function(d, b) { return (typeof resetOOMFailure == "function") ? "void " + prefix + "resetOOMFailure" + "(" + ");" : "void 0;"; } },

    // [TestingFunctions.cpp, but SLOW]
    // Make garbage collection extremely frequent
    { w: 1,  v: function(d, b) { return (rnd(100) === 0) ? (enableGCZeal()) : "void 0;"; } },

    { w: 10, v: callSetGCCallback },
  ];

  var testingFunctions = Random.weighted(browser ? sharedTestingFunctions : sharedTestingFunctions.concat(shellOnlyTestingFunctions));

  return { testingFunctions: testingFunctions, enableGCZeal: enableGCZeal };
}
<commit_msg>Initial support for the recomputeWrappers function.<commit_after>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

// Generate calls to SpiderMonkey "testing functions" for:
// * testing that they do not cause assertions/crashes
// * testing that they do not alter visible results (compare_jit with and without the call)

function fuzzTestingFunctionsCtor(browser, fGlobal, fObject)
{
  var prefix = browser ? "fuzzPriv." : "";

  function numberOfInstructions() { return Math.floor(Random.ludOneTo(10000)); }
  function numberOfAllocs() { return Math.floor(Random.ludOneTo(500)); }
  function gcSliceSize() { return Math.floor(Random.ludOneTo(0x100000000)); }
  function maybeCommaShrinking() { return rnd(5) ? "" : ", 'shrinking'"; }

  function enableGCZeal()
  {
    // As of m-c 405243:02aa9c921aed 2018-02-26
    // https://hg.mozilla.org/mozilla-central/file/02aa9c921aed/js/src/gc/GC.cpp#l1000
    max_level = 18;
    max_level++;  // rnd function starts from zero
    var level = final_level = rnd(max_level - 3); // 3 levels disabled below

    // Generate the second level.
    // ref https://hg.mozilla.org/mozilla-central/file/02aa9c921aed/js/src/gc/GC.cpp#l1001
    var level_two = rnd(max_level - 3); // 3 levels disabled below
    if (level_two >= 3) ++level_two; // gczeal 3 does not exist, so repurpose it
    if (level_two >= 5) ++level_two; // gczeal 5 does not exist, so repurpose it
    if (level_two >= 6) ++level_two; // gczeal 6 does not exist, so repurpose it

    if (level >= 3) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 3 does not exist, so repurpose it
    if (level >= 5) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 5 does not exist, so repurpose it
    if (level >= 6) final_level = '"' + (++level) + ";" + level_two + '"'; // gczeal 6 does not exist, so repurpose it

    var period = numberOfAllocs();
    return prefix + "gczeal" + "(" + final_level + ", " + period + ");";
  }

  function callSetGCCallback() {
    // https://dxr.mozilla.org/mozilla-central/source/js/src/shell/js.cpp - SetGCCallback
    var phases = Random.index(["both", "begin", "end"]);
    var actionAndOptions = rnd(2) ? 'action: "majorGC", depth: ' + rnd(17) : 'action: "minorGC"';
    var arg = "{ " + actionAndOptions + ", phases: \"" + phases + "\" }";
    return prefix + "setGCCallback(" + arg + ");";
  }

  function tryCatch(statement)
  {
    return "try { " + statement + " } catch(e) { }";
  }

  function setGcparam() {
    switch(rnd(2)) {
      case 0:  return _set("sliceTimeBudget", rnd(100));
      default: return _set("markStackLimit", rnd(2) ? (1 + rnd(30)) : 4294967295); // Artificially trigger delayed marking
    }

    function _set(name, value) {
      // try..catch because gcparam sets may throw, depending on GC state (see bug 973571)
      return tryCatch(prefix + "gcparam" + "('" + name + "', " + value + ");");
    }
  }

  // Functions shared between the SpiderMonkey shell and Firefox browser
  // https://mxr.mozilla.org/mozilla-central/source/js/src/builtin/TestingFunctions.cpp
  var sharedTestingFunctions = [
    // Force garbage collection (global or specific compartment)
    { w: 10, v: function(d, b) { return "void " + prefix + "gc" + "("                                            + ");"; } },
    { w: 10, v: function(d, b) { return "void " + prefix + "gc" + "(" + "'compartment'" + maybeCommaShrinking() + ");"; } },
    { w: 5,  v: function(d, b) { return "void " + prefix + "gc" + "(" + fGlobal(d, b)   + maybeCommaShrinking() + ");"; } },

    // Run a minor garbage collection on the nursery.
    { w: 20, v: function(d, b) { return prefix + "minorgc" + "(false);"; } },
    { w: 20, v: function(d, b) { return prefix + "minorgc" + "(true);"; } },

    // Start, continue, or abort incremental garbage collection.
    // startgc can throw: "Incremental GC already in progress"
    { w: 20, v: function(d, b) { return tryCatch(prefix + "startgc" + "(" + gcSliceSize() + maybeCommaShrinking() + ");"); } },
    { w: 20, v: function(d, b) { return prefix + "gcslice" + "(" + gcSliceSize() + ");"; } },
    { w: 10, v: function(d, b) { return prefix + "abortgc" + "(" + ");"; } },

    // Schedule the given objects to be marked in the next GC slice.
    { w: 10, v: function(d, b) { return prefix + "selectforgc" + "(" + fObject(d, b) + ");"; } },

    // Add a compartment to the next garbage collection.
    { w: 10, v: function(d, b) { return "void " + prefix + "schedulegc" + "(" + fGlobal(d, b) + ");"; } },

    // Schedule a GC for after N allocations.
    { w: 10, v: function(d, b) { return "void " + prefix + "schedulegc" + "(" + numberOfAllocs() + ");"; } },

    // Change a GC parameter.
    { w: 10, v: setGcparam },

    // Verify write barriers. This functions is effective in pairs.
    // The first call sets up the start barrier, the second call sets up the end barrier.
    // Nothing happens when there is only one call.
    { w: 10, v: function(d, b) { return prefix + "verifyprebarriers" + "();"; } },

    // hasChild(parent, child): Return true if |child| is a child of |parent|, as determined by a call to TraceChildren.
    // We ignore the return value because hasChild can be used to see which WeakMap entries have been GCed.
    { w: 1,  v: function(d, b) { return "void " + prefix + "hasChild(" + fObject(d, b) + ", " + fObject(d, b) + ");"; } },

    // Various validation functions (toggles)
    { w: 5,  v: function(d, b) { return prefix + "fullcompartmentchecks" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "fullcompartmentchecks" + "(true);"; } },
    { w: 5,  v: function(d, b) { return prefix + "setIonCheckGraphCoherency" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "setIonCheckGraphCoherency" + "(true);"; } },
    { w: 1,  v: function(d, b) { return prefix + "enableOsiPointRegisterChecks" + "();"; } },

    // Various validation functions (immediate)
    { w: 1,  v: function(d, b) { return prefix + "assertJitStackInvariants" + "();"; } },

    // Run-time equivalents to --baseline-eager, --baseline-warmup-threshold, --ion-eager, --ion-warmup-threshold
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('baseline.warmup.trigger', " + rnd(20) + ");"; } },
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('ion.warmup.trigger', " + rnd(40) + ");"; } },

    // Test the baseline compiler
    { w: 10,  v: function(d, b) { return prefix + "baselineCompile" + "();"; } },

    // Force inline cache.
    { w: 1,  v: function(d, b) { return prefix + "setJitCompilerOption" + "('ion.forceinlineCaches\', " + rnd(2) + ");"; } },

    // Run-time equivalents to --no-ion, --no-baseline
    // These can throw: "Can't turn off JITs with JIT code on the stack."
    { w: 1,  v: function(d, b) { return tryCatch(prefix + "setJitCompilerOption" + "('ion.enable', " + rnd(2) + ");"); } },
    { w: 1,  v: function(d, b) { return tryCatch(prefix + "setJitCompilerOption" + "('baseline.enable', " + rnd(2) + ");"); } },

    // Test the built-in profiler.
    { w: 1,  v: function(d, b) { return prefix + "enableGeckoProfiling" + "();"; } },
    { w: 1,  v: function(d, b) { return prefix + "enableGeckoProfilingWithSlowAssertions" + "();"; } },
    { w: 5,  v: function(d, b) { return prefix + "disableGeckoProfiling" + "();"; } },
    { w: 1,  v: function(d, b) { return "void " + prefix + "readGeckoProfilingStack" + "();"; } },

    // I'm not sure what this does in the shell.
    { w: 5,  v: function(d, b) { return prefix + "deterministicgc" + "(false);"; } },
    { w: 1,  v: function(d, b) { return prefix + "deterministicgc" + "(true);"; } },

    // Causes JIT code to always be preserved by GCs afterwards (see https://bugzilla.mozilla.org/show_bug.cgi?id=750834)
    { w: 5,  v: function(d, b) { return prefix + "gcPreserveCode" + "();"; } },

    // Generate an LCOV trace (but throw away the returned string)
    { w: 1,  v: function(d, b) { return "void " + prefix + "getLcovInfo" + "();"; } },
    { w: 1,  v: function(d, b) { return "void " + prefix + "getLcovInfo" + "(" + fGlobal(d, b) + ");"; } },

    // JIT bailout
    { w: 5,  v: function(d, b) { return prefix + "bailout" + "();"; } },
    { w: 10, v: function(d, b) { return prefix + "bailAfter" + "(" + numberOfInstructions() + ");"; } },
  ];

  // Functions only in the SpiderMonkey shell
  // https://mxr.mozilla.org/mozilla-central/source/js/src/shell/js.cpp
  var shellOnlyTestingFunctions = [
    // ARM simulator settings
    // These throw when not in the ARM simulator.
    { w: 1,  v: function(d, b) { return tryCatch("(void" + prefix + "disableSingleStepProfiling" + "()" + ")"); } },
    { w: 1,  v: function(d, b) { return tryCatch("(" + prefix + "enableSingleStepProfiling" + "()" + ")"); } },

    // Force garbage collection with function relazification
    { w: 10, v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "();"; } },
    { w: 10, v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "('compartment');"; } },
    { w: 5,  v: function(d, b) { return "void " + prefix + "relazifyFunctions" + "(" + fGlobal(d, b) + ");"; } },

    // Test recomputeWrappers - see bug 1492406
    { w: 10,  v: function(d, b) { return prefix + "recomputeWrappers" + "();"; } },
    // Also test recomputeWrappers calling newGlobal, see the bug

    // [TestingFunctions.cpp, but debug-only and CRASHY]
    // After N js_malloc memory allocations, fail every following allocation
    { w: 1,  v: function(d, b) { return (typeof oomAfterAllocations == "function" && rnd(1000) === 0) ? prefix + "oomAfterAllocations" + "(" + (numberOfAllocs() - 1) + ");" : "void 0;"; } },
    // After N js_malloc memory allocations, fail one allocation
    { w: 1,  v: function(d, b) { return (typeof oomAtAllocation == "function" && rnd(100) === 0) ? prefix + "oomAtAllocation" + "(" + (numberOfAllocs() - 1) + ");" : "void 0;"; } },
    // Reset either of the above
    { w: 1,  v: function(d, b) { return (typeof resetOOMFailure == "function") ? "void " + prefix + "resetOOMFailure" + "(" + ");" : "void 0;"; } },

    // [TestingFunctions.cpp, but SLOW]
    // Make garbage collection extremely frequent
    { w: 1,  v: function(d, b) { return (rnd(100) === 0) ? (enableGCZeal()) : "void 0;"; } },

    { w: 10, v: callSetGCCallback },
  ];

  var testingFunctions = Random.weighted(browser ? sharedTestingFunctions : sharedTestingFunctions.concat(shellOnlyTestingFunctions));

  return { testingFunctions: testingFunctions, enableGCZeal: enableGCZeal };
}
<|endoftext|>


<commit_before>import { BufferGeometry } from '../core/BufferGeometry';
import { Float32Attribute, Uint16Attribute } from '../core/BufferAttribute';

/**
 * @author Mugen87 / https://github.com/Mugen87
 *
 * Parametric Surfaces Geometry
 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 */

function ParametricBufferGeometry( func, slices, stacks ) {

	BufferGeometry.call( this );

	this.type = 'ParametricBufferGeometry';

	this.parameters = {
		func: func,
		slices: slices,
		stacks: stacks
	};

	// generate vertices and uvs

	var vertices = [];
	var uvs = [];

	var i, j, p;
	var u, v;

	var sliceCount = slices + 1;

	for ( i = 0; i <= stacks; i ++ ) {

		v = i / stacks;

		for ( j = 0; j <= slices; j ++ ) {

			u = j / slices;

			p = func( u, v );
			vertices.push( p.x, p.y, p.z );

			uvs.push( j / slices, i / stacks );

		}

	}

	// generate indices

	var indices = [];
	var a, b, c, d;

	for ( i = 0; i < stacks; i ++ ) {

		for ( j = 0; j < slices; j ++ ) {

			a = i * sliceCount + j;
			b = i * sliceCount + j + 1;
			c = ( i + 1 ) * sliceCount + j + 1;
			d = ( i + 1 ) * sliceCount + j;

			// faces one and two

			indices.push( a, b, d );
			indices.push( b, c, d );

		}

	}

	// build geometry

	this.setIndex( Uint16Attribute( indices, 1 ) );
	this.addAttribute( 'position', Float32Attribute( vertices, 3 ) );
	this.addAttribute( 'uv', Float32Attribute( uvs, 2 ) );

	// generate normals

	this.computeVertexNormals();

}

ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;

export { ParametricBufferGeometry };
<commit_msg>ParametricBufferGeometry: Simplify Code (#9703)<commit_after>import { BufferGeometry } from '../core/BufferGeometry';
import { Float32Attribute, Uint16Attribute } from '../core/BufferAttribute';

/**
 * @author Mugen87 / https://github.com/Mugen87
 *
 * Parametric Surfaces Geometry
 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 */

function ParametricBufferGeometry( func, slices, stacks ) {

	BufferGeometry.call( this );

	this.type = 'ParametricBufferGeometry';

	this.parameters = {
		func: func,
		slices: slices,
		stacks: stacks
	};

	// generate vertices and uvs

	var vertices = [];
	var uvs = [];

	var i, j, p;
	var u, v;

	var sliceCount = slices + 1;

	for ( i = 0; i <= stacks; i ++ ) {

		v = i / stacks;

		for ( j = 0; j <= slices; j ++ ) {

			u = j / slices;

			p = func( u, v );
			vertices.push( p.x, p.y, p.z );

			uvs.push( u, v );

		}

	}

	// generate indices

	var indices = [];
	var a, b, c, d;

	for ( i = 0; i < stacks; i ++ ) {

		for ( j = 0; j < slices; j ++ ) {

			a = i * sliceCount + j;
			b = i * sliceCount + j + 1;
			c = ( i + 1 ) * sliceCount + j + 1;
			d = ( i + 1 ) * sliceCount + j;

			// faces one and two

			indices.push( a, b, d );
			indices.push( b, c, d );

		}

	}

	// build geometry

	this.setIndex( Uint16Attribute( indices, 1 ) );
	this.addAttribute( 'position', Float32Attribute( vertices, 3 ) );
	this.addAttribute( 'uv', Float32Attribute( uvs, 2 ) );

	// generate normals

	this.computeVertexNormals();

}

ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;

export { ParametricBufferGeometry };
<|endoftext|>


<commit_before>import angular from 'angular';
import { requestAnimFrame, KeyCodes, ColumnsByPin } from 'utils/utils';
import { ColumnTotalWidth } from 'utils/math';

export class BodyController{

  constructor($scope, $timeout, $log, throttle){
    angular.extend(this, {
      $scope: $scope,
      options: $scope.options,
      selected: $scope.selected
    });

    this.rows = [];
    this._viewportRowsStart = 0;
    this._viewportRowsEnd = 0;
    this._maxVisibleRowCount = Math.ceil(this.options.cache.bodyHeight / this.options.rowHeight) + 1;

    if(this.options.scrollbarV){
      $scope.$watch('options.cache.offsetY', throttle(this.getRows.bind(this), 10));
    }

    this.columnsByPin = ColumnsByPin($scope.options.columns);
    this.groupColumn = this.getGroupColumn();
    if(this.groupColumn){
      this.rowsByGroup = this.getRowsByGroup();
      this.depthByRow = this.getDepthByRow();
    }

    $scope.$watch('options.columns', (newVal) => {
      this.columnsByPin = ColumnsByPin(newVal);
    }, true);

    $scope.$watchCollection('values', (newVal, oldVal) => {
      if(newVal) {
        this._rowsCount = $scope.values.length;
        if(this.options.scrollbarV){
          this.getRows();
        } else {
          this.rows.splice(0, this.rows.length);
          this.rows.push(...$scope.values);
        }
      }
    });
  }

  getGroupColumn(){
    var obj;
    this.$scope.options.columns.forEach((c) => {
      if(c.isTreeColumn){
        obj = c;
        return false;
      }
    });
    return obj;
  }

  getDepthByRow(){
    var obj = {};

    // todo
    // rowsByGroup = {
    //    "Apple" : [
    //      { name: "Apple IBS", parent: "Apple" }
    //    ],
    //    "Apple IBS": [
    //      { name: "Apple IBS South", parent: "Apple IBS" }
    //    ]
    //  }

    /* angular.forEach(this.rowsByGroup, (rows, key) => {
      if(rows.length){
        //var children = rows[0][this.groupColumn.relationProp];
      }

    }); */

    return obj;
  }

  getFirstLastIndexes(rowCount){
    var firstRowIndex = Math.max(Math.floor((this.$scope.options.cache.offsetY || 0) / this.options.rowHeight, 0), 0),
        endIndex = Math.min(firstRowIndex + this._maxVisibleRowCount, rowCount);

    return {
      first: firstRowIndex,
      last: endIndex
    };
  }

  getRowsByGroup(){
    var obj = {};

    // {
    //    "Acme" : [
    //      { name: "Acme Holdings", parent: "Acme" }
    //    ],
    //    "Acme Holdings": [
    //      { name: "Acme Ltd", parent: "Acme Holdings" }
    //    ]
    //  }
    this.$scope.values.forEach((val) => {
      var relVal = val[this.groupColumn.relationProp];
      if(relVal){
        if(obj[relVal]){
          obj[relVal].push(val);
        } else {
          obj[relVal] = [ val ];
        }
      }
    });

    return obj;
  }

  getRows(){
    var indexes = this.getFirstLastIndexes(this._rowsCount),
        temp = this.$scope.values;

    if(this.groupColumn){
      var idx = 0,
          rowIndex = indexes.first,
          last = indexes.last
      temp = [];

      while(rowIndex < last && last <= this._rowsCount){
        var row = this.$scope.values[rowIndex],
            relVal = row[this.groupColumn.relationProp],
            keyVal = row[this.groupColumn.prop],
            rows = this.rowsByGroup[keyVal],
            expanded = this.$scope.expanded[keyVal];

        if(!relVal){
          temp[idx++] = row;
        }

        if(rows && rows.length){
          if(expanded){
            rows.forEach((r) => {
              temp[idx++] = r;
            });
          } else {
            last = last + 1 >= this._rowsCount ? last : last + 1;
          }
        }

        rowIndex++;
      }

      // Have to splice out the list to force
      // the list to update if we collapse
      // and have less rows than expanded
      this.rows.splice(0, this.rows.length);
    }

    var rowIndex = indexes.first,
        idx = 0;

    while (rowIndex < indexes.last || (this.options.cache.bodyHeight < this._viewportHeight && rowIndex < this._rowsCount)) {
      var row = temp[rowIndex];
      if(row){
        row.$$index = rowIndex;
        this.rows[idx] = row;
      }
      idx++;
      this._viewportRowsEnd = rowIndex++;
    }
  }

  styles(){
    var styles = {
      width: this.options.cache.innerWidth + 'px'
    };

    if(!this.options.scrollbarV){
      styles.overflow = 'hidden';
    } else {
      styles.height = this.options.cache.bodyHeight + 'px';
    }

    return styles;
  }

  rowStyles(scope, row){
    if(this.options.scrollbarV){
      return {
        transform: `translate3d(0, ${row.$$index * scope.options.rowHeight}px, 0)`
      }
    }
  }

  rowClasses(scope, row){
    var styles = {
      'hover': !this.scrolling && this.hover === row,
      'selected': this.isSelected(row)
    };

    if(this.groupColumn){
      styles['dt-leaf'] = this.rowsByGroup[row[this.groupColumn.relationProp]];
      styles['dt-has-leafs'] = this.rowsByGroup[row[this.groupColumn.prop]];
    }

    return styles;
  }

  isSelected(row){
    var selected = false;

    if(this.options.selectable){
      if(this.options.multiSelect){
        selected = this.selected.indexOf(row) > -1;
      } else {
        selected = this.selected === row;
      }
    }

    return selected;
  }

  keyDown(ev, index, row){
    ev.preventDefault();

    if (ev.keyCode === KeyCodes.DOWNARROW) {
      var next = ev.target.nextElementSibling;
      if(next){
        next.focus();
      }
    } else if (ev.keyCode === KeyCodes.UPARROW) {
      var prev = ev.target.previousElementSibling;
      if(prev){
        prev.focus();
      }
    } else if(ev.keyCode === KeyCodes.ENTER){
      this.selectRow(index, row);
    }
  }

  rowClicked(event, index, row){
    event.preventDefault();
    this.selectRow(index, row);

    if(this.$scope.onSelect){
      this.$scope.onSelect({ row: row });
    }
  }

  selectRow(index, row){
    if(this.options.selectable){
      if(this.options.multiSelect){
        var isCtrlKeyDown = event.ctrlKey || event.metaKey,
            isShiftKeyDown = event.shiftKey;

        if(isShiftKeyDown){
          this.selectRowsBetween(index, row);
        } else {
          var idx = this.selected.indexOf(row);
          if(idx > -1){
            this.selected.splice(idx, 1);
          } else {
            this.selected.push(row);
          }
        }
        this.prevIndex = index;
      } else {
        this.selected = row;
      }
    }
  }

  selectRowsBetween(index){
    this.rows.forEach((row, i) => {
      if(i >= this.prevIndex && i <= index){
        var idx = this.selected.indexOf(row);
        if(idx === -1){
          this.selected.push(row);
        }
      }
    });
  }

  totalRowHeight(data){
    return data.length * this.options.rowHeight;
  }

  getValue(idx){
    return this.rows[idx];
  }

  stylesByGroup(scope, group){
    var styles = {
      width: ColumnTotalWidth(this.columnsByPin[group]) + 'px'
    };

    if(scope.values){
      styles.height = this.totalRowHeight(scope.values) + 'px';
    }

    return styles;
  }

  centerStyle(scope){
    return {
      width: scope.options.cache.innerWidth - ColumnTotalWidth(this.columnsByPin.left) + 'px'
    };
  }

  rowMouseEnter(row){
    if(!this.scrolling){
      this.hover = row;
    }
  }

  rowMouseLeave(row){
    this.hover = false;
  }

  getRowExpanded(scope, row){
    if(!this.groupColumn) return;
    return scope.expanded[row[this.groupColumn.prop]];
  }

  getRowHasChildren(row){
    if(!this.groupColumn) return;
    var children = this.rowsByGroup[row[this.groupColumn.prop]];
    return children !== undefined || (children && !children.length);
  }

  onTreeToggle(scope, row, cell){
    var val  = row[this.groupColumn.prop];
    scope.expanded[val] = !scope.expanded[val];
    this.getRows();

    scope.onTreeToggle({
      row: row,
      cell: cell
    });
  }
}

export function BodyDirective($timeout){
  return {
    restrict: 'E',
    controller: 'BodyController',
    controllerAs: 'body',
    scope: {
      values: '=',
      options: '=',
      selected: '=',
      expanded: '=',
      onTreeToggle: '&'
    },
    template: `

            <dt-row ng-repeat="r in body.rows track by $index"
                    value="body.getValue($index)"
                    tabindex="{{$index}}"
                    ng-keydown="body.keyDown($event, $index, r)"
                    ng-click="body.rowClicked($event, $index, r)"
                    ng-class="body.rowClasses(this, r)"
                    ng-mouseenter="body.rowMouseEnter(r)"
                    ng-mouseleave="body.rowMouseLeave(r)"
                    ng-style="body.rowStyles(this, r)"
                    columns="body.columnsByPin.left"
                    has-children="body.getRowHasChildren(r)"
                    expanded="body.getRowExpanded(this, r)"
                    on-tree-toggle="body.onTreeToggle(this, row, cell)">

              <dt-row ng-repeat="r in body.rows track by $index"
                      value="body.getValue($index)"
                      tabindex="{{$index}}"
                      ng-keydown="body.keyDown($event, $index, r)"
                      ng-click="body.rowClicked($event, $index, r)"
                      ng-mouseenter="body.rowMouseEnter(r)"
                      on-tree-toggle="body.onTreeToggle(this, row, cell)"
                      ng-mouseleave="body.rowMouseLeave(r)"
                      ng-class="body.rowClasses(this, r)"
                      columns="body.columnsByPin.center"
                      has-children="body.getRowHasChildren(r)"
                      expanded="body.getRowExpanded(this, r)"
                      ng-style="body.rowStyles(this, r)">

            <dt-row ng-repeat="r in body.rows track by $index"
                    value="body.getValue($index)"
                    tabindex="{{$index}}"
                    ng-keydown="body.keyDown($event, $index, r)"
                    ng-click="body.rowClicked($event, $index, r)"
                    ng-mouseenter="body.rowMouseEnter(r)"
                    on-tree-toggle="body.onTreeToggle(this, cell)"
                    ng-class="body.rowClasses(this, r)"
                    ng-mouseleave="body.rowMouseLeave(r)"
                    columns="body.columnsByPin.right"
                    children="body.getRowHasChildren(r)"
                    expanded="body.getRowExpanded(this, r)"
                    ng-style="body.rowStyles(this, r)">

`,
    replace:true,
    link: function($scope, $elm, $attrs, ctrl){
      var ticking = false,
          lastScrollY = 0,
          lastScrollX = 0,
          timer;

      function update(){
        $timeout(() => {
          $scope.options.cache.offsetY = lastScrollY;
          $scope.options.cache.offsetX = lastScrollX;
        });

        $timeout.cancel(timer)
        timer = $timeout(() => {
          ctrl.scrolling = false;
        }, 10);

        ticking = false;
      };

      function requestTick() {
        if(!ticking) {
          requestAnimFrame(update);
          ticking = true;
        }
      };

      $elm.on('scroll', function(ev) {
        ctrl.scrolling = true;
        lastScrollY = this.scrollTop;
        requestTick();
      });

      angular.element($elm[0].querySelector('.dt-row-center'))
        .on('scroll', function() {
          lastScrollX = this.scrollLeft;
          requestTick();
        });
    }
  };
};
<commit_msg>Create index on the tree column. Assign depths to rows<commit_after>import angular from 'angular';
import { requestAnimFrame, KeyCodes, ColumnsByPin } from 'utils/utils';
import { ColumnTotalWidth } from 'utils/math';

export class BodyController{

  constructor($scope, $timeout, $log, throttle){
    angular.extend(this, {
      $scope: $scope,
      options: $scope.options,
      selected: $scope.selected
    });

    this.rows = [];
    this._viewportRowsStart = 0;
    this._viewportRowsEnd = 0;
    this._maxVisibleRowCount = Math.ceil(this.options.cache.bodyHeight / this.options.rowHeight) + 1;

    if(this.options.scrollbarV){
      $scope.$watch('options.cache.offsetY', throttle(this.getRows.bind(this), 10));
    }

    this.columnsByPin = ColumnsByPin($scope.options.columns);
    this.groupColumn = this.getGroupColumn();
    if(this.groupColumn){
      this.rowsByGroup = this.getRowsByGroup();
      this.depthByRow = this.getDepthByRow();
    }

    $scope.$watch('options.columns', (newVal) => {
      this.columnsByPin = ColumnsByPin(newVal);
    }, true);

    $scope.$watchCollection('values', (newVal, oldVal) => {
      if(newVal) {
        this.index();
        this._rowsCount = $scope.values.length;
        if(this.options.scrollbarV){
          this.getRows();
        } else {
          this.rows.splice(0, this.rows.length);
          this.rows.push(...$scope.values);
        }
      }
    });
  }

  getGroupColumn(){
    var obj;
    this.$scope.options.columns.forEach((c) => {
      if(c.isTreeColumn){
        obj = c;
        return false;
      }
    });
    return obj;
  }

  getDepthByRow(){
    var obj = {};

    // todo
    // rowsByGroup = {
    //    "Apple" : [
    //      { name: "Apple IBS", parent: "Apple" }
    //    ],
    //    "Apple IBS": [
    //      { name: "Apple IBS South", parent: "Apple IBS" }
    //    ]
    //  }

    /* angular.forEach(this.rowsByGroup, (rows, key) => {
      if(rows.length){
        //var children = rows[0][this.groupColumn.relationProp];
      }

    }); */

    return obj;
  }

  getFirstLastIndexes(rowCount){
    var firstRowIndex = Math.max(Math.floor((this.$scope.options.cache.offsetY || 0) / this.options.rowHeight, 0), 0),
        endIndex = Math.min(firstRowIndex + this._maxVisibleRowCount, rowCount);

    return {
      first: firstRowIndex,
      last: endIndex
    };
  }

  getRowsByGroup(){
    var obj = {};

    // {
    //    "Acme" : [
    //      { name: "Acme Holdings", parent: "Acme" }
    //    ],
    //    "Acme Holdings": [
    //      { name: "Acme Ltd", parent: "Acme Holdings" }
    //    ]
    //  }
    this.$scope.values.forEach((val) => {
      var relVal = val[this.groupColumn.relationProp];
      if(relVal){
        if(obj[relVal]){
          obj[relVal].push(val);
        } else {
          obj[relVal] = [ val ];
        }
      }
    });

    return obj;
  }

  /**
   * Creates an index on the treeColumn if there is one
   * and assigns depths to all rows
   */
  index(){
    var treeColumn = this.getGroupColumn();
    if (!treeColumn){
      return;
    } else {
      treeColumn = treeColumn.prop;
    }
    var parent;
    this.$scope.index = {};

    this.$scope.values.forEach((obj) => {
      this.$scope.index[obj[treeColumn]] = obj;
      if (obj.parent === undefined){
        obj._depth = 0;
      } else {
        parent = this.$scope.index[obj.parent];
        obj._depth = parent._depth + 1;
        if (parent._children){
          parent._children.push(obj[treeColumn]);
        } else {
          parent._children = [obj[treeColumn]];
        }
      }
    })
  }

  getRows(){
    var indexes = this.getFirstLastIndexes(this._rowsCount),
        temp = this.$scope.values;

    if(this.groupColumn){
      var idx = 0,
          rowIndex = indexes.first,
          last = indexes.last
      temp = [];

      while(rowIndex < last && last <= this._rowsCount){
        var row = this.$scope.values[rowIndex],
            relVal = row[this.groupColumn.relationProp],
            keyVal = row[this.groupColumn.prop],
            rows = this.rowsByGroup[keyVal],
            expanded = this.$scope.expanded[keyVal];

        if(!relVal){
          temp[idx++] = row;
        }

        if(rows && rows.length){
          if(expanded){
            rows.forEach((r) => {
              temp[idx++] = r;
            });
          } else {
            last = last + 1 >= this._rowsCount ? last : last + 1;
          }
        }

        rowIndex++;
      }

      // Have to splice out the list to force
      // the list to update if we collapse
      // and have less rows than expanded
      this.rows.splice(0, this.rows.length);
    }

    var rowIndex = indexes.first,
        idx = 0;

    while (rowIndex < indexes.last || (this.options.cache.bodyHeight < this._viewportHeight && rowIndex < this._rowsCount)) {
      var row = temp[rowIndex];
      if(row){
        row.$$index = rowIndex;
        this.rows[idx] = row;
      }
      idx++;
      this._viewportRowsEnd = rowIndex++;
    }
  }

  styles(){
    var styles = {
      width: this.options.cache.innerWidth + 'px'
    };

    if(!this.options.scrollbarV){
      styles.overflow = 'hidden';
    } else {
      styles.height = this.options.cache.bodyHeight + 'px';
    }

    return styles;
  }

  rowStyles(scope, row){
    if(this.options.scrollbarV){
      return {
        transform: `translate3d(0, ${row.$$index * scope.options.rowHeight}px, 0)`
      }
    }
  }

  rowClasses(scope, row){
    var styles = {
      'hover': !this.scrolling && this.hover === row,
      'selected': this.isSelected(row)
    };

    if(this.groupColumn){
      styles['dt-leaf'] = this.rowsByGroup[row[this.groupColumn.relationProp]];
      styles['dt-has-leafs'] = this.rowsByGroup[row[this.groupColumn.prop]];
      styles['dt-tree-depth-' + row._depth] = true;
    }

    return styles;
  }

  isSelected(row){
    var selected = false;

    if(this.options.selectable){
      if(this.options.multiSelect){
        selected = this.selected.indexOf(row) > -1;
      } else {
        selected = this.selected === row;
      }
    }

    return selected;
  }

  keyDown(ev, index, row){
    ev.preventDefault();

    if (ev.keyCode === KeyCodes.DOWNARROW) {
      var next = ev.target.nextElementSibling;
      if(next){
        next.focus();
      }
    } else if (ev.keyCode === KeyCodes.UPARROW) {
      var prev = ev.target.previousElementSibling;
      if(prev){
        prev.focus();
      }
    } else if(ev.keyCode === KeyCodes.ENTER){
      this.selectRow(index, row);
    }
  }

  rowClicked(event, index, row){
    event.preventDefault();
    this.selectRow(index, row);

    if(this.$scope.onSelect){
      this.$scope.onSelect({ row: row });
    }
  }

  selectRow(index, row){
    if(this.options.selectable){
      if(this.options.multiSelect){
        var isCtrlKeyDown = event.ctrlKey || event.metaKey,
            isShiftKeyDown = event.shiftKey;

        if(isShiftKeyDown){
          this.selectRowsBetween(index, row);
        } else {
          var idx = this.selected.indexOf(row);
          if(idx > -1){
            this.selected.splice(idx, 1);
          } else {
            this.selected.push(row);
          }
        }
        this.prevIndex = index;
      } else {
        this.selected = row;
      }
    }
  }

  selectRowsBetween(index){
    this.rows.forEach((row, i) => {
      if(i >= this.prevIndex && i <= index){
        var idx = this.selected.indexOf(row);
        if(idx === -1){
          this.selected.push(row);
        }
      }
    });
  }

  totalRowHeight(data){
    return data.length * this.options.rowHeight;
  }

  getValue(idx){
    return this.rows[idx];
  }

  stylesByGroup(scope, group){
    var styles = {
      width: ColumnTotalWidth(this.columnsByPin[group]) + 'px'
    };

    if(scope.values){
      styles.height = this.totalRowHeight(scope.values) + 'px';
    }

    return styles;
  }

  centerStyle(scope){
    return {
      width: scope.options.cache.innerWidth - ColumnTotalWidth(this.columnsByPin.left) + 'px'
    };
  }

  rowMouseEnter(row){
    if(!this.scrolling){
      this.hover = row;
    }
  }

  rowMouseLeave(row){
    this.hover = false;
  }

  getRowExpanded(scope, row){
    if(!this.groupColumn) return;
    return scope.expanded[row[this.groupColumn.prop]];
  }

  getRowHasChildren(row){
    if(!this.groupColumn) return;
    var children = this.rowsByGroup[row[this.groupColumn.prop]];
    return children !== undefined || (children && !children.length);
  }

  onTreeToggle(scope, row, cell){
    var val  = row[this.groupColumn.prop];
    scope.expanded[val] = !scope.expanded[val];
    this.getRows();

    scope.onTreeToggle({
      row: row,
      cell: cell
    });
  }
}

export function BodyDirective($timeout){
  return {
    restrict: 'E',
    controller: 'BodyController',
    controllerAs: 'body',
    scope: {
      values: '=',
      options: '=',
      selected: '=',
      expanded: '=',
      onTreeToggle: '&'
    },
    template: `

            <dt-row ng-repeat="r in body.rows track by $index"
                    value="body.getValue($index)"
                    tabindex="{{$index}}"
                    ng-keydown="body.keyDown($event, $index, r)"
                    ng-click="body.rowClicked($event, $index, r)"
                    ng-class="body.rowClasses(this, r)"
                    ng-mouseenter="body.rowMouseEnter(r)"
                    ng-mouseleave="body.rowMouseLeave(r)"
                    ng-style="body.rowStyles(this, r)"
                    columns="body.columnsByPin.left"
                    has-children="body.getRowHasChildren(r)"
                    expanded="body.getRowExpanded(this, r)"
                    on-tree-toggle="body.onTreeToggle(this, row, cell)">

              <dt-row ng-repeat="r in body.rows track by $index"
                      value="body.getValue($index)"
                      tabindex="{{$index}}"
                      ng-keydown="body.keyDown($event, $index, r)"
                      ng-click="body.rowClicked($event, $index, r)"
                      ng-mouseenter="body.rowMouseEnter(r)"
                      on-tree-toggle="body.onTreeToggle(this, row, cell)"
                      ng-mouseleave="body.rowMouseLeave(r)"
                      ng-class="body.rowClasses(this, r)"
                      columns="body.columnsByPin.center"
                      has-children="body.getRowHasChildren(r)"
                      expanded="body.getRowExpanded(this, r)"
                      ng-style="body.rowStyles(this, r)">

            <dt-row ng-repeat="r in body.rows track by $index"
                    value="body.getValue($index)"
                    tabindex="{{$index}}"
                    ng-keydown="body.keyDown($event, $index, r)"
                    ng-click="body.rowClicked($event, $index, r)"
                    ng-mouseenter="body.rowMouseEnter(r)"
                    on-tree-toggle="body.onTreeToggle(this, cell)"
                    ng-class="body.rowClasses(this, r)"
                    ng-mouseleave="body.rowMouseLeave(r)"
                    columns="body.columnsByPin.right"
                    children="body.getRowHasChildren(r)"
                    expanded="body.getRowExpanded(this, r)"
                    ng-style="body.rowStyles(this, r)">

`,
    replace:true,
    link: function($scope, $elm, $attrs, ctrl){
      var ticking = false,
          lastScrollY = 0,
          lastScrollX = 0,
          timer;

      function update(){
        $timeout(() => {
          $scope.options.cache.offsetY = lastScrollY;
          $scope.options.cache.offsetX = lastScrollX;
        });

        $timeout.cancel(timer)
        timer = $timeout(() => {
          ctrl.scrolling = false;
        }, 10);

        ticking = false;
      };

      function requestTick() {
        if(!ticking) {
          requestAnimFrame(update);
          ticking = true;
        }
      };

      $elm.on('scroll', function(ev) {
        ctrl.scrolling = true;
        lastScrollY = this.scrollTop;
        requestTick();
      });

      angular.element($elm[0].querySelector('.dt-row-center'))
        .on('scroll', function() {
          lastScrollX = this.scrollLeft;
          requestTick();
        });
    }
  };
};
<|endoftext|>