<commit_before>/* -*- Mode: Javascript; js-indent-level: 2 -*- */

var async = require('async');
var naan = require('naan');
var _ = require('underscore');
var util = require('util');

var node = module.exports = {
  /**
   * Save or update an object. If a new object is passed, the callback will
   * return a copy of that object with the <options.id> key set to the id of the
   * created object.
   */
  save: function(obj, key, val, callback) {
    if (typeof key == 'function') {
      callback = key;
      key = val = undefined;
    }

    if (Array.isArray(obj)) {
      var txn = this._safeBatch();
      var args = [key, val];
      async.map(obj, naan.ecurry(txn.save, args, [1, 2]), callback);
      return this._safeBatchCommit(txn);
    }

    var id = this._getId(obj, !key);

    if (!this._isValidId(id)) {
      if (typeof obj !== 'object') {
        return callback(new Error("No data to save"));
      }

      this.node._create(obj, callback);
    } else {
      if (key) this.node._updateProp(obj, key, val, callback);
      else this.node._update(obj, callback);
    }
  },

  /**
   * Create a new object. Maps to /node.
   */
  _create: function(obj, callback) {
    var op = this.operation('node', obj);
    this.call(op, function(err, body, location) {
      if (err) {
        return callback(err);
      }

      var result = _.clone(obj);
      result[this.options.id] = this._extractId(location);

      callback(null, result);
    });
  },

  /**
   * Save the properties of an object. Maps to PUT /node/{id}/properties.
   */
  _update: function(obj, callback) {
    var id = this._getId(obj, true);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var untouchedObj = _.clone(obj);
    if (untouchedObj[this.options.id] != null) {
      delete untouchedObj[this.options.id];
    }

    var endpoint = util.format('%s/properties', this._nodeRoot(id));
    var op = this.operation(endpoint, 'PUT', untouchedObj);
    this.call(op, function(err, body, response) {
      if (err) {
        return callback(err);
      } else {
        return callback(null, obj);
      }
    });
  },

  _updateProp: function(obj, key, val, callback) {
    var id = this._getId(obj);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint = util.format('%s/properties/%s', this._nodeRoot(id), key);
    var op = this.operation(endpoint, 'PUT', val);
    this.call(op, function(err, body) {
      if (err) return callback(err);
      else {
        obj = _.clone(obj);
        obj[key] = val;
        callback(null, obj);
      }
    });
  },

  /**
   * Read an object's properties. Maps to GET node/{id}/properties.
   */
  read: function(id, property, callback) {
    if (typeof property == 'function') {
      callback = property;
      property = null;
    }

    if (Array.isArray(id)) {
      var txn = this._safeBatch();
      async.map(id, naan.ncurry(txn.read, property, 1), callback);
      return this._safeBatchCommit(txn);
    }

    id = this._getId(id);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint;
    if (!property)
      endpoint = util.format('%s/properties', this._nodeRoot(id));
    else
      endpoint = util.format('%s/properties/%s', this._nodeRoot(id), property);
    var op = this.operation(endpoint);
    this.call(op, function(err, body) {
      if (err) {
        return callback(err);
      } else {
        if (!property) body[this.options.id] = id;
        return callback(null, body);
      }
    });
  },

  /**
   * Delete an object. Maps to DELETE node/{id}
   * If force is truthy, delete node and all its relations.
   */
  delete: function(id, force, callback) {
    var property = null;
    if (typeof force == 'function') {
      callback = force;
      force = false;
    } else if (typeof force == 'string') {
      property = force;
      force = false;
    }

    if (Array.isArray(id)) {
      var txn = this._safeBatch();
      async.map(id, naan.ncurry(txn.node.delete, force || property, 1), callback);
      return this._safeBatchCommit(txn);
    }

    var object = id;
    id = this._getId(id);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    if (!force) {
      var endpoint;
      if (!property) endpoint = this._nodeRoot(id);
      else
        endpoint = util.format('%s/properties/%s', this._nodeRoot(id), property);
      var op = this.operation(endpoint, 'DELETE');
      this.call(op, function(err) {
        if (!property || err || typeof object != 'object') callback(err);
        else {
          delete object[property];
          callback(null, object);
        }
      });
    } else {
      this.query([
        'START node=node({root})',
        'MATCH node-[rel?]-()',
        'DELETE node, rel'
      ].join(' '), {root: id}, function(err) { callback(err) });
    }
  },

  /**
   * Relate objects together. maps to POST node/{first}/relationships
   */
  relate: function(startNode, type, endNode, properties, callback) {
    this.rel.create(startNode, type, endNode, properties, callback);
  },

  /**
   * Retrieve a set of relationships for the given node. Optionally specify the
   * direction and relationship name.
   *
   * `direction` must be one of "all", "in" or "out".
   *
   * db.relationships(obj|id, [direction, [relationshipName]], callback)
   */
  relationships: function(obj, direction, relName, callback) {
    if (typeof direction === 'function') {
      callback = direction;
      direction = 'all';
      relName = '';
    } else {
      if (typeof relName === 'function') {
        callback = relName;
        relName = '';
      }

      if (typeof direction !== 'string') {
        return callback(new Error('Invalid direction - ' + direction));
      } else if (typeof relName !== 'string') {
        return callback(new Error('Invalid relationship name - ' + relName));
      }

      direction = direction.toLowerCase();
      if (['in', 'all', 'out'].indexOf(direction) === -1) {
        return callback(new Error('Invalid direction - ' + direction));
      }
    }

    if (Array.isArray(obj)) {
      var txn = this._safeBatch();
      var args = [ direction, relName ];
      var rels = naan.ecurry(txn.node.relationships, args, [1, 2]);
      async.map(obj, rels, callback);
      return this._safeBatchCommit(txn);
    }

    var objId = this._getId(obj);

    if (!this._isValidId(objId)) {
      callback(new Error("Invalid ID"));
    }

    var nodeRoot = this._nodeRoot(objId);
    var endpoint = util.format('%s/relationships/%s', nodeRoot, direction);
    if (relName) {
      endpoint += "/" + relName;
    }
    var op = this.operation(endpoint);
    var self = this;
    this.call(op, function(err, rels) {
      if (err) {
        callback(err);
      } else {
        rels = rels.map(function(rel) {
          return self._createRelationshipObject(rel);
        });
        callback(null, rels);
      }
    });
  },

  /**
   * Perform a query based on a predicate. The predicate is translated to a
   * cypher query.
   */
  find: function(predicate, any, start, callback) {
    if (typeof any === 'function') {
      callback = any;
      any = false;
      start = 'node(*)';
    } else if (typeof start === 'function') {
      callback = start;
      start = 'node(*)';
    }

    if (Array.isArray(predicate)) {
      var txn = this._safeBatch();
      var finder = naan.ecurry(txn.node.find, [any, start], [1, 2]);
      async.map(predicate, finder, callback);
      return this._safeBatchCommit(txn);
    }

    if (typeof predicate !== 'object') {
      callback(new Error('Invalid Predicate'));
    }

    var matchers = Object.keys(predicate).reduce(function(matchers, key) {
      return matchers.push(util.format(" (n.%s = {%s}) ", key, key)), matchers;
    }, []);

    var cypher = [
      "START n = " + start + " WHERE",
      matchers.join(any ? "or" : "and"),
      "RETURN n"
    ].join(" ");

    var self = this;
    this.query(cypher, predicate, callback);
  },

  saveUnique: function(node, index, key, value, returnExistingOnConflict, cb) {
    if (typeof returnExistingOnConflict == 'function') {
      cb = returnExistingOnConflict;
      returnExistingOnConflict = false;
    }

    if (returnExistingOnConflict) {
      this.node.index.getOrSaveUnique(node, index, key, value, cb);
    } else {
      this.node.index.saveUniqueOrFail(node, index, key, value, cb);
    }
  },

  label: function(node, label, callback) {
    if (Array.isArray(node)) {
      var txn = this._safeBatch();
      var args = [key, val];
      async.map(obj, naan.ncurry(txn.save, label, 1), callback);
      return this._safeBatchCommit(txn);
    }

    var id = this._getId(node);

    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint = util.format('%s/labels', this._nodeRoot(id));
    var op = this.operation(endpoint, 'POST', label);
    this.call(function(err) {
      if (err) callback(err);
      else callback();
    });
  },

  nodesWithLabel: function(label, callback) {
    var endpoint = util.format('label/%s', label);
    var op = this.operation(endpoint, 'GET');
    this.call(op, function(err, nodes) {
      if (err || !nodes) return callback(err, nodes);
      nodes = nodes.map(this._createNodeObject);
      callback(null, nodes);
    });
  }
}
<commit_msg>labels: supply operation to call on label save<commit_after>/* -*- Mode: Javascript; js-indent-level: 2 -*- */

var async = require('async');
var naan = require('naan');
var _ = require('underscore');
var util = require('util');

