<commit_before>const Tree = require('merkle-radix-tree')
const Graph = require('ipld-graph-builder')
const chunk = require('chunk')
const Message = require('primea-message')
const Kernel = require('./kernel.js')
const Scheduler = require('./scheduler.js')
const DFSchecker = require('./dfsChecker.js')

module.exports = class Hypervisor {
  /**
   * The Hypervisor manages the container instances by instantiating them and
   * destorying them when possible. It also facilitates localating Containers
   * @param {Graph} dag an instance of [ipfs.dag](https://github.com/ipfs/interface-ipfs-core/tree/master/API/dag#dag-api)
   * @param {object} state - the starting state
   */
  constructor (dag, state = {'/': Tree.emptyTreeState}) {
    this.graph = new Graph(dag)
    this.tree = new Tree({
      graph: this.graph,
      root: state
    })
    this.scheduler = new Scheduler()
    this.state = state
    this._containerTypes = {}
    this._nodesToCheck = new Set()

    this.ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr'
    this.MAX_DATA_BYTES = 65533
  }

  /**
   * add a potaintail node in the state graph to check for garbage collection
   * @param {string} id
   */
  addNodeToCheck (id) {
    this._nodesToCheck.add(id)
  }

  /**
   * given a port, this finds the corridsponeding endpoint port of the channel
   * @param {object} port
   * @returns {Promise}
   */
  async getDestPort (port) {
    if (port.destPort) {
      return port.destPort
    } else {
      const containerState = await this.tree.get(port.destId)
      return this.graph.get(containerState, `ports/${port.destName}`)
    }
  }

  async send (port, message) {
    if (port.destId) {
      const id = port.destId
      const instance = await this.getInstance(id)
      instance.queue(port.destName, message)
    } else {
      // port is unbound
      port.destPort.messages.push(message)
    }
  }

  // loads an instance of a container from the state
  async _loadInstance (id, state) {
    if (!state) {
      state = await this.tree.get(id)
    }
    const container = this._containerTypes[state.type]
    let code

    // checks if the code stored in the state is an array and that the elements
    // are merkle link
    if (state.code && state.code[0]['/']) {
      await this.graph.tree(state.code, 1)
      code = state.code.map(a => a['/']).reduce((a, b) => a + b)
    } else {
      code = state.code
    }

    // create a new kernel instance
    const kernel = new Kernel({
      hypervisor: this,
      state: state,
      code: code,
      container: container,
      id: id
    })

    // save the newly created instance
    this.scheduler.update(kernel)
    return kernel
  }

  // get a hash from a POJO
  _getHashFromObj (obj) {
    return this.graph.flush(obj).then(obj => obj['/'])
  }

  /**
   * gets an existsing container instances
   * @param {string} id - the containers ID
   * @returns {Promise}
   */
  async getInstance (id) {
    let instance = this.scheduler.getInstance(id)
    if (instance) {
      return instance
    } else {
      const resolve = this.scheduler.lock(id)
      const instance = await this._loadInstance(id)
      await instance.startup()
      resolve(instance)
      return instance
    }
  }

  /**
   * creates an new container instances and save it in the state
   * @param {string} type - the type of container to create
   * @param {*} code
   * @param {array} entryPorts
   * @param {object} id
   * @param {object} id.nonce
   * @param {object} id.parent
   * @returns {Promise}
   */
  async createInstance (type, message = new Message(), id = {nonce: 0, parent: null}) {
    const idHash = await this._getHashFromObj(id)
    const state = {
      nonce: [0],
      ports: {},
      type: type
    }

    if (message.data.length) {
      state.code = message.data
    }

    // create the container instance
    const instance = await this._loadInstance(idHash, state)

    // send the intialization message
    await instance.create(message)

    if (Object.keys(instance.ports.ports).length || instance.id === this.ROOT_ID) {
      if (state.code && state.code.length > this.MAX_DATA_BYTES) {
        state.code = chunk(state.code, this.MAX_DATA_BYTES).map(chk => {
          return {
            '/': chk
          }
        })
      }
      // save the container in the state
      await this.tree.set(idHash, state)
    } else {
      this.scheduler.done(idHash)
    }

    return instance
  }

  createChannel () {
    const port1 = {
      messages: []
    }

    const port2 = {
      messages: [],
      destPort: port1
    }

    port1.destPort = port2
    return [port1, port2]
  }

  /**
   * creates a state root starting from a given container and a given number of
   * ticks
   * @param {Number} ticks the number of ticks at which to create the state root
   * @returns {Promise}
   */
  async createStateRoot (ticks) {
    await this.scheduler.wait(ticks)

    const unlinked = await DFSchecker(this.tree, this._nodesToCheck, (id) => {
      return this.ROOT_ID === id
    })
    for (const id of unlinked) {
      await this.tree.delete(id)
    }
    return this.graph.flush(this.state)
  }

  /**
   * regirsters a container with the hypervisor
   * @param {Class} Constructor - a Class for instantiating the container
   * @param {*} args - any args that the contructor takes
   * @param {interger} typeId - the container's type identification ID
   */
  registerContainer (Constructor, args, typeId = Constructor.typeId) {
    this._containerTypes[typeId] = {
      Constructor: Constructor,
      args: args
    }
  }
}
<commit_msg>cleanup<commit_after>const Tree = require('merkle-radix-tree')
const Graph = require('ipld-graph-builder')
const chunk = require('chunk')
const Message = require('primea-message')
const Kernel = require('./kernel.js')
const Scheduler = require('./scheduler.js')
const DFSchecker = require('./dfsChecker.js')

module.exports = class Hypervisor {
  /**
   * The Hypervisor manages the container instances by instantiating them and
   * destorying them when possible. It also facilitates localating Containers
   * @param {Graph} dag an instance of [ipfs.dag](https://github.com/ipfs/interface-ipfs-core/tree/master/API/dag#dag-api)
   * @param {object} state - the starting state
   */
  constructor (dag, state = {'/': Tree.emptyTreeState}) {
    this.graph = new Graph(dag)
    this.tree = new Tree({
      graph: this.graph,
      root: state
    })
    this.scheduler = new Scheduler()
    this.state = state
    this._containerTypes = {}
    this._nodesToCheck = new Set()

    this.ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr'
    this.MAX_DATA_BYTES = 65533
  }

  /**
   * add a potaintail node in the state graph to check for garbage collection
   * @param {string} id
   */
  addNodeToCheck (id) {
    this._nodesToCheck.add(id)
  }

  /**
   * given a port, this finds the corridsponeding endpoint port of the channel
   * @param {object} port
   * @returns {Promise}
   */
  async getDestPort (port) {
    if (port.destPort) {
      return port.destPort
    } else {
      const containerState = await this.tree.get(port.destId)
      return this.graph.get(containerState, `ports/${port.destName}`)
    }
  }

  async send (port, message) {
    const id = port.destId
    if (id) {
      const instance = await this.getInstance(id)
      instance.queue(port.destName, message)
    } else {
      // port is unbound
      port.destPort.messages.push(message)
    }
  }

  // loads an instance of a container from the state
  async _loadInstance (id, state) {
    if (!state) {
      state = await this.tree.get(id)
    }
    const container = this._containerTypes[state.type]
    let code

    // checks if the code stored in the state is an array and that the elements
    // are merkle link
    if (state.code && state.code[0]['/']) {
      await this.graph.tree(state.code, 1)
      code = state.code.map(a => a['/']).reduce((a, b) => a + b)
    } else {
      code = state.code
    }

    // create a new kernel instance
    const kernel = new Kernel({
      hypervisor: this,
      state: state,
      code: code,
      container: container,
      id: id
    })

    // save the newly created instance
    this.scheduler.update(kernel)
    return kernel
  }

  // get a hash from a POJO
  _getHashFromObj (obj) {
    return this.graph.flush(obj).then(obj => obj['/'])
  }

  /**
   * gets an existsing container instances
   * @param {string} id - the containers ID
   * @returns {Promise}
   */
  async getInstance (id) {
    let instance = this.scheduler.getInstance(id)
    if (instance) {
      return instance
    } else {
      const resolve = this.scheduler.lock(id)
      const instance = await this._loadInstance(id)
      await instance.startup()
      resolve(instance)
      return instance
    }
  }

  /**
   * creates an new container instances and save it in the state
   * @param {string} type - the type of container to create
   * @param {*} code
   * @param {array} entryPorts
   * @param {object} id
   * @param {object} id.nonce
   * @param {object} id.parent
   * @returns {Promise}
   */
  async createInstance (type, message = new Message(), id = {nonce: 0, parent: null}) {
    const idHash = await this._getHashFromObj(id)
    const state = {
      nonce: [0],
      ports: {},
      type: type
    }

    if (message.data.length) {
      state.code = message.data
    }

    // create the container instance
    const instance = await this._loadInstance(idHash, state)

    // send the intialization message
    await instance.create(message)

    if (Object.keys(instance.ports.ports).length || instance.id === this.ROOT_ID) {
      if (state.code && state.code.length > this.MAX_DATA_BYTES) {
        state.code = chunk(state.code, this.MAX_DATA_BYTES).map(chk => {
          return {
            '/': chk
          }
        })
      }
      // save the container in the state
      await this.tree.set(idHash, state)
    } else {
      this.scheduler.done(idHash)
    }

    return instance
  }

  createChannel () {
    const port1 = {
      messages: []
    }

    const port2 = {
      messages: [],
      destPort: port1
    }

    port1.destPort = port2
    return [port1, port2]
  }

  /**
   * creates a state root starting from a given container and a given number of
   * ticks
   * @param {Number} ticks the number of ticks at which to create the state root
   * @returns {Promise}
   */
  async createStateRoot (ticks) {
    await this.scheduler.wait(ticks)

    const unlinked = await DFSchecker(this.tree, this._nodesToCheck, (id) => {
      return this.ROOT_ID === id
    })
    for (const id of unlinked) {
      await this.tree.delete(id)
    }
    return this.graph.flush(this.state)
  }

  /**
   * regirsters a container with the hypervisor
   * @param {Class} Constructor - a Class for instantiating the container
   * @param {*} args - any args that the contructor takes
   * @param {interger} typeId - the container's type identification ID
   */
  registerContainer (Constructor, args, typeId = Constructor.typeId) {
    this._containerTypes[typeId] = {
      Constructor: Constructor,
      args: args
    }
  }
}
<|endoftext|>


<commit_before>var Service, Characteristic;
const http_request = require('http').request;
const https_request = require('https').request;

const CELSIUS_UNITS = 'C',
      FAHRENHEIT_UNITS = 'F';
const DEF_MIN_TEMPERATURE = -100,
      DEF_MAX_TEMPERATURE = 130,
      DEF_UNITS = CELSIUS_UNITS,
      DEF_TIMEOUT = 5000,
      DEF_INTERVAL = 120000; //120s

module.exports = function (homebridge) {
   Service = homebridge.hap.Service;
   Characteristic = homebridge.hap.Characteristic;
   homebridge.registerAccessory("homebridge-http-temperature", "HttpTemperature", HttpTemperature);
}

