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

    var   Class             = require('ee-class')
        , log               = require('ee-log')
        , type              = require('ee-types')
        , EventEmitter      = require('ee-event-emitter')
        , argv              = require('ee-argv')
        , async             = require('ee-async')
        , DBCluster         = require('../../ee-db-cluster')
        , Database          = require('./Database')
        , StaticORM         = require('./StaticORM')
        , Set               = require('./Set')
        , ExtensionManager  = require('./ExtensionManager')
        , ModelDefinition   = require('./ModelDefinition')
        , debug             = argv.has('debug-sql')
        , dev               = argv.has('dev-orm')
        , staticORM
        , ORM;

    ORM = new Class({
        inherits: EventEmitter

        // indicates if the orm was loaded
        , _loaded: false

        // indicates that the laoding process has started
        , _loading: false

        /*
         * class constructor, initialize everything
         */
        , init: function(options) {
            // store my options
            Class.define(this, '_options', Class(options));

            // list of databse defintions
            Class.define(this, '_dbs', Class([]));

            // all loaded extension
            Class.define(this, '_extensions', Class(new ExtensionManager(this)));

            // the actual database connections
            Class.define(this, '_databases', Class({}));

            // indicators
            Class.define(this, '_loaded', Class(false).Writable());
            Class.define(this, '_loading', Class(false).Writable());

            // db connectivity
            this._initializeDatabases(options);

            // load the orm, but wait for the next cycle doing
            // this, preventing a reload when the user adds his
            // extensions in time
            process.nextTick(function() {
                this._initializeOrm(function(err){
                    this._loaded = true;
                    this._loading = false;
                    this.emit('load', err);
                }.bind(this));
            }.bind(this));
        }

        /*
         * accepts extension to the orm
         */
        , use: function(extension) {
            if (!extension || !type.function(extension.isExtension) || !extension.isExtension()) throw new Error('cannot add extion to orm, it doesn\'t register itself as one!');

            // register the extension
            this._extensions.register(extension);
            return this;
        }

        /*
         * return a specific extension
         */
        , getExtension: function(name) {
            return this._extensions.get(name);
        }

        /*
         * indicates if the orm was laoded already
         */
        , isLoaded: function() {
            return !!this._loaded;
        }

        /*
         * rebuilds the orm from scratch
         */
        , reload: function(callback) {
            if (!this._loading) {
                this._loaded = false;

                this._initializeOrm(function(err) {
                    this._loaded = true;
                    this._loading = false;
                    this.emit('reload', err);
                    if (callback) callback(err);
                }.bind(this));
            }
            else {
                this.once('reload', function() {
                    this.relaod(callback);
                }.bind(this));
            }
        }

        /*
         * return the ORM object used to create filters & more
         */
        , getORM: function() {
            return ORM;
        }

        /*
         * initializtes the orm, reads the db definition, checks if for relations
         * and their names
         */
        , _initializeOrm: function(callback) {
            if (dev) log.debug('initializing ORM ...');

            // inidcate that we're busy loading the db
            this._loading = true;

            async.each(this._dbs

            // remove existing
            , function(db, next) {
                if (this[db.databaseName] && this[db.databaseName].createTransaction) {
                    if (dev) log.debug('removing existing db instance «'+db.databaseName+'»...');
                    delete this[db.databaseName];
                }

                next(null, db);
            }.bind(this)

            // get definition from database
            , function(db, next){
                this._databases[db.databaseName].describe([db.databaseName], function(err, databases){
                    if (dev) log.debug('got db definition for «'+db.databaseName+'»...');

                    if (err) next(err);
                    else {
                        // push config to next step
                        next(null, db, databases[db.databaseName]);
                    }
                }.bind(this));
            }.bind(this)

            // initialize orm per databse
            , function(db, definition, next){
                var newDefinition = {};

                if (this[db.databaseName]) next(new Error('Failed to load ORM for database «'+db.databaseName+'», the name is reserved for the orm.').setName('ORMException'));
                else {
                    // build the model definitions from the raw definitions
                    Object.keys(definition).forEach(function(modelName) {
                        newDefinition[modelName] = new ModelDefinition(definition[modelName]);
                    }.bind(this));

                    // create names for mapping / reference accessor, handle duplicates
                    this._manageAccessorNames(newDefinition, db);

                    if (dev) log.debug('creating new db instance for «'+db.databaseName+'»...');

                    this[db.databaseName] = new Database({
                          orm:          this
                        , definition:   newDefinition
                        , database:     this._databases[db.databaseName]
                        , timeouts:     db.config.timeouts
                        , databaseName: db.databaseName
                        , extensions:   this._extensions
                    });

                    this[db.databaseName].on('load', next);
                }
            }.bind(this)

            // check for errors
            , function(err, results){
                 if (dev) log.warn('all dbs loaded ...');

                if (err) callback(err);
                else callback();
            }.bind(this));
        }

        /*
         * checks if there are names that are used twice, if so it
         * disables them for direct access
         */
        , _manageAccessorNames: function(definition, db) {
            var   timestamps    = db.config.timestamps || {}
                , nestedSet     = db.config.nestedSet || {};

            Object.keys(definition).forEach(function(tablename){
                var   model         = definition[tablename]
                    , usedNames     = {}
                    , isNestedSet   = 0;

                Object.keys(model.columns).forEach(function(columnName){
                    var   column = model.columns[columnName]
                        , name;

                    if (column.mapsTo) {
                        column.mapsTo.forEach(function(mapping){
                            name = mapping.name;

                            if (name !== model.name) {
                                if (model.columns[name]) {
                                    // the name is used by a column, cannot reference directly
                                    if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                    mapping.useGenericAccessor = true;
                                }
                                else if (usedNames[name]) {
                                    // the name was used before by either a mapping or a reference
                                    // we cannot use it
                                    if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                    usedNames[name].useGenericAccessor = true;
                                    mapping.useGenericAccessor = true;
                                }
                                else usedNames[name] = mapping;
                            }
                        }.bind(this));
                    }
                    if (column.belongsTo) {
                        column.belongsTo.forEach(function(beloning){
                            name = beloning.name;

                            if (model.columns[name]) {
                                if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                // the name is used by a column, cannot reference directly
                                beloning.useGenericAccessor = true;
                            }
                            else if (usedNames[name]) {
                                if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                // the name was used before by either a mapping or a reference
                                // we cannot use it
                                usedNames[name].useGenericAccessor = true;
                                beloning.useGenericAccessor = true;
                            }
                            else usedNames[name] = beloning;
                        }.bind(this));
                    }
                    if (column.referencedModel && column.referencedModel.name !== model.name) {
                        name = column.referencedModel.name;

                        if (model.columns[name]) {
                            if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                            // the name is used by a column, cannot reference directly
                            column.useGenericAccessor = true;
                        }
                        else if (usedNames[name]) {
                            if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                            // the name was used before by either a mapping or a reference
                            // we cannot use it
                            usedNames[name].useGenericAccessor = true;
                            column.useGenericAccessor = true;
                        }
                        else usedNames[name] = column;
                    }
                }.bind(this));

                // did we find a nested set on the model?
                if (isNestedSet === 2) {
                    Class.define(model, 'isNestedSet', Class(true).Enumerable());
                    Class.define(model, 'nestedSetLeft', Class(nestedSet.left).Enumerable());
                    Class.define(model, 'nestedSetRight', Class(nestedSet.right).Enumerable());
                }
            }.bind(this));
        }

        /*
         * returns the orm databse object
         */
        , getDatabase: function(id){
            if (!type.string(id) || !id.length) throw new Error('cannot return a db without knowing which on to return (argument 0 must be the db id!)');
            return this._databases[id];
        }

        /*
         * yeah, this one is required
         */
        , doItAll: function() {
            log.wtf('hui');
        }

        /*
         * initializes the db clusters, connectors to the database
         */
        , _initializeDatabases: function(options){
            if (type.object(options)) {
                Object.keys(options).forEach(function(databaseName){
                    if (!type.string(options[databaseName].type)) throw new Error('['+databaseName+'] > Database type not in config specified (type: \'mysql\' / \'postgres\')!');
                    if (!type.array(options[databaseName].hosts) || !options[databaseName].hosts.length) throw new Error('['+databaseName+'] > Please add at least one host per db in the config!');

                    this._dbs.push({
                          databaseName  : databaseName
                        , config        : options[databaseName]
                    });

                    this._databases[databaseName] = new DBCluster({type: options[databaseName].type});

                    options[databaseName].hosts.forEach(function(config){
                        config.database = config.database || databaseName;
                        this._databases[databaseName].addNode(config);
                    }.bind(this));
                }.bind(this));
            }
            else throw new Error('no database configuration present!');
        }
    });

    // set static methods on the ORM constructor
    Class.implement(new StaticORM(), ORM);

    // export the set so extensions can make use of it
    ORM.Set = Set;

    module.exports = ORM;
}();
<commit_msg>fixed dependecies<commit_after>!function(){
    'use strict';

    var   Class             = require('ee-class')
        , log               = require('ee-log')
        , type              = require('ee-types')
        , EventEmitter      = require('ee-event-emitter')
        , argv              = require('ee-argv')
        , async             = require('ee-async')
        , DBCluster         = require('ee-db-cluster')
        , Database          = require('./Database')
        , StaticORM         = require('./StaticORM')
        , Set               = require('./Set')
        , ExtensionManager  = require('./ExtensionManager')
        , ModelDefinition   = require('./ModelDefinition')
        , debug             = argv.has('debug-sql')
        , dev               = argv.has('dev-orm')
        , staticORM
        , ORM;

    ORM = new Class({
        inherits: EventEmitter

        // indicates if the orm was loaded
        , _loaded: false

        // indicates that the laoding process has started
        , _loading: false

        /*
         * class constructor, initialize everything
         */
        , init: function(options) {
            // store my options
            Class.define(this, '_options', Class(options));

            // list of databse defintions
            Class.define(this, '_dbs', Class([]));

            // all loaded extension
            Class.define(this, '_extensions', Class(new ExtensionManager(this)));

            // the actual database connections
            Class.define(this, '_databases', Class({}));

            // indicators
            Class.define(this, '_loaded', Class(false).Writable());
            Class.define(this, '_loading', Class(false).Writable());

            // db connectivity
            this._initializeDatabases(options);

            // load the orm, but wait for the next cycle doing
            // this, preventing a reload when the user adds his
            // extensions in time
            process.nextTick(function() {
                this._initializeOrm(function(err){
                    this._loaded = true;
                    this._loading = false;
                    this.emit('load', err);
                }.bind(this));
            }.bind(this));
        }

        /*
         * accepts extension to the orm
         */
        , use: function(extension) {
            if (!extension || !type.function(extension.isExtension) || !extension.isExtension()) throw new Error('cannot add extion to orm, it doesn\'t register itself as one!');

            // register the extension
            this._extensions.register(extension);
            return this;
        }

        /*
         * return a specific extension
         */
        , getExtension: function(name) {
            return this._extensions.get(name);
        }

        /*
         * indicates if the orm was laoded already
         */
        , isLoaded: function() {
            return !!this._loaded;
        }

        /*
         * rebuilds the orm from scratch
         */
        , reload: function(callback) {
            if (!this._loading) {
                this._loaded = false;

                this._initializeOrm(function(err) {
                    this._loaded = true;
                    this._loading = false;
                    this.emit('reload', err);
                    if (callback) callback(err);
                }.bind(this));
            }
            else {
                this.once('reload', function() {
                    this.relaod(callback);
                }.bind(this));
            }
        }

        /*
         * return the ORM object used to create filters & more
         */
        , getORM: function() {
            return ORM;
        }

        /*
         * initializtes the orm, reads the db definition, checks if for relations
         * and their names
         */
        , _initializeOrm: function(callback) {
            if (dev) log.debug('initializing ORM ...');

            // inidcate that we're busy loading the db
            this._loading = true;

            async.each(this._dbs

            // remove existing
            , function(db, next) {
                if (this[db.databaseName] && this[db.databaseName].createTransaction) {
                    if (dev) log.debug('removing existing db instance «'+db.databaseName+'»...');
                    delete this[db.databaseName];
                }

                next(null, db);
            }.bind(this)

            // get definition from database
            , function(db, next){
                this._databases[db.databaseName].describe([db.databaseName], function(err, databases){
                    if (dev) log.debug('got db definition for «'+db.databaseName+'»...');

                    if (err) next(err);
                    else {
                        // push config to next step
                        next(null, db, databases[db.databaseName]);
                    }
                }.bind(this));
            }.bind(this)

            // initialize orm per databse
            , function(db, definition, next){
                var newDefinition = {};

                if (this[db.databaseName]) next(new Error('Failed to load ORM for database «'+db.databaseName+'», the name is reserved for the orm.').setName('ORMException'));
                else {
                    // build the model definitions from the raw definitions
                    Object.keys(definition).forEach(function(modelName) {
                        newDefinition[modelName] = new ModelDefinition(definition[modelName]);
                    }.bind(this));

                    // create names for mapping / reference accessor, handle duplicates
                    this._manageAccessorNames(newDefinition, db);

                    if (dev) log.debug('creating new db instance for «'+db.databaseName+'»...');

                    this[db.databaseName] = new Database({
                          orm:          this
                        , definition:   newDefinition
                        , database:     this._databases[db.databaseName]
                        , timeouts:     db.config.timeouts
                        , databaseName: db.databaseName
                        , extensions:   this._extensions
                    });

                    this[db.databaseName].on('load', next);
                }
            }.bind(this)

            // check for errors
            , function(err, results){
                 if (dev) log.warn('all dbs loaded ...');

                if (err) callback(err);
                else callback();
            }.bind(this));
        }

        /*
         * checks if there are names that are used twice, if so it
         * disables them for direct access
         */
        , _manageAccessorNames: function(definition, db) {
            var   timestamps    = db.config.timestamps || {}
                , nestedSet     = db.config.nestedSet || {};

            Object.keys(definition).forEach(function(tablename){
                var   model         = definition[tablename]
                    , usedNames     = {}
                    , isNestedSet   = 0;

                Object.keys(model.columns).forEach(function(columnName){
                    var   column = model.columns[columnName]
                        , name;

                    if (column.mapsTo) {
                        column.mapsTo.forEach(function(mapping){
                            name = mapping.name;

                            if (name !== model.name) {
                                if (model.columns[name]) {
                                    // the name is used by a column, cannot reference directly
                                    if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                    mapping.useGenericAccessor = true;
                                }
                                else if (usedNames[name]) {
                                    // the name was used before by either a mapping or a reference
                                    // we cannot use it
                                    if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                    usedNames[name].useGenericAccessor = true;
                                    mapping.useGenericAccessor = true;
                                }
                                else usedNames[name] = mapping;
                            }
                        }.bind(this));
                    }
                    if (column.belongsTo) {
                        column.belongsTo.forEach(function(beloning){
                            name = beloning.name;

                            if (model.columns[name]) {
                                if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                // the name is used by a column, cannot reference directly
                                beloning.useGenericAccessor = true;
                            }
                            else if (usedNames[name]) {
                                if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                                // the name was used before by either a mapping or a reference
                                // we cannot use it
                                usedNames[name].useGenericAccessor = true;
                                beloning.useGenericAccessor = true;
                            }
                            else usedNames[name] = beloning;
                        }.bind(this));
                    }
                    if (column.referencedModel && column.referencedModel.name !== model.name) {
                        name = column.referencedModel.name;

                        if (model.columns[name]) {
                            if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                            // the name is used by a column, cannot reference directly
                            column.useGenericAccessor = true;
                        }
                        else if (usedNames[name]) {
                            if (debug) log.warn('«'+model.name+'» cannot use the accessor «'+name+'», it\'s already used by another property');
                            // the name was used before by either a mapping or a reference
                            // we cannot use it
                            usedNames[name].useGenericAccessor = true;
                            column.useGenericAccessor = true;
                        }
                        else usedNames[name] = column;
                    }
                }.bind(this));

                // did we find a nested set on the model?
                if (isNestedSet === 2) {
                    Class.define(model, 'isNestedSet', Class(true).Enumerable());
                    Class.define(model, 'nestedSetLeft', Class(nestedSet.left).Enumerable());
                    Class.define(model, 'nestedSetRight', Class(nestedSet.right).Enumerable());
                }
            }.bind(this));
        }

        /*
         * returns the orm databse object
         */
        , getDatabase: function(id){
            if (!type.string(id) || !id.length) throw new Error('cannot return a db without knowing which on to return (argument 0 must be the db id!)');
            return this._databases[id];
        }

        /*
         * yeah, this one is required
         */
        , doItAll: function() {
            log.wtf('hui');
        }

        /*
         * initializes the db clusters, connectors to the database
         */
        , _initializeDatabases: function(options){
            if (type.object(options)) {
                Object.keys(options).forEach(function(databaseName){
                    if (!type.string(options[databaseName].type)) throw new Error('['+databaseName+'] > Database type not in config specified (type: \'mysql\' / \'postgres\')!');
                    if (!type.array(options[databaseName].hosts) || !options[databaseName].hosts.length) throw new Error('['+databaseName+'] > Please add at least one host per db in the config!');

                    this._dbs.push({
                          databaseName  : databaseName
                        , config        : options[databaseName]
                    });

                    this._databases[databaseName] = new DBCluster({type: options[databaseName].type});

                    options[databaseName].hosts.forEach(function(config){
                        config.database = config.database || databaseName;
                        this._databases[databaseName].addNode(config);
                    }.bind(this));
                }.bind(this));
            }
            else throw new Error('no database configuration present!');
        }
    });

    // set static methods on the ORM constructor
    Class.implement(new StaticORM(), ORM);

    // export the set so extensions can make use of it
    ORM.Set = Set;

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


<commit_before>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var util = require('util');
var assert = require('assert');

var swiz = require('swiz');
var trim = require('./../lib/util').trim;

assert.trimEqual = function(actual, expected, message) {
  actual = trim(actual);
  expected = trim(expected);
  assert.equal(actual, expected, message);
};

// Mock set of serialization defs
var def = {
  'Node' : [
    ['id' , {'src' : 'hash_id', 'type' : 'string',
      'desc' : 'hash ID for the node'}],
    ['is_active' , {'src' : 'active', 'type' : 'bool',
      'desc' : 'is the node active?'}],
    ['name' , {'src' : 'get_name', 'type' : 'string', 'desc' : 'name' }],
    ['agent_name' , {'type': 'string'}],
    ['ipaddress' , {'src' : 'get_public_address', 'type' : 'ip'}],
    ['public_ips' , {'cache_key' : 'node_addrs_public', 'type' : 'list<ip>'}],
    ['state', {'enumerated' : {inactive: 0, active: 1, full_no_new_checks: 2}}],
    ['opts', {'src': 'options', 'type': 'NodeOpts'}],
    ['data', {'src': 'data', 'type': 'map<string, object>'}]
  ],
  'NodeOpts': [
    ['option1', {'src': 'opt1', 'type': 'string'}],
    ['option2', {'src': 'opt2', 'type': 'string'}],
    ['option3', {'src': 'opt3', 'type': 'string'}]
  ]
};

/** Completely mock node object.
* @constructor
*/
function Node() {
  this.hash_id = '15245';
  this.active = true;
  this.agent_name = 'gl<ah';
  this.public_ips = ['123.45.55.44', '122.123.32.2'];
  this.public_address = '123.33.22.1';
  this.state = 1;
  this.options = {
    'opt1': 'defaultval',
    'opt2': 'defaultval',
    'opt3': function(callback) {
      callback(null, 'something');
    }
  };

  this.options.getSerializerType = function() {
    return 'NodeOpts';
  };

  this.data = {
    'foo': 'thingone',
    'bar': 'thingtwo'
  };
}

/**
 * Dummy funct
 * @param {function(*,*)} callback junk.
 */
Node.prototype.get_name = function(callback) {
  callback(null, 'gggggg');
};

/**
 * Dummy funct
 * @param {function(*,*)} callback junk.
*/
Node.prototype.get_public_address = function(callback) {
  callback(null, this.public_address);
};

/**
 * Dummy funct
 * @return {string} junk.
*/
Node.prototype.getSerializerType = function() {return 'Node';};

exports['test_xml_escape_string'] = function(test, assert) {
  var sw = new swiz.Swiz(def);
  assert.deepEqual(sw.xmlEscapeString('<&blah>'), '<&blah>');

  test.finish();
};

exports['test_build_object'] = function(test, assert) {
  var blahnode = new Node();
  var sw = new swiz.Swiz(def);
  sw.buildObject(blahnode, function(err, result) {
    assert.ifError(err);
    assert.deepEqual(result, {
      id: 15245,
      is_active: true,
      name: 'gggggg',
      agent_name: 'gl<ah',
      ipaddress: '123.33.22.1',
      public_ips: ['123.45.55.44', '122.123.32.2'],
      opts: {
        option1: 'defaultval',
        option2: 'defaultval',
        option3: 'something'
      },
      data: {
        foo: 'thingone',
        bar: 'thingtwo'
      },
      state: 'active'
    });
    test.finish();
  });
};

exports['test_serial_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id><is_active>false</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1>' +
            '<option2>defaultval</option2>' +
            '<option3>something</option3>' +
            '</NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_xml_stripNulls'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = null;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id>' +
            '<name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1>' +
            '<option2>defaultval</option2>' +
            '<option3>something</option3>' +
            '</NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_json'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blahnode,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep.id, 15245);
        assert.deepEqual(rep.is_active, false);
        assert.deepEqual(rep.name, 'gggggg');
        assert.deepEqual(rep.agent_name, 'gl<ah');
        assert.deepEqual(rep.ipaddress, '123.33.22.1');
        assert.deepEqual(rep.public_ips, ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep.opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep.data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep.state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_json_stripNulls'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = null;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blahnode,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep.id, 15245);
        assert.ok(!rep.hasOwnProperty('is_active'));
        assert.deepEqual(rep.name, 'gggggg');
        assert.deepEqual(rep.agent_name, 'gl<ah');
        assert.deepEqual(rep.ipaddress, '123.33.22.1');
        assert.deepEqual(rep.public_ips, ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep.opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep.data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep.state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_array_xml'] = function(test, assert) {
  var blahnode = new Node();
  var blahnode2 = new Node();
  blahnode2.hash_id = '444';
  blahnode2.agent_name = 'your mom';
  var blaharr = [blahnode, blahnode2];
  var sw = new swiz.Swiz(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blaharr,
      function(err, results)
      {
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<group><Node><id>15245</id><is_active>true</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1><option2>defaultval</option2>' +
            '<option3>something</option3></NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>' +
            '<Node><id>444</id><is_active>true</' +
            'is_active><name>gggggg</name><agent_name>your mom</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1><option2>defaultval</option2>' +
            '<option3>something</option3></NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>' +
            '</group>');

        test.finish();
      }
  );
};

exports['test_error_type'] = function(test, assert) {
  var blah = { };
  var sw = new swiz.Swiz(def);
  blah.getSerializerType = function() {return 'monito';};
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blah,
      function(err, results)
      {
        assert.ok(err instanceof Error);

        test.finish();
      }
  );
};