var node = module.exports = {
  /**
   * Save or update an object. If a new object is passed, the callback will
   * return a copy of that object with the <options.id> key set to the id of the
   * created object.
   */
  save: function(obj, key, val, callback) {
    if (typeof key == 'function') {
      callback = key;
      key = val = undefined;
    }

    if (Array.isArray(obj)) {
      var txn = this._safeBatch();
      var args = [key, val];
      async.map(obj, naan.ecurry(txn.save, args, [1, 2]), callback);
      return this._safeBatchCommit(txn);
    }

    var id = this._getId(obj, !key);

    if (!this._isValidId(id)) {
      if (typeof obj !== 'object') {
        return callback(new Error("No data to save"));
      }

      this.node._create(obj, callback);
    } else {
      if (key) this.node._updateProp(obj, key, val, callback);
      else this.node._update(obj, callback);
    }
  },

  /**
   * Create a new object. Maps to /node.
   */
  _create: function(obj, callback) {
    var op = this.operation('node', obj);
    this.call(op, function(err, body, location) {
      if (err) {
        return callback(err);
      }

      var result = _.clone(obj);
      result[this.options.id] = this._extractId(location);

      callback(null, result);
    });
  },

  /**
   * Save the properties of an object. Maps to PUT /node/{id}/properties.
   */
  _update: function(obj, callback) {
    var id = this._getId(obj, true);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var untouchedObj = _.clone(obj);
    if (untouchedObj[this.options.id] != null) {
      delete untouchedObj[this.options.id];
    }

    var endpoint = util.format('%s/properties', this._nodeRoot(id));
    var op = this.operation(endpoint, 'PUT', untouchedObj);
    this.call(op, function(err, body, response) {
      if (err) {
        return callback(err);
      } else {
        return callback(null, obj);
      }
    });
  },

  _updateProp: function(obj, key, val, callback) {
    var id = this._getId(obj);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint = util.format('%s/properties/%s', this._nodeRoot(id), key);
    var op = this.operation(endpoint, 'PUT', val);
    this.call(op, function(err, body) {
      if (err) return callback(err);
      else {
        obj = _.clone(obj);
        obj[key] = val;
        callback(null, obj);
      }
    });
  },

  /**
   * Read an object's properties. Maps to GET node/{id}/properties.
   */
  read: function(id, property, callback) {
    if (typeof property == 'function') {
      callback = property;
      property = null;
    }

    if (Array.isArray(id)) {
      var txn = this._safeBatch();
      async.map(id, naan.ncurry(txn.read, property, 1), callback);
      return this._safeBatchCommit(txn);
    }

    id = this._getId(id);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint;
    if (!property)
      endpoint = util.format('%s/properties', this._nodeRoot(id));
    else
      endpoint = util.format('%s/properties/%s', this._nodeRoot(id), property);
    var op = this.operation(endpoint);
    this.call(op, function(err, body) {
      if (err) {
        return callback(err);
      } else {
        if (!property) body[this.options.id] = id;
        return callback(null, body);
      }
    });
  },

  /**
   * Delete an object. Maps to DELETE node/{id}
   * If force is truthy, delete node and all its relations.
   */
  delete: function(id, force, callback) {
    var property = null;
    if (typeof force == 'function') {
      callback = force;
      force = false;
    } else if (typeof force == 'string') {
      property = force;
      force = false;
    }

    if (Array.isArray(id)) {
      var txn = this._safeBatch();
      async.map(id, naan.ncurry(txn.node.delete, force || property, 1), callback);
      return this._safeBatchCommit(txn);
    }

    var object = id;
    id = this._getId(id);
    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    if (!force) {
      var endpoint;
      if (!property) endpoint = this._nodeRoot(id);
      else
        endpoint = util.format('%s/properties/%s', this._nodeRoot(id), property);
      var op = this.operation(endpoint, 'DELETE');
      this.call(op, function(err) {
        if (!property || err || typeof object != 'object') callback(err);
        else {
          delete object[property];
          callback(null, object);
        }
      });
    } else {
      this.query([
        'START node=node({root})',
        'MATCH node-[rel?]-()',
        'DELETE node, rel'
      ].join(' '), {root: id}, function(err) { callback(err) });
    }
  },

  /**
   * Relate objects together. maps to POST node/{first}/relationships
   */
  relate: function(startNode, type, endNode, properties, callback) {
    this.rel.create(startNode, type, endNode, properties, callback);
  },

  /**
   * Retrieve a set of relationships for the given node. Optionally specify the
   * direction and relationship name.
   *
   * `direction` must be one of "all", "in" or "out".
   *
   * db.relationships(obj|id, [direction, [relationshipName]], callback)
   */
  relationships: function(obj, direction, relName, callback) {
    if (typeof direction === 'function') {
      callback = direction;
      direction = 'all';
      relName = '';
    } else {
      if (typeof relName === 'function') {
        callback = relName;
        relName = '';
      }

      if (typeof direction !== 'string') {
        return callback(new Error('Invalid direction - ' + direction));
      } else if (typeof relName !== 'string') {
        return callback(new Error('Invalid relationship name - ' + relName));
      }

      direction = direction.toLowerCase();
      if (['in', 'all', 'out'].indexOf(direction) === -1) {
        return callback(new Error('Invalid direction - ' + direction));
      }
    }

    if (Array.isArray(obj)) {
      var txn = this._safeBatch();
      var args = [ direction, relName ];
      var rels = naan.ecurry(txn.node.relationships, args, [1, 2]);
      async.map(obj, rels, callback);
      return this._safeBatchCommit(txn);
    }

    var objId = this._getId(obj);

    if (!this._isValidId(objId)) {
      callback(new Error("Invalid ID"));
    }

    var nodeRoot = this._nodeRoot(objId);
    var endpoint = util.format('%s/relationships/%s', nodeRoot, direction);
    if (relName) {
      endpoint += "/" + relName;
    }
    var op = this.operation(endpoint);
    var self = this;
    this.call(op, function(err, rels) {
      if (err) {
        callback(err);
      } else {
        rels = rels.map(function(rel) {
          return self._createRelationshipObject(rel);
        });
        callback(null, rels);
      }
    });
  },

  /**
   * Perform a query based on a predicate. The predicate is translated to a
   * cypher query.
   */
  find: function(predicate, any, start, callback) {
    if (typeof any === 'function') {
      callback = any;
      any = false;
      start = 'node(*)';
    } else if (typeof start === 'function') {
      callback = start;
      start = 'node(*)';
    }

    if (Array.isArray(predicate)) {
      var txn = this._safeBatch();
      var finder = naan.ecurry(txn.node.find, [any, start], [1, 2]);
      async.map(predicate, finder, callback);
      return this._safeBatchCommit(txn);
    }

    if (typeof predicate !== 'object') {
      callback(new Error('Invalid Predicate'));
    }

    var matchers = Object.keys(predicate).reduce(function(matchers, key) {
      return matchers.push(util.format(" (n.%s = {%s}) ", key, key)), matchers;
    }, []);

    var cypher = [
      "START n = " + start + " WHERE",
      matchers.join(any ? "or" : "and"),
      "RETURN n"
    ].join(" ");

    var self = this;
    this.query(cypher, predicate, callback);
  },

  saveUnique: function(node, index, key, value, returnExistingOnConflict, cb) {
    if (typeof returnExistingOnConflict == 'function') {
      cb = returnExistingOnConflict;
      returnExistingOnConflict = false;
    }

    if (returnExistingOnConflict) {
      this.node.index.getOrSaveUnique(node, index, key, value, cb);
    } else {
      this.node.index.saveUniqueOrFail(node, index, key, value, cb);
    }
  },

  label: function(node, label, callback) {
    if (Array.isArray(node)) {
      var txn = this._safeBatch();
      var args = [key, val];
      async.map(obj, naan.ncurry(txn.save, label, 1), callback);
      return this._safeBatchCommit(txn);
    }

    var id = this._getId(node);

    if (!this._isValidId(id)) {
      return callback(new Error("Invalid ID"));
    }

    var endpoint = util.format('%s/labels', this._nodeRoot(id));
    var op = this.operation(endpoint, 'POST', label);
    this.call(op, function(err) {
      if (err) callback(err);
      else callback();
    });
  },

  nodesWithLabel: function(label, callback) {
    var endpoint = util.format('label/%s', label);
    var op = this.operation(endpoint, 'GET');
    this.call(op, function(err, nodes) {
      if (err || !nodes) return callback(err, nodes);
      nodes = nodes.map(this._createNodeObject);
      callback(null, nodes);
    });
  }
}
<|endoftext|>


<commit_before>import { EventTargetAssembler } from './eventtarget'
import { Node } from './core'

/**
 * Node DOM interface assembler
 */
export class NodeAssembler extends EventTargetAssembler {
    /**
     * @param {*} init
     * @returns {Node|*}
     */
    assemble(init) {
        if(init && init.constructor === Object && init.node instanceof Node) {
            this.init(init)
        }
        else super.assemble(init)
        return this.node
    }

    /**
     * @param {Node|*} node
     */
    set node(node) {
        const { domInterface, name } = this.constructor
        if(node instanceof domInterface) this.setInstance(node)
        else {
            const message = `Failed to set 'node' on '${ name }': parameter is not of expected type.`
            throw TypeError(message)
        }
    }

    /**
     * @returns {Node|*}
     */
    get node() {
        return this._target
    }

    /**
     * @returns {Function}
     */
    static get domInterface() {
        return Node
    }
}
<commit_msg>NodeAssembler: set init.node first, don't set it twice<commit_after>import { EventTargetAssembler } from './eventtarget'
import { Node } from './core'

/**
 * Node DOM interface assembler
 */
export class NodeAssembler extends EventTargetAssembler {
    /**
     * @param {*} init
     * @returns {Node|*}
     */
    assemble(init) {
        if(init && init.constructor === Object && init.node instanceof Node) {
            this.node = init.node
            this.init(init)
        }
        else super.assemble(init)
        return this.node
    }

    /**
     * @param {Node|*} node
     */
    set node(node) {
        if(node !== this.node) {
            const { domInterface, name } = this.constructor
            if(node instanceof domInterface) this.setInstance(node)
            else {
                const message = `Failed to set 'node' on '${ name }': parameter is not of expected type.`
                throw TypeError(message)
            }
        }
    }

    /**
     * @returns {Node|*}
     */
    get node() {
        return this._target
    }

    /**
     * @returns {Function}
     */
    static get domInterface() {
        return Node
    }
}
<|endoftext|>


<commit_before>'use strict';

const Client = require('ssh2').Client;
const path = require('path');
const Promise = require('bluebird');

const utils = require('./utils');

const emptyFunc = () => {};

module.exports = class Node {
  constructor(nodeinfo, interval=1000) {
    /* istanbul ignore next */
    if (!nodeinfo) throw new Error('Node object requires at least one argument.')

    this.nodeinfo = nodeinfo;
    this.conn = new Client();
    this.interval = interval;
  }

  watchStats(cb=emptyFunc, delay=undefined) {
    setTimeout(async () => {
      this.stats = {
        gpu: await this._module.getGPUUsage(this.conn),
        cpu: await this._module.getCPUUsage(this.conn),
        memory: await this._module.getMemory(this.conn),
        uptime: await this._module.getUptime(this.conn)
      }
      cb(this.stats);

      this.watchStats(cb, this.interval);
    }, delay ? delay : this.interval);
  }

  connect() {
    this.conn.connect(this.nodeinfo);

    return new Promise((resolve, reject) => {
      this.conn.on('ready', () => {
        this._module = require(path.join(__dirname, 'os', 'linux'));
        resolve();
      })
    })
  }

  getHostname() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getHostname(this.conn);
  }

  getOS() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getOS(this.conn);
  }

  getCPUUsage() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getCPUUsage(this.conn);
  }

  getGPUs() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getGPUs(this.conn);
  }

  getCPUs() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getCPUs(this.conn);
  }

  getInfo() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getInfo(this.conn)
      .then((info) => {
        this.info = info;
        return info;
      });
  }

  getUptime() {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getUptime(this.conn);
  }

  sshExec(cmd) {
    /* istanbul ignore next */
    if (!this._module) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return utils.sshExec(this.conn, cmd);
  }

  close() {
    return new Promise((resolve, reject) => {
      this.conn.on('close', (error) => {
        if (error) return reject(new Error('Unable to close connection.'));

        resolve();
      })

      this.conn.end();
    })
  }
}<commit_msg>update<commit_after>'use strict';