function HttpTemperature(log, config) {
   this.log = log;

   this.name = config.name;
   this.url = config.url;
   const protocol = config.http_protocol ? config.protocol.toLowerCase() :
      (this.url.indexOf('http://') !== -1 ? 'http' : 'https');
   this.request = protocol === 'http' ? http_request : https_request;
   this.request_opts = {
      method: config.http_method || "GET",
      timeout: config.timeout || DEF_TIMEOUT,
   };
   this.manufacturer = config["manufacturer"] || "@metbosch";
   this.model = config["model"] || "Model not available";
   this.serial = config["serial"] || "Non-defined serial";
   this.fieldName = ( config["field_name"] != null ? config["field_name"] : "temperature" );
   this.minTemperature = config["min_temp"] || DEF_MIN_TEMPERATURE;
   this.maxTemperature = config["max_temp"] || DEF_MAX_TEMPERATURE;
   this.units = config["units"] || DEF_UNITS;
   this.update_interval = Number( config["update_interval"] || DEF_INTERVAL );
   this.debug = config["debug"] || false;

   //Check auth option
   if (config.auth && config.auth.user !== undefined && config.auth.pass !== undefined) {
      this.request_opts.auth = config.auth.user + ':' + config.auth.pass;
   } else if (config.auth) {
      this.log('Ignoring invalid auth options. "user" and "pass" must be provided');
   }

   //Check headers option
   if (config.http_headers) {
      this.request_opts.headers = config.http_headers;
   }

   //Check if units field is valid
   this.units = this.units.toUpperCase()
   if (this.units !== CELSIUS_UNITS && this.units !== FAHRENHEIT_UNITS) {
      this.log('Bad temperature units : "' + this.units + '" (assuming Celsius)');
      this.units = CELSIUS_UNITS;
   }

   // Internal variables
   this.last_value = null;
   this.waiting_response = false;
}

HttpTemperature.prototype = {

   logDebug: function (str) {
      if (this.debug) {
         this.log(str)
      }
   },

   updateState: function () {
      //Ensure previous call finished
      if (this.waiting_response) {
         this.logDebug('Avoid updateState as previous response does not arrived yet');
         return;
      }
      this.waiting_response = true;
      this.last_value = new Promise((resolve, reject) => {
         this.logDebug('Requesting temperature on "' + this.url);
         this.request(this.url, this.request_opts, (res) => {
            let body = '';
            res.on('data', (chunk) => {
               body += chunk;
            });
            res.on('end', () => {
               let value = null;
               try {
                  const value_str = this.fieldName === '' ? body : this.getFromObject(JSON.parse(body), this.fieldName, '');
                  value = Number(value_str);
                  if (value_str === '' || isNaN(value)) {
                     throw new Error('Received value is not a number: "' + value_str + '" ("' + body.substring(0, 100) + '")');
                  } else if (value < this.minTemperature || value > this.maxTemperature) {
                     var msg = 'Received value is out of bounds: "' + value + '". min=' + this.minTemperature +
                               ', max= ' + this.maxTemperature;
                     throw new Error(msg);
                  }
                  this.logDebug('HTTP successful response: ' + value);
                  if (this.units === FAHRENHEIT_UNITS) {
                     value = (value - 32)/1.8;
                     this.logDebug('Converted Fahrenheit temperature to celsius: ' + value);
                  }
               } catch (error) {
                  reject(error);
               }
               resolve(value);
            });
         }).on('error', reject).end();
      });
      this.last_value.then((value) => {
         this.temperatureService
            .getCharacteristic(Characteristic.CurrentTemperature).updateValue(value);
         this.temperatureService
            .getCharacteristic(Characteristic.StatusFault).updateValue(Characteristic.StatusFault.NO_FAULT);
         this.waiting_response = false;
      }).catch((error) => {
         this.temperatureService
            .getCharacteristic(Characteristic.StatusFault).updateValue(Characteristic.StatusFault.GENERAL_FAULT);
         this.log('Error updating state: ' + error.message);
         this.waiting_response = false;
      });
   },

   getState: function (callback) {
      this.logDebug('Call to getState: waiting_response is "' + this.waiting_response + '"' );
      this.updateState(); //This sets the promise in last_value
      this.last_value.then((value) => {
         callback(null, value);
      }).catch((error) => {
         callback(error, null);
      });
   },

   getServices: function () {
      this.informationService = new Service.AccessoryInformation();
      this.informationService
      .setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
      .setCharacteristic(Characteristic.Model, this.model)
      .setCharacteristic(Characteristic.SerialNumber, this.serial);

      this.temperatureService = new Service.TemperatureSensor(this.name);
      this.temperatureService
         .getCharacteristic(Characteristic.CurrentTemperature)
         .on('get', this.getState.bind(this))
         .setProps({
             minValue: this.minTemperature,
             maxValue: this.maxTemperature
         });

      if (this.update_interval > 0) {
         this.timer = setInterval(this.updateState.bind(this), this.update_interval);
      }

      return [this.informationService, this.temperatureService];
   },

   getFromObject: function (obj, path, def) {
      if (!path) return obj;

      const fullPath = path
        .replace(/\[/g, '.')
        .replace(/]/g, '')
        .split('.')
        .filter(Boolean);

      // Iterate all path elements to get the leaf, or untill the key is not found in the JSON
      return fullPath.every(everyFunc) ? obj : def;

      function everyFunc (step) {
        // Dynamically update the obj variable for the next call
        return !(step && (obj = obj[step]) === undefined);
      }
   }
};
<commit_msg>Remove unwanted characters from the input<commit_after>var Service, Characteristic;
const http_request = require('http').request;
const https_request = require('https').request;

const CELSIUS_UNITS = 'C',
      FAHRENHEIT_UNITS = 'F';
const DEF_MIN_TEMPERATURE = -100,
      DEF_MAX_TEMPERATURE = 130,
      DEF_UNITS = CELSIUS_UNITS,
      DEF_TIMEOUT = 5000,
      DEF_INTERVAL = 120000; //120s

module.exports = function (homebridge) {
   Service = homebridge.hap.Service;
   Characteristic = homebridge.hap.Characteristic;
   homebridge.registerAccessory("homebridge-http-temperature", "HttpTemperature", HttpTemperature);
}

function HttpTemperature(log, config) {
   this.log = log;

   this.name = config.name;
   this.url = config.url;
   const protocol = config.http_protocol ? config.protocol.toLowerCase() :
      (this.url.indexOf('http://') !== -1 ? 'http' : 'https');
   this.request = protocol === 'http' ? http_request : https_request;
   this.request_opts = {
      method: config.http_method || "GET",
      timeout: config.timeout || DEF_TIMEOUT,
   };
   this.manufacturer = config["manufacturer"] || "@metbosch";
   this.model = config["model"] || "Model not available";
   this.serial = config["serial"] || "Non-defined serial";
   this.fieldName = ( config["field_name"] != null ? config["field_name"] : "temperature" );
   this.minTemperature = config["min_temp"] || DEF_MIN_TEMPERATURE;
   this.maxTemperature = config["max_temp"] || DEF_MAX_TEMPERATURE;
   this.units = config["units"] || DEF_UNITS;
   this.update_interval = Number( config["update_interval"] || DEF_INTERVAL );
   this.debug = config["debug"] || false;

   //Check auth option
   if (config.auth && config.auth.user !== undefined && config.auth.pass !== undefined) {
      this.request_opts.auth = config.auth.user + ':' + config.auth.pass;
   } else if (config.auth) {
      this.log('Ignoring invalid auth options. "user" and "pass" must be provided');
   }

   //Check headers option
   if (config.http_headers) {
      this.request_opts.headers = config.http_headers;
   }

   //Check if units field is valid
   this.units = this.units.toUpperCase()
   if (this.units !== CELSIUS_UNITS && this.units !== FAHRENHEIT_UNITS) {
      this.log('Bad temperature units : "' + this.units + '" (assuming Celsius)');
      this.units = CELSIUS_UNITS;
   }

   // Internal variables
   this.last_value = null;
   this.waiting_response = false;
}

HttpTemperature.prototype = {

   logDebug: function (str) {
      if (this.debug) {
         this.log(str)
      }
   },

   updateState: function () {
      //Ensure previous call finished
      if (this.waiting_response) {
         this.logDebug('Avoid updateState as previous response does not arrived yet');
         return;
      }
      this.waiting_response = true;
      this.last_value = new Promise((resolve, reject) => {
         this.logDebug('Requesting temperature on "' + this.url);
         this.request(this.url, this.request_opts, (res) => {
            let body = '';
            res.on('data', (chunk) => {
               body += chunk;
            });
            res.on('end', () => {
               let value = null;
               try {
                  const value_str = this.fieldName === '' ? body : this.getFromObject(JSON.parse(body), this.fieldName, '');
                  value_str = value_str.replace(/[^0-9.]/g, '');
                  value = Number(value_str);
                  if (value_str === '' || isNaN(value)) {
                     throw new Error('Received value is not a number: "' + value_str + '" ("' + body.substring(0, 100) + '")');
                  } else if (value < this.minTemperature || value > this.maxTemperature) {
                     var msg = 'Received value is out of bounds: "' + value + '". min=' + this.minTemperature +
                               ', max= ' + this.maxTemperature;
                     throw new Error(msg);
                  }
                  this.logDebug('HTTP successful response: ' + value);
                  if (this.units === FAHRENHEIT_UNITS) {
                     value = (value - 32)/1.8;
                     this.logDebug('Converted Fahrenheit temperature to celsius: ' + value);
                  }
               } catch (error) {
                  reject(error);
               }
               resolve(value);
            });
         }).on('error', reject).end();
      });
      this.last_value.then((value) => {
         this.temperatureService
            .getCharacteristic(Characteristic.CurrentTemperature).updateValue(value);
         this.temperatureService
            .getCharacteristic(Characteristic.StatusFault).updateValue(Characteristic.StatusFault.NO_FAULT);
         this.waiting_response = false;
      }).catch((error) => {
         this.temperatureService
            .getCharacteristic(Characteristic.StatusFault).updateValue(Characteristic.StatusFault.GENERAL_FAULT);
         this.log('Error updating state: ' + error.message);
         this.waiting_response = false;
      });
   },

   getState: function (callback) {
      this.logDebug('Call to getState: waiting_response is "' + this.waiting_response + '"' );
      this.updateState(); //This sets the promise in last_value
      this.last_value.then((value) => {
         callback(null, value);
      }).catch((error) => {
         callback(error, null);
      });
   },

   getServices: function () {
      this.informationService = new Service.AccessoryInformation();
      this.informationService
      .setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
      .setCharacteristic(Characteristic.Model, this.model)
      .setCharacteristic(Characteristic.SerialNumber, this.serial);

      this.temperatureService = new Service.TemperatureSensor(this.name);
      this.temperatureService
         .getCharacteristic(Characteristic.CurrentTemperature)
         .on('get', this.getState.bind(this))
         .setProps({
             minValue: this.minTemperature,
             maxValue: this.maxTemperature
         });

      if (this.update_interval > 0) {
         this.timer = setInterval(this.updateState.bind(this), this.update_interval);
      }

      return [this.informationService, this.temperatureService];
   },

   getFromObject: function (obj, path, def) {
      if (!path) return obj;

      const fullPath = path
        .replace(/\[/g, '.')
        .replace(/]/g, '')
        .split('.')
        .filter(Boolean);

      // Iterate all path elements to get the leaf, or untill the key is not found in the JSON
      return fullPath.every(everyFunc) ? obj : def;

      function everyFunc (step) {
        // Dynamically update the obj variable for the next call
        return !(step && (obj = obj[step]) === undefined);
      }
   }
};
<|endoftext|>