exports['test_serial_array_json'] = function(test, assert) {
  var blahnode = new Node();
  var blahnode2 = new Node();
  blahnode2.hash_id = '444';
  blahnode2.agent_name = 'your mom';
  var blaharr = [blahnode, blahnode2];
  var sw = new swiz.Swiz(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blaharr,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep[0].id, 15245);
        assert.deepEqual(rep[0].is_active, true);
        assert.deepEqual(rep[0].name, 'gggggg');
        assert.deepEqual(rep[0].agent_name, 'gl<ah');
        assert.deepEqual(rep[0].ipaddress, '123.33.22.1');
        assert.deepEqual(rep[0].public_ips,
            ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep[0].opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep[0].data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep[0].state, 'active');
        assert.deepEqual(rep[1].id, 444);
        assert.deepEqual(rep[1].is_active, true);
        assert.deepEqual(rep[1].name, 'gggggg');
        assert.deepEqual(rep[1].agent_name, 'your mom');
        assert.deepEqual(rep[1].ipaddress, '123.33.22.1');
        assert.deepEqual(rep[1].public_ips,
            ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep[1].opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep[1].data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep[1].state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_edge_cases_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  blahnode.public_ips = [];
  blahnode.options = {};
  var sw = new swiz.Swiz(def, { stripNulls: true });
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id><is_active>false</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<state>active</state>' +
            '<opts />' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_invalid_serializer_type_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.getSerializerType = function() {
    return 'foobar';
  };
  var sw = new swiz.Swiz(def, { stripNulls: true });
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        assert.ok(err);
        assert.ok(!results);
        test.finish();
      }
  );
};
<commit_msg>Remove obsolete test.<commit_after>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var util = require('util');
var assert = require('assert');