const Client = require('ssh2').Client;
const path = require('path');
const Promise = require('bluebird');

const utils = require('./utils');

const emptyFunc = () => {};

module.exports = class Node {
  constructor(nodeinfo, interval=1000) {
    /* istanbul ignore next */
    if (!nodeinfo) throw new Error('Node object requires at least one argument.')

    this._isConnected = false;
    this.nodeinfo = nodeinfo;
    this.conn = new Client();
    this.interval = interval;
  }

  watchStats(cb=emptyFunc, delay=undefined) {
    if (!this._isConnected) return;

    setTimeout(async () => {
      this.stats = {
        gpu: await this._module.getGPUUsage(this.conn),
        cpu: await this._module.getCPUUsage(this.conn),
        memory: await this._module.getMemory(this.conn),
        uptime: await this._module.getUptime(this.conn)
      }
      cb(this.stats);

      this.watchStats(cb, this.interval);
    }, delay ? delay : this.interval);
  }

  connect() {
    this.conn.connect(this.nodeinfo);

    return new Promise((resolve, reject) => {
      this.conn.on('ready', () => {
        this._isConnected = true;
        this._module = require(path.join(__dirname, 'os', 'linux'));
        resolve();
      })
    })
  }

  getHostname() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getHostname(this.conn);
  }

  getOS() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getOS(this.conn);
  }

  getCPUUsage() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getCPUUsage(this.conn);
  }

  getGPUs() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getGPUs(this.conn);
  }

  getCPUs() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getCPUs(this.conn);
  }

  getInfo() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getInfo(this.conn)
      .then((info) => {
        this.info = info;
        return info;
      });
  }

  getUptime() {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return this._module.getUptime(this.conn);
  }

  sshExec(cmd) {
    /* istanbul ignore next */
    if (!this._isConnected) throw Error('SSH connection is not opened yet. Call connect() to open.');

    return utils.sshExec(this.conn, cmd);
  }

  close() {
    return new Promise((resolve, reject) => {
      this.conn.on('close', (error) => {
        if (error) return reject(new Error('Unable to close connection.'));
        this._isConnected = false;
        resolve();
      })

      this.conn.end();
    })
  }
}<|endoftext|>


<commit_before>/*jslint node: true, unparam: true, nomen: true */
(function () {
    'use strict';

    var lib = function (config) {
        var requirejs = require('requirejs'),
            lodash = require('lodash'),
            service;

        requirejs.config(config);

        service = {
            load: function (modulePath) {
                return requirejs(modulePath);
            },
            inject: function (modelPath, data) {
                var that = this,
                    relationPicker = function (data) {
                        return function (value, key) {
                            var relation,
                                relation_key = value.key || key;
                            relation = lodash.reduce(relation_key.split('.'), function (result, key) {
                                return result[key];
                            }, data);
                            return relation !== undefined;
                        }
                    },
                    loadMixins = function (Model, MainModel) {
                        var ToInjectInto = MainModel || Model;

                        if (Model.mixins === undefined || lodash.isEmpty(Model.mixins)) {
                            return ToInjectInto;
                        }

                        lodash.map(Model.mixins, function (options, mixinPath) {
                            var Mixin = service.load(mixinPath);

                            // merge relations
                            if (Mixin.relations !== undefined) {
                                lodash.merge(ToInjectInto.relations, Mixin.relations);
                            }

                            Mixin.call(ToInjectInto.prototype, options);

                            // merge sub-mixins
                            loadMixins(Mixin, ToInjectInto);
                        });
                    },
                    create_model = function (Model, rawData) {
                        var instance = new Model(rawData),
                            relations = lodash.pickBy(Model.relations, relationPicker(rawData));

                        // On a filtré parmi les relations du modèle, on ne traite que celles qui correspondent
                        // à des données dans cet objet
                        lodash.map(relations, function (relationData, relationName) {
                            var modelPath2 = relationData.path || relationData,
                                content = (relationData.key && lodash.reduce(relationData.key.split('.'), function (result, key) {
                                        return result[key];
                                    }, instance)) || instance[relationName];

                            instance[relationName] = that.inject(modelPath2, content);

                        });
                        return instance;
                    };

                // si on n'a pas reçu de données, on s'assure quand même qu'on ait un objet.
                if (!data) {
                    data = {};
                }

                var Model = service.load(modelPath),
                    inject_data = function (data) {
                        return create_model(Model, data);
                    };

                // injection des mixins
                loadMixins(Model);

                // tableau d'objets à injecter
                if (lodash.isArray(data)) {
                    return lodash.map(data, inject_data);
                }

                // un seul objet à injecter
                return inject_data(data);
            },

            getEmpty: function (modelPath) {
                return service.inject(modelPath);
            }
        };

        return service;
    };

    module.exports = lib;
}());<commit_msg>- throw error in case Model is not found<commit_after>/*jslint node: true, unparam: true, nomen: true */
(function () {
    'use strict';

    var lib = function (config) {
        var requirejs = require('requirejs'),
            lodash = require('lodash'),
            service;

        requirejs.config(config);

        service = {
            load: function (modulePath) {
                return requirejs(modulePath);
            },
            inject: function (modelPath, data) {
                var that = this,
                    relationPicker = function (data) {
                        return function (value, key) {
                            var relation,
                                relation_key = value.key || key;
                            relation = lodash.reduce(relation_key.split('.'), function (result, key) {
                                return result[key];
                            }, data);
                            return relation !== undefined;
                        }
                    },
                    loadMixins = function (Model, MainModel) {
                        var ToInjectInto = MainModel || Model;

                        if (!Model) {
                            var err = new Error('Model with path [' + modelPath + '] is undefined');
                            err.requirejs_config = config;
                            throw err;
                        }

                        if (Model.mixins === undefined || lodash.isEmpty(Model.mixins)) {
                            return ToInjectInto;
                        }

                        lodash.map(Model.mixins, function (options, mixinPath) {
                            var Mixin = service.load(mixinPath);

                            // merge relations
                            if (Mixin.relations !== undefined) {
                                lodash.merge(ToInjectInto.relations, Mixin.relations);
                            }

                            Mixin.call(ToInjectInto.prototype, options);

                            // merge sub-mixins
                            loadMixins(Mixin, ToInjectInto);
                        });
                    },
                    create_model = function (Model, rawData) {
                        var instance = new Model(rawData),
                            relations = lodash.pickBy(Model.relations, relationPicker(rawData));

                        // On a filtré parmi les relations du modèle, on ne traite que celles qui correspondent
                        // à des données dans cet objet
                        lodash.map(relations, function (relationData, relationName) {
                            var modelPath2 = relationData.path || relationData,
                                content = (relationData.key && lodash.reduce(relationData.key.split('.'), function (result, key) {
                                        return result[key];
                                    }, instance)) || instance[relationName];

                            instance[relationName] = that.inject(modelPath2, content);

                        });
                        return instance;
                    };

                // si on n'a pas reçu de données, on s'assure quand même qu'on ait un objet.
                if (!data) {
                    data = {};
                }

                var Model = service.load(modelPath),
                    inject_data = function (data) {
                        return create_model(Model, data);
                    };

                // injection des mixins
                loadMixins(Model);

                // tableau d'objets à injecter
                if (lodash.isArray(data)) {
                    return lodash.map(data, inject_data);
                }

                // un seul objet à injecter
                return inject_data(data);
            },

            getEmpty: function (modelPath) {
                return service.inject(modelPath);
            }
        };

        return service;
    };

    module.exports = lib;
}());<|endoftext|>


<commit_before>/*!
 * YUI Onyx
 * Copyright 2011 Yahoo! Inc.
 * Licensed under the BSD license.
 */

/**
 * Onyx is a library for streaming files
 * over HTTP.
 *
 * @module onyx
 */

/**
 * Dependencies.
 */
var fs = require("fs");
var path = require("path");
var util = require("util");
var assert = require("assert");
var mime = require("./mime");

/**
 * Onyx streams a collection of files
 * as a response to an HTTP request.
 *
 * @class Onyx
 * @constructor
 */
function Onyx () {
}

var proto = Onyx.prototype;

/**
 * Returns the values of an object as an array.
 *
 * @method makeArray
 * @protected
 * @param {Object} obj
 * @return {Array}
 */
proto.makeArray = function (obj) {
    var arr = [], key;
    for (key in obj) {
        arr.push(obj[key]);
    }
    return arr;
}

/**
 * Implementation of a fs.stat collector for
 * multiple files.
 *
 * @method statCollector
 * @protected
 * @param {Array} files An array of fille-qualified filenames.
 * @param {Object} source A map of filenames to their `fs.stat` results.
 * @param {Function} cb Callback, 2-arity: error or null, the map of stat results.
 */
proto.statCollector = function statCollector (files, source, cb) {
    var file = files.shift();
    var onyx = this;

    if (file) {
        fs.stat(file, function (err, stat) {
            if (err) {
                return cb(err);
            }
            source[file] = stat;
            statCollector.call(onyx, files, source, cb);
        });
        return;
    }

    var stats = onyx.makeArray(source);

    var result = {
        size : stats.reduce(function (total, stat) {
            return total + stat.size;
        }, 0),
        mtime : stats.reduce(function (latest, stat) {
            return (latest > stat.mtime) ? latest : stat.mtime;
        }, 0),
        files : source
    };

    cb(null, result);
};