<commit_before>var bindings = require('bindings')('storm-replay');

module.exports = {
    extractFile: function(Archive, File) {
        // 'replay.attributes.events',
        // 'replay.details',
        // 'replay.game.events',
        // 'replay.initData',
        // 'replay.load.info',
        // 'replay.message.events',
        // 'replay.smartcam.events',
        // 'replay.sync.events'
        var ret = bindings.extractFile(Archive, File);
        var obj = {
            err: (ret.length === undefined),
            content: {
                data: ret,
                size: ret.length
            }
        };
        return obj;
    },

    getHeader: function(Archive) {
        var ret = bindings.getHeader(Archive);
        var obj = {
            err: (ret.length === undefined),
            header: {
                data: ret,
                size: ret.length
            },
            content: {
                data: ret.slice(16, 16 + ret.readUInt32LE(12)),
                size: ret.readUInt32LE(12)
            }
        };
        return obj;
    }
};

// var data = bindings.extractFile('replays/garden-of-terror.StormReplay', 'replay.game.events');
// var header = bindings.getHeader('replays/garden-of-terror.StormReplay');
<commit_msg>return objects directly<commit_after>var bindings = require('bindings')('storm-replay');

module.exports = {
    extractFile: function(Archive, File) {
        // 'replay.attributes.events',
        // 'replay.details',
        // 'replay.game.events',
        // 'replay.initData',
        // 'replay.load.info',
        // 'replay.message.events',
        // 'replay.smartcam.events',
        // 'replay.sync.events'
        var ret = bindings.extractFile(Archive, File);
        return {
            err: (ret.length === undefined),
            content: {
                data: ret,
                size: ret.length
            }
        };
    },

    getHeader: function(Archive) {
        var ret = bindings.getHeader(Archive);
        return {
            err: (ret.length === undefined),
            header: {
                data: ret,
                size: ret.length
            },
            content: {
                data: ret.slice(16, 16 + ret.readUInt32LE(12)),
                size: ret.readUInt32LE(12)
            }
        };
    }
};
<|endoftext|>


<commit_before>/*global __dirname, unexpected*/
var metalSmith = require('metalsmith');
var path = require('path');
var _ = require('lodash');

function idToName(id) {
    return id.replace(/-/g, ' ');
}

function getTypeHierarchy(typeIndex, typeName) {
    var tree = {};
    Object.keys(typeIndex[typeName] || {}).forEach(function (childTypeName) {
        tree[childTypeName] = getTypeHierarchy(typeIndex, childTypeName);
    });

    return tree;
}

function flattenTypeHierarchy(typeHierarchy, assertionsByType) {
    var result = [];
    Object.keys(typeHierarchy).sort(function (a, b) {
        var aChildren = Object.keys(typeHierarchy[a]);
        var bChildren = Object.keys(typeHierarchy[b]);
        if (aChildren.length === 0 && bChildren.length > 0) {
            return -1;
        }
        if (aChildren.length > 0 && bChildren.length === 0) {
            return 1;
        }
        var aLength = assertionsByType[a] ? assertionsByType[a].length : 0;
        var bLength = assertionsByType[b] ? assertionsByType[b].length : 0;
        if (aLength > bLength) {
            return -1;
        }
        if (aLength < bLength) {
            return 1;
        }

        a = a.toLowerCase();
        b = b.toLowerCase();
        if (a < b) { return -1; }
        if (a > b) { return 1; }
        return 0;
    }).forEach(function (typeName) {
        result.push(typeName);
        Array.prototype.push.apply(result, flattenTypeHierarchy(typeHierarchy[typeName], assertionsByType));
    });
    return result;
}

function addTypeToIndex(typeIndex, type) {
    if (type.baseType) {
        typeIndex[type.baseType.name] = typeIndex[type.baseType.name] || {};
        typeIndex[type.baseType.name][type.name] = type.name;
        addTypeToIndex(typeIndex, type.baseType);
    }
}

function createExpect(options) {
    if (options.unexpected) {
        return options.unexpected.clone();
    }

    if (typeof unexpected !== 'undefined') {
        return unexpected.clone();
    }

    return require('unexpected').clone();
}

module.exports = function generate(options) {
    if (options.require) {
        var moduleNames = options.require;
        if (!Array.isArray(moduleNames)) {
            moduleNames = [ moduleName ];
        }
        moduleNames.forEach(function (moduleName) {
            if (/^[\.\/]/.test(moduleName)) {
                moduleName = path.resolve(process.cwd(), moduleName);
            }
            require(moduleName);
        });
    }

    var expect = createExpect(options);

    function sortTypesByHierarchy(assertionsByType) {
        var typeIndex = {};
        var unknownTypes = [];
        Object.keys(assertionsByType).forEach(function (typeName) {
            var type = expect.getType(typeName);
            if (type) {
                addTypeToIndex(typeIndex, type);
            } else {
                unknownTypes.push(typeName);
            }
        });

        var typeHierarchy = { 'any': getTypeHierarchy(typeIndex, 'any') };

        var result = {};

        flattenTypeHierarchy(typeHierarchy, assertionsByType).concat(unknownTypes).forEach(function (typeName) {
            if (assertionsByType[typeName]) {
                result[typeName] = assertionsByType[typeName];
            }
        });

        return result;
    }

    var assertionsPattern = options.assertions || 'assertions/*/*.md';
    var output = options.output || 'site-build';

    metalSmith('.')
        .destination(output)
        .source('documentation')
        .use(require('metalsmith-collections')({
            assertions: {
                pattern: assertionsPattern
            },
            apiPages: {
                pattern: 'api/*.md'
            },
            pages: {
                pattern: '*.md'
            }
        }))
        .use(require('./lib/include-static-assets')({ path: path.resolve(__dirname, 'static') }))
    // Dynamicly generate metadata for assertion files
        .use(function (files, metalsmith, next) {
            Object.keys(files).filter(function (file) {
                return /\.md$/.test(file);
            }).forEach(function (file) {
                var id = file.match(/([^\/]+)\.md$/)[1];
                var name = idToName(id);

                if (!files[file].title) {
                    files[file].title = name;
                }

                if (files[file].collection.indexOf('apiPages') !== -1) {
                    files[file].template = 'api.ejs';
                } else if (files[file].collection.indexOf('assertions') !== -1) {
                    var type = file.match(/^assertions\/([^\/]+)/)[1];

                    files[file].declarations = _.uniq((expect.assertions[name] || []).filter(function (assertionRule) {
                        return assertionRule.subject.type.name === type;
                    }).map(function (assertionRule) {
                        return assertionRule.declaration.replace(/<.*?>/, '<' + assertionRule.subject.type.name + '>');
                    }));

                    files[file].template = 'assertion.ejs';
                    files[file].windowTitle = type + ' - ' + name;
                    files[file].type = type;
                }

                if (!files[file].windowTitle) {
                    files[file].windowTitle = files[file].title;
                }

                files[file].url = '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
            });
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();

            metadata.collections.apiPages.sort(function (a, b) {
                var aTitle = a.title.toLowerCase();
                var bTitle = b.title.toLowerCase();
                if (aTitle < bTitle) { return -1; }
                if (aTitle > bTitle) { return 1; }
                return 0;
            });

            // Make sure that the most important types are listed first and in this order:
            var assertionsByType = {};
            metadata.collections.assertions.forEach(function (assertion) {
                assertionsByType[assertion.type] = assertionsByType[assertion.type] || [];
                assertionsByType[assertion.type].push(assertion);
            });

            assertionsByType = sortTypesByHierarchy(assertionsByType);
            Object.keys(assertionsByType).forEach(function (type) {
                assertionsByType[type].sort(function (a, b) {
                    var aName = a.title.toLowerCase();
                    var bName = b.title.toLowerCase();
                    if (aName < bName) { return -1; }
                    if (aName > bName) { return 1; }
                    return 0;
                });
            });
            metadata.assertionsByType = assertionsByType;
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();
            Object.keys(metadata.assertionsByType).forEach(function (type) {
                var declarations = [];
                metadata.assertionsByType[type].forEach(function (assertion) {
                    Array.prototype.push.apply(declarations, assertion.declarations);
                });

                var path = 'assertions/' + type + '/';
                var file = 'assertions/' + type + '.html';
                files[file] = {
                    windowTitle: type,
                    title: type,
                    declarations: _.uniq(declarations),
                    template: 'type.ejs',
                    url: path,
                    contents: ''
                };
            });
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();
            var indexData = [];

            metadata.collections.apiPages.forEach(function (assertion) {
                indexData.push({
                    label: assertion.title + ' (api)',
                    url: assertion.url
                });
            });

            metadata.collections.assertions.forEach(function (assertion) {
                indexData.push({
                    label: assertion.title + ' (' + assertion.type + ')',
                    url: assertion.url
                });
            });
            files['searchIndex.json'] = { contents: JSON.stringify(indexData, null, 2) };
            next();
        })
        .use(require('metalsmith-unexpected-markdown')({
            unexpected: expect,
            updateExamples: !!options['update-examples']
        }))
    // permalinks with no options will just make pretty urls...
        .use(require('metalsmith-permalinks')({ relative: false }))
        .use(function (files, metalsmith, next) {
            // Useful for debugging ;-)
            // require('uninspected').log(files);
            next();
        })
        .use(require('metalsmith-less')())
        .use(require('metalsmith-relative')())
        .use(require('metalsmith-templates')({
            engine: 'ejs',
            directory: path.resolve(__dirname, 'templates')
        }))
        .use(require('metalsmith-autoprefixer')({ browsers: 'last 2 versions', cascade: false }))
        .use(require('./lib/delete-less-files')())
        .build(function (err) {
            if (err) { throw err; }
            console.log('wrote site to ' + output);
        });
};
<commit_msg>Argh, fix typo<commit_after>/*global __dirname, unexpected*/
var metalSmith = require('metalsmith');
var path = require('path');
var _ = require('lodash');

function idToName(id) {
    return id.replace(/-/g, ' ');
}

function getTypeHierarchy(typeIndex, typeName) {
    var tree = {};
    Object.keys(typeIndex[typeName] || {}).forEach(function (childTypeName) {
        tree[childTypeName] = getTypeHierarchy(typeIndex, childTypeName);
    });

    return tree;
}

function flattenTypeHierarchy(typeHierarchy, assertionsByType) {
    var result = [];
    Object.keys(typeHierarchy).sort(function (a, b) {
        var aChildren = Object.keys(typeHierarchy[a]);
        var bChildren = Object.keys(typeHierarchy[b]);
        if (aChildren.length === 0 && bChildren.length > 0) {
            return -1;
        }
        if (aChildren.length > 0 && bChildren.length === 0) {
            return 1;
        }
        var aLength = assertionsByType[a] ? assertionsByType[a].length : 0;
        var bLength = assertionsByType[b] ? assertionsByType[b].length : 0;
        if (aLength > bLength) {
            return -1;
        }
        if (aLength < bLength) {
            return 1;
        }

        a = a.toLowerCase();
        b = b.toLowerCase();
        if (a < b) { return -1; }
        if (a > b) { return 1; }
        return 0;
    }).forEach(function (typeName) {
        result.push(typeName);
        Array.prototype.push.apply(result, flattenTypeHierarchy(typeHierarchy[typeName], assertionsByType));
    });
    return result;
}