var swiz = require('swiz');
var trim = require('./../lib/util').trim;

assert.trimEqual = function(actual, expected, message) {
  actual = trim(actual);
  expected = trim(expected);
  assert.equal(actual, expected, message);
};

// Mock set of serialization defs
var def = {
  'Node' : [
    ['id' , {'src' : 'hash_id', 'type' : 'string',
      'desc' : 'hash ID for the node'}],
    ['is_active' , {'src' : 'active', 'type' : 'bool',
      'desc' : 'is the node active?'}],
    ['name' , {'src' : 'get_name', 'type' : 'string', 'desc' : 'name' }],
    ['agent_name' , {'type': 'string'}],
    ['ipaddress' , {'src' : 'get_public_address', 'type' : 'ip'}],
    ['public_ips' , {'cache_key' : 'node_addrs_public', 'type' : 'list<ip>'}],
    ['state', {'enumerated' : {inactive: 0, active: 1, full_no_new_checks: 2}}],
    ['opts', {'src': 'options', 'type': 'NodeOpts'}],
    ['data', {'src': 'data', 'type': 'map<string, object>'}]
  ],
  'NodeOpts': [
    ['option1', {'src': 'opt1', 'type': 'string'}],
    ['option2', {'src': 'opt2', 'type': 'string'}],
    ['option3', {'src': 'opt3', 'type': 'string'}]
  ]
};

/** Completely mock node object.
* @constructor
*/
function Node() {
  this.hash_id = '15245';
  this.active = true;
  this.agent_name = 'gl<ah';
  this.public_ips = ['123.45.55.44', '122.123.32.2'];
  this.public_address = '123.33.22.1';
  this.state = 1;
  this.options = {
    'opt1': 'defaultval',
    'opt2': 'defaultval',
    'opt3': function(callback) {
      callback(null, 'something');
    }
  };

  this.options.getSerializerType = function() {
    return 'NodeOpts';
  };

  this.data = {
    'foo': 'thingone',
    'bar': 'thingtwo'
  };
}

/**
 * Dummy funct
 * @param {function(*,*)} callback junk.
 */
Node.prototype.get_name = function(callback) {
  callback(null, 'gggggg');
};

/**
 * Dummy funct
 * @param {function(*,*)} callback junk.
*/
Node.prototype.get_public_address = function(callback) {
  callback(null, this.public_address);
};

/**
 * Dummy funct
 * @return {string} junk.
*/
Node.prototype.getSerializerType = function() {return 'Node';};

exports['test_build_object'] = function(test, assert) {
  var blahnode = new Node();
  var sw = new swiz.Swiz(def);
  sw.buildObject(blahnode, function(err, result) {
    assert.ifError(err);
    assert.deepEqual(result, {
      id: 15245,
      is_active: true,
      name: 'gggggg',
      agent_name: 'gl<ah',
      ipaddress: '123.33.22.1',
      public_ips: ['123.45.55.44', '122.123.32.2'],
      opts: {
        option1: 'defaultval',
        option2: 'defaultval',
        option3: 'something'
      },
      data: {
        foo: 'thingone',
        bar: 'thingtwo'
      },
      state: 'active'
    });
    test.finish();
  });
};