/**
 * Aggregate fs#stat across multiple files.
 *
 * The callback recieves an object with:
 *
 * - size: total size of all files
 * - mtime: latest mtime
 * - files: individual stat objects per-file
 *
 * @method mstat
 * @private
 * @param {Array} files
 * @param {Function} cb Callback
 */
proto.mstat = function (files, cb) {
    if (!Array.isArray(files)) {
        throw new Error("files must be an array");
    }

    this.statCollector(files.slice(0), {}, cb);
};

/**
 * Implementation of the actual file transfer.
 */
function xfer (res, files, cb) {
    var file = files.shift();

    if (!file) {
        return cb(null);
    }

    fs.createReadStream(file
    ).on("data", function (chunk) {
        res.write(chunk);
    }).on("error", cb
    ).on("close", function xferClose () {
        xfer(res, files, cb);
    });
}

/**
 * For a given baton containing stats, files, and
 * a HTTP response, stream them to the HTTP response
 * and callback when complete.
 *
 * @method stream
 * @protected
 * @param {Object} baton The baton, containing files, res, and stat.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.stream  = function stream (baton, cb) {
    var res = baton.res,
        files = baton.files.slice(0);

    xfer(res, files, cb);
};

/**
 * Given a baton of an HTTP request and response,
 * file stats and an array of files, handle the HTTP response
 * by writing the correct headers for the combined files
 * using `stream` to stream the files themselves.
 *
 * Conditional GET and HEAD requests are supported.
 *
 * Scripts, stylesheets and text are assumed to be UTF-8 encoded
 * when sending the Content-Type HTTP header.
 *
 * The request is **not** ended by this function. You must call
 * res.end in your callback function. For why, see streamFiles below.
 *
 * @method handle
 * @private
 * @param {Object} baton A baton, see streamFiles below.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.handle = function (status, baton, cb) {
    var onyx = this;
    var req = baton.req;
    var res = baton.res;
    var stat = baton.stat;
    var files = baton.files;
    var headers = {};
    var mtime = Date.parse(stat.mtime);

    headers.Date = (new Date()).toUTCString();
    headers["Last-Modified"] = (new Date(stat.mtime)).toUTCString();

    // No inode on ETag, since they vary per-system.
    headers.Etag = JSON.stringify([stat.size, mtime].join("-"));

    // Conditional GET.
    if (req.headers["if-none-match"] === headers.Etag &&
        Date.parse(req.headers["if-modified-since"]) >= mtime) {
        res.writeHead(304, headers);
        cb(null);
    } else if (req.method === "HEAD") {
        res.writeHead(200, headers);
        cb(null);
    } else {
        headers["Content-Type"] = mime.contentTypes[path.extname(files[0]).slice(1)]
                                || "application/octet-stream";

        switch (headers["Content-Type"]) {
            case "application/javascript":
            case "text/html":
            case "text/css":
            case "text/plain":
                headers["Content-Type"] += "; charset=utf-8";
                break;
            default:
                delete baton.prepend;
                delete baton.postpend;
                break;
        }

        var size = stat.size;

        if (baton.prepend) {
            size += baton.prepend.length;
        }

        if (baton.postpend) {
            size += baton.postpend.length;
        }

        headers["Content-Length"] = size;

        res.writeHead(status, headers);

        if (baton.prepend) {
            res.write(baton.prepend);
        }

        onyx.stream(baton, function (err) {
            if (!err && baton.postpend) {
                res.write(baton.postpend);
            }
            cb(err);
        });
    }
}

/**
 * Given an object with an HTTP request, response and
 * file array, respond to the request with all of the files
 * in the same request in the order they appear in the file
 * array.
 *
 * The HTTP request is **not** ended by this function. Call
 * res.end directly in your callback after checking for an
 * error. That's because in the event of a stream error,
 * error handling middleware needs to be able to respond
 * correctly: your callback should call next(err) if an
 * error occurred, instead of calling res.end.
 *
 * The implementation assumes text files are UTF-8 encoded
 * for the purpose of setting the Content-Type header; however,
 * the file contents are sent unchanged byte-for-byte.
 *
 * The baton argument should be an object with the properties:
 *
 * - req: HTTP request.
 * - res: HTTP response.
 * - files: Array of files.
 * - prepend: String to send before the file contents.
 * - postpend: String to send after the file contents.
 *
 * @method streamFiles
 * @param {Object} baton A baton.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.streamFiles = function (baton, cb) {
    var onyx = this;

    if (baton.files.some(function (file) {
        return decodeURIComponent(file).indexOf("..") !== -1;
    })) {
        // This should be a Bad Request; however, if we got
        // this far with an unsafe filename we'll go with a 500.
        return cb(new Error("Relative paths not allowed."));
    }

    this.mstat(baton.files, function (err, stat) {
        if (err) {
            return cb(err);
        }
        baton.stat = stat;
        onyx.handle(200, baton, cb);
    });
};

exports.Onyx = Onyx;
<commit_msg>Add missing semicolons for onyx.js.<commit_after>/*!
 * YUI Onyx
 * Copyright 2011 Yahoo! Inc.
 * Licensed under the BSD license.
 */

/**
 * Onyx is a library for streaming files
 * over HTTP.
 *
 * @module onyx
 */

/**
 * Dependencies.
 */
var fs = require("fs");
var path = require("path");
var util = require("util");
var assert = require("assert");
var mime = require("./mime");

/**
 * Onyx streams a collection of files
 * as a response to an HTTP request.
 *
 * @class Onyx
 * @constructor
 */
function Onyx () {
}

var proto = Onyx.prototype;

/**
 * Returns the values of an object as an array.
 *
 * @method makeArray
 * @protected
 * @param {Object} obj
 * @return {Array}
 */
proto.makeArray = function (obj) {
    var arr = [], key;
    for (key in obj) {
        arr.push(obj[key]);
    }
    return arr;
};

/**
 * Implementation of a fs.stat collector for
 * multiple files.
 *
 * @method statCollector
 * @protected
 * @param {Array} files An array of fille-qualified filenames.
 * @param {Object} source A map of filenames to their `fs.stat` results.
 * @param {Function} cb Callback, 2-arity: error or null, the map of stat results.
 */
proto.statCollector = function statCollector (files, source, cb) {
    var file = files.shift();
    var onyx = this;

    if (file) {
        fs.stat(file, function (err, stat) {
            if (err) {
                return cb(err);
            }
            source[file] = stat;
            statCollector.call(onyx, files, source, cb);
        });
        return;
    }

    var stats = onyx.makeArray(source);

    var result = {
        size : stats.reduce(function (total, stat) {
            return total + stat.size;
        }, 0),
        mtime : stats.reduce(function (latest, stat) {
            return (latest > stat.mtime) ? latest : stat.mtime;
        }, 0),
        files : source
    };

    cb(null, result);
};

/**
 * Aggregate fs#stat across multiple files.
 *
 * The callback recieves an object with:
 *
 * - size: total size of all files
 * - mtime: latest mtime
 * - files: individual stat objects per-file
 *
 * @method mstat
 * @private
 * @param {Array} files
 * @param {Function} cb Callback
 */
proto.mstat = function (files, cb) {
    if (!Array.isArray(files)) {
        throw new Error("files must be an array");
    }

    this.statCollector(files.slice(0), {}, cb);
};

/**
 * Implementation of the actual file transfer.
 */
function xfer (res, files, cb) {
    var file = files.shift();

    if (!file) {
        return cb(null);
    }

    fs.createReadStream(file
    ).on("data", function (chunk) {
        res.write(chunk);
    }).on("error", cb
    ).on("close", function xferClose () {
        xfer(res, files, cb);
    });
}

/**
 * For a given baton containing stats, files, and
 * a HTTP response, stream them to the HTTP response
 * and callback when complete.
 *
 * @method stream
 * @protected
 * @param {Object} baton The baton, containing files, res, and stat.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.stream  = function stream (baton, cb) {
    var res = baton.res,
        files = baton.files.slice(0);

    xfer(res, files, cb);
};

/**
 * Given a baton of an HTTP request and response,
 * file stats and an array of files, handle the HTTP response
 * by writing the correct headers for the combined files
 * using `stream` to stream the files themselves.
 *
 * Conditional GET and HEAD requests are supported.
 *
 * Scripts, stylesheets and text are assumed to be UTF-8 encoded
 * when sending the Content-Type HTTP header.
 *
 * The request is **not** ended by this function. You must call
 * res.end in your callback function. For why, see streamFiles below.
 *
 * @method handle
 * @private
 * @param {Object} baton A baton, see streamFiles below.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.handle = function (status, baton, cb) {
    var onyx = this;
    var req = baton.req;
    var res = baton.res;
    var stat = baton.stat;
    var files = baton.files;
    var headers = {};
    var mtime = Date.parse(stat.mtime);

    headers.Date = (new Date()).toUTCString();
    headers["Last-Modified"] = (new Date(stat.mtime)).toUTCString();

    // No inode on ETag, since they vary per-system.
    headers.Etag = JSON.stringify([stat.size, mtime].join("-"));

    // Conditional GET.
    if (req.headers["if-none-match"] === headers.Etag &&
        Date.parse(req.headers["if-modified-since"]) >= mtime) {
        res.writeHead(304, headers);
        cb(null);
    } else if (req.method === "HEAD") {
        res.writeHead(200, headers);
        cb(null);
    } else {
        headers["Content-Type"] = mime.contentTypes[path.extname(files[0]).slice(1)]
                                || "application/octet-stream";

        switch (headers["Content-Type"]) {
            case "application/javascript":
            case "text/html":
            case "text/css":
            case "text/plain":
                headers["Content-Type"] += "; charset=utf-8";
                break;
            default:
                delete baton.prepend;
                delete baton.postpend;
                break;
        }

        var size = stat.size;

        if (baton.prepend) {
            size += baton.prepend.length;
        }

        if (baton.postpend) {
            size += baton.postpend.length;
        }

        headers["Content-Length"] = size;

        res.writeHead(status, headers);

        if (baton.prepend) {
            res.write(baton.prepend);
        }

        onyx.stream(baton, function (err) {
            if (!err && baton.postpend) {
                res.write(baton.postpend);
            }
            cb(err);
        });
    }
};

/**
 * Given an object with an HTTP request, response and
 * file array, respond to the request with all of the files
 * in the same request in the order they appear in the file
 * array.
 *
 * The HTTP request is **not** ended by this function. Call
 * res.end directly in your callback after checking for an
 * error. That's because in the event of a stream error,
 * error handling middleware needs to be able to respond
 * correctly: your callback should call next(err) if an
 * error occurred, instead of calling res.end.
 *
 * The implementation assumes text files are UTF-8 encoded
 * for the purpose of setting the Content-Type header; however,
 * the file contents are sent unchanged byte-for-byte.
 *
 * The baton argument should be an object with the properties:
 *
 * - req: HTTP request.
 * - res: HTTP response.
 * - files: Array of files.
 * - prepend: String to send before the file contents.
 * - postpend: String to send after the file contents.
 *
 * @method streamFiles
 * @param {Object} baton A baton.
 * @param {Function} cb Callback, 1-arity, the error or null.
 */