function addTypeToIndex(typeIndex, type) {
    if (type.baseType) {
        typeIndex[type.baseType.name] = typeIndex[type.baseType.name] || {};
        typeIndex[type.baseType.name][type.name] = type.name;
        addTypeToIndex(typeIndex, type.baseType);
    }
}

function createExpect(options) {
    if (options.unexpected) {
        return options.unexpected.clone();
    }

    if (typeof unexpected !== 'undefined') {
        return unexpected.clone();
    }

    return require('unexpected').clone();
}

module.exports = function generate(options) {
    if (options.require) {
        var moduleNames = options.require;
        if (!Array.isArray(moduleNames)) {
            moduleNames = [ moduleNames ];
        }
        moduleNames.forEach(function (moduleName) {
            if (/^[\.\/]/.test(moduleName)) {
                moduleName = path.resolve(process.cwd(), moduleName);
            }
            require(moduleName);
        });
    }

    var expect = createExpect(options);

    function sortTypesByHierarchy(assertionsByType) {
        var typeIndex = {};
        var unknownTypes = [];
        Object.keys(assertionsByType).forEach(function (typeName) {
            var type = expect.getType(typeName);
            if (type) {
                addTypeToIndex(typeIndex, type);
            } else {
                unknownTypes.push(typeName);
            }
        });

        var typeHierarchy = { 'any': getTypeHierarchy(typeIndex, 'any') };

        var result = {};

        flattenTypeHierarchy(typeHierarchy, assertionsByType).concat(unknownTypes).forEach(function (typeName) {
            if (assertionsByType[typeName]) {
                result[typeName] = assertionsByType[typeName];
            }
        });

        return result;
    }

    var assertionsPattern = options.assertions || 'assertions/*/*.md';
    var output = options.output || 'site-build';

    metalSmith('.')
        .destination(output)
        .source('documentation')
        .use(require('metalsmith-collections')({
            assertions: {
                pattern: assertionsPattern
            },
            apiPages: {
                pattern: 'api/*.md'
            },
            pages: {
                pattern: '*.md'
            }
        }))
        .use(require('./lib/include-static-assets')({ path: path.resolve(__dirname, 'static') }))
    // Dynamicly generate metadata for assertion files
        .use(function (files, metalsmith, next) {
            Object.keys(files).filter(function (file) {
                return /\.md$/.test(file);
            }).forEach(function (file) {
                var id = file.match(/([^\/]+)\.md$/)[1];
                var name = idToName(id);

                if (!files[file].title) {
                    files[file].title = name;
                }

                if (files[file].collection.indexOf('apiPages') !== -1) {
                    files[file].template = 'api.ejs';
                } else if (files[file].collection.indexOf('assertions') !== -1) {
                    var type = file.match(/^assertions\/([^\/]+)/)[1];

                    files[file].declarations = _.uniq((expect.assertions[name] || []).filter(function (assertionRule) {
                        return assertionRule.subject.type.name === type;
                    }).map(function (assertionRule) {
                        return assertionRule.declaration.replace(/<.*?>/, '<' + assertionRule.subject.type.name + '>');
                    }));

                    files[file].template = 'assertion.ejs';
                    files[file].windowTitle = type + ' - ' + name;
                    files[file].type = type;
                }

                if (!files[file].windowTitle) {
                    files[file].windowTitle = files[file].title;
                }

                files[file].url = '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
            });
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();

            metadata.collections.apiPages.sort(function (a, b) {
                var aTitle = a.title.toLowerCase();
                var bTitle = b.title.toLowerCase();
                if (aTitle < bTitle) { return -1; }
                if (aTitle > bTitle) { return 1; }
                return 0;
            });

            // Make sure that the most important types are listed first and in this order:
            var assertionsByType = {};
            metadata.collections.assertions.forEach(function (assertion) {
                assertionsByType[assertion.type] = assertionsByType[assertion.type] || [];
                assertionsByType[assertion.type].push(assertion);
            });

            assertionsByType = sortTypesByHierarchy(assertionsByType);
            Object.keys(assertionsByType).forEach(function (type) {
                assertionsByType[type].sort(function (a, b) {
                    var aName = a.title.toLowerCase();
                    var bName = b.title.toLowerCase();
                    if (aName < bName) { return -1; }
                    if (aName > bName) { return 1; }
                    return 0;
                });
            });
            metadata.assertionsByType = assertionsByType;
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();
            Object.keys(metadata.assertionsByType).forEach(function (type) {
                var declarations = [];
                metadata.assertionsByType[type].forEach(function (assertion) {
                    Array.prototype.push.apply(declarations, assertion.declarations);
                });

                var path = 'assertions/' + type + '/';
                var file = 'assertions/' + type + '.html';
                files[file] = {
                    windowTitle: type,
                    title: type,
                    declarations: _.uniq(declarations),
                    template: 'type.ejs',
                    url: path,
                    contents: ''
                };
            });
            next();
        })
        .use(function (files, metalsmith, next) {
            var metadata = metalsmith.metadata();
            var indexData = [];

            metadata.collections.apiPages.forEach(function (assertion) {
                indexData.push({
                    label: assertion.title + ' (api)',
                    url: assertion.url
                });
            });

            metadata.collections.assertions.forEach(function (assertion) {
                indexData.push({
                    label: assertion.title + ' (' + assertion.type + ')',
                    url: assertion.url
                });
            });
            files['searchIndex.json'] = { contents: JSON.stringify(indexData, null, 2) };
            next();
        })
        .use(require('metalsmith-unexpected-markdown')({
            unexpected: expect,
            updateExamples: !!options['update-examples']
        }))
    // permalinks with no options will just make pretty urls...
        .use(require('metalsmith-permalinks')({ relative: false }))
        .use(function (files, metalsmith, next) {
            // Useful for debugging ;-)
            // require('uninspected').log(files);
            next();
        })
        .use(require('metalsmith-less')())
        .use(require('metalsmith-relative')())
        .use(require('metalsmith-templates')({
            engine: 'ejs',
            directory: path.resolve(__dirname, 'templates')
        }))
        .use(require('metalsmith-autoprefixer')({ browsers: 'last 2 versions', cascade: false }))
        .use(require('./lib/delete-less-files')())
        .build(function (err) {
            if (err) { throw err; }
            console.log('wrote site to ' + output);
        });
};
<|endoftext|>


<commit_before>var rest = require('superagent');
var _ = require('underscore');
var crypto = require('crypto');