exports['test_serial_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id><is_active>false</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1>' +
            '<option2>defaultval</option2>' +
            '<option3>something</option3>' +
            '</NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_xml_stripNulls'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = null;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id>' +
            '<name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1>' +
            '<option2>defaultval</option2>' +
            '<option3>something</option3>' +
            '</NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_json'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blahnode,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep.id, 15245);
        assert.deepEqual(rep.is_active, false);
        assert.deepEqual(rep.name, 'gggggg');
        assert.deepEqual(rep.agent_name, 'gl<ah');
        assert.deepEqual(rep.ipaddress, '123.33.22.1');
        assert.deepEqual(rep.public_ips, ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep.opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep.data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep.state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_json_stripNulls'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = null;
  var sw = new swiz.Swiz(def, { stripNulls: true });
  //swiz.loadDefinitions(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blahnode,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep.id, 15245);
        assert.ok(!rep.hasOwnProperty('is_active'));
        assert.deepEqual(rep.name, 'gggggg');
        assert.deepEqual(rep.agent_name, 'gl<ah');
        assert.deepEqual(rep.ipaddress, '123.33.22.1');
        assert.deepEqual(rep.public_ips, ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep.opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep.data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep.state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_array_xml'] = function(test, assert) {
  var blahnode = new Node();
  var blahnode2 = new Node();
  blahnode2.hash_id = '444';
  blahnode2.agent_name = 'your mom';
  var blaharr = [blahnode, blahnode2];
  var sw = new swiz.Swiz(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blaharr,
      function(err, results)
      {
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<group><Node><id>15245</id><is_active>true</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1><option2>defaultval</option2>' +
            '<option3>something</option3></NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>' +
            '<Node><id>444</id><is_active>true</' +
            'is_active><name>gggggg</name><agent_name>your mom</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<public_ips>123.45.55.44</public_ips>' +
            '<public_ips>122.123.32.2</public_ips>' +
            '<state>active</state>' +
            '<opts><NodeOpts>' +
            '<option1>defaultval</option1><option2>defaultval</option2>' +
            '<option3>something</option3></NodeOpts></opts>' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>' +
            '</group>');

        test.finish();
      }
  );
};

exports['test_error_type'] = function(test, assert) {
  var blah = { };
  var sw = new swiz.Swiz(def);
  blah.getSerializerType = function() {return 'monito';};
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blah,
      function(err, results)
      {
        assert.ok(err instanceof Error);

        test.finish();
      }
  );
};

exports['test_serial_array_json'] = function(test, assert) {
  var blahnode = new Node();
  var blahnode2 = new Node();
  blahnode2.hash_id = '444';
  blahnode2.agent_name = 'your mom';
  var blaharr = [blahnode, blahnode2];
  var sw = new swiz.Swiz(def);
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_JSON, 1, blaharr,
      function(err, results)
      {
        var rep = JSON.parse(results);
        assert.deepEqual(rep[0].id, 15245);
        assert.deepEqual(rep[0].is_active, true);
        assert.deepEqual(rep[0].name, 'gggggg');
        assert.deepEqual(rep[0].agent_name, 'gl<ah');
        assert.deepEqual(rep[0].ipaddress, '123.33.22.1');
        assert.deepEqual(rep[0].public_ips,
            ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep[0].opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep[0].data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep[0].state, 'active');
        assert.deepEqual(rep[1].id, 444);
        assert.deepEqual(rep[1].is_active, true);
        assert.deepEqual(rep[1].name, 'gggggg');
        assert.deepEqual(rep[1].agent_name, 'your mom');
        assert.deepEqual(rep[1].ipaddress, '123.33.22.1');
        assert.deepEqual(rep[1].public_ips,
            ['123.45.55.44', '122.123.32.2']);
        assert.deepEqual(rep[1].opts, {
          option1: 'defaultval',
          option2: 'defaultval',
          option3: 'something'
        });
        assert.deepEqual(rep[1].data, {
          foo: 'thingone',
          bar: 'thingtwo'
        });
        assert.deepEqual(rep[1].state, 'active');
        test.finish();
      }
  );
};

exports['test_serial_edge_cases_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.active = false;
  blahnode.public_ips = [];
  blahnode.options = {};
  var sw = new swiz.Swiz(def, { stripNulls: true });
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        // need to make an appointemnt with a DOM for this one.
        assert.trimEqual(results, '<?xml version=\'1.0\' encoding=\'utf-8\'?>\n' +
            '<Node><id>15245</id><is_active>false</' +
            'is_active><name>gggggg</name><agent_name>gl<ah</' +
            'agent_name><ipaddress>123.33.22.1</ipaddress>' +
            '<state>active</state>' +
            '<opts />' +
            '<data><foo>thingone</foo><bar>thingtwo</bar></data></Node>');

        test.finish();
      }
  );
};

exports['test_serial_invalid_serializer_type_xml'] = function(test, assert) {
  var blahnode = new Node();
  blahnode.getSerializerType = function() {
    return 'foobar';
  };
  var sw = new swiz.Swiz(def, { stripNulls: true });
  sw.serialize(swiz.SERIALIZATION.SERIALIZATION_XML, 1, blahnode,
      function(err, results)
      {
        assert.ok(err);
        assert.ok(!results);
        test.finish();
      }
  );
};
<|endoftext|>


<commit_before>var Promise = require('promise');

var fs = require('fs');

function Shx(fileName) {
	var self = this;
	this._p = new Promise(function(resolve, reject) {
		fs.open(fileName, 'r', function(err, fd) {
			if (err)
				reject(err);
			else {
				self._fd = fd;
				fs.read(fd, new Buffer(100), 0, 100, 0, function(err, bytes, buffer) {
					if (err)
						reject(err);
					else
						self._parseHeader(bytes, buffer, resolve, reject);
				});
			}
		});
	});
}

Shx.prototype._parseHeader = function(bytes, buffer, resolve, reject) {
	if (bytes !== 100)
		return reject(new Error('Invalid file length'));

	var header = {
		code: buffer.readInt32BE(0),
		fileLength: buffer.readInt32BE(24) * 2,
		version: buffer.readInt32LE(28),
		shapeType: buffer.readInt32LE(32)
	};

	if (header.code !== 9994)
		return reject(new Error('Invalid shx file code'));

	if (header.version !== 1000)
		return reject(new Error('Invalid shx version'));

	if (header.fileLength <= 0)
		return reject(new Error('Invalid shx file length'));

	this._header = header;

	resolve(header);
};

Shx.prototype.get = function(index, callback) {
	var self = this;
	this._p.then(
		function() {
			self._get(index, callback);
		},
		function(err) {
			callback(err);
		}
	);
};

Shx.prototype._get = function(index, callback) {
	var offset = 100 + index * 8;
	fs.read(this._fd, new Buffer(8), 0, 8, offset, function(err, bytes, buffer) {
		if (err)
			callback(err);
		else if (bytes !== 8)
			callback(new Error('Invalid record length'));
		else {
			callback(null, {
				index: index,
				offset: buffer.readInt32BE(0) * 2,
				length: buffer.readInt32BE(4)
			});
		}
	});
};

module.exports = Shx;<commit_msg>Record represent SHX record<commit_after>var Promise = require('promise');

var fs = require('fs');

function Shx(fileName) {
	var self = this;
	this._p = new Promise(function(resolve, reject) {
		fs.open(fileName, 'r', function(err, fd) {
			if (err)
				reject(err);
			else {
				self._fd = fd;
				fs.read(fd, new Buffer(100), 0, 100, 0, function(err, bytes, buffer) {
					if (err)
						reject(err);
					else
						self._parseHeader(bytes, buffer, resolve, reject);
				});
			}
		});
	});
}

Shx.prototype._parseHeader = function(bytes, buffer, resolve, reject) {
	if (bytes !== 100)
		return reject(new Error('Invalid file length'));

	var header = {
		code: buffer.readInt32BE(0),
		fileLength: buffer.readInt32BE(24) * 2,
		version: buffer.readInt32LE(28),
		shapeType: buffer.readInt32LE(32)
	};

	if (header.code !== 9994)
		return reject(new Error('Invalid shx file code'));

	if (header.version !== 1000)
		return reject(new Error('Invalid shx version'));

	if (header.fileLength <= 0)
		return reject(new Error('Invalid shx file length'));

	this._header = header;

	resolve(header);
};

Shx.prototype.get = function(index, callback) {
	var self = this;
	this._p.then(
		function() {
			self._get(index, callback);
		},
		function(err) {
			callback(err);
		}
	);
};

Shx.prototype._get = function(index, callback) {
	var offset = 100 + index * 8;
	fs.read(this._fd, new Buffer(8), 0, 8, offset, function(err, bytes, buffer) {
		if (err)
			callback(err);
		else if (bytes !== 8)
			callback(new Error('Invalid record length'));
		else {
			callback(null, {
				index: index,
				offset: buffer.readInt32BE(0),
				length: buffer.readInt32BE(4)
			});
		}
	});
};

module.exports = Shx;<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const electron = require('electron');
const path = require('path');
const ncp = require('ncp');
const __ = require('mini-utils');
const child_process = require('child_process');