proto.streamFiles = function (baton, cb) {
    var onyx = this;

    if (baton.files.some(function (file) {
        return decodeURIComponent(file).indexOf("..") !== -1;
    })) {
        // This should be a Bad Request; however, if we got
        // this far with an unsafe filename we'll go with a 500.
        return cb(new Error("Relative paths not allowed."));
    }

    this.mstat(baton.files, function (err, stat) {
        if (err) {
            return cb(err);
        }
        baton.stat = stat;
        onyx.handle(200, baton, cb);
    });
};

exports.Onyx = Onyx;
<|endoftext|>


<commit_before>var FrameType = {
  BEACON: 0x00,
  DATA: 0x01,
  ACK: 0x02,
  MAC_CMD: 0x03
};

var AddressingMode = {
  NOT_PRESENT: 0x00,
  SHORT_ADDRESS: 0x02,
  EUI: 0x03
};

var SecurityLevel = {
  NONE: 0x00,
  MIC_32: 0x01,
  MIC_64: 0x02,
  MIC_128: 0x03,
  ENC: 0x04,
  ENC_MIC_32: 0x05,
  ENC_MIC_64: 0x06,
  ENC_MIC_128: 0x07
}

var KeyIdentifierMode = {
  IMPLICIT: 0x00,
  KEY_IDX_ONLY: 0x01,
  KEY_SOURCE_4: 0x02,
  KEY_SOURCE_8: 0x03
}

exports.FrameType = FrameType;
exports.AddressingMode = AddressingMode;
exports.SecurityLevel = SecurityLevel;
exports.KeyIdentifierMode = KeyIdentifierMode;

function OSNPFrame() {
  this.frameControlLow = null;
  this.frameControlHigh = null;
  this.destinationPAN = null;
  this.destinationAddress = null;
  this.sourcePAN = null;
  this.sourceAddress = null;
  this.securityControl = null;
  this.frameCounter = null;
  this.keySource = null;
  this.keyIndex = null;
  this.payload = null;
}

OSNPFrame.prototype.getDestinationAddressingMode = function() {
  return (this.frameControlHigh >>> 2) & 0x03;
}

OSNPFrame.prototype.getSourceAddressingMode = function() {
  return (this.frameControlHigh >>> 6) & 0x03;
}

OSNPFrame.prototype.hasPANIDCompression = function() {
  return (this.frameControlLow & 0x40) == 0x40;
}

OSNPFrame.prototype.hasSecurityEnabled = function() {
  return (this.frameControlLow & 0x08) == 0x08;
}

OSNPFrame.prototype.hasSecurityHeader = function() {
  return this.hasSecurityEnabled() && ((this.frameControlHigh & 0x30) != 0x00);
}

OSNPFrame.prototype.getKeyIdentifierMode = function() {
  return (this.securityControl >>> 3) & 0x03;
}

OSNPFrame.prototype.getEncodedLength = function() {
  var len = 3;
  if (this.destinationPAN != null) {
    len += this.destinationAddress.length + 2;
  }

  if (!this.hasPANIDCompression() && this.sourcePAN != null) {
    len += 2;
  }

  if (this.sourceAddress != null) {
    len += this.sourceAddress.length;
  }

  if (this.hasSecurityHeader()) {
    len += 5;
    if (this.keySource != null) {
      len += this.keySource.length + 1;
    } else if (this.getKeyIdentifierMode() == KeyIdentifierMode.KEY_IDX_ONLY) {
      len++;
    }
  }

  len += this.payload.length;

  return len;
}

OSNPFrame.prototype.encode = function(buf) {
  if (buf == undefined) {
    buf = new Buffer(this.getEncodedLength());
  }
  var index = 0;
  buf.writeUInt8(this.frameControlLow, index++);
  buf.writeUInt8(this.frameControlHigh, index++);
  buf.writeUInt8(this.sequenceNumber, index++);

  if (this.destinationPAN != null) {
    this.destinationPAN.copy(buf, index);
    index += 2;
    this.destinationAddress.copy(buf, index);
    index += this.destinationAddress.length;
  }

  if (!this.hasPANIDCompression() && this.sourcePAN != null) {
    this.sourcePAN.copy(buf, index);
    index += 2;
  }

  if (this.sourceAddress != null) {
    this.sourceAddress.copy(buf, index);
    index += this.sourceAddress.length;
  }

  if (this.hasSecurityHeader()) {
    buf.writeUInt8(this.securityControl, index++);
    buf.writeUInt32LE(this.frameCounter, index);
    index += 4;

    if (this.keySource != null) {
      this.keySource.copy(buf, index);
      index += this.keySource.length;
      buf.writeUInt8(this.keyIndex, index++);
    } else if (this.getKeyIdentifierMode() == KeyIdentifierMode.KEY_IDX_ONLY) {
      buf.writeUInt8(this.keyIndex, index++);
    }
  }

  this.payload.copy(buf, index);

  return buf;
}

var panID;
var shortAddress;
var eui;

var sequenceNumber = 0;

exports.setPANID = function(aPANID) {
  panID = aPANID;
}

exports.getPANID = function() {
  return panID;
}

exports.setShortAddress = function(aShortAddress) {
  shortAddress = aShortAddress;
}

exports.getShortAddress = function() {
  return shortAddress;
}

exports.setEUI = function(aEUI) {
  eui = aEUI;
}

exports.getEUI = function() {
  return eui;
}

exports.parseFrame = function(frame) {
  var osnpFrame = new OSNPFrame();
  var index = 0;
  osnpFrame.frameControlLow = frame.readUInt8(index++);
  osnpFrame.frameControlHigh = frame.readUInt8(index++);
  osnpFrame.sequenceNumber = frame.readUInt8(index++);

  switch (osnpFrame.getDestinationAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    osnpFrame.destinationPAN = frame.slice(index, index + 2);
    index += 2;
    osnpFrame.destinationAddress = frame.slice(index, index + 2);
    index += 2;
    break;
  case AddressingMode.EUI:
    osnpFrame.destinationPAN = frame.slice(index, index + 2);
    index += 2;
    osnpFrame.destinationAddress = frame.slice(index, index + 8);
    index += 8;
    break;
  }

  if (osnpFrame.getSourceAddressingMode() != AddressingMode.NOT_PRESENT) {
    if(osnpFrame.hasPANIDCompression()) {
      osnpFrame.sourcePAN = osnpFrame.destinationPAN;
    } else {
      osnpFrame.sourcePAN = frame.slice(index, index + 2);
      index += 2;
    }
  }

  switch (osnpFrame.getSourceAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    osnpFrame.sourceAddress = frame.slice(index, index + 2);
    index += 2;
    break;
  case AddressingMode.EUI:
    osnpFrame.sourceAddress = frame.slice(index, index + 8);
    index += 8;
    break;
  }
  if (osnpFrame.hasSecurityHeader()) {
    osnpFrame.securityControl = frame.readUInt8(index++);
    osnpFrame.frameCounter = frame.readUInt32LE(index);
    index += 4;

    switch (osnpFrame.getKeyIdentifierMode()) {
    case KeyIdentifierMode.KEY_IDX_ONLY:
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    case KeyIdentifierMode.KEY_SOURCE_4:
      osnpFrame.keySource = frame.slice(index, index + 4);
      index += 4;
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    case KeyIdentifierMode.KEY_SOURCE_8:
      osnpFrame.keySource = frame.slice(index, index + 8);
      index += 8;
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    }
  }

  osnpFrame.payload = frame.slice(index, frame.length - 2);

  return osnpFrame;
}

exports.createFrame = function(frameControlLow, frameControlHigh) {
  var frame = new OSNPFrame();

  frame.frameControlLow = frameControlLow;
  frame.frameControlHigh = frameControlHigh;

  frame.sequenceNumber = sequenceNumber++;

  if (sequenceNumber >= 255) {
    sequenceNumber = 0;
  }

  if (frame.hasPANIDCompression() && (frame.getDestinationAddressingMode() != AddressingMode.NOT_PRESENT)) {
    frame.destinationPAN = panID;
  }

  switch (frame.getSourceAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    frame.sourcePAN = panID;
    frame.sourceAddress = shortAddress;
    break;
  case AddressingMode.EUI:
    frame.sourcePAN = panID;
    frame.sourceAddress = eui;
    break;
  }

  frame.payload = new Buffer(0);

  return frame;
}

exports.createResponse = function(originalFrame) {
  var frameControlLow = (originalFrame.frameControlLow & 0xEF) | 0x20;
  var frameControlHigh = (originalFrame.getSourceAddressingMode() << 2) | (originalFrame.getDestinationAddressingMode() << 6) | (originalFrame.frameControlHigher & 0x30);
  var frame = exports.createFrame(frameControlLow,  frameControlHigh);

  frame.destinationPAN = originalFrame.sourcePAN;
  frame.destinationAddress = originalFrame.sourceAddress;
  frame.securityControl = originalFrame.securityControl;
  frame.frameCounter = originalFrame.frameCounter;
  frame.keySource = originalFrame.keySource;
  frame.keyIndex = originalFrame.keyIndex;

  return frame;
}
<commit_msg>added few helper functions<commit_after>var FrameType = {
  BEACON: 0x00,
  DATA: 0x01,
  ACK: 0x02,
  MAC_CMD: 0x03
};

var FrameVersion = {
  V2003: 0x00,
  V2006: 0x01
}