function KeenApi(config) {
	if (!config) {
		throw new Error("The 'config' parameter must be specified and must be a JS object.");
	}
	if (!config.projectId) {
		throw new Error("The 'config' object must contain a 'projectId'.");
	}

	this.projectId = config.projectId;
	this.writeKey = config.writeKey;
	this.readKey = config.readKey;
	this.masterKey = config.masterKey;
	this.baseUrl = config.baseUrl || 'https://api.keen.io/';
	this.apiVersion = config.apiVersion || '3.0';

	var baseUrl = this.baseUrl;
	var apiVersion = this.apiVersion;

	var request = {
		get: function(apiKey, path, callback) {
			rest
				.get(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		},
		post: function(apiKey, path, data, callback) {
			rest
				.post(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.set('Content-Type', 'application/json')
				.send(data || {})
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		},
		del: function(apiKey, path, callback) {
			rest
				.del(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.set('Content-Length', 0)
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		}
	};

	// Handle logic of processing response, including error messages
	// The error handling should be strengthened over time to be more meaningful and robust
	function processResponse(err, res, callback) {
		callback = callback || function() {};

		if (!res.ok && !err) {
			var is_err = res.body && res.body.error_code;
			err = new Error(is_err ? res.body.message : 'Unknown error occurred');
			err.code = is_err ? res.body.error_code : 'UnknownError';
		}

		if (err) return callback(err);
		return callback(null, res.body);
	}

	// Public Methods

	this.projects = {
		list: function(callback) {
			request.get(this.masterKey, '/projects', callback);
		},
		view: function(projectId, callback) {
			request.get(this.masterKey, '/projects/' + projectId, callback);
		}
	};

	this.events = {
		list: function(projectId, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events', callback);
		},
		insert: function(projectId, events, callback) {
			events = events || [];
			var data = {};
			events.forEach(function(event) {
				var collection = event.collection;
				if (typeof data[collection] == 'undefined') {
					data[collection] = [];
				}
				var item = (event.data || {});
				if (typeof event.keen == 'object') {
					item.keen = event.keen;
				}
				data[collection].push(item);
			});
			request.post(this.writeKey, '/projects/' + projectId + '/events', data, callback);
		}
	};

	this.properties = {
		view: function(projectId, collection, property, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
		},
		remove: function(projectId, collection, property, callback) {
			request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
		}
	};

	this.collections = {
		view: function(projectId, collection, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
		},
		remove: function(projectId, collection, callback) {
			request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
		}
	};

	this.addEvent = function(eventCollection, event, callback) {
		if (!this.writeKey) {
			var errorMessage = "You must specify a non-null, non-empty 'writeKey' in your 'config' object when calling keen.configure()!";
			var error = new Error(errorMessage);
			if (callback) {
				callback(error);
			} else {
				throw error;
			}
			return;
		}

		request.post(this.writeKey, "/projects/" + this.projectId + "/events/" + eventCollection, event, callback);
	};

	this.addEvents = function(events, callback) {
		if (!this.writeKey) {
			var errorMessage = "You must specify a non-null, non-empty 'writeKey' in your 'config' object when calling keen.configure()!";
			var error = new Error(errorMessage);
			if (callback) {
				callback(error);
			} else {
				throw error;
			}
			return;
		}

		request.post(this.writeKey, "/projects/" + this.projectId + "/events", events, callback);
	};
}

function configure(config) {
	return new KeenApi(config);
}

function encryptScopedKey(apiKey, options) {
	var iv = crypto.randomBytes(16);
	var cipher = crypto.createCipheriv("aes-256-cbc", apiKey, iv);
	var jsonOptions = JSON.stringify(options);
	var encryptOutput1 = cipher.update(jsonOptions, "utf8", "hex");
	var encryptOutput2 = cipher.final("hex");
	var ivPlusEncrypted = iv.toString("hex") + encryptOutput1 + encryptOutput2;
	return ivPlusEncrypted;
}

function decryptScopedKey(apiKey, scopedKey) {
	var hexedIv = scopedKey.substring(0, 32);
	var hexedCipherText = scopedKey.substring(32, scopedKey.length);
	var iv = new Buffer(hexedIv, "hex");
	var cipherText = new Buffer(hexedCipherText, "hex");
	var decipher = crypto.createDecipheriv("aes-256-cbc", apiKey, iv);
	var decryptOutput1 = decipher.update(cipherText);
	var decryptOutput2 = decipher.final();
	var decrypted = decryptOutput1 + decryptOutput2;
	return JSON.parse(decrypted);
}

module.exports = {
	configure: configure,
	encryptScopedKey: encryptScopedKey,
	decryptScopedKey: decryptScopedKey
};<commit_msg>guard against null response<commit_after>var rest = require('superagent');
var _ = require('underscore');
var crypto = require('crypto');

function KeenApi(config) {
	if (!config) {
		throw new Error("The 'config' parameter must be specified and must be a JS object.");
	}
	if (!config.projectId) {
		throw new Error("The 'config' object must contain a 'projectId'.");
	}

	this.projectId = config.projectId;
	this.writeKey = config.writeKey;
	this.readKey = config.readKey;
	this.masterKey = config.masterKey;
	this.baseUrl = config.baseUrl || 'https://api.keen.io/';
	this.apiVersion = config.apiVersion || '3.0';

	var baseUrl = this.baseUrl;
	var apiVersion = this.apiVersion;

	var request = {
		get: function(apiKey, path, callback) {
			rest
				.get(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		},
		post: function(apiKey, path, data, callback) {
			rest
				.post(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.set('Content-Type', 'application/json')
				.send(data || {})
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		},
		del: function(apiKey, path, callback) {
			rest
				.del(baseUrl + apiVersion + path)
				.set('Authorization', apiKey)
				.set('Content-Length', 0)
				.end(function(err, res) {
					processResponse(err, res, callback);
				});
		}
	};

	// Handle logic of processing response, including error messages
	// The error handling should be strengthened over time to be more meaningful and robust
	function processResponse(err, res, callback) {
		callback = callback || function() {};

		if (res && !res.ok && !err) {
			var is_err = res.body && res.body.error_code;
			err = new Error(is_err ? res.body.message : 'Unknown error occurred');
			err.code = is_err ? res.body.error_code : 'UnknownError';
		}

		if (err) return callback(err);
		return callback(null, res.body);
	}

	// Public Methods

	this.projects = {
		list: function(callback) {
			request.get(this.masterKey, '/projects', callback);
		},
		view: function(projectId, callback) {
			request.get(this.masterKey, '/projects/' + projectId, callback);
		}
	};

	this.events = {
		list: function(projectId, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events', callback);
		},
		insert: function(projectId, events, callback) {
			events = events || [];
			var data = {};
			events.forEach(function(event) {
				var collection = event.collection;
				if (typeof data[collection] == 'undefined') {
					data[collection] = [];
				}
				var item = (event.data || {});
				if (typeof event.keen == 'object') {
					item.keen = event.keen;
				}
				data[collection].push(item);
			});
			request.post(this.writeKey, '/projects/' + projectId + '/events', data, callback);
		}
	};

	this.properties = {
		view: function(projectId, collection, property, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
		},
		remove: function(projectId, collection, property, callback) {
			request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection + '/properties/' + property, callback);
		}
	};

	this.collections = {
		view: function(projectId, collection, callback) {
			request.get(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
		},
		remove: function(projectId, collection, callback) {
			request.del(this.masterKey, '/projects/' + projectId + '/events/' + collection, callback);
		}
	};

	this.addEvent = function(eventCollection, event, callback) {
		if (!this.writeKey) {
			var errorMessage = "You must specify a non-null, non-empty 'writeKey' in your 'config' object when calling keen.configure()!";
			var error = new Error(errorMessage);
			if (callback) {
				callback(error);
			} else {
				throw error;
			}
			return;
		}

		request.post(this.writeKey, "/projects/" + this.projectId + "/events/" + eventCollection, event, callback);
	};

	this.addEvents = function(events, callback) {
		if (!this.writeKey) {
			var errorMessage = "You must specify a non-null, non-empty 'writeKey' in your 'config' object when calling keen.configure()!";
			var error = new Error(errorMessage);
			if (callback) {
				callback(error);
			} else {
				throw error;
			}
			return;
		}

		request.post(this.writeKey, "/projects/" + this.projectId + "/events", events, callback);
	};
}

function configure(config) {
	return new KeenApi(config);
}

function encryptScopedKey(apiKey, options) {
	var iv = crypto.randomBytes(16);
	var cipher = crypto.createCipheriv("aes-256-cbc", apiKey, iv);
	var jsonOptions = JSON.stringify(options);
	var encryptOutput1 = cipher.update(jsonOptions, "utf8", "hex");
	var encryptOutput2 = cipher.final("hex");
	var ivPlusEncrypted = iv.toString("hex") + encryptOutput1 + encryptOutput2;
	return ivPlusEncrypted;
}

function decryptScopedKey(apiKey, scopedKey) {
	var hexedIv = scopedKey.substring(0, 32);
	var hexedCipherText = scopedKey.substring(32, scopedKey.length);
	var iv = new Buffer(hexedIv, "hex");
	var cipherText = new Buffer(hexedCipherText, "hex");
	var decipher = crypto.createDecipheriv("aes-256-cbc", apiKey, iv);
	var decryptOutput1 = decipher.update(cipherText);
	var decryptOutput2 = decipher.final();
	var decrypted = decryptOutput1 + decryptOutput2;
	return JSON.parse(decrypted);
}

module.exports = {
	configure: configure,
	encryptScopedKey: encryptScopedKey,
	decryptScopedKey: decryptScopedKey
};<|endoftext|>


<commit_before>var through = require('through2'),
  gutil = require('gulp-util'),
  doT = require('./lib/doT');

module.exports = function(options) {
  'use strict';

  var pluginName = 'gulp-weibo-dot2js';
  var INCLUDE_PATTERN = /(['"])Weibo_Multi_Template_Engine_Include_id\:(.)+?\:(.)+?\1/g;

  // if necessary check for required param(s), e.g. options hash, etc.
  // if (!param) {
  //  throw new gutil.PluginError(pluginName, 'No param supplied');
  // }
  //
  options = options || {};

  // see 'Writing a plugin'
  // https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/README.md
  function pluginDemo(file, enc, callback) {
    /*jshint validthis:true*/

    // Do nothing if no contents
    if (file.isNull()) {
      this.push(file);
      return callback();
    }

    if (file.isStream()) {

      // http://nodejs.org/api/stream.html
      // http://nodejs.org/api/child_process.html
      // https://github.com/dominictarr/event-stream

      // accepting streams is optional
      this.emit('error',
        new gutil.PluginError(pluginName, 'Stream content is not supported'));
      return callback();
    }

    // check if file.contents is a `Buffer`
    if (file.isBuffer()) {

      var func = doT.compile(file.contents, options.compressionSpace).toString();
      func = func.replace(/^function anonymous\(/, 'module.exports = function (');
      func = func.replace('\n/**/', ''); // for node.js 0.11

      // 处理 include
      var incRuleList = func.match(INCLUDE_PATTERN);
      if (incRuleList && incRuleList.length) {
        incRuleList.forEach(function(incRule) {
          incRule = incRule.replace(/['"]+|\\['"]/g, '');
          var arr = incRule.split(':');
          var _path = arr[1].replace(/^\//,'').replace(/\.html$/,'');
          var _varname = arr[2];
          func = func.replace(new RegExp('([\'"])' + incRule + '\\1', 'g'), '(function(){var tpl = require(\'' + _path + '\');return tpl(' + _varname + ');})()');
        });
      }

      if (options.tplFunc) {
        func = 'var tplFunc = require(\'' + options.tplFunc + '\');\n' + func;
      }
      // manipulate buffer in some way
      // http://nodejs.org/api/buffer.html
      file.contents = new Buffer(func);

      this.push(file);

    }
    return callback();
  }

  return through.obj(pluginDemo);
};
<commit_msg>fix windows test error<commit_after>var through = require('through2'),
  gutil = require('gulp-util'),
  doT = require('./lib/doT');

module.exports = function(options) {
  'use strict';

  var pluginName = 'gulp-weibo-dot2js';
  var INCLUDE_PATTERN = /(['"])Weibo_Multi_Template_Engine_Include_id\:(.)+?\:(.)+?\1/g;

  // if necessary check for required param(s), e.g. options hash, etc.
  // if (!param) {
  //  throw new gutil.PluginError(pluginName, 'No param supplied');
  // }
  //
  options = options || {};

  // see 'Writing a plugin'
  // https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/README.md
  function pluginDemo(file, enc, callback) {
    /*jshint validthis:true*/

    // Do nothing if no contents
    if (file.isNull()) {
      this.push(file);
      return callback();
    }

    if (file.isStream()) {

      // http://nodejs.org/api/stream.html
      // http://nodejs.org/api/child_process.html
      // https://github.com/dominictarr/event-stream

      // accepting streams is optional
      this.emit('error',
        new gutil.PluginError(pluginName, 'Stream content is not supported'));
      return callback();
    }

    // check if file.contents is a `Buffer`
    if (file.isBuffer()) {

      var func = doT.compile(file.contents, options.compressionSpace).toString();
      func = func.replace(/^function anonymous\(/, 'module.exports = function (');
      func = func.replace('\n/**/', ''); // for node.js 0.11
      func = func.replace(/\r\n/g, '\n'); // for windows test

      // 处理 include
      var incRuleList = func.match(INCLUDE_PATTERN);
      if (incRuleList && incRuleList.length) {
        incRuleList.forEach(function(incRule) {
          incRule = incRule.replace(/['"]+|\\['"]/g, '');
          var arr = incRule.split(':');
          var _path = arr[1].replace(/^\//,'').replace(/\.html$/,'');
          var _varname = arr[2];
          func = func.replace(new RegExp('([\'"])' + incRule + '\\1', 'g'), '(function(){var tpl = require(\'' + _path + '\');return tpl(' + _varname + ');})()');
        });
      }

      if (options.tplFunc) {
        func = 'var tplFunc = require(\'' + options.tplFunc + '\');\n' + func;
      }
      // manipulate buffer in some way
      // http://nodejs.org/api/buffer.html
      file.contents = new Buffer(func);

      this.push(file);

    }
    return callback();
  }

  return through.obj(pluginDemo);
};
<|endoftext|>


<commit_before>'use strict';

var os = require('os');
var tmp = require('tmp');
var fs = require('fs');

var platform = os.platform();
var isWindows = platform === 'win32';
tmp.setGracefulCleanup();

module.exports = function smartPipe(buffer, opts) {
	opts = opts || {};
	var result = {};
	if (isWindows) {
		var tmpFile = tmp.fileSync({postfix: opts.postfix || '.tmp'});

		result.buffer = new Buffer(0);
		result.file = tmpFile.name;
		result.clean = function () {
			tmpFile.removeCallback();
		};

		fs.writeSync(tmpFile.fd, buffer);
		fs.closeSync(tmpFile.fd);
	} else {
		result.buffer = buffer;
		result.file = opts.dash ? '-' : platform === 'linux' ?
			'/proc/self/fd/0' : '/dev/stdin';
		result.clean = function () {};
	}

	return result;
};
<commit_msg>cleaned up ternary operator<commit_after>'use strict';

var os = require('os');
var tmp = require('tmp');
var fs = require('fs');

var platform = os.platform();
var isWindows = platform === 'win32';
tmp.setGracefulCleanup();

module.exports = function smartPipe(buffer, opts) {
	opts = opts || {};
	var result = {};
	if (isWindows) {
		var tmpFile = tmp.fileSync({postfix: opts.postfix || '.tmp'});

		result.buffer = new Buffer(0);
		result.file = tmpFile.name;
		result.clean = function () {
			tmpFile.removeCallback();
		};

		fs.writeSync(tmpFile.fd, buffer);
		fs.closeSync(tmpFile.fd);
	} else {
		result.buffer = buffer;
		result.file = opts.dash
			? '-'
			: platform === 'linux'
				? '/proc/self/fd/0'
				: '/dev/stdin';
		result.clean = function () {};
	}

	return result;
};
<|endoftext|>


<commit_before>'use strict'

var pkg = require('./package.json')
var Promise = require('bluebird')
var request = require('request')
var os = require('os')
var https = require('https')
var net = require('net')

var system = (process.platform === 'linux') ? require('./src/system.js') : require('./src/mockSystem.js')
var getCollectorUrl = require('./src/collector.js')
var Context = require('./src/context.js')
var Callback = require('./src/callback.js')

const VERSION = pkg.version
const MODULE_LOAD_TIME = Date.now()
const httpsAgent = new https.Agent({
  maxCachedSessions: 1,
  keepAlive: true
});
httpsAgent.createConnection = function(options, callback) {
  /* noDelay is documented as defaulting to true, but docs lie.
     this sacrifices throughput for latency and should be faster
     for how we submit data. */
  var socket = net.createConnection(options).noDelay(true)
  if (callback) {
    callback(undefined, socket)
    return
  }
  return socket
}

// Default on module load; changed to false on first handler invocation.
var COLDSTART = true

function _make_generateLog(metrics, func, start_time, config, context) {
  var pre_stat_promise = system.readstat('self')

  return function generateLog(err, callback) {
    Promise.join(
        pre_stat_promise,
        system.readstat('self'),
        system.readstatus('self'),
        system.readbootid()
      ).spread((
        pre_proc_self_stat,
        proc_self_stat,
        proc_self_status,
        boot_id
      ) => {
        var runtime_env = {
          agent: {
            runtime: 'nodejs',
            version: VERSION,
            load_time: MODULE_LOAD_TIME
          },
          host: {
            container_id: boot_id
          },
          os: {
            hostname: os.hostname(),
            uptime: os.uptime(),
            totalmem: os.totalmem(),
            freemem: os.freemem(),
            usedmem: os.totalmem() - os.freemem(),
            cpus: os.cpus(),
            arch: os.arch(),
            linux: {
              pid: {
                self: {
                  stat_start: pre_proc_self_stat,
                  stat: proc_self_stat,
                  status: proc_self_status
                }
              }
            }
          },
          nodejs: {
            title: process.title,
            version: process.version,
            modulesloadList: process.modulesloadList,
            versions: process.versions,
            arch: process.arch,
            platform: process.platform,
            argv: process.argv,
            execArgv: process.execArgv,
            pid: process.pid,
            features: process.features,
            execPath: process.execPath,
            debugPort: process.debugPort,
            _maxListeners: process._maxListeners,
            config: process.config,
            maxTickDepth: process.maxTickDepth,
            // /* Circular ref */ mainModule: process.mainModule,
            release: process.release,
            uptime: process.uptime(),
            getuid: process.getuid(),
            getgid: process.getgid(),
            geteuid: process.geteuid(),
            getegid: process.getegid(),
            memoryUsage: process.memoryUsage(),
          }
        }

        var retainErr = {}
        if (err) {
          retainErr = ((err) => {
            return {
              name: err.name,
              message: err.message,
              stack: err.stack,
              lineNumber: err.lineNumber,
              columnNumber: err.columnNumber,
              fileName: err.fileName
            }
          })((typeof(err) === 'string') ? new Error(err) : err)
        }

        var time_sec_nanosec = process.hrtime(start_time)

        /*
         depreciated fields:
         - time_sec_nanosec (use duration; 11/23/2016)
         - time_sec (use duration; 11/23/2016)
        */
        var response_body = {
          environment: runtime_env,
          aws: {
            functionName: context.functionName,
            functionVersion: context.functionVersion,
            invokedFunctionArn: context.invokedFunctionArn,
            memoryLimitInMB: context.memoryLimitInMB,
            awsRequestId: context.awsRequestId,
            logGroupName: context.logGroupName,
            logStreamName: context.logStreamName
          },
          coldstart: COLDSTART,
          errors: retainErr,
          custom_metrics: metrics,
          time_sec_nanosec: time_sec_nanosec,
          time_sec: time_sec_nanosec[0],
          time_nanosec: time_sec_nanosec[1],
          duration: Math.ceil(time_sec_nanosec[0] * 1000000000.0 + time_sec_nanosec[1]),
          client_id: config.clientId
        }

        if (COLDSTART === true) {
          COLDSTART = false
        }

        if (context.getRemainingTimeInMillis) {
          response_body.aws.getRemainingTimeInMillis = context.getRemainingTimeInMillis()
        }

        if (config.debug) {
          console.log('IOPIPE-DEBUG: ', JSON.stringify(response_body))
        }

        request(
          {
            url: getCollectorUrl(config.url),
            method: 'POST',
            json: true,
            body: response_body,
            agent: httpsAgent,
            timeout: config.networkTimeout,
          },
          function(err) {
            // Log errors, don't block on failed requests
            if (err && config.debug) {
              console.log('Write to IOpipe failed:')
              console.log(err)
            }
            callback()
          }
        )
      }
    )
  }
}

function setConfig(configObject) {
  return {
    url: (configObject && configObject.url) ? configObject.url : '',
    clientId: configObject && (configObject.token || configObject.clientId) || process.env.IOPIPE_TOKEN || process.env.IOPIPE_CLIENTID || '',
    debug: configObject && configObject.debug || process.env.IOPIPE_DEBUG || false,
    networkTimeout: configObject && configObject.networkTimeout || 5000,
    timeoutWindow: configObject && configObject.timeoutWindow || 50
  }
}

module.exports = function(options) {
  var fn = function(func) {
    fn.metricsQueue = []
    const config = setConfig(options)

    if (!config.clientId) {
      // No-op if user doesn't set an IOpipe token.
      return func
    }

    return function() {
      fn.metricsQueue = []
      let args = [].slice.call(arguments)

      var start_time = process.hrtime()
      var generateLog = _make_generateLog(fn.metricsQueue, func, start_time, config, args[1])

      var end_time = 599900  /* Maximum execution: 100ms short of 5 minutes */
      if (config.timeoutWindow > 0 && args[1] && args[1].getRemainingTimeInMillis) {
        end_time = Math.max(0, args[1].getRemainingTimeInMillis() - config.timeoutWindow)
      }

      var timeout = setTimeout(() => {
        generateLog(new Error("Timeout Exceeded."), function noop() {})
      }, end_time)

      var callback = (err, cb) => {
        clearTimeout(timeout)
        generateLog(err, cb)
      }

      /* Mangle arguments, wrapping callbacks. */
      args[1] = Context(callback, args[1])
      args[2] = Callback(callback, args[2])

      try {
        return func.apply(this, args)
      }
      catch (err) {
        clearTimeout(timeout)
        generateLog(err, function noop() {})
        return undefined
      }
    }
  }

  // Alias decorate to the wrapper function
  fn.decorate = fn

  fn.log = function(name, value) {
    var numberValue, stringValue
    if (typeof value === 'number') {
      numberValue = value
    } else {
      if(typeof value === 'object') {
        JSON.stringify(value)
      } else {
        stringValue = String(value)
      }
    }
    fn.metricsQueue.push({
      name: name,
      n: numberValue,
      s: stringValue
    })
  }

  return fn
}
<commit_msg>Patch, calling super method to get socket first<commit_after>'use strict'

var pkg = require('./package.json')
var Promise = require('bluebird')
var request = require('request')
var os = require('os')
var https = require('https')
var net = require('net')

var system = (process.platform === 'linux') ? require('./src/system.js') : require('./src/mockSystem.js')
var getCollectorUrl = require('./src/collector.js')
var Context = require('./src/context.js')
var Callback = require('./src/callback.js')

const VERSION = pkg.version
const MODULE_LOAD_TIME = Date.now()
const httpsAgent = new https.Agent({
  maxCachedSessions: 1,
  keepAlive: true
});

httpsAgent.originalCreateConnection = httpsAgent.createConnection
httpsAgent.createConnection = function(port, host, options) {
  /* noDelay is documented as defaulting to true, but docs lie.
     this sacrifices throughput for latency and should be faster
     for how we submit data. */
  var socket = httpsAgent.originalCreateConnection(port, host, options);
  socket.setNoDelay(true);
  return socket
}

// Default on module load; changed to false on first handler invocation.
var COLDSTART = true

function _make_generateLog(metrics, func, start_time, config, context) {
  var pre_stat_promise = system.readstat('self')

  return function generateLog(err, callback) {
    Promise.join(
        pre_stat_promise,
        system.readstat('self'),
        system.readstatus('self'),
        system.readbootid()
      ).spread((
        pre_proc_self_stat,
        proc_self_stat,
        proc_self_status,
        boot_id
      ) => {
        var runtime_env = {
          agent: {
            runtime: 'nodejs',
            version: VERSION,
            load_time: MODULE_LOAD_TIME
          },
          host: {
            container_id: boot_id
          },
          os: {
            hostname: os.hostname(),
            uptime: os.uptime(),
            totalmem: os.totalmem(),
            freemem: os.freemem(),
            usedmem: os.totalmem() - os.freemem(),
            cpus: os.cpus(),
            arch: os.arch(),
            linux: {
              pid: {
                self: {
                  stat_start: pre_proc_self_stat,
                  stat: proc_self_stat,
                  status: proc_self_status
                }
              }
            }
          },
          nodejs: {
            title: process.title,
            version: process.version,
            modulesloadList: process.modulesloadList,
            versions: process.versions,
            arch: process.arch,
            platform: process.platform,
            argv: process.argv,
            execArgv: process.execArgv,
            pid: process.pid,
            features: process.features,
            execPath: process.execPath,
            debugPort: process.debugPort,
            _maxListeners: process._maxListeners,
            config: process.config,
            maxTickDepth: process.maxTickDepth,
            // /* Circular ref */ mainModule: process.mainModule,
            release: process.release,
            uptime: process.uptime(),
            getuid: process.getuid(),
            getgid: process.getgid(),
            geteuid: process.geteuid(),
            getegid: process.getegid(),
            memoryUsage: process.memoryUsage(),
          }
        }

        var retainErr = {}
        if (err) {
          retainErr = ((err) => {
            return {
              name: err.name,
              message: err.message,
              stack: err.stack,
              lineNumber: err.lineNumber,
              columnNumber: err.columnNumber,
              fileName: err.fileName
            }
          })((typeof(err) === 'string') ? new Error(err) : err)
        }

        var time_sec_nanosec = process.hrtime(start_time)

        /*
         depreciated fields:
         - time_sec_nanosec (use duration; 11/23/2016)
         - time_sec (use duration; 11/23/2016)
        */
        var response_body = {
          environment: runtime_env,
          aws: {
            functionName: context.functionName,
            functionVersion: context.functionVersion,
            invokedFunctionArn: context.invokedFunctionArn,
            memoryLimitInMB: context.memoryLimitInMB,
            awsRequestId: context.awsRequestId,
            logGroupName: context.logGroupName,
            logStreamName: context.logStreamName
          },
          coldstart: COLDSTART,
          errors: retainErr,
          custom_metrics: metrics,
          time_sec_nanosec: time_sec_nanosec,
          time_sec: time_sec_nanosec[0],
          time_nanosec: time_sec_nanosec[1],
          duration: Math.ceil(time_sec_nanosec[0] * 1000000000.0 + time_sec_nanosec[1]),
          client_id: config.clientId
        }

        if (COLDSTART === true) {
          COLDSTART = false
        }

        if (context.getRemainingTimeInMillis) {
          response_body.aws.getRemainingTimeInMillis = context.getRemainingTimeInMillis()
        }

        if (config.debug) {
          console.log('IOPIPE-DEBUG: ', JSON.stringify(response_body))
        }

        request(
          {
            url: getCollectorUrl(config.url),
            method: 'POST',
            json: true,
            body: response_body,
            agent: httpsAgent,
            timeout: config.networkTimeout,
          },
          function(err) {
            // Log errors, don't block on failed requests
            if (err && config.debug) {
              console.log('Write to IOpipe failed:')
              console.log(err)
            }
            callback()
          }
        )
      }
    )
  }
}

function setConfig(configObject) {
  return {
    url: (configObject && configObject.url) ? configObject.url : '',
    clientId: configObject && (configObject.token || configObject.clientId) || process.env.IOPIPE_TOKEN || process.env.IOPIPE_CLIENTID || '',
    debug: configObject && configObject.debug || process.env.IOPIPE_DEBUG || false,
    networkTimeout: configObject && configObject.networkTimeout || 5000,
    timeoutWindow: configObject && configObject.timeoutWindow || 50
  }
}

module.exports = function(options) {
  var fn = function(func) {
    fn.metricsQueue = []
    const config = setConfig(options)

    if (!config.clientId) {
      // No-op if user doesn't set an IOpipe token.
      return func
    }

    return function() {
      fn.metricsQueue = []
      let args = [].slice.call(arguments)

      var start_time = process.hrtime()
      var generateLog = _make_generateLog(fn.metricsQueue, func, start_time, config, args[1])

      var end_time = 599900  /* Maximum execution: 100ms short of 5 minutes */
      if (config.timeoutWindow > 0 && args[1] && args[1].getRemainingTimeInMillis) {
        end_time = Math.max(0, args[1].getRemainingTimeInMillis() - config.timeoutWindow)
      }

      var timeout = setTimeout(() => {
        generateLog(new Error("Timeout Exceeded."), function noop() {})
      }, end_time)

      var callback = (err, cb) => {
        clearTimeout(timeout)
        generateLog(err, cb)
      }

      /* Mangle arguments, wrapping callbacks. */
      args[1] = Context(callback, args[1])
      args[2] = Callback(callback, args[2])

      try {
        return func.apply(this, args)
      }
      catch (err) {
        clearTimeout(timeout)
        generateLog(err, function noop() {})
        return undefined
      }
    }
  }

  // Alias decorate to the wrapper function
  fn.decorate = fn

  fn.log = function(name, value) {
    var numberValue, stringValue
    if (typeof value === 'number') {
      numberValue = value
    } else {
      if(typeof value === 'object') {
        JSON.stringify(value)
      } else {
        stringValue = String(value)
      }
    }
    fn.metricsQueue.push({
      name: name,
      n: numberValue,
      s: stringValue
    })
  }

  return fn
}
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var app = express();
var PORT = 8081;

app.get('/', function(req, res, next) {
  console.log('request received');
});

app.listen(PORT);
console.log('listening on port ' + PORT);
<commit_msg>Make get route greedy<commit_after>'use strict';

var express = require('express');
var app = express();
var PORT = 8081;

app.get('/*', function(req, res, next) {
  console.log('request received');
});

app.listen(PORT);
console.log('listening on port ' + PORT);
<|endoftext|>


<commit_before>var bcrypt = require('bcrypt')

function verify(value, hash, next) {
    bcrypt.compare(value, hash, function(err, res) {
        if (err)
            return next(err)
        return next(null, res)
    })
}

function set(value, hashField, next) {
    var self = this

    bcrypt.genSalt(10, function(err, salt) {
        if (err)
            return next(err)
        bcrypt.hash(value, salt, function(err, hash) {
            if (err)
                return next(err)

            // Set new hash
            self[hashField] = hash
            return next()
        })
    })
}

function getVerifierForField(fieldName) {
    return function(value, next) {
        bcrypt.compare(value, this[fieldName], function(err, res) {
            if (err)
                return next(err)
            return next(null, res)
        })
    }
}

function getSetterForField(fieldName) {
    return function(value, next) {
        var self = this

        bcrypt.genSalt(10, function(err, salt) {
            if (err)
                return next(err)
            bcrypt.hash(value, salt, function(err, hash) {
                if (err)
                    return next(err)

                // Set new hash
                self[fieldName] = hash
                return next()
            })
        })
    }
}

function setEncryption(schema, options) {
    if (typeof options === 'string') {
        var capitlaizedFieldName = options.charAt(0).toUpperCase() + options.slice(1)

        options = {
            field: options,
            verify: 'verify' + capitlaizedFieldName,
            set: 'set' + capitlaizedFieldName
        }
    }
    schema.methods[options.verify] = getVerifierForField(options.field)
    schema.methods[options.set] = getSetterForField(options.field)
}

module.exports = {
    verify: verify,
    set: set,
    setEncryption: setEncryption,
}

if (process.env.NODE_ENV === 'test') {
    // Export private members
    module.exports = {
        verify: verify,
        set: set,
        setEncryption: setEncryption,
        getSetterForField: getSetterForField,
        getVerifierForField: getVerifierForField
    }
}
<commit_msg>Add saltIterations option<commit_after>var bcrypt = require('bcrypt')

function verify(value, hash, next) {
    bcrypt.compare(value, hash, function(err, res) {
        if (err)
            return next(err)
        return next(null, res)
    })
}

function set(value, hashField, saltIterations, next) {
    var self = this

    if(typeof saltIterations === 'function'){
        next = saltIterations
        saltIterations = 10
    }

    bcrypt.genSalt(saltIterations, function(err, salt) {
        if (err)
            return next(err)
        bcrypt.hash(value, salt, function(err, hash) {
            if (err)
                return next(err)

            // Set new hash
            self[hashField] = hash
            return next()
        })
    })
}

function getVerifierForField(options) {
    return function(value, next) {
        bcrypt.compare(value, this[options.field], function(err, res) {
            if (err)
                return next(err)
            return next(null, res)
        })
    }
}

function getSetterForField(options) {
    return function(value, next) {
        var self = this

        bcrypt.genSalt(options.saltIterations, function(err, salt) {
            if (err)
                return next(err)
            bcrypt.hash(value, salt, function(err, hash) {
                if (err)
                    return next(err)

                // Set new hash
                self[options.field] = hash
                return next()
            })
        })
    }
}

function setEncryption(schema, options) {
    if (typeof options === 'string') {
        var capitlaizedFieldName = options.charAt(0).toUpperCase() + options.slice(1)

        options = {
            field: options,
            verify: 'verify' + capitlaizedFieldName,
            set: 'set' + capitlaizedFieldName,
            saltIterations: 10
        }
    }

    if (!options.saltIterations) {
        options.saltIterations = 10
    }

    schema.methods[options.verify] = getVerifierForField(options)
    schema.methods[options.set] = getSetterForField(options)
}

module.exports = {
    verify: verify,
    set: set,
    setEncryption: setEncryption,
}

if (process.env.NODE_ENV === 'test') {
    // Export private members
    module.exports = {
        verify: verify,
        set: set,
        setEncryption: setEncryption,
        getSetterForField: getSetterForField,
        getVerifierForField: getVerifierForField
    }
}
<|endoftext|>


<commit_before>'use strict'

var util = require('util')
var os = require('os')
var http = require('http')
var EventEmitter = require('events').EventEmitter
var bonjour = require('bonjour')
var ipp = require('ipp-encoder')
var debug = require('debug')(require('./package').name)
var utils = require('./lib/utils')
var groups = require('./lib/groups')
var operations = require('./lib/operations')
var Request = require('./lib/request')

var C = ipp.CONSTANTS

module.exports = Printer

function Printer (opts) {
  if (!(this instanceof Printer)) return new Printer(opts)
  if (!opts) opts = { name: 'Node JS' }
  else if (typeof opts === 'string') opts = { name: opts }

  EventEmitter.call(this)

  this.started = Date.now()
  this.jobs = []
  this._jobId = 0
  this.name = opts.name
  this.attributes = [
    { tag: C.URI, name: 'printer-uri-supported', value: this.uri },
    { tag: C.KEYWORD, name: 'uri-security-supported', value: 'none' }, // none, ssl3, tls
    { tag: C.KEYWORD, name: 'uri-authentication-supported', value: 'none' }, // none, requesting-user-name, basic, digest, certificate
    { tag: C.NAME_WITH_LANG, name: 'printer-name', value: this.name },
    { tag: C.ENUM, name: 'printer-state', value: C.PRINTER_IDLE },
    { tag: C.KEYWORD, name: 'printer-state-reasons', value: 'none' },
    { tag: C.KEYWORD, name: 'ipp-versions-supported', value: '1.1' }, // 1.0, 1.1
    { tag: C.ENUM, name: 'operations-supported', values: [C.PRINT_JOB, C.VALIDATE_JOB, C.GET_JOBS, C.GET_PRINTER_ATTRIBUTES, C.CANCEL_JOB, C.GET_JOB_ATTRIBUTES] }, // C.PRINT_JOB, C.PRINT_URI, C.VALIDATE_JOB, C.CREATE_JOB, C.SEND_DOCUMENT, C.SEND_URI, C.CANCEL_JOB, C.GET_JOB_ATTRIBUTES, C.GET_JOBS, C.GET_PRINTER_ATTRIBUTES, C.HOLD_JOB, C.RELEASE_JOB, C.RESTART_JOB, C.PAUSE_PRINTER, C.RESUME_PRINTER, C.PURGE_JOBS
    { tag: C.CHARSET, name: 'charset-configured', value: 'utf-8' },
    { tag: C.CHARSET, name: 'charset-supported', value: 'utf-8' },
    { tag: C.NATURAL_LANG, name: 'natural-language-configured', value: 'en-us' },
    { tag: C.NATURAL_LANG, name: 'generated-natural-language-supported', value: 'en-us' },
    { tag: C.MIME_MEDIA_TYPE, name: 'document-format-default', value: 'application/postscript' },
    { tag: C.MIME_MEDIA_TYPE, name: 'document-format-supported', values: ['text/html', 'text/plain', 'application/vnd.hp-PCL', 'application/octet-stream', 'application/pdf', 'application/postscript'] },
    { tag: C.BOOLEAN, name: 'printer-is-accepting-jobs', value: true },
    { tag: C.INTEGER, name: 'queued-job-count', value: jobCount },
    { tag: C.KEYWORD, name: 'pdl-override-supported', value: 'not-attempted' }, // attempted, not-attempted
    { tag: C.INTEGER, name: 'printer-up-time', value: utils.time.bind(null, this) },
    { tag: C.KEYWORD, name: 'compression-supported', value: 'none' } // none, deflate, gzip, compress
  ]

  var self = this

  this.server = http.createServer(function handleRequest (req, res) {
    debug('incoming request: %s %s', req.method, req.url)

    if (req.method !== 'POST') {
      res.writeHead(405)
      res.end()
      return
    } else if (req.headers['content-type'] !== 'application/ipp') {
      res.writeHead(400)
      res.end()
      return
    }

    var body

    req.on('data', onData)
    req.on('end', onEnd)

    function onData (chunk) {
      body = body ? Buffer.concat([body, chunk]) : chunk

      try {
        body = ipp.request.decode(body)
      } catch (e) {
        debug('incomplete IPP body - waiting for more data...')
        return
      }

      var ippRequest = new Request(body)

      if (body.data.length) {
        debug('writing %d left over bytes to ippRequest', body.data.length)
        ippRequest.write(body.data)
      }

      req.removeListener('data', onData)
      req.removeListener('end', onEnd)
      req.on('end', ippRequest.end.bind(ippRequest))
      req.pipe(ippRequest)

      self.emit('request', ippRequest)
      router(self, ippRequest, res)
    }

    function onEnd () {
      self.emit('error', new Error('Malformed IPP request'))
    }
  })

  this.server.listen(opts.port, function () {
    self.port = self.server.address().port
    debug('IPP printer "%s" listening on port %s', self.name, self.port)
    bonjour.tcp.publish({ type: 'ipp', port: self.port, name: self.name })
  })

  function jobCount () {
    return self.jobs.length
  }
}

util.inherits(Printer, EventEmitter)

Printer.prototype.uri = function () {
  return 'ipp://' + os.hostname() + '.:' + this.port + '/'
}

Printer.prototype.getJob = function (id) {
  for (var i = 0, l = this.jobs.length; i < l; i++) {
    if (this.jobs[i].id === id) return this.jobs[i]
  }
}

function router (printer, req, res) {
  debug('new IPP request %d (operation: %d)', req.requestId, req.operationId, util.inspect(req.groups, { depth: null }))

  res.send = send.bind(null, req, res)

  if (req.version.major !== 1) return res.send(C.SERVER_ERROR_VERSION_NOT_SUPPORTED)

  switch (req.operationId) {
    // Printer Operations
    case C.PRINT_JOB: return operations.printJob(printer, req, res)
    case C.VALIDATE_JOB: return operations.validateJob(printer, req, res)
    case C.GET_PRINTER_ATTRIBUTES: return operations.getPrinterAttributes(printer, req, res)
    case C.GET_JOBS: return operations.getJobs(printer, req, res)
    case C.PRINT_URI:
    case C.CREATE_JOB:
    case C.PAUSE_PRINTER:
    case C.RESUME_PRINTER:
    case C.PURGE_JOBS: return printer.emit('error', new Error('Unsupported operation id: ' + req.operationId))

    // Job Operations
    case C.CANCEL_JOB: return operations.cancelJob(printer, req, res)
    case C.GET_JOB_ATTRIBUTES: return operations.getJobAttributes(printer, req, res)
    case C.SEND_DOCUMENT:
    case C.SEND_URI:
    case C.HOLD_JOB:
    case C.RELEASE_JOB:
    case C.RESTART_JOB: return printer.emit('error', new Error('Unsupported operation id: ' + req.operationId))

    default: return printer.emit('error', new Error('Unknown operation id: ' + req.operationId))
  }
}

function send (req, res, statusCode, _groups) {
  if (typeof statusCode === 'object') return send(req, res, C.SUCCESSFUL_OK, statusCode)
  if (statusCode === undefined) statusCode = C.SUCCESSFUL_OK

  var obj = {}
  obj.statusCode = statusCode
  obj.requestId = req.requestId
  obj.groups = [groups.operationAttributesTag(ipp.STATUS_CODES[statusCode])]
  if (_groups) obj.groups = obj.groups.concat(_groups)

  var buf = ipp.response.encode(obj)

  res.writeHead(200, {
    'Content-Length': buf.length,
    'Content-Type': 'application/ipp'
  })

  res.end(buf)
}
<commit_msg>Output IPP response when in DEBUG mode<commit_after>'use strict'

var util = require('util')
var os = require('os')
var http = require('http')
var EventEmitter = require('events').EventEmitter
var bonjour = require('bonjour')
var ipp = require('ipp-encoder')
var debug = require('debug')(require('./package').name)
var utils = require('./lib/utils')
var groups = require('./lib/groups')
var operations = require('./lib/operations')
var Request = require('./lib/request')

var C = ipp.CONSTANTS

module.exports = Printer

function Printer (opts) {
  if (!(this instanceof Printer)) return new Printer(opts)
  if (!opts) opts = { name: 'Node JS' }
  else if (typeof opts === 'string') opts = { name: opts }

  EventEmitter.call(this)

  this.started = Date.now()
  this.jobs = []
  this._jobId = 0
  this.name = opts.name
  this.attributes = [
    { tag: C.URI, name: 'printer-uri-supported', value: this.uri },
    { tag: C.KEYWORD, name: 'uri-security-supported', value: 'none' }, // none, ssl3, tls
    { tag: C.KEYWORD, name: 'uri-authentication-supported', value: 'none' }, // none, requesting-user-name, basic, digest, certificate
    { tag: C.NAME_WITH_LANG, name: 'printer-name', value: this.name },
    { tag: C.ENUM, name: 'printer-state', value: C.PRINTER_IDLE },
    { tag: C.KEYWORD, name: 'printer-state-reasons', value: 'none' },
    { tag: C.KEYWORD, name: 'ipp-versions-supported', value: '1.1' }, // 1.0, 1.1
    { tag: C.ENUM, name: 'operations-supported', values: [C.PRINT_JOB, C.VALIDATE_JOB, C.GET_JOBS, C.GET_PRINTER_ATTRIBUTES, C.CANCEL_JOB, C.GET_JOB_ATTRIBUTES] }, // C.PRINT_JOB, C.PRINT_URI, C.VALIDATE_JOB, C.CREATE_JOB, C.SEND_DOCUMENT, C.SEND_URI, C.CANCEL_JOB, C.GET_JOB_ATTRIBUTES, C.GET_JOBS, C.GET_PRINTER_ATTRIBUTES, C.HOLD_JOB, C.RELEASE_JOB, C.RESTART_JOB, C.PAUSE_PRINTER, C.RESUME_PRINTER, C.PURGE_JOBS
    { tag: C.CHARSET, name: 'charset-configured', value: 'utf-8' },
    { tag: C.CHARSET, name: 'charset-supported', value: 'utf-8' },
    { tag: C.NATURAL_LANG, name: 'natural-language-configured', value: 'en-us' },
    { tag: C.NATURAL_LANG, name: 'generated-natural-language-supported', value: 'en-us' },
    { tag: C.MIME_MEDIA_TYPE, name: 'document-format-default', value: 'application/postscript' },
    { tag: C.MIME_MEDIA_TYPE, name: 'document-format-supported', values: ['text/html', 'text/plain', 'application/vnd.hp-PCL', 'application/octet-stream', 'application/pdf', 'application/postscript'] },
    { tag: C.BOOLEAN, name: 'printer-is-accepting-jobs', value: true },
    { tag: C.INTEGER, name: 'queued-job-count', value: jobCount },
    { tag: C.KEYWORD, name: 'pdl-override-supported', value: 'not-attempted' }, // attempted, not-attempted
    { tag: C.INTEGER, name: 'printer-up-time', value: utils.time.bind(null, this) },
    { tag: C.KEYWORD, name: 'compression-supported', value: 'none' } // none, deflate, gzip, compress
  ]

  var self = this

  this.server = http.createServer(function handleRequest (req, res) {
    debug('incoming request: %s %s', req.method, req.url)

    if (req.method !== 'POST') {
      res.writeHead(405)
      res.end()
      return
    } else if (req.headers['content-type'] !== 'application/ipp') {
      res.writeHead(400)
      res.end()
      return
    }

    var body

    req.on('data', onData)
    req.on('end', onEnd)

    function onData (chunk) {
      body = body ? Buffer.concat([body, chunk]) : chunk

      try {
        body = ipp.request.decode(body)
      } catch (e) {
        debug('incomplete IPP body - waiting for more data...')
        return
      }

      var ippRequest = new Request(body)

      if (body.data.length) {
        debug('writing %d left over bytes to ippRequest', body.data.length)
        ippRequest.write(body.data)
      }

      req.removeListener('data', onData)
      req.removeListener('end', onEnd)
      req.on('end', ippRequest.end.bind(ippRequest))
      req.pipe(ippRequest)

      self.emit('request', ippRequest)
      router(self, ippRequest, res)
    }

    function onEnd () {
      self.emit('error', new Error('Malformed IPP request'))
    }
  })

  this.server.listen(opts.port, function () {
    self.port = self.server.address().port
    debug('IPP printer "%s" listening on port %s', self.name, self.port)
    bonjour.tcp.publish({ type: 'ipp', port: self.port, name: self.name })
  })

  function jobCount () {
    return self.jobs.length
  }
}

util.inherits(Printer, EventEmitter)

Printer.prototype.uri = function () {
  return 'ipp://' + os.hostname() + '.:' + this.port + '/'
}

Printer.prototype.getJob = function (id) {
  for (var i = 0, l = this.jobs.length; i < l; i++) {
    if (this.jobs[i].id === id) return this.jobs[i]
  }
}

function router (printer, req, res) {
  debug('new IPP request %d (operation: %d)', req.requestId, req.operationId, util.inspect(req.groups, { depth: null }))

  res.send = send.bind(null, req, res)

  if (req.version.major !== 1) return res.send(C.SERVER_ERROR_VERSION_NOT_SUPPORTED)

  switch (req.operationId) {
    // Printer Operations
    case C.PRINT_JOB: return operations.printJob(printer, req, res)
    case C.VALIDATE_JOB: return operations.validateJob(printer, req, res)
    case C.GET_PRINTER_ATTRIBUTES: return operations.getPrinterAttributes(printer, req, res)
    case C.GET_JOBS: return operations.getJobs(printer, req, res)
    case C.PRINT_URI:
    case C.CREATE_JOB:
    case C.PAUSE_PRINTER:
    case C.RESUME_PRINTER:
    case C.PURGE_JOBS: return printer.emit('error', new Error('Unsupported operation id: ' + req.operationId))

    // Job Operations
    case C.CANCEL_JOB: return operations.cancelJob(printer, req, res)
    case C.GET_JOB_ATTRIBUTES: return operations.getJobAttributes(printer, req, res)
    case C.SEND_DOCUMENT:
    case C.SEND_URI:
    case C.HOLD_JOB:
    case C.RELEASE_JOB:
    case C.RESTART_JOB: return printer.emit('error', new Error('Unsupported operation id: ' + req.operationId))

    default: return printer.emit('error', new Error('Unknown operation id: ' + req.operationId))
  }
}

function send (req, res, statusCode, _groups) {
  if (typeof statusCode === 'object') return send(req, res, C.SUCCESSFUL_OK, statusCode)
  if (statusCode === undefined) statusCode = C.SUCCESSFUL_OK

  var obj = {}
  obj.statusCode = statusCode
  obj.requestId = req.requestId
  obj.groups = [groups.operationAttributesTag(ipp.STATUS_CODES[statusCode])]
  if (_groups) obj.groups = obj.groups.concat(_groups)

  var buf = ipp.response.encode(obj)

  res.writeHead(200, {
    'Content-Length': buf.length,
    'Content-Type': 'application/ipp'
  })

  debug('responding to request %d', req.requestId, util.inspect(obj, { depth: null }))
  res.end(buf)
}
<|endoftext|>