const langs = ['JavaScript', 'CoffeeScript'];
const types = [
  [
    'Basic',
    'Simple application, with a single view'
  ],
  [
    'Tabbed',
    'Application with tabs, like this IDE'
  ]
];

let currWatch = null;

const setWatch = (dir) => {
  currWatch && currWatch.close();
  currWatch = fs.watch(dir, {
    persistent: false,
    recursive: true
  }, (e) => app.web.reloadProject());
}

module.exports = {
  appWillClose: () => currWatch && currWatch.close(),
  newProject: (cb) => {
    app.web.createDialog({
      type: 1,
      choices: langs,
      text: 'Project Language:'
    }, (lang) => {
      if (!lang) return cb(new Error('User canceled the dialog'), null);
      app.web.createDialog({
        type: 1,
        choices: types,
        text: 'Application Type:'
      }, (type) => {
        if (!type) return cb(new Error('User canceled the dialog'), null);
        app.web.createDialog({
          type: 2,
          text: 'Project Name'
        }, (name) => {
          const d = new Date();
          const proj = {
            dates: {
              created: `${d.getMonth()}-${d.getDate()}-${d.getFullYear()}`,
              lastModified: `${d.getMonth()}-${d.getDate()}-${d.getFullYear()}`
            },
            projectLanguage: lang,
            projectLanguageString: langs[lang],
            projectType: type,
            projectTypeString: types[type].option,
            projectName: name
          }
          electron.dialog.showOpenDialog(app.currentWindow._window, {
            title: 'Save project to:',
            defaultPath: __.homeDir(),
            properties: ['openDirectory', 'createDirectory']
          }, (dirs) => {
            if (!dirs || !dirs[0]) return cb(new Error('User canceled the dialog'), null);
            const dir = dirs[0];
            proj.path = `${dir}/${name}`
            fs.mkdir(proj.path, (err) => {
              if (err) return cb(err, null);
              ncp(`${__dirname}/projectTemplates/${types[type][0].toLowerCase()}/${langs[lang].toLowerCase()}`, proj.path, (err) => {
                if (err) return cb(err, null);
                fs.writeFile(`${proj.path}/${name}.oxyproj`, JSON.stringify(proj, null, '  '), (err) => {
                  if (err) return cb(err, null);
                  fs.writeFile(`${proj.path}/package.json`, JSON.stringify({
                    name: name,
                    version: '1.0.0',
                    description: name.substr(0, 1).toUpperCase() + name.slice(1),
                    main: 'index.js',
                    dependencies: {
                      'hydrogen-helpers': '*',
                      'electron-prebuilt': '>=0.37.1 || <0.37' // must be 0.37.1+ or less than 0.37 (0.37 has a bug that won't let it start on OSX)
                    }
                  }, null, '  '), (err) => {
                    if (err) return cb(err, null);
                    fs.writeFile(`${proj.path}/app.json`, JSON.stringify({
                      appTitle: name.toLowerCase(),
                      titleBarName: name.substr(0, 1).toUpperCase() + name.slice(1)
                    }, null, '  '), (err) => {
                      if (err) return cb(err, null);
                      app.web.createToast('Installing modules...');
                      child_process.exec('npm install', {
                        cwd: proj.path
                      }, (err, stdout, stderr) => {
                        if (err) return cb(err, null);
                        cb(null, proj);
                        setWatch(proj.path);
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  },
  openProject: (cb) => {
    electron.dialog.showOpenDialog(app.currentWindow._window, {
      title: 'Open a project:',
      defaultPath: __.homeDir(),
      filters: [
        {
          name: 'Project Files',
          extensions: ['oxyproj']
        }
      ],
      properties: ['openFile', 'createDirectory']
    }, (files) => {
      if (!files || !files[0]) return cb(new Error('User canceled the dialog'), null);
      const file = files[0];
      fs.readFile(file, (err, cont) => {
        if (err) return cb(err, null);
        const proj = JSON.parse(String(cont));
        const pPath = path.dirname(file);
        if (proj.path !== pPath) {
          proj.path = pPath;
          fs.writeFile(file, JSON.stringify(proj, null, '  '), (err) => {
            if (err) return cb(err, null);
            cb(null, proj);
          });
        } else {
          cb(null, proj);
          setWatch(proj.path);
        }
      });
    });
  },
  rmRf: (list, cb) => {
    const tmp = (i) => {
      if (i >= list.length) return cb(null);
      fs.stat(list[i], (err, stats) => {
        if (err) return cb(err);
        if (stats.isDirectory()) {
          fs.readdir(list[i], (err, files) => {
            if (err) return cb(err);
            const arr = [];
            for (const file of files) arr.push(`${list[i]}/${file}`);
            module.exports.rmRf(arr, (err) => {
              if (err) cb(err);
              tmp(i+1);
            });
          });
        } else {
          fs.unlink(list[i], (err) => {
            if (err) return cb(err);
            tmp(i+1);
          });
        }
      });
    }
    tmp(0);
  },
  recurseList: (dir, cb) => {
    fs.readdir(dir, (err, files) => {
      if (err) return cb(err);
      let ret2 = [];
      const tmp = (i) => {
        if (i >= files.length) return  cb(null, ret2);
        const path2 = `${dir}/${files[i]}`;
        fs.stat(path2, (err, stats) => {
          if (err) return cb(err);
          if (stats.isDirectory()) {
            module.exports.recurseList(path2, (err, files2) => {
              if (err) return cb(err);
              ret2 = ret2.concat(files2);
              tmp(i+1);
            });
          } else {
            ret2.push(path2);
            tmp(i+1);
          }
        });
      }
      tmp(0);
    });
  },
  cleanDS_Stores: (dir, cb) => {
    module.exports.recurseList(dir, (err, list) => {
      if (err) return cb(err);
      const arr = [];
      for (let item of list) if (path.basename(item) === '.DS_Store') arr.push(item);
      module.exports.rmRf(arr, (err) => {
        if (err) return cb(err);
        cb(null);
      });
    });
  }
}
<commit_msg>Fix command not found issue<commit_after>'use strict';

const fs = require('fs');
const electron = require('electron');
const path = require('path');
const ncp = require('ncp');
const __ = require('mini-utils');
const child_process = require('child_process');

const langs = ['JavaScript', 'CoffeeScript'];
const types = [
  [
    'Basic',
    'Simple application, with a single view'
  ],
  [
    'Tabbed',
    'Application with tabs, like this IDE'
  ]
];

let currWatch = null;

const setWatch = (dir) => {
  currWatch && currWatch.close();
  currWatch = fs.watch(dir, {
    persistent: false,
    recursive: true
  }, (e) => app.web.reloadProject());
}

module.exports = {
  appWillClose: () => currWatch && currWatch.close(),
  newProject: (cb) => {
    app.web.createDialog({
      type: 1,
      choices: langs,
      text: 'Project Language:'
    }, (lang) => {
      if (!lang) return cb(new Error('User canceled the dialog'), null);
      app.web.createDialog({
        type: 1,
        choices: types,
        text: 'Application Type:'
      }, (type) => {
        if (!type) return cb(new Error('User canceled the dialog'), null);
        app.web.createDialog({
          type: 2,
          text: 'Project Name'
        }, (name) => {
          const d = new Date();
          const proj = {
            dates: {
              created: `${d.getMonth()}-${d.getDate()}-${d.getFullYear()}`,
              lastModified: `${d.getMonth()}-${d.getDate()}-${d.getFullYear()}`
            },
            projectLanguage: lang,
            projectLanguageString: langs[lang],
            projectType: type,
            projectTypeString: types[type].option,
            projectName: name
          }
          electron.dialog.showOpenDialog(app.currentWindow._window, {
            title: 'Save project to:',
            defaultPath: __.homeDir(),
            properties: ['openDirectory', 'createDirectory']
          }, (dirs) => {
            if (!dirs || !dirs[0]) return cb(new Error('User canceled the dialog'), null);
            const dir = dirs[0];
            proj.path = `${dir}/${name}`
            fs.mkdir(proj.path, (err) => {
              if (err) return cb(err, null);
              ncp(`${__dirname}/projectTemplates/${types[type][0].toLowerCase()}/${langs[lang].toLowerCase()}`, proj.path, (err) => {
                if (err) return cb(err, null);
                fs.writeFile(`${proj.path}/${name}.oxyproj`, JSON.stringify(proj, null, '  '), (err) => {
                  if (err) return cb(err, null);
                  fs.writeFile(`${proj.path}/package.json`, JSON.stringify({
                    name: name,
                    version: '1.0.0',
                    description: name.substr(0, 1).toUpperCase() + name.slice(1),
                    main: 'index.js',
                    dependencies: {
                      'hydrogen-helpers': '*',
                      'electron-prebuilt': '>=0.37.1 || <0.37' // must be 0.37.1+ or less than 0.37 (0.37 has a bug that won't let it start on OSX)
                    }
                  }, null, '  '), (err) => {
                    if (err) return cb(err, null);
                    fs.writeFile(`${proj.path}/app.json`, JSON.stringify({
                      appTitle: name.toLowerCase(),
                      titleBarName: name.substr(0, 1).toUpperCase() + name.slice(1)
                    }, null, '  '), (err) => {
                      if (err) return cb(err, null);
                      app.web.createToast('Installing modules...');
                      child_process.exec('/usr/bin/env npm install', {
                        cwd: proj.path
                      }, (err, stdout, stderr) => {
                        if (err) return cb(err, null);
                        cb(null, proj);
                        setWatch(proj.path);
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  },
  openProject: (cb) => {
    electron.dialog.showOpenDialog(app.currentWindow._window, {
      title: 'Open a project:',
      defaultPath: __.homeDir(),
      filters: [
        {
          name: 'Project Files',
          extensions: ['oxyproj']
        }
      ],
      properties: ['openFile', 'createDirectory']
    }, (files) => {
      if (!files || !files[0]) return cb(new Error('User canceled the dialog'), null);
      const file = files[0];
      fs.readFile(file, (err, cont) => {
        if (err) return cb(err, null);
        const proj = JSON.parse(String(cont));
        const pPath = path.dirname(file);
        if (proj.path !== pPath) {
          proj.path = pPath;
          fs.writeFile(file, JSON.stringify(proj, null, '  '), (err) => {
            if (err) return cb(err, null);
            cb(null, proj);
          });
        } else {
          cb(null, proj);
          setWatch(proj.path);
        }
      });
    });
  },
  rmRf: (list, cb) => {
    const tmp = (i) => {
      if (i >= list.length) return cb(null);
      fs.stat(list[i], (err, stats) => {
        if (err) return cb(err);
        if (stats.isDirectory()) {
          fs.readdir(list[i], (err, files) => {
            if (err) return cb(err);
            const arr = [];
            for (const file of files) arr.push(`${list[i]}/${file}`);
            module.exports.rmRf(arr, (err) => {
              if (err) cb(err);
              tmp(i+1);
            });
          });
        } else {
          fs.unlink(list[i], (err) => {
            if (err) return cb(err);
            tmp(i+1);
          });
        }
      });
    }
    tmp(0);
  },
  recurseList: (dir, cb) => {
    fs.readdir(dir, (err, files) => {
      if (err) return cb(err);
      let ret2 = [];
      const tmp = (i) => {
        if (i >= files.length) return  cb(null, ret2);
        const path2 = `${dir}/${files[i]}`;
        fs.stat(path2, (err, stats) => {
          if (err) return cb(err);
          if (stats.isDirectory()) {
            module.exports.recurseList(path2, (err, files2) => {
              if (err) return cb(err);
              ret2 = ret2.concat(files2);
              tmp(i+1);
            });
          } else {
            ret2.push(path2);
            tmp(i+1);
          }
        });
      }
      tmp(0);
    });
  },
  cleanDS_Stores: (dir, cb) => {
    module.exports.recurseList(dir, (err, list) => {
      if (err) return cb(err);
      const arr = [];
      for (let item of list) if (path.basename(item) === '.DS_Store') arr.push(item);
      module.exports.rmRf(arr, (err) => {
        if (err) return cb(err);
        cb(null);
      });
    });
  }
}
<|endoftext|>


<commit_before>
module.exports = act;

act.usage = "\nfhc act <app-id> <server-function> <params> [--live]";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common.js");
var util = require('util');
var ini = require('./utils/ini');
var request = require('request');
var read = require('./read.js').read;

// main act entry point
function act (args, cb) {
  if (args.length < 2) return cb(act.usage);

  var target = ini.get('live') ? 'live' : 'development';
  // tmp hack for using as a script, check if the last arg is trying to override target
  if (args[args.length -1] === 'live' || args[args.length -1] === 'development') {
    target = args[args.length -1];
    args.pop();
  }

  var appId = fhc.appId(args[0]);
  var funct = args[1];
  var data = args[2] ? JSON.parse(args[2]): {};
  log.silly(data, "act params");

  // read app to get widget guid and cloud type
  read([appId], function (err, res) {
    if(err) return cb(err);

    var app = res.app;
    var inst = res.inst;
    var widgId = app.guid;
    var nodejs = 'boolean' === typeof inst.nodejs ? inst.nodejs : (inst.nodejs === 'true' ? true : false);

    if (nodejs) {
      if ("live" === target) {
        doLiveAct(appId, funct, data, cb);
      }else {
        doDevAct(appId, funct, data, cb);
      }
    } else {
      // rhino apps don't have a dev and live, just one environment,
      // which is in millicore
      if ("live" === target) {
        return cb("Live environment not available for Rhino Apps", null);
      } else {
        doMillicoreAct(appId, widgId, funct, data, cb);
      }
    }
  });
}

// TODO - full development proxy (no proxy through millicore)
function doMillicoreAct(appId, widgId, funct, data, cb) {
  log.silly(widgId, "widgId");
  fhreq.POST(fhreq.getFeedHenryUrl(), "box/srv/1.1/act/" + fhc.target + "/" + widgId + "/" + funct + "/" + appId, data, function (err, remoteData, raw, response) {
    if (err) {
      log.verbose("Error in act: " + err);
      log.verbose(remoteData, "list");
      return cb(err);
    }
    return cb(err, remoteData);
  });
}

// TODO - cache the endpoint lookup (so we don't have to call every time)
function doAct(appEnv, appId, funct, data, cb) {
  log.silly(appEnv, "doAct appEnv");
  log.silly(appId, "doAct appId");
  log.silly(funct, "doAct funct");
  log.silly(data, "doAct data");
  common.getAppNameUrl(appId, appEnv, function(err, appName, appUrl) {
    if(err) return cb(err);
    if (!appUrl.match(/\/$/)) appUrl = appUrl + '/';
    log.silly(appName, "doAct appName");
    log.silly(appUrl, "doAct appUrl");
    log.silly(funct, "doAct function");
    log.silly(data, "doAct data");

    // post to /cloud
    request({uri: appUrl + "cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
      if(err) return cb(err);
      log.silly(response.statusCode, "act response statusCode");
      log.silly(body, "act response body");
      if(response.statusCode !== 200) return cb("Bad response: " + util.inspect(body) + " code: " + response.statusCode);
      return cb(undefined, body);
    });
  });
}

// Do our live action
function doLiveAct(appId, funct, data, cb) {
  doAct('live', appId, funct, data, cb);
}

// Do our dev action
function doDevAct(appId, funct, data, cb) {
  doAct('development', appId, funct, data, cb);
}

// bash completion
act.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;

  // only complete for 3'rd param, i.e. 'fhc act <tab>'
  if (argv.length === 2) {
    common.getAppIds(cb);
  }
};
<commit_msg>Undo logging level over-writes<commit_after>
module.exports = act;

act.usage = "\nfhc act <app-id> <server-function> <params> [--live]";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common.js");
var util = require('util');
var ini = require('./utils/ini');
var request = require('request');
var read = require('./read.js').read;

// main act entry point
function act (args, cb) {
  if (args.length < 2) return cb(act.usage);

  var target = ini.get('live') ? 'live' : 'development';
  // tmp hack for using as a script, check if the last arg is trying to override target
  if (args[args.length -1] === 'live' || args[args.length -1] === 'development') {
    target = args[args.length -1];
    args.pop();
  }

  var appId = fhc.appId(args[0]);
  var funct = args[1];
  var data = args[2] ? JSON.parse(args[2]): {};
  log.silly(data, "act params");

  // read app to get widget guid and cloud type
  read([appId], function (err, res) {
    if(err) return cb(err);

    var app = res.app;
    var inst = res.inst;
    var widgId = app.guid;
    var nodejs = 'boolean' === typeof inst.nodejs ? inst.nodejs : (inst.nodejs === 'true' ? true : false);

    if (nodejs) {
      if ("live" === target) {
        doLiveAct(appId, funct, data, cb);
      }else {
        doDevAct(appId, funct, data, cb);
      }
    } else {
      // rhino apps don't have a dev and live, just one environment,
      // which is in millicore
      if ("live" === target) {
        return cb("Live environment not available for Rhino Apps", null);
      } else {
        doMillicoreAct(appId, widgId, funct, data, cb);
      }
    }
  });
}

// TODO - full development proxy (no proxy through millicore)
function doMillicoreAct(appId, widgId, funct, data, cb) {
  log.silly(widgId, "widgId");
  fhreq.POST(fhreq.getFeedHenryUrl(), "box/srv/1.1/act/" + fhc.target + "/" + widgId + "/" + funct + "/" + appId, data, function (err, remoteData, raw, response) {
    if (err) {
      log.silly("Error in act: " + err);
      return cb(err);
    }
    return cb(err, remoteData);
  });
}

// TODO - cache the endpoint lookup (so we don't have to call every time)
function doAct(appEnv, appId, funct, data, cb) {
  log.silly(appEnv, "Act call appEnv");
  log.silly(appId, "Act call appId");
  log.silly(funct, "Act call funct");
  log.silly(data, "Act call data");
  common.getAppNameUrl(appId, appEnv, function(err, appName, appUrl) {
    if(err) return cb(err);
    if (!appUrl.match(/\/$/)) appUrl = appUrl + '/';
    log.silly(appName, "Act call appName");
    log.verbose(appUrl + "cloud/" + funct, "Act call appUrl");

    // post to /cloud
    request({uri: appUrl + "cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
      if(err) return cb(err);
      log.verbose(response.statusCode, "Act call response statusCode");
      log.silly(body, "Act call response body");
      if(response.statusCode !== 200) return cb("Bad response: " + util.inspect(body) + " code: " + response.statusCode);
      return cb(undefined, body);
    });
  });
}

// Do our live action
function doLiveAct(appId, funct, data, cb) {
  doAct('live', appId, funct, data, cb);
}

// Do our dev action
function doDevAct(appId, funct, data, cb) {
  doAct('development', appId, funct, data, cb);
}

// bash completion
act.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;

  // only complete for 3'rd param, i.e. 'fhc act <tab>'
  if (argv.length === 2) {
    common.getAppIds(cb);
  }
};
<|endoftext|>


<commit_before>var fs = require('fs');
var util = require('util');
var path = require('path');
var mkdirp = require('mkdirp');

var Misc = require('./misc.js');

var SEPARATOR = ':';

// Private method to generate event names for plugins.
function _getPluginEventName(plugin, event) {
    return plugin + SEPARATOR + event;
}

// Private function to create shortened plugin name
function _getShortPluginName(pluginName) {
    if(pluginName.indexOf('vapor-') === 0) {
        return pluginName.replace('vapor-', '');
    }

    return pluginName;
}

/**
 * Exports API class.
 */
module.exports = API;

/**
 * API class constructor.
 *
 * Instance of this class is passed to plugins exported function.
 * @class
 * @param    {Vapor}  Vapor      Vapor instance.
 * @param    {string} pluginName Specific plugin name which uses this API instance.
 * @param    {Object} data       Data object that is passed to API instance.
 * @property {string} pluginName Name of the plugin which uses this specific API instance.
 * @property {Object} data       Data object that is passed to API instance via `Vapor.use` method.
 */
function API(Vapor, pluginName, data) {
    // Private properties
    this._vapor = Vapor;
    this._dataDir = path.join(Vapor.config.dataDir, Misc.DATA_PLUGIN_DIR, Vapor.config.username, pluginName);

    // Public properties
    this.pluginName = pluginName;
    this.data = data;
}

/**
 * Connect to Steam network.
 */
API.prototype.connect = function() {
    this._vapor.connect();
};

/**
 * Disconnect from Steam network.
 */
API.prototype.disconnect = function() {
    this._vapor.disconnect();
};

/**
 * Returns active Steam client used by Vapor.
 * @return {SteamClient} Active Steam client.
 */
API.prototype.getClient = function() {
    return this._vapor.client;
};

/**
 * Returns active Steam handler used by Vapor.
 * @param  {string} handler Can be either `steamUser`, `steamFriends`, `steamTrading`,
 * `steamGameCoordinator` or `steamGroups`.
 * @return {Object}         Active Steam handler.
 */
API.prototype.getHandler = function(handler) {
    switch (handler) {
        case 'steamUser':
            return this._vapor.steamUser;
        case 'steamFriends':
            return this._vapor.steamFriends;
        case 'steamTrading':
            return this._vapor.steamTrading;
        case 'steamGameCoordinator':
            return this._vapor.steamGameCoordinator;
        case 'steamGroups':
            return this._vapor.steamGroups;
        default:
            throw new Error('Unknown handler ' + handler + ' in "getHandler" method.');
    }
};

/**
 * Returns instance of Utils class.
 * @return {Utils} Instantiated Utils class.
 */
API.prototype.getUtils = function() {
    return this._vapor.utils;
};

/**
 * Returns Steam object.
 *
 * This is especially useful for all the ESomething enums.
 * @return {Steam} Steam.
 */
API.prototype.getSteam = function() {
    return this._vapor.Steam;
};

/**
 * Returns Vapor config object.
 * @return {Object} Config object.
 */
API.prototype.getConfig = function() {
    return this._vapor.config;
};

/**
 * Allows plugin to emit custom events via Vapor's event emitter.
 *
 * This function allows to pass multiple data arguments.
 *
 * Also see {@link API#registerHandler}.
 * @example
 * API.emitEvent('myCustomPluginEvent', someString, someObject);
 * @param  {string} event Event name.
 * @param  {...*}   args  Data arguments.
 */
API.prototype.emitEvent = function() {
    var args = Array.prototype.slice.call(arguments);
    args[0] = _getPluginEventName(this.pluginName, args[0]);

    this._vapor.emit.apply(this._vapor, args);
};

/**
 * Allows plugin to register custom handler for any event.
 *
 * Also see {@link API#emitEvent}.
 * @example
 * // Listen to 'friendMsg' event emitted by 'steamFriends'
 * API.registerHandler({
 *         emitter: 'steamFriends',
 *         event: 'friendMsg'
 *     },
 *     function(user, message, type) {
 *         if(type === Steam.EChatEntryType.ChatMsg) {
 *             log.info(user + " says: " + message);
 *         }
 *     }
 * );
 *
 * // Listen to another plugin's custom event
 * API.registerHandler({
 *         emitter: 'plugin',
 *         plugin: 'another-plugin-name'
 *         event: 'myCustomPluginEvent'
 *     },
 *     function(someString, someObject) {
 *         log.info(someString, someObject);
 *     }
 * );
 *
 * @param  {Object}    options          Options object.
 * @param  {string}    options.emitter  Can be either `vapor`, `client`, `steamUser`,
 * `steamFriends`, `steamTrading`, `steamGameCoordinator` or `plugin`.
 * @param  {string}    options.plugin - If emitter is `plugin`, this is plugin's name.
 * @param  {string}    options.event    Event name.
 * @param  {function}  callback         Callback function.
 */
API.prototype.registerHandler = function(options, callback) {
    if(options.emitter === 'plugin' && !options.plugin) {
        throw new Error('Missing "plugin" property in options in "registerHandler" method.');
    }

    if(typeof callback !== 'function') {
        throw new Error('Callback must be a function.');
    }

    var vapor = this._vapor;

    switch(options.emitter) {
        case 'vapor':
            vapor.on(options.event, callback);
            break;

        case 'client':
            vapor.client.on(options.event, callback);
            break;

        case 'steamUser':
            vapor.steamUser.on(options.event, callback);
            break;

        case 'steamFriends':
            vapor.steamFriends.on(options.event, callback);
            break;

        case 'steamTrading':
            vapor.steamTrading.on(options.event, callback);
            break;

        case 'steamGameCoordinator':
            vapor.steamGameCoordinator.on(options.event, callback);
            break;

        case 'plugin':
            var eventName = _getPluginEventName(options.plugin, options.event);
            vapor.on(eventName, callback);
            break;

        default:
            throw new Error('Unknown event emitter ' + options.emitter + ' in "registerHandler" method.');
    }
};

/**
 * Allows plugin to remove all handlers for a specific event.
 * @param  {Object}  options          Options object.
 * @param  {string}  options.emitter  Can be either `vapor`, `client`, `steamUser`,
 * `steamFriends`, `steamTrading`, `steamGameCoordinator` or `plugin`.
 * @param  {string}  options.plugin - If emitter is 'plugin', this is plugin's name.
 * @param  {string}  options.event    Event name.
 */
API.prototype.removeAllHandlers = function(options) {
    if(options.emitter === 'plugin' && !options.plugin) {
        throw new Error('Missing "plugin" property in options in "removeAllHandlers" method.');
    }

    var vapor = this._vapor;

    switch(options.emitter) {
        case 'vapor':
            vapor.removeAllListeners(options.event);
            break;

        case 'client':
            vapor.client.removeAllListeners(options.event);
            break;

        case 'steamUser':
            vapor.steamUser.removeAllListeners(options.event);
            break;

        case 'steamFriends':
            vapor.steamFriends.removeAllListeners(options.event);
            break;

        case 'steamTrading':
            vapor.steamTrading.removeAllListeners(options.event);
            break;

        case 'steamGameCoordinator':
            vapor.steamGameCoordinator.removeAllListeners(options.event);
            break;

        case 'plugin':
            var eventName = _getPluginEventName(options.plugin, options.event);
            vapor.removeAllListeners(eventName);
            break;

        default:
            throw new Error('Unknown event emitter ' + options.emitter + ' in "removeAllHandlers" method.');
    }
};

/**
 * Returns plugin's data folder path.
 *
 * Plugin can use this folder to store persistent data.
 * @return {string} Full path to plugin's data folder.
 */
API.prototype.getDataFolderPath = function() {
    if(!fs.existsSync(this._dataDir)) {
        mkdirp.sync(this._dataDir);
    }

    return this._dataDir;
};

/**
 * Returns wrapped logger instance prefixed with plugin's name.
 * @return {Object} Logger.
 */
API.prototype.getLogger = function() {
    var log = this._vapor.log;
    var name = _getShortPluginName(this.pluginName);

    function filter(args, loggerFunc) {
        var message = util.format.apply(util.format, args);
        loggerFunc('[%s] %s', name, message);
    }

    // This is quite ugly.
    return {
        verbose: function() {
            filter(arguments, log.verbose);
        },
        debug: function() {
            filter(arguments, log.debug);
        },
        info: function() {
            filter(arguments, log.info);
        },
        warn: function() {
            filter(arguments, log.warn);
        },
        error: function() {
            filter(arguments, log.error);
        }
    };
};

/**
 * Calls Vapor's internal webLogOn method.
 *
 * Listen to `cookies` event to receive new array of cookies.
 *
 * You should call this function ONLY if you believe cookies have expired, e.g.
 * you logged into your account from another IP / browser and you are getting
 * HTTP 403 etc.
 *
 * You do NOT have to call this method on startup as it's automatically called
 * by Vapor after successfully logging in.
 */
API.prototype.webLogOn = function() {
    var vapor = this._vapor;

    vapor.steamUser.requestWebAPIAuthenticateUserNonce(function(nonce) {
        vapor.webLogOn(nonce.webapi_authenticate_user_nonce);
    }.bind(vapor));
};
<commit_msg>remove useless bind<commit_after>var fs = require('fs');
var util = require('util');
var path = require('path');
var mkdirp = require('mkdirp');

var Misc = require('./misc.js');

var SEPARATOR = ':';

// Private method to generate event names for plugins.
function _getPluginEventName(plugin, event) {
    return plugin + SEPARATOR + event;
}

// Private function to create shortened plugin name
function _getShortPluginName(pluginName) {
    if(pluginName.indexOf('vapor-') === 0) {
        return pluginName.replace('vapor-', '');
    }

    return pluginName;
}

/**
 * Exports API class.
 */
module.exports = API;

/**
 * API class constructor.
 *
 * Instance of this class is passed to plugins exported function.
 * @class
 * @param    {Vapor}  Vapor      Vapor instance.
 * @param    {string} pluginName Specific plugin name which uses this API instance.
 * @param    {Object} data       Data object that is passed to API instance.
 * @property {string} pluginName Name of the plugin which uses this specific API instance.
 * @property {Object} data       Data object that is passed to API instance via `Vapor.use` method.
 */
function API(Vapor, pluginName, data) {
    // Private properties
    this._vapor = Vapor;
    this._dataDir = path.join(Vapor.config.dataDir, Misc.DATA_PLUGIN_DIR, Vapor.config.username, pluginName);

    // Public properties
    this.pluginName = pluginName;
    this.data = data;
}

/**
 * Connect to Steam network.
 */
API.prototype.connect = function() {
    this._vapor.connect();
};

/**
 * Disconnect from Steam network.
 */
API.prototype.disconnect = function() {
    this._vapor.disconnect();
};

/**
 * Returns active Steam client used by Vapor.
 * @return {SteamClient} Active Steam client.
 */
API.prototype.getClient = function() {
    return this._vapor.client;
};

/**
 * Returns active Steam handler used by Vapor.
 * @param  {string} handler Can be either `steamUser`, `steamFriends`, `steamTrading`,
 * `steamGameCoordinator` or `steamGroups`.
 * @return {Object}         Active Steam handler.
 */
API.prototype.getHandler = function(handler) {
    switch (handler) {
        case 'steamUser':
            return this._vapor.steamUser;
        case 'steamFriends':
            return this._vapor.steamFriends;
        case 'steamTrading':
            return this._vapor.steamTrading;
        case 'steamGameCoordinator':
            return this._vapor.steamGameCoordinator;
        case 'steamGroups':
            return this._vapor.steamGroups;
        default:
            throw new Error('Unknown handler ' + handler + ' in "getHandler" method.');
    }
};

/**
 * Returns instance of Utils class.
 * @return {Utils} Instantiated Utils class.
 */
API.prototype.getUtils = function() {
    return this._vapor.utils;
};

/**
 * Returns Steam object.
 *
 * This is especially useful for all the ESomething enums.
 * @return {Steam} Steam.
 */
API.prototype.getSteam = function() {
    return this._vapor.Steam;
};

/**
 * Returns Vapor config object.
 * @return {Object} Config object.
 */
API.prototype.getConfig = function() {
    return this._vapor.config;
};

/**
 * Allows plugin to emit custom events via Vapor's event emitter.
 *
 * This function allows to pass multiple data arguments.
 *
 * Also see {@link API#registerHandler}.
 * @example
 * API.emitEvent('myCustomPluginEvent', someString, someObject);
 * @param  {string} event Event name.
 * @param  {...*}   args  Data arguments.
 */
API.prototype.emitEvent = function() {
    var args = Array.prototype.slice.call(arguments);
    args[0] = _getPluginEventName(this.pluginName, args[0]);

    this._vapor.emit.apply(this._vapor, args);
};

/**
 * Allows plugin to register custom handler for any event.
 *
 * Also see {@link API#emitEvent}.
 * @example
 * // Listen to 'friendMsg' event emitted by 'steamFriends'
 * API.registerHandler({
 *         emitter: 'steamFriends',
 *         event: 'friendMsg'
 *     },
 *     function(user, message, type) {
 *         if(type === Steam.EChatEntryType.ChatMsg) {
 *             log.info(user + " says: " + message);
 *         }
 *     }
 * );
 *
 * // Listen to another plugin's custom event
 * API.registerHandler({
 *         emitter: 'plugin',
 *         plugin: 'another-plugin-name'
 *         event: 'myCustomPluginEvent'
 *     },
 *     function(someString, someObject) {
 *         log.info(someString, someObject);
 *     }
 * );
 *
 * @param  {Object}    options          Options object.
 * @param  {string}    options.emitter  Can be either `vapor`, `client`, `steamUser`,
 * `steamFriends`, `steamTrading`, `steamGameCoordinator` or `plugin`.
 * @param  {string}    options.plugin - If emitter is `plugin`, this is plugin's name.
 * @param  {string}    options.event    Event name.
 * @param  {function}  callback         Callback function.
 */
API.prototype.registerHandler = function(options, callback) {
    if(options.emitter === 'plugin' && !options.plugin) {
        throw new Error('Missing "plugin" property in options in "registerHandler" method.');
    }

    if(typeof callback !== 'function') {
        throw new Error('Callback must be a function.');
    }

    var vapor = this._vapor;

    switch(options.emitter) {
        case 'vapor':
            vapor.on(options.event, callback);
            break;

        case 'client':
            vapor.client.on(options.event, callback);
            break;

        case 'steamUser':
            vapor.steamUser.on(options.event, callback);
            break;

        case 'steamFriends':
            vapor.steamFriends.on(options.event, callback);
            break;

        case 'steamTrading':
            vapor.steamTrading.on(options.event, callback);
            break;

        case 'steamGameCoordinator':
            vapor.steamGameCoordinator.on(options.event, callback);
            break;

        case 'plugin':
            var eventName = _getPluginEventName(options.plugin, options.event);
            vapor.on(eventName, callback);
            break;

        default:
            throw new Error('Unknown event emitter ' + options.emitter + ' in "registerHandler" method.');
    }
};

/**
 * Allows plugin to remove all handlers for a specific event.
 * @param  {Object}  options          Options object.
 * @param  {string}  options.emitter  Can be either `vapor`, `client`, `steamUser`,
 * `steamFriends`, `steamTrading`, `steamGameCoordinator` or `plugin`.
 * @param  {string}  options.plugin - If emitter is 'plugin', this is plugin's name.
 * @param  {string}  options.event    Event name.
 */
API.prototype.removeAllHandlers = function(options) {
    if(options.emitter === 'plugin' && !options.plugin) {
        throw new Error('Missing "plugin" property in options in "removeAllHandlers" method.');
    }

    var vapor = this._vapor;

    switch(options.emitter) {
        case 'vapor':
            vapor.removeAllListeners(options.event);
            break;

        case 'client':
            vapor.client.removeAllListeners(options.event);
            break;

        case 'steamUser':
            vapor.steamUser.removeAllListeners(options.event);
            break;

        case 'steamFriends':
            vapor.steamFriends.removeAllListeners(options.event);
            break;

        case 'steamTrading':
            vapor.steamTrading.removeAllListeners(options.event);
            break;

        case 'steamGameCoordinator':
            vapor.steamGameCoordinator.removeAllListeners(options.event);
            break;

        case 'plugin':
            var eventName = _getPluginEventName(options.plugin, options.event);
            vapor.removeAllListeners(eventName);
            break;

        default:
            throw new Error('Unknown event emitter ' + options.emitter + ' in "removeAllHandlers" method.');
    }
};

/**
 * Returns plugin's data folder path.
 *
 * Plugin can use this folder to store persistent data.
 * @return {string} Full path to plugin's data folder.
 */
API.prototype.getDataFolderPath = function() {
    if(!fs.existsSync(this._dataDir)) {
        mkdirp.sync(this._dataDir);
    }

    return this._dataDir;
};

/**
 * Returns wrapped logger instance prefixed with plugin's name.
 * @return {Object} Logger.
 */
API.prototype.getLogger = function() {
    var log = this._vapor.log;
    var name = _getShortPluginName(this.pluginName);

    function filter(args, loggerFunc) {
        var message = util.format.apply(util.format, args);
        loggerFunc('[%s] %s', name, message);
    }

    // This is quite ugly.
    return {
        verbose: function() {
            filter(arguments, log.verbose);
        },
        debug: function() {
            filter(arguments, log.debug);
        },
        info: function() {
            filter(arguments, log.info);
        },
        warn: function() {
            filter(arguments, log.warn);
        },
        error: function() {
            filter(arguments, log.error);
        }
    };
};

/**
 * Calls Vapor's internal webLogOn method.
 *
 * Listen to `cookies` event to receive new array of cookies.
 *
 * You should call this function ONLY if you believe cookies have expired, e.g.
 * you logged into your account from another IP / browser and you are getting
 * HTTP 403 etc.
 *
 * You do NOT have to call this method on startup as it's automatically called
 * by Vapor after successfully logging in.
 */
API.prototype.webLogOn = function() {
    var vapor = this._vapor;

    vapor.steamUser.requestWebAPIAuthenticateUserNonce(function(nonce) {
        vapor.webLogOn(nonce.webapi_authenticate_user_nonce);
    });
};
<|endoftext|>