var AddressingMode = {
  NOT_PRESENT: 0x00,
  SHORT_ADDRESS: 0x02,
  EUI: 0x03
};

var SecurityLevel = {
  NONE: 0x00,
  MIC_32: 0x01,
  MIC_64: 0x02,
  MIC_128: 0x03,
  ENC: 0x04,
  ENC_MIC_32: 0x05,
  ENC_MIC_64: 0x06,
  ENC_MIC_128: 0x07
}

var KeyIdentifierMode = {
  IMPLICIT: 0x00,
  KEY_IDX_ONLY: 0x01,
  KEY_SOURCE_4: 0x02,
  KEY_SOURCE_8: 0x03
}

exports.FrameType = FrameType;
exports.AddressingMode = AddressingMode;
exports.SecurityLevel = SecurityLevel;
exports.KeyIdentifierMode = KeyIdentifierMode;

function OSNPFrame() {
  this.frameControlLow = null;
  this.frameControlHigh = null;
  this.destinationPAN = null;
  this.destinationAddress = null;
  this.sourcePAN = null;
  this.sourceAddress = null;
  this.securityControl = null;
  this.frameCounter = null;
  this.keySource = null;
  this.keyIndex = null;
  this.payload = null;
}

OSNPFrame.prototype.getDestinationAddressingMode = function() {
  return (this.frameControlHigh >>> 2) & 0x03;
}

OSNPFrame.prototype.getSourceAddressingMode = function() {
  return (this.frameControlHigh >>> 6) & 0x03;
}

OSNPFrame.prototype.getFrameVersion = function() {
  return (this.frameControlHigh >>> 4) & 0x03;
}

OSNPFrame.prototype.hasPANIDCompression = function() {
  return (this.frameControlLow & 0x40) == 0x40;
}

OSNPFrame.prototype.hasSecurityEnabled = function() {
  return (this.frameControlLow & 0x08) == 0x08;
}

OSNPFrame.prototype.hasSecurityHeader = function() {
  return this.hasSecurityEnabled() && ((this.frameControlHigh & 0x30) != 0x00);
}

OSNPFrame.prototype.hasFramePending = function() {
  return (this.frameControlLow & 0x10) == 0x10;
}

OSNPFrame.prototype.hasAckRequested = function() {
  return (this.frameControlLow & 0x20) == 0x20;
}

OSNPFrame.prototype.getKeyIdentifierMode = function() {
  return (this.securityControl >>> 3) & 0x03;
}

OSNPFrame.prototype.getEncodedLength = function() {
  var len = 3;
  if (this.destinationPAN != null) {
    len += this.destinationAddress.length + 2;
  }

  if (!this.hasPANIDCompression() && this.sourcePAN != null) {
    len += 2;
  }

  if (this.sourceAddress != null) {
    len += this.sourceAddress.length;
  }

  if (this.hasSecurityHeader()) {
    len += 5;
    if (this.keySource != null) {
      len += this.keySource.length + 1;
    } else if (this.getKeyIdentifierMode() == KeyIdentifierMode.KEY_IDX_ONLY) {
      len++;
    }
  }

  len += this.payload.length;

  return len;
}

OSNPFrame.prototype.encode = function(buf) {
  if (buf == undefined) {
    buf = new Buffer(this.getEncodedLength());
  }
  var index = 0;
  buf.writeUInt8(this.frameControlLow, index++);
  buf.writeUInt8(this.frameControlHigh, index++);
  buf.writeUInt8(this.sequenceNumber, index++);

  if (this.destinationPAN != null) {
    this.destinationPAN.copy(buf, index);
    index += 2;
    this.destinationAddress.copy(buf, index);
    index += this.destinationAddress.length;
  }

  if (!this.hasPANIDCompression() && this.sourcePAN != null) {
    this.sourcePAN.copy(buf, index);
    index += 2;
  }

  if (this.sourceAddress != null) {
    this.sourceAddress.copy(buf, index);
    index += this.sourceAddress.length;
  }

  if (this.hasSecurityHeader()) {
    buf.writeUInt8(this.securityControl, index++);
    buf.writeUInt32LE(this.frameCounter, index);
    index += 4;

    if (this.keySource != null) {
      this.keySource.copy(buf, index);
      index += this.keySource.length;
      buf.writeUInt8(this.keyIndex, index++);
    } else if (this.getKeyIdentifierMode() == KeyIdentifierMode.KEY_IDX_ONLY) {
      buf.writeUInt8(this.keyIndex, index++);
    }
  }

  this.payload.copy(buf, index);

  return buf;
}

var panID;
var shortAddress;
var eui;

var sequenceNumber = 0;

exports.setPANID = function(aPANID) {
  panID = aPANID;
}

exports.getPANID = function() {
  return panID;
}

exports.setShortAddress = function(aShortAddress) {
  shortAddress = aShortAddress;
}

exports.getShortAddress = function() {
  return shortAddress;
}

exports.setEUI = function(aEUI) {
  eui = aEUI;
}

exports.getEUI = function() {
  return eui;
}

exports.parseFrame = function(frame) {
  var osnpFrame = new OSNPFrame();
  var index = 0;
  osnpFrame.frameControlLow = frame.readUInt8(index++);
  osnpFrame.frameControlHigh = frame.readUInt8(index++);
  osnpFrame.sequenceNumber = frame.readUInt8(index++);

  switch (osnpFrame.getDestinationAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    osnpFrame.destinationPAN = frame.slice(index, index + 2);
    index += 2;
    osnpFrame.destinationAddress = frame.slice(index, index + 2);
    index += 2;
    break;
  case AddressingMode.EUI:
    osnpFrame.destinationPAN = frame.slice(index, index + 2);
    index += 2;
    osnpFrame.destinationAddress = frame.slice(index, index + 8);
    index += 8;
    break;
  }

  if (osnpFrame.getSourceAddressingMode() != AddressingMode.NOT_PRESENT) {
    if(osnpFrame.hasPANIDCompression()) {
      osnpFrame.sourcePAN = osnpFrame.destinationPAN;
    } else {
      osnpFrame.sourcePAN = frame.slice(index, index + 2);
      index += 2;
    }
  }

  switch (osnpFrame.getSourceAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    osnpFrame.sourceAddress = frame.slice(index, index + 2);
    index += 2;
    break;
  case AddressingMode.EUI:
    osnpFrame.sourceAddress = frame.slice(index, index + 8);
    index += 8;
    break;
  }
  if (osnpFrame.hasSecurityHeader()) {
    osnpFrame.securityControl = frame.readUInt8(index++);
    osnpFrame.frameCounter = frame.readUInt32LE(index);
    index += 4;

    switch (osnpFrame.getKeyIdentifierMode()) {
    case KeyIdentifierMode.KEY_IDX_ONLY:
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    case KeyIdentifierMode.KEY_SOURCE_4:
      osnpFrame.keySource = frame.slice(index, index + 4);
      index += 4;
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    case KeyIdentifierMode.KEY_SOURCE_8:
      osnpFrame.keySource = frame.slice(index, index + 8);
      index += 8;
      osnpFrame.keyIndex = frame.readUInt8(index++);
      break;
    }
  }

  osnpFrame.payload = frame.slice(index, frame.length - 2);

  return osnpFrame;
}

exports.createFrame = function(frameControlLow, frameControlHigh) {
  var frame = new OSNPFrame();

  frame.frameControlLow = frameControlLow;
  frame.frameControlHigh = frameControlHigh;

  frame.sequenceNumber = sequenceNumber++;

  if (sequenceNumber >= 255) {
    sequenceNumber = 0;
  }

  if (frame.hasPANIDCompression() && (frame.getDestinationAddressingMode() != AddressingMode.NOT_PRESENT)) {
    frame.destinationPAN = panID;
  }

  switch (frame.getSourceAddressingMode()) {
  case AddressingMode.SHORT_ADDRESS:
    frame.sourcePAN = panID;
    frame.sourceAddress = shortAddress;
    break;
  case AddressingMode.EUI:
    frame.sourcePAN = panID;
    frame.sourceAddress = eui;
    break;
  }

  frame.payload = new Buffer(0);

  return frame;
}

exports.createResponse = function(originalFrame) {
  var frameControlLow = (originalFrame.frameControlLow & 0xEF) | 0x20;
  var frameControlHigh = (originalFrame.getSourceAddressingMode() << 2) | (originalFrame.getDestinationAddressingMode() << 6) | (originalFrame.frameControlHigher & 0x30);
  var frame = exports.createFrame(frameControlLow,  frameControlHigh);

  frame.destinationPAN = originalFrame.sourcePAN;
  frame.destinationAddress = originalFrame.sourceAddress;
  frame.securityControl = originalFrame.securityControl;
  frame.frameCounter = originalFrame.frameCounter;
  frame.keySource = originalFrame.keySource;
  frame.keyIndex = originalFrame.keyIndex;

  return frame;
}

exports.makeFrameControlLow(frameType, securityEnabled, framePending, ackRequest, panIDCompression) {
  return frameType | (securityEnabled ? 0x08 : 0x00) | (framePending ? 0x10 : 0x00) | (ackRequest ? 0x20 : 0x00) | (panIDCompression ? 0x40 : 0x00);
}

exports.makeFrameControlHigh(destinationAddressingMode, frameVersion, sourceAddressingMode) {
  return (destinationAddressingMode << 2) | (frameVersion << 4) | (sourceAddressingMode << 6);
}
  <|endoftext|>


<commit_before>(function() {
  'use strict';

  var keylime = require('keylime'),
      mach = require('mach'),
      _ = require('lodash'),
      p = require('path'),
      Promise = require('bluebird'),

      renderExtension = mach.extend(require('./mach/render_extension')),

      Path = require('./pimm/support/path'),
      Controller = require('./pimm/controller'),
      ControllerManager = require('./pimm/controller_manager'),
      ViewManager = require('./pimm/view_manager'),
      Router = require('./pimm/router'),

      Pimm = keylime('Pimm');

  Pimm
    .attr('dir', '.' + p.sep)
    .attr('port', 3000)
    .attr('static', false)
    .attr('session', false)
    .attr('caching', true)
    .attr('templating', 'jade')

    .attr('_stack', mach.stack)
    .attr('_controller_manager', ControllerManager.create.bind(ControllerManager))
    .attr('_view_manager', ViewManager.create.bind(ViewManager))
    .attr('_router', Router.create.bind(Router))
    .attr('_config', {})
    .attr('_middleware', [])
    .attr('_default_middleware', [
      {middleware: mach.logger},
      {middleware: mach.params},
      {middleware: mach.gzip}
    ])

    /**
     * Interface to a generic configuration storage. Pimm does not use
     * this config interface for determining behavior, but you can use
     * it for storing global configuration values.
     *
     *    // main application.js file
     *    app
     *      .config('redis', {host: 'localhost'})
     *      .config('debug', true);
     *
     *    // some other module.js
     *    var app = require('./application');
     *
     *    app.config('redis');   // => gets the redis conf
     *    app.config();          // => gets all config
     */
    .method('config', function config() {
      var args = [].slice.call(arguments);

      switch (_.size(args)) {
        case 2:
          this._config[args[0]] = args[1];
          return this;
        case 1:
          return this._config[args[0]];
        default:
          return this._config;
      }
    })

    /**
     * Adds middleware to the stack (chainable);
     */
    .method('use', function use() {
      var middleware = _.first(arguments),
          args = _.drop(arguments, 1);

      if (!_.isFunction(middleware)) {
        throw new Error('You must supply a function argument to the \'use\' method.');
      }

      this._middleware.push({
        middleware: middleware,
        args: args
      });
      return this;
    })

    /**
     * Add routes to the Pimm application. Use the `this` keyword
     * inside the function to add routes.
     *
     * (See router.js to see what routing methods are available)
     *
     *    app.routes(function() {
     *      this.resources('posts');
     *
     *      this.namespace('admin', function() {
     *        this.resources('users');
     *      });
     *    });
     */
    .method('routes', function routes(func) {
      if (_.isFunction(func)) {
        func.call(this._router);
      }
      return this;
    })

    /**
     * Starts the application.
     *
     *    app.start().then(function() {
     *      console.log('App started!');
     *    });
     */
    .method('start', function start() {
      return Promise.all([this._loadControllers(), this._loadViews()])
      .bind(this)
      .then(function() {
        this._addStaticMiddleware();
        this._addSessionMiddleware();
        this._loadMiddleware();
        this._normalizeRoutes();
        this._activateRoutes();
        mach.serve(this._stack, this.port);
        return true;
      });
    })

    /**
     * Adds and queued up middleware to the mach stack.
     */
    .method('_loadMiddleware', function loadMiddleware() {
      _.each(_.flatten([this._default_middleware, this._middleware]), _.bind(function(middleware) {
        this._stack.use.apply(this._stack, _.flatten([middleware.middleware, middleware.args]));
      }, this));
    })

    /**
     * Adds a static file server, if Pimm is configured.
     */
    .method('_addStaticMiddleware', function addStaticMiddleware() {
      var opts = {index: true};

      if (!this.static) {
        return;
      }

      if (_.isPlainObject(this.static)) {
        opts = _.extend(opts, this.static);
        opts.root = new Path({value: this.static.dir || './public'}).resolve();
      } else if (_.isString(this.static)) {
        opts.root = new Path({value: this.static || './public'}).resolve();
      }

      this._default_middleware.push({
        middleware: mach.file,
        args: [opts]
      });
    })

    /**
     * Adds session middleware.
     */
    .method('_addSessionMiddleware', function addSessionMiddleware() {
      var opts = {};

      if (!this.session) {
        return;
      }

      if (_.isPlainObject(this.session)) {
        opts = _.extend(opts, this.session);
      } else if (_.isString(this.session)) {
        opts.secret = this.session;
      }

      this._default_middleware.push({
        middleware: mach.session,
        args: [opts]
      });
    })

    /**
     * Delegates to the controller manager for loading up
     * controllers and mapping them to signatures for routing.
     */
    .method('_loadControllers', function loadControllers() {
      var controllerPath = new Path({value: this.dir}).resolve('controllers');

      this._controller_manager.dir = controllerPath;
      this._controller_manager._view_manager = this._view_manager;
      return this._controller_manager.load()
      .catch(function checkError(e) {
        return _.contains(e.message, 'ENOENT');
      }, function logError(e) {
        console.log('>> WARNING: No controllers directory found '+e.cause.path);
      });
    })

    /**
     * Delegates to the view manager for loading up views.
     */
    .method('_loadViews', function loadViews() {
      var viewPath = new Path({value: this.dir}).resolve('views');

      this._view_manager.engine = this.templating;
      this._view_manager.caching = this.caching;
      this._view_manager.dir = viewPath;
      this._view_manager.sharedData.Pimm = {
        config: this._config
      };
      return this._view_manager.load()
      .catch(function checkError(e) {
        return _.contains(e.message, 'ENOENT');
      }, function logError(e) {
        console.log('>> WARNING: No views directory found '+e.cause.path);
      });
    })

    /**
     * Removes any routes that don't have real controller
     * methods backing them up.
     */
    .method('_normalizeRoutes', function normalizeRoutes() {
      this._router.routes = _.filter(this._router.routes, _.bind(function checkRoute(route) {
        var handler = _.isFunction(route.action) ? route.action : this._controller_manager.methodForSignature(route.action);
        return _.isFunction(handler);
      }, this));
    })

    /**
     * Maps all the routes to controller handlers.
     */
    .method('_activateRoutes', function activateRoutes() {
      _.each(this._router.routes, _.bind(function activateRoute(route) {
        var handler = _.isFunction(route.action) ? route.action : this._controller_manager.methodForSignature(route.action);
        this._stack[route.method](route.path, handler);
      }, this));
    });

  module.exports = Pimm;
  module.exports.Controller = Controller;
}());
<commit_msg>fix removed lodash method<commit_after>(function() {
  'use strict';

  var keylime = require('keylime'),
      mach = require('mach'),
      _ = require('lodash'),
      p = require('path'),
      Promise = require('bluebird'),

      renderExtension = mach.extend(require('./mach/render_extension')),

      Path = require('./pimm/support/path'),
      Controller = require('./pimm/controller'),
      ControllerManager = require('./pimm/controller_manager'),
      ViewManager = require('./pimm/view_manager'),
      Router = require('./pimm/router'),

      Pimm = keylime('Pimm');

  Pimm
    .attr('dir', '.' + p.sep)
    .attr('port', 3000)
    .attr('static', false)
    .attr('session', false)
    .attr('caching', true)
    .attr('templating', 'jade')

    .attr('_stack', mach.stack)
    .attr('_controller_manager', ControllerManager.create.bind(ControllerManager))
    .attr('_view_manager', ViewManager.create.bind(ViewManager))
    .attr('_router', Router.create.bind(Router))
    .attr('_config', {})
    .attr('_middleware', [])
    .attr('_default_middleware', [
      {middleware: mach.logger},
      {middleware: mach.params},
      {middleware: mach.gzip}
    ])

    /**
     * Interface to a generic configuration storage. Pimm does not use
     * this config interface for determining behavior, but you can use
     * it for storing global configuration values.
     *
     *    // main application.js file
     *    app
     *      .config('redis', {host: 'localhost'})
     *      .config('debug', true);
     *
     *    // some other module.js
     *    var app = require('./application');
     *
     *    app.config('redis');   // => gets the redis conf
     *    app.config();          // => gets all config
     */
    .method('config', function config() {
      var args = [].slice.call(arguments);

      switch (_.size(args)) {
        case 2:
          this._config[args[0]] = args[1];
          return this;
        case 1:
          return this._config[args[0]];
        default:
          return this._config;
      }
    })

    /**
     * Adds middleware to the stack (chainable);
     */
    .method('use', function use() {
      var middleware = _.first(arguments),
          args = _.drop(arguments, 1);

      if (!_.isFunction(middleware)) {
        throw new Error('You must supply a function argument to the \'use\' method.');
      }

      this._middleware.push({
        middleware: middleware,
        args: args
      });
      return this;
    })

    /**
     * Add routes to the Pimm application. Use the `this` keyword
     * inside the function to add routes.
     *
     * (See router.js to see what routing methods are available)
     *
     *    app.routes(function() {
     *      this.resources('posts');
     *
     *      this.namespace('admin', function() {
     *        this.resources('users');
     *      });
     *    });
     */
    .method('routes', function routes(func) {
      if (_.isFunction(func)) {
        func.call(this._router);
      }
      return this;
    })

    /**
     * Starts the application.
     *
     *    app.start().then(function() {
     *      console.log('App started!');
     *    });
     */
    .method('start', function start() {
      return Promise.all([this._loadControllers(), this._loadViews()])
      .bind(this)
      .then(function() {
        this._addStaticMiddleware();
        this._addSessionMiddleware();
        this._loadMiddleware();
        this._normalizeRoutes();
        this._activateRoutes();
        mach.serve(this._stack, this.port);
        return true;
      });
    })

    /**
     * Adds and queued up middleware to the mach stack.
     */
    .method('_loadMiddleware', function loadMiddleware() {
      _.each(_.flatten([this._default_middleware, this._middleware]), _.bind(function(middleware) {
        this._stack.use.apply(this._stack, _.flatten([middleware.middleware, middleware.args]));
      }, this));
    })

    /**
     * Adds a static file server, if Pimm is configured.
     */
    .method('_addStaticMiddleware', function addStaticMiddleware() {
      var opts = {index: true};

      if (!this.static) {
        return;
      }

      if (_.isPlainObject(this.static)) {
        opts = _.extend(opts, this.static);
        opts.root = new Path({value: this.static.dir || './public'}).resolve();
      } else if (_.isString(this.static)) {
        opts.root = new Path({value: this.static || './public'}).resolve();
      }

      this._default_middleware.push({
        middleware: mach.file,
        args: [opts]
      });
    })

    /**
     * Adds session middleware.
     */
    .method('_addSessionMiddleware', function addSessionMiddleware() {
      var opts = {};

      if (!this.session) {
        return;
      }

      if (_.isPlainObject(this.session)) {
        opts = _.extend(opts, this.session);
      } else if (_.isString(this.session)) {
        opts.secret = this.session;
      }

      this._default_middleware.push({
        middleware: mach.session,
        args: [opts]
      });
    })

    /**
     * Delegates to the controller manager for loading up
     * controllers and mapping them to signatures for routing.
     */
    .method('_loadControllers', function loadControllers() {
      var controllerPath = new Path({value: this.dir}).resolve('controllers');

      this._controller_manager.dir = controllerPath;
      this._controller_manager._view_manager = this._view_manager;
      return this._controller_manager.load()
      .catch(function checkError(e) {
        return _.includes(e.message, 'ENOENT');
      }, function logError(e) {
        console.log('>> WARNING: No controllers directory found '+e.cause.path);
      });
    })

    /**
     * Delegates to the view manager for loading up views.
     */
    .method('_loadViews', function loadViews() {
      var viewPath = new Path({value: this.dir}).resolve('views');

      this._view_manager.engine = this.templating;
      this._view_manager.caching = this.caching;
      this._view_manager.dir = viewPath;
      this._view_manager.sharedData.Pimm = {
        config: this._config
      };
      return this._view_manager.load()
      .catch(function checkError(e) {
        return _.includes(e.message, 'ENOENT');
      }, function logError(e) {
        console.log('>> WARNING: No views directory found '+e.cause.path);
      });
    })

    /**
     * Removes any routes that don't have real controller
     * methods backing them up.
     */
    .method('_normalizeRoutes', function normalizeRoutes() {
      this._router.routes = _.filter(this._router.routes, _.bind(function checkRoute(route) {
        var handler = _.isFunction(route.action) ? route.action : this._controller_manager.methodForSignature(route.action);
        return _.isFunction(handler);
      }, this));
    })

    /**
     * Maps all the routes to controller handlers.
     */
    .method('_activateRoutes', function activateRoutes() {
      _.each(this._router.routes, _.bind(function activateRoute(route) {
        var handler = _.isFunction(route.action) ? route.action : this._controller_manager.methodForSignature(route.action);
        this._stack[route.method](route.path, handler);
      }, this));
    });

  module.exports = Pimm;
  module.exports.Controller = Controller;
}());
<|endoftext|>


<commit_before>// Plug application system.
// Copyright © 2011 Jan Keromnes, Thaddee Tyl. All rights reserved.
// The following code is covered by the GPLv2 license.

var fs = require('./fs'),
    driver = require('./driver'),
    nodepath = require('path'),
    lookup = require('./lookup');

// We need Camp's socket.io object here. We get it at initialization.
var camp;

exports.main = function (server) { camp = server; };

// The plug system.

exports.resolve = function (query, path, endres, ask) {

  // Get the file/folder corresponding to the query.
  ///console.log('PLUG: what is %s?', path[1]);
  path[1] = path[1];
  fs.file (path[1], function (err, file) {

    function sendraw() {
      path[0] = path[1];
      endres(); // bypass template engine
      console.log('ending', path[0]);
    }

    function end(err, plug, data) {
      if (err) {
        console.error(err);
        path[0] = '/404.html';
        endres();
        return;
      }
      if (!plug || plug === 'none')
        sendraw();
      else {
        if (nodepath.extname(plug).length === 0) plug += '.html';
        fs.file(plug, function(err, file) {
          // TODO template with file.content instead of giving plug path.
          if (err) sendraw();
          else {
            path[0] = plug;
            endres(data || {});
          }
        });
      }
    }

    // If there was an error, abort!
    if (err) {
      ask.res.statusCode = 404;
      end(err, '404.html', {error: err.message});
      return;
    }

    // TODO If file requires a password and nothing matches, abort!

    // set HTTP header Last-Modified
    if (file.meta['Last-Modified']) {
      ask.res.setHeader('Last-Modified',
          (new Date(file.meta['Last-Modified'])).toGMTString());
    }

    // PLUG MECHANISM

    var data = {};

    // Environment variable lookup mechanism.
    data.lookup = lookup(file, query);

    // File info.
    data.file = file;
    data.file.mime = file.meta.type;
    data.files = [];
    data.title = nodepath.basename(file.path) || 'The File Tree';
    data.extname = nodepath.extname(file.path).slice(1);

    // Navigation crumbs
    data.nav = [];
    var crumbs = path[1].split('/').filter(function(e) {
      return e.length > 0;
    });
    var subpath = '/';
    data.nav.push({name: '/', path: subpath});
    for (var i = 0; i < crumbs.length; i++) {
      crumbs[i] += (i < crumbs.length - 1 || file.isOfType('dir') ? '/' : '');
      subpath += crumbs[i];
      data.nav.push({name: crumbs[i], path: subpath});
    }

    findPlug(file, path, data, end);
  });
};

// Find the correct plug.
//
// 1. Look for the non-inherited `plug` metadata.
// 2. Look for the inherited `plugs.<file type>` metadata.
function findPlug(file, path, data, end) {
  var plug = data.lookup('plug');

  if (plug === 'none') {
    end(); // no plug
    return;
  }

  if (file.isOfType('dir')) {

    // Handle missing final '/'.
    // FIXME consider redirecting user to path[1] + '/' instead.
    if (path[1][path[1].length-1] !== '/') {
      path[1] += '/';
    }

    // Get subfiles.
    file.files (function (err, files) {
      if (err)  console.error(err);
      for (var i = 0; i < files.length; i++) {
        var filepath = driver.normalize(
          files[i].path + (files[i].isOfType('dir') ? '/' : ''));
        data.files.push({name: nodepath.basename(filepath),
                         path: filepath,
                         type: files[i].meta.type});
      }
      ///console.log('server:root: data sent from dir is', data);

      if (plug == null) {
        data.lookup('plugs.dir', function(plug) {
          end(err, plug || 'gateway.html', data);
        });
      } else {
        end(err, plug, data);
      }
    });

  } else if (file.isOfType('text')) {

    file.ot(camp.io, function(err) {
      if (plug == null) {
        data.lookup('plugs.text', function(plug) {
          end(err, plug || 'pencil.html', data);
        });
      } else {
        end(err, plug, data);
      }
    });

  } else if (file.isOfType('binary')) {

    if (plug == null) {
      data.lookup('plugs.binary', function(plug) {
        end(null, plug || 'none', data);
      });
    } else {
      end(null, plug, data);
    }
  }
}
<commit_msg>[plug] clearer logs<commit_after>// Plug application system.
// Copyright © 2011 Jan Keromnes, Thaddee Tyl. All rights reserved.
// The following code is covered by the GPLv2 license.

var fs = require('./fs'),
    driver = require('./driver'),
    nodepath = require('path'),
    lookup = require('./lookup');

// We need Camp's socket.io object here. We get it at initialization.
var camp;

exports.main = function (server) { camp = server; };

// The plug system.

exports.resolve = function (query, path, endres, ask) {

  // Get the file/folder corresponding to the query.
  ///console.log('PLUG: what is %s?', path[1]);
  path[1] = path[1];
  fs.file (path[1], function (err, file) {

    function sendraw() {
      console.log('send', path[1]);
      path[0] = path[1];
      endres(); // bypass template engine
    }

    function end(err, plug, data) {
      if (err) {
        console.error(err);
        path[0] = '/404.html';
        endres();
        return;
      }
      if (!plug || plug === 'none')
        sendraw();
      else {
        if (nodepath.extname(plug).length === 0) plug += '.html';
        fs.file(plug, function(err, file) {
          // TODO template with file.content instead of giving plug path.
          if (err) sendraw();
          else {
            console.log('plug', plug, '<', path[1]);
            path[0] = plug;
            endres(data || {});
          }
        });
      }
    }

    // If there was an error, abort!
    if (err) {
      ask.res.statusCode = 404;
      end(err, '404.html', {error: err.message});
      return;
    }

    // TODO If file requires a password and nothing matches, abort!

    // set HTTP header Last-Modified
    if (file.meta['Last-Modified']) {
      ask.res.setHeader('Last-Modified',
          (new Date(file.meta['Last-Modified'])).toGMTString());
    }

    // PLUG MECHANISM

    var data = {};

    // Environment variable lookup mechanism.
    data.lookup = lookup(file, query);

    // File info.
    data.file = file;
    data.file.mime = file.meta.type;
    data.files = [];
    data.title = nodepath.basename(file.path) || 'The File Tree';
    data.extname = nodepath.extname(file.path).slice(1);

    // Navigation crumbs
    data.nav = [];
    var crumbs = path[1].split('/').filter(function(e) {
      return e.length > 0;
    });
    var subpath = '/';
    data.nav.push({name: '/', path: subpath});
    for (var i = 0; i < crumbs.length; i++) {
      crumbs[i] += (i < crumbs.length - 1 || file.isOfType('dir') ? '/' : '');
      subpath += crumbs[i];
      data.nav.push({name: crumbs[i], path: subpath});
    }

    findPlug(file, path, data, end);
  });
};

// Find the correct plug.
//
// 1. Look for the non-inherited `plug` metadata.
// 2. Look for the inherited `plugs.<file type>` metadata.
function findPlug(file, path, data, end) {
  var plug = data.lookup('plug');

  if (plug === 'none') {
    end(); // no plug
    return;
  }

  if (file.isOfType('dir')) {

    // Handle missing final '/'.
    // FIXME consider redirecting user to path[1] + '/' instead.
    if (path[1][path[1].length-1] !== '/') {
      path[1] += '/';
    }

    // Get subfiles.
    file.files (function (err, files) {
      if (err)  console.error(err);
      for (var i = 0; i < files.length; i++) {
        var filepath = driver.normalize(
          files[i].path + (files[i].isOfType('dir') ? '/' : ''));
        data.files.push({name: nodepath.basename(filepath),
                         path: filepath,
                         type: files[i].meta.type});
      }
      ///console.log('server:root: data sent from dir is', data);

      if (plug == null) {
        data.lookup('plugs.dir', function(plug) {
          end(err, plug || 'gateway.html', data);
        });
      } else {
        end(err, plug, data);
      }
    });

  } else if (file.isOfType('text')) {

    file.ot(camp.io, function(err) {
      if (plug == null) {
        data.lookup('plugs.text', function(plug) {
          end(err, plug || 'pencil.html', data);
        });
      } else {
        end(err, plug, data);
      }
    });

  } else if (file.isOfType('binary')) {

    if (plug == null) {
      data.lookup('plugs.binary', function(plug) {
        end(null, plug || 'none', data);
      });
    } else {
      end(null, plug, data);
    }
  }
}
<|endoftext|>