<commit_before>
'use strict';

const is = require('is');
const hooks = require('promised-hooks');
const arrify = require('arrify');

const utils = require('./utils');
const datastoreSerializer = require('./serializer').Datastore;
const defaultValues = require('./helpers/defaultValues');

class Entity {
    constructor(data, id, ancestors, namespace, key) {
        this.className = 'Entity';

        this.schema = this.constructor.schema;
        this.excludeFromIndexes = [];

        if (key) {
            if (key.constructor.name === 'Key') {
                this.entityKey = key;
            } else {
                throw new Error('Entity Key must be an instance of gcloud Key');
            }
        } else {
            this.entityKey = createKey(this, id, ancestors, namespace);
        }

        // create entityData from data passed
        this.entityData = buildEntityData(this, data || {});

        // wrap entity with hook methods
        hooks.wrap(this);

        // add middleware defined on Schena
        registerHooksFromSchema(this);
    }

    plain(options) {
        options = typeof options === 'undefined' ? {} : options;

        if (typeof options !== 'undefined' && !is.object(options)) {
            throw new Error('Options must be an Object');
        }
        const readAll = !!options.readAll || false;
        const virtuals = !!options.virtuals || false;
        const showKey = !!options.showKey || false;

        if (virtuals) {
            this.addVirtuals(this.entityData);
        }

        const data = datastoreSerializer.fromDatastore.call(this, this.entityData, { readAll, showKey });

        return data;
    }

    get(path) {
        if ({}.hasOwnProperty.call(this.schema.virtuals, path)) {
            return this.schema.virtuals[path].applyGetters(this.entityData);
        }
        return this.entityData[path];
    }

    set(path, value) {
        if ({}.hasOwnProperty.call(this.schema.virtuals, path)) {
            return this.schema.virtuals[path].applySetters(value, this.entityData);
        }

        this.entityData[path] = value;
        return this;
    }

    /**
     * Return a Model from Gstore
     * @param name : model name
     */
    model(name) {
        return this.constructor.gstore.model(name);
    }

    /**
     * Fetch entity from Datastore
     *
     * @param {Function} cb Callback
     */
    datastoreEntity(cb) {
        const _this = this;

        return this.gstore.ds.get(this.entityKey).then(onSuccess, onError);

        // ------------------------

        function onSuccess(result) {
            const datastoreEntity = result ? result[0] : null;

            if (!datastoreEntity) {
                return cb({
                    code: 404,
                    message: 'Entity not found',
                });
            }

            _this.entityData = datastoreEntity;
            return cb(null, _this);
        }

        function onError(err) {
            return cb(err);
        }
    }

    addVirtuals() {
        const { virtuals } = this.schema;
        const { entityData } = this;

        Object.keys(virtuals).forEach((k) => {
            if ({}.hasOwnProperty.call(entityData, k)) {
                virtuals[k].applySetters(entityData[k], entityData);
            } else {
                virtuals[k].applyGetters(entityData);
            }
        });

        return this.entityData;
    }
}

// Private
// -------
function createKey(self, id, ancestors, namespace) {
    const hasAncestors = typeof ancestors !== 'undefined' && ancestors !== null && is.array(ancestors);

    /*
    /* Create copy of ancestors to avoid mutating the Array
    */
    if (hasAncestors) {
        ancestors = ancestors.slice();
    }

    let path;
    if (id) {
        id = parseId(self, id);
        path = hasAncestors ? ancestors.concat([self.entityKind, id]) : [self.entityKind, id];
    } else {
        if (hasAncestors) {
            ancestors.push(self.entityKind);
        }
        path = hasAncestors ? ancestors : self.entityKind;
    }

    if (namespace && !is.array(path)) {
        path = [path];
    }
    return namespace ? self.gstore.ds.key({ namespace, path }) : self.gstore.ds.key(path);
}

function parseId(self, id) {
    const { options } = self.schema;

    if (is.string(id)) {
        if (options && options.keyType === 'name') {
            return id;
        } else if (options.keyType === 'id') {
            return self.gstore.ds.int(id);
        }
        // auto convert string number to number
        return isFinite(id) ? self.gstore.ds.int(id) : id;
    } else if (!is.number(id)) {
        throw new Error('id must be a string or a number');
    }

    return id;
}

function buildEntityData(self, data) {
    const { schema } = self;
    const isJoiSchema = !is.undef(schema._joi);

    let entityData = {};

    if (data) {
        // If Joi schema, get its default values
        if (isJoiSchema) {
            const { error, value } = schema._joi.validate(data);

            if (!error) {
                entityData = Object.assign({}, value);
            }
        }

        Object.keys(data).forEach((k) => {
            entityData[k] = data[k];
        });
    }

    let isTypeArray;

    Object.keys(schema.paths).forEach((k) => {
        const prop = schema.paths[k];
        const hasValue = {}.hasOwnProperty.call(entityData, k);
        const isOptional = {}.hasOwnProperty.call(prop, 'optional') && prop.optional !== false;
        const isRequired = {}.hasOwnProperty.call(prop, 'required') && prop.required === true;

        // Set Default Values
        if (!isJoiSchema && !hasValue && !isOptional) {
            let value = null;

            if ({}.hasOwnProperty.call(prop, 'default')) {
                if (typeof prop.default === 'function') {
                    value = prop.default();
                } else {
                    value = prop.default;
                }
            }

            if (({}).hasOwnProperty.call(defaultValues.__map__, value)) {
                /**
                 * If default value is in the gstore.defaultValue hashTable
                 * then execute the handler for that shortcut
                 */
                value = defaultValues.__handler__(value);
            } else if (value === null && {}.hasOwnProperty.call(prop, 'values') && !isRequired) {
                // Default to first value of the allowed values if **not** required
                [value] = prop.values;
            }

            entityData[k] = value;
        }

        // Set excludeFromIndexes
        /**
         * There is an inconsistency in @google-cloud for Array type
         * We cannot (so far) use the Array way of declaring excludeFromIndexes
         * (like we can do with string, int and object)
         * ---> see serializer/datastore.js
         */
        isTypeArray = prop.type === 'array' || (prop.joi && prop.joi._type === 'array');
        if (prop.excludeFromIndexes === true && !isTypeArray) {
            self.excludeFromIndexes.push(k);
        } else if (!is.boolean(prop.excludeFromIndexes)) {
            // For embedded entities we can set which properties are excluded from indexes
            // by passing a string | array of properties
            const excludeFromIndexes = arrify(prop.excludeFromIndexes);

            let excludedProps;
            if (prop.type === 'array') {
                excludedProps = excludeFromIndexes.map(excluded => `${k}[].${excluded}`);
            } else {
                excludedProps = excludeFromIndexes.map(excluded => `${k}.${excluded}`);
            }

            self.excludeFromIndexes = [...self.excludeFromIndexes, ...excludedProps];
        }
    });

    // add Symbol Key to the entityData
    entityData[self.gstore.ds.KEY] = self.entityKey;

    return entityData;
}

function registerHooksFromSchema(self) {
    const callQueue = self.schema.callQueue.entity;

    if (!Object.keys(callQueue).length) {
        return self;
    }

    Object.keys(callQueue).forEach(addHooks);

    // ---------------------------------------

    function addHooks(method) {
        if (!self[method]) {
            return;
        }

        // Add Pre hooks
        callQueue[method].pres.forEach((fn) => {
            self.pre(method, fn);
        });

        // Add Pre hooks
        callQueue[method].post.forEach((fn) => {
            self.post(method, fn);
        });
    }
    return self;
}

// Promisify Entity methods
Entity.prototype.datastoreEntity = utils.promisify(Entity.prototype.datastoreEntity);

module.exports = Entity;
<commit_msg>comment: parseId function<commit_after>
'use strict';

const is = require('is');
const hooks = require('promised-hooks');
const arrify = require('arrify');

const utils = require('./utils');
const datastoreSerializer = require('./serializer').Datastore;
const defaultValues = require('./helpers/defaultValues');

class Entity {
    constructor(data, id, ancestors, namespace, key) {
        this.className = 'Entity';

        this.schema = this.constructor.schema;
        this.excludeFromIndexes = [];

        if (key) {
            if (key.constructor.name === 'Key') {
                this.entityKey = key;
            } else {
                throw new Error('Entity Key must be an instance of gcloud Key');
            }
        } else {
            this.entityKey = createKey(this, id, ancestors, namespace);
        }

        // create entityData from data passed
        this.entityData = buildEntityData(this, data || {});

        // wrap entity with hook methods
        hooks.wrap(this);

        // add middleware defined on Schena
        registerHooksFromSchema(this);
    }

    plain(options) {
        options = typeof options === 'undefined' ? {} : options;

        if (typeof options !== 'undefined' && !is.object(options)) {
            throw new Error('Options must be an Object');
        }
        const readAll = !!options.readAll || false;
        const virtuals = !!options.virtuals || false;
        const showKey = !!options.showKey || false;

        if (virtuals) {
            this.addVirtuals(this.entityData);
        }

        const data = datastoreSerializer.fromDatastore.call(this, this.entityData, { readAll, showKey });

        return data;
    }

    get(path) {
        if ({}.hasOwnProperty.call(this.schema.virtuals, path)) {
            return this.schema.virtuals[path].applyGetters(this.entityData);
        }
        return this.entityData[path];
    }

    set(path, value) {
        if ({}.hasOwnProperty.call(this.schema.virtuals, path)) {
            return this.schema.virtuals[path].applySetters(value, this.entityData);
        }

        this.entityData[path] = value;
        return this;
    }

    /**
     * Return a Model from Gstore
     * @param name : model name
     */
    model(name) {
        return this.constructor.gstore.model(name);
    }

    /**
     * Fetch entity from Datastore
     *
     * @param {Function} cb Callback
     */
    datastoreEntity(cb) {
        const _this = this;

        return this.gstore.ds.get(this.entityKey).then(onSuccess, onError);

        // ------------------------

        function onSuccess(result) {
            const datastoreEntity = result ? result[0] : null;

            if (!datastoreEntity) {
                return cb({
                    code: 404,
                    message: 'Entity not found',
                });
            }

            _this.entityData = datastoreEntity;
            return cb(null, _this);
        }

        function onError(err) {
            return cb(err);
        }
    }

    addVirtuals() {
        const { virtuals } = this.schema;
        const { entityData } = this;

        Object.keys(virtuals).forEach((k) => {
            if ({}.hasOwnProperty.call(entityData, k)) {
                virtuals[k].applySetters(entityData[k], entityData);
            } else {
                virtuals[k].applyGetters(entityData);
            }
        });

        return this.entityData;
    }
}

// Private
// -------
function createKey(self, id, ancestors, namespace) {
    const hasAncestors = typeof ancestors !== 'undefined' && ancestors !== null && is.array(ancestors);

    /*
    /* Create copy of ancestors to avoid mutating the Array
    */
    if (hasAncestors) {
        ancestors = ancestors.slice();
    }

    let path;
    if (id) {
        id = parseId(self, id);
        path = hasAncestors ? ancestors.concat([self.entityKind, id]) : [self.entityKind, id];
    } else {
        if (hasAncestors) {
            ancestors.push(self.entityKind);
        }
        path = hasAncestors ? ancestors : self.entityKind;
    }

    if (namespace && !is.array(path)) {
        path = [path];
    }
    return namespace ? self.gstore.ds.key({ namespace, path }) : self.gstore.ds.key(path);
}

/**
 * Parse the id and according to the keyType config in the Schema ("name"|"id"|<undefined>)
 * it will convert an '123'(string) id to 123 (int).
 * @param {*} self -- the entity instance
 * @param {*} id -- id passed in constructor
 */
function parseId(self, id) {
    const { options } = self.schema;

    if (is.string(id)) {
        if (options && options.keyType === 'name') {
            return id;
        } else if (options.keyType === 'id') {
            return self.gstore.ds.int(id);
        }
        // auto convert string number to number
        return isFinite(id) ? self.gstore.ds.int(id) : id;
    } else if (!is.number(id)) {
        throw new Error('id must be a string or a number');
    }

    return id;
}

function buildEntityData(self, data) {
    const { schema } = self;
    const isJoiSchema = !is.undef(schema._joi);

    let entityData = {};

    if (data) {
        // If Joi schema, get its default values
        if (isJoiSchema) {
            const { error, value } = schema._joi.validate(data);

            if (!error) {
                entityData = Object.assign({}, value);
            }
        }

        Object.keys(data).forEach((k) => {
            entityData[k] = data[k];
        });
    }

    let isTypeArray;

    Object.keys(schema.paths).forEach((k) => {
        const prop = schema.paths[k];
        const hasValue = {}.hasOwnProperty.call(entityData, k);
        const isOptional = {}.hasOwnProperty.call(prop, 'optional') && prop.optional !== false;
        const isRequired = {}.hasOwnProperty.call(prop, 'required') && prop.required === true;

        // Set Default Values
        if (!isJoiSchema && !hasValue && !isOptional) {
            let value = null;

            if ({}.hasOwnProperty.call(prop, 'default')) {
                if (typeof prop.default === 'function') {
                    value = prop.default();
                } else {
                    value = prop.default;
                }
            }

            if (({}).hasOwnProperty.call(defaultValues.__map__, value)) {
                /**
                 * If default value is in the gstore.defaultValue hashTable
                 * then execute the handler for that shortcut
                 */
                value = defaultValues.__handler__(value);
            } else if (value === null && {}.hasOwnProperty.call(prop, 'values') && !isRequired) {
                // Default to first value of the allowed values if **not** required
                [value] = prop.values;
            }

            entityData[k] = value;
        }

        // Set excludeFromIndexes
        /**
         * There is an inconsistency in @google-cloud for Array type
         * We cannot (so far) use the Array way of declaring excludeFromIndexes
         * (like we can do with string, int and object)
         * ---> see serializer/datastore.js
         */
        isTypeArray = prop.type === 'array' || (prop.joi && prop.joi._type === 'array');
        if (prop.excludeFromIndexes === true && !isTypeArray) {
            self.excludeFromIndexes.push(k);
        } else if (!is.boolean(prop.excludeFromIndexes)) {
            // For embedded entities we can set which properties are excluded from indexes
            // by passing a string | array of properties
            const excludeFromIndexes = arrify(prop.excludeFromIndexes);

            let excludedProps;
            if (prop.type === 'array') {
                excludedProps = excludeFromIndexes.map(excluded => `${k}[].${excluded}`);
            } else {
                excludedProps = excludeFromIndexes.map(excluded => `${k}.${excluded}`);
            }

            self.excludeFromIndexes = [...self.excludeFromIndexes, ...excludedProps];
        }
    });

    // add Symbol Key to the entityData
    entityData[self.gstore.ds.KEY] = self.entityKey;

    return entityData;
}

function registerHooksFromSchema(self) {
    const callQueue = self.schema.callQueue.entity;

    if (!Object.keys(callQueue).length) {
        return self;
    }

    Object.keys(callQueue).forEach(addHooks);

    // ---------------------------------------

    function addHooks(method) {
        if (!self[method]) {
            return;
        }

        // Add Pre hooks
        callQueue[method].pres.forEach((fn) => {
            self.pre(method, fn);
        });

        // Add Pre hooks
        callQueue[method].post.forEach((fn) => {
            self.post(method, fn);
        });
    }
    return self;
}

// Promisify Entity methods
Entity.prototype.datastoreEntity = utils.promisify(Entity.prototype.datastoreEntity);

module.exports = Entity;
<|endoftext|>


<commit_before>/*The MIT License (MIT)

Copyright (c) 2015 Jens Malmborg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

var mat4 = require('/gl-matrix/mat4.js');
var vec3 = require('/gl-matrix/vec3.js');

var _forward = vec3.fromValues(0,0,1);
var _up = vec3.fromValues(0,1,0);
var _right = vec3.fromValues(-1,0,0);

function Entity(){
    this.components = {};
    this.children = [];
    this.transform = mat4.create();
    this.rotation = mat4.create();
    this._forward = vec3.clone(_forward);
    this._up = vec3.clone(_up);
    this._right = vec3.clone(_right);
}

Entity.prototype.addComponent = function (component) {
    if (component.entity) {
        var name = component.constructor.name.toLowerCase();
        throw new TypeError(
            "Component \'" + name + "\' is owned by another entity.");
    }
    component.entity = this;
    var name = component.constructor.name.toLowerCase();
    this.components[name.replace('component', '')] = component;
};

Entity.prototype.addChild = function (entity) {
    if (entity.parent) {
        entity.parent.removeChild(entity);
    }
    this.children.push(entity);
    entity.parent = this;
};

Entity.prototype.removeChild = function (entity) {
    var index = this.children.indexOf(entity);
    if (index === -1) {
        return;
    }
    this.children.splice(index, 1);
    entity.parent = null;
};

Entity.prototype.update = function (elapsed) {
    for (var name in this.components) {
        if (!this.components[name].enabled) {
            continue;
        }
        this.components[name].update(elapsed);
    }
    for (var i=0; i<this.children.length; i++) {
        this.children[i].update(elapsed);
    }
};

Entity.prototype.draw = function () {
    for (var name in this.components) {
        if (!this.components[name].visible) {
            continue;
        }
        this.components[name].draw();
    }
    for (var i=0; i<this.children.length; i++) {
        this.children[i].draw();
    }
};

Entity.prototype.translate = function(x, y, z) {
    if (arguments.length === 1) {
        mat4.translate(this.transform, this.transform, arguments[0]);
    } else if (arguments.length === 3) {
        mat4.translate(this.transform, this.transform, vec3.fromValues(x,y,z));
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.rotate = function(x, y, z) {
    if (arguments.length === 1) {
        x = arguments[0][0];
        y = arguments[0][1];
        z = arguments[0][2];
    } else if (arguments.length !== 3) {
        throw new TypeError('Wrong number of arguments.');
    }
    mat4.rotateX(this.transform, this.transform, x);
    mat4.rotateY(this.transform, this.transform, y);
    mat4.rotateZ(this.transform, this.transform, z);
    mat4.rotateX(this.rotation, this.rotation, x);
    mat4.rotateY(this.rotation, this.rotation, y);
    mat4.rotateZ(this.rotation, this.rotation, z);
    vec3.transformMat4(this._forward, _forward, this.rotation);
    vec3.normalize(this._forward, this._forward);
};

Entity.prototype.scale = function(x, y, z) {
    if (arguments.length === 1) {
        mat4.scale(this.transform, this.transform, arguments[0]);
    } else if (arguments.length === 3) {
        mat4.scale(this.transform, this.transform, vec3.fromValues(x,y,z));
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.position = function(x, y, z) {
    if (arguments.length === 0) {
        return vec3.fromValues(
            this.transform[12], this.transform[13], this.transform[14]);
    } else if (arguments.length === 1) {
        this.transform[12] = arguments[0][0];
        this.transform[13] = arguments[0][1];
        this.transform[14] = arguments[0][2];
    } else if (arguments.length === 3) {
        this.transform[12] = x;
        this.transform[13] = y;
        this.transform[14] = z;
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.forward = function() {
    return this._forward;
};

Entity.prototype.right = function() {
    vec3.transformMat4(this._right, _right, this.rotation);
    return vec3.normalize(this._right, this._right);
};

Entity.prototype.up = function() {
    vec3.cross(this._up, this.right(), this._forward);
    return vec3.normalize(this._up, this._up);
};

Entity.prototype.getTransform = function() {
    if (!this.parent) {
        return this.transform;
    }
    return mat4.multiply(
        mat4.create(), this.parent.getTransform(), this.transform);
};

function Component() {
    this.enabled = true;
    this.visible = true;
}

Component.prototype.update = function(elapsed) {
};

Component.prototype.draw = function() {
};

module.exports.Entity = Entity;
module.exports.Component = Component;<commit_msg>Changed position to a Vector3.<commit_after>/*The MIT License (MIT)

Copyright (c) 2015 Jens Malmborg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

var mat4 = require('/gl-matrix/mat4.js');
var vec3 = require('/gl-matrix/vec3.js');
var Vector3 = require('/matrix.js').Vector3;

var _forward = vec3.fromValues(0,0,1);
var _up = vec3.fromValues(0,1,0);
var _right = vec3.fromValues(-1,0,0);

function Entity(){
    this.components = {};
    this.children = [];
    this.transform = mat4.create();
    this.rotation = mat4.create();
    this._forward = vec3.clone(_forward);
    this._up = vec3.clone(_up);
    this._right = vec3.clone(_right);
}

Entity.prototype.addComponent = function (component) {
    if (component.entity) {
        var name = component.constructor.name.toLowerCase();
        throw new TypeError(
            "Component \'" + name + "\' is owned by another entity.");
    }
    component.entity = this;
    var name = component.constructor.name.toLowerCase();
    this.components[name.replace('component', '')] = component;
};

Entity.prototype.addChild = function (entity) {
    if (entity.parent) {
        entity.parent.removeChild(entity);
    }
    this.children.push(entity);
    entity.parent = this;
};

Entity.prototype.removeChild = function (entity) {
    var index = this.children.indexOf(entity);
    if (index === -1) {
        return;
    }
    this.children.splice(index, 1);
    entity.parent = null;
};

Entity.prototype.update = function (elapsed) {
    for (var name in this.components) {
        if (!this.components[name].enabled) {
            continue;
        }
        this.components[name].update(elapsed);
    }
    for (var i=0; i<this.children.length; i++) {
        this.children[i].update(elapsed);
    }
};

Entity.prototype.draw = function () {
    for (var name in this.components) {
        if (!this.components[name].visible) {
            continue;
        }
        this.components[name].draw();
    }
    for (var i=0; i<this.children.length; i++) {
        this.children[i].draw();
    }
};

Entity.prototype.translate = function(x, y, z) {
    if (arguments.length === 1) {
        mat4.translate(this.transform, this.transform, arguments[0]);
    } else if (arguments.length === 3) {
        mat4.translate(this.transform, this.transform, vec3.fromValues(x,y,z));
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.rotate = function(x, y, z) {
    if (arguments.length === 1) {
        x = arguments[0][0];
        y = arguments[0][1];
        z = arguments[0][2];
    } else if (arguments.length !== 3) {
        throw new TypeError('Wrong number of arguments.');
    }
    mat4.rotateX(this.transform, this.transform, x);
    mat4.rotateY(this.transform, this.transform, y);
    mat4.rotateZ(this.transform, this.transform, z);
    mat4.rotateX(this.rotation, this.rotation, x);
    mat4.rotateY(this.rotation, this.rotation, y);
    mat4.rotateZ(this.rotation, this.rotation, z);
    vec3.transformMat4(this._forward, _forward, this.rotation);
    vec3.normalize(this._forward, this._forward);
};

Entity.prototype.scale = function(x, y, z) {
    if (arguments.length === 1) {
        mat4.scale(this.transform, this.transform, arguments[0]);
    } else if (arguments.length === 3) {
        mat4.scale(this.transform, this.transform, vec3.fromValues(x,y,z));
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.position = function(x, y, z) {
    if (arguments.length === 0) {
        return new Vector3(
            this.transform[12], this.transform[13], this.transform[14])
    } else if (arguments.length === 1) {
        this.transform[12] = arguments[0][0];
        this.transform[13] = arguments[0][1];
        this.transform[14] = arguments[0][2];
    } else if (arguments.length === 3) {
        this.transform[12] = x;
        this.transform[13] = y;
        this.transform[14] = z;
    } else {
        throw new TypeError('Wrong number of arguments.');
    }
};

Entity.prototype.forward = function() {
    return this._forward;
};

Entity.prototype.right = function() {
    vec3.transformMat4(this._right, _right, this.rotation);
    return vec3.normalize(this._right, this._right);
};

Entity.prototype.up = function() {
    vec3.cross(this._up, this.right(), this._forward);
    return vec3.normalize(this._up, this._up);
};

Entity.prototype.getTransform = function() {
    if (!this.parent) {
        return this.transform;
    }
    return mat4.multiply(
        mat4.create(), this.parent.getTransform(), this.transform);
};

function Component() {
    this.enabled = true;
    this.visible = true;
}

Component.prototype.update = function(elapsed) {
};

Component.prototype.draw = function() {
};

module.exports.Entity = Entity;
module.exports.Component = Component;<|endoftext|>


<commit_before>var terraformer = require('terraformer');
var terraformerParser = require('terraformer-arcgis-parser');

module.exports = {

  attributes: {
  },

  fieldTypes: {
    'string': 'esriFieldTypeString',
    'integer': 'esriFieldTypeInteger',
    'date': 'esriFieldTypeDate',
    'datetime': 'esriFieldTypeDate',
    'float': 'esriFieldTypeDouble'
  },

  fieldType: function( value ){
    //if ( parseInt(value) ){
    //  return this.fieldTypes[ 'integer' ];
    //} else {
      var type = typeof( value );
      if ( type == 'number'){
        type = ( this.isInt( value ) ) ? 'integer' : 'float';
      }
      return this.fieldTypes[ type ];
    //}
  },

  // is the value an integer?
  isInt: function( v ){
    return Math.round( v ) == v;
  },

  fields: function( props, idField ){
    var self = this;
    var fields = [];
    Object.keys( props ).forEach(function( key ){
      var type = (( idField && key == idField ) ? 'esriFieldTypeOID' : self.fieldType( props[ key ] ));
      if (type){
        var fld = {
          name: key,
          type: type,
          alias: key
        };

        if (type == 'esriFieldTypeString'){
          fld.length = 128;
        }

        fields.push( fld );
      }
    });

    if ( !idField ){
      fields.push({
        name: 'id',
        type: 'esriFieldTypeOID',
        alias: 'id'
      });
    }
    return fields;
  },

  // load a template json file and attach fields
  process: function( tmpl, data, params ){
    var template = require(__dirname + tmpl);
    if ( !data.length && data.features && data.features.length ){
      template.fields = this.fields( data.features[0].properties, params.idField );
    } else if (data[0] && data[0].features[0] && data[0].features[0].length ) {
      template.fields = this.fields( data[0].features[0].properties, params.idField );
    } else {
      template.fields = [];
    }
    return template;
  },

  extent: function( features ){
    return Extent.bounds( features );
  },

  setGeomType: function( json, feature ){
     var tmpl_dir = '/../templates/';
     if ( feature.geometry.type.toLowerCase() == 'polygon' || feature.geometry.type.toLowerCase() == 'multipolygon') {
        json.geometryType = 'esriGeometryPolygon';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/polygon.json');
      } else if ( feature.geometry.type.toLowerCase() == 'linestring' || feature.geometry.type.toLowerCase() == 'multilinestring'){
        json.geometryType = 'esriGeometryPolyline';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/line.json');
      } else {
        json.geometryType = 'esriGeometryPoint';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/point.json');
      }
    return json;
  },

  // returns the feature service metadata (/FeatureServere and /FeatureServer/0)
  info: function( data, layer, params, callback ){
    var json;
    if ( layer !== undefined ) {
      // send the layer json
      data = (data && data[ layer ]) ? data[ layer ] : data;
      json = this.process('/../templates/featureLayer.json', data, params );
      json.name = data.name || 'Layer '+ layer;
      // set the geometry based on the first feature
      // TODO: could clean this up or use a flag in the url to pull out feature of specific type like nixta
      json = this.setGeomType( json, data.features[0] );
    } else {
      // no layer, send the service json
      json = this.process('/../templates/featureService.json', (data && data[ 0 ]) ? data[ 0 ] : data, params);
      if ( data.length ){
        data.forEach(function( d, i){
          json.layers[i] = {
            id: i,
            name: d.name || 'layer '+i,
            parentLayerId: -1,
            defaultVisibility: true,
            subLayerIds: null,
            minScale: 99999.99,
            maxScale: 0
          };
        });
      } else {
        json.layers[0] = {
          id: 0,
          name: "layer 1",
          parentLayerId: -1,
          defaultVisibility: true,
          subLayerIds: null,
          minScale: 99999.99,
          maxScale: 0
        };
      }
    }
    json.fullExtent = json.initialExtent = json.extent = this.extent( (!data.length) ? data.features : data[0].features );
    this.send( json, params, callback );
  },

  // todo support many layers
  layers: function( data, params, callback ){
    var layerJson, json,
      self = this;

    if ( !data.length ){
      layerJson = this.process('/../templates/featureLayer.json', data, params );
      layerJson.extent = layerJson.fullExtent = layerJson.initialExtent = this.extent( data.features );
      json = { layers: [ layerJson ], tables: [] };
      this.send( json, params, callback );
    } else {
      json = { layers: [], tables: [] };
      data.forEach(function( layer, i ){
        layerJson = self.process('/../templates/featureLayer.json', layer, params );
        layerJson.id = i;
        layerJson.extent = layerJson.fullExtent = layerJson.initialExtent = self.extent( layer.features );
        json.layers.push( layerJson );
      });
      this.send( json, params, callback );
    }
  },

  // processes params based on query params
  query: function( data, params, callback ){
    var self = this;
      tmpl_dir = '/../templates/';

    if ( params.objectIds ) {
      this.queryIds( data, params, function( json ){
        self.send( json, params, callback );
      });
    } else {
      var json = this.process( tmpl_dir + 'featureSet.json', data, params );
      // geojson to esri json
      if ( !data.type ) data.type = 'FeatureCollection';
      json.features = terraformerParser.convert( data );
      if ( json.features && json.features.length && json.features[0].geometry.rings ) {
        json.geometryType = 'esriGeometryPolygon';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/polygon.json');
      } else if ( json.features && json.features.length && json.features[0].geometry.paths ){
        json.geometryType = 'esriGeometryPolyline';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/line.json');
      } else {
        json.geometryType = 'esriGeometryPoint';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/point.json');
      }

      // create an id field if not existing
      if ( !params.idField ) {
        json.features.forEach(function( f, i ){
          if ( !f.attributes.id ){
            f.attributes.id = i+1;
          }
        });
      }
      // send back to controller
      this.send( json, params, callback );
    }
  },

  queryIds: function( data, params, callback ){
    var json = this.process('/../templates/featureSet.json', data, params );
    var allFeatures = terraformerParser.convert( data ),
      features = [];
    allFeatures.forEach(function( f, i ){
      var id;
      if ( !params.idField ){
        // Assign a new id, create an 'id'
        id = i+1;
        if ( !f.attributes.id ){
          f.attributes.id = id;
        }
      } else {
        id = f.attributes[ params.idField ];
      }
      if ( params.objectIds.indexOf( id ) > -1 ){
        features.push( f );
      }
    });
    json.features = features;
    if ( callback ) callback( json );
  },

  // filter the data based on any given query params
  send: function(json, params, callback){
    Query.filter( json, params, callback );
  }

};
<commit_msg>adding id attribute<commit_after>var terraformer = require('terraformer');
var terraformerParser = require('terraformer-arcgis-parser');

module.exports = {

  attributes: {
  },

  fieldTypes: {
    'string': 'esriFieldTypeString',
    'integer': 'esriFieldTypeInteger',
    'date': 'esriFieldTypeDate',
    'datetime': 'esriFieldTypeDate',
    'float': 'esriFieldTypeDouble'
  },

  fieldType: function( value ){
    //if ( parseInt(value) ){
    //  return this.fieldTypes[ 'integer' ];
    //} else {
      var type = typeof( value );
      if ( type == 'number'){
        type = ( this.isInt( value ) ) ? 'integer' : 'float';
      }
      return this.fieldTypes[ type ];
    //}
  },

  // is the value an integer?
  isInt: function( v ){
    return Math.round( v ) == v;
  },

  fields: function( props, idField ){
    var self = this;
    var fields = [];
    Object.keys( props ).forEach(function( key ){
      var type = (( idField && key == idField ) ? 'esriFieldTypeOID' : self.fieldType( props[ key ] ));
      if (type){
        var fld = {
          name: key,
          type: type,
          alias: key
        };

        if (type == 'esriFieldTypeString'){
          fld.length = 128;
        }

        fields.push( fld );
      }
    });

    if ( !idField ){
      fields.push({
        name: 'id',
        type: 'esriFieldTypeOID',
        alias: 'id'
      });
    }
    return fields;
  },

  // load a template json file and attach fields
  process: function( tmpl, data, params ){
    var template = require(__dirname + tmpl);
    if ( !data.length && data.features && data.features.length ){
      template.fields = this.fields( data.features[0].properties, params.idField );
    } else if (data[0] && data[0].features[0] && data[0].features[0].length ) {
      template.fields = this.fields( data[0].features[0].properties, params.idField );
    } else {
      template.fields = [];
    }
    return template;
  },

  extent: function( features ){
    return Extent.bounds( features );
  },

  setGeomType: function( json, feature ){
     var tmpl_dir = '/../templates/';
     if ( feature.geometry.type.toLowerCase() == 'polygon' || feature.geometry.type.toLowerCase() == 'multipolygon') {
        json.geometryType = 'esriGeometryPolygon';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/polygon.json');
      } else if ( feature.geometry.type.toLowerCase() == 'linestring' || feature.geometry.type.toLowerCase() == 'multilinestring'){
        json.geometryType = 'esriGeometryPolyline';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/line.json');
      } else {
        json.geometryType = 'esriGeometryPoint';
        json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/point.json');
      }
    return json;
  },

  // returns the feature service metadata (/FeatureServere and /FeatureServer/0)
  info: function( data, layer, params, callback ){
    var json;
    if ( layer !== undefined ) {
      // send the layer json
      data = (data && data[ layer ]) ? data[ layer ] : data;
      json = this.process('/../templates/featureLayer.json', data, params );
      json.name = data.name || 'Layer '+ layer;
      // set the geometry based on the first feature
      // TODO: could clean this up or use a flag in the url to pull out feature of specific type like nixta
      json = this.setGeomType( json, data.features[0] );
    } else {
      // no layer, send the service json
      json = this.process('/../templates/featureService.json', (data && data[ 0 ]) ? data[ 0 ] : data, params);
      if ( data.length ){
        data.forEach(function( d, i){
          json.layers[i] = {
            id: i,
            name: d.name || 'layer '+i,
            parentLayerId: -1,
            defaultVisibility: true,
            subLayerIds: null,
            minScale: 99999.99,
            maxScale: 0
          };
        });
      } else {
        json.layers[0] = {
          id: 0,
          name: "layer 1",
          parentLayerId: -1,
          defaultVisibility: true,
          subLayerIds: null,
          minScale: 99999.99,
          maxScale: 0
        };
      }
    }
    json.fullExtent = json.initialExtent = json.extent = this.extent( (!data.length) ? data.features : data[0].features );
    this.send( json, params, callback );
  },

  // todo support many layers
  layers: function( data, params, callback ){
    var layerJson, json,
      self = this;

    if ( !data.length ){
      layerJson = this.process('/../templates/featureLayer.json', data, params );
      layerJson.extent = layerJson.fullExtent = layerJson.initialExtent = this.extent( data.features );
      json = { layers: [ layerJson ], tables: [] };
      this.send( json, params, callback );
    } else {
      json = { layers: [], tables: [] };
      data.forEach(function( layer, i ){
        layerJson = self.process('/../templates/featureLayer.json', layer, params );
        layerJson.id = i;
        layerJson.extent = layerJson.fullExtent = layerJson.initialExtent = self.extent( layer.features );
        json.layers.push( layerJson );
      });
      this.send( json, params, callback );
    }
  },

  // processes params based on query params
  query: function( data, params, callback ){
    var self = this;
      tmpl_dir = '/../templates/';

    if ( params.objectIds ) {
      this.queryIds( data, params, function( json ){
        self.send( json, params, callback );
      });
    } else {
      var json = this.process( tmpl_dir + 'featureSet.json', data, params );
      // geojson to esri json
      if ( !data.type ) data.type = 'FeatureCollection';
      json.features = terraformerParser.convert( data , {idAttribute: 'id'});
      if ( json.features && json.features.length && json.features[0].geometry.rings ) {
        json.geometryType = 'esriGeometryPolygon';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/polygon.json');
      } else if ( json.features && json.features.length && json.features[0].geometry.paths ){
        json.geometryType = 'esriGeometryPolyline';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/line.json');
      } else {
        json.geometryType = 'esriGeometryPoint';
        //json.drawingInfo.renderer = require(__dirname + tmpl_dir + 'renderers/point.json');
      }

      // create an id field if not existing
      if ( !params.idField ) {
        json.features.forEach(function( f, i ){
          if ( !f.attributes.id ){
            f.attributes.id = i+1;
          }
        });
      }
      // send back to controller
      this.send( json, params, callback );
    }
  },

  queryIds: function( data, params, callback ){
    var json = this.process('/../templates/featureSet.json', data, params );
    var allFeatures = terraformerParser.convert( data ),
      features = [];
    allFeatures.forEach(function( f, i ){
      var id;
      if ( !params.idField ){
        // Assign a new id, create an 'id'
        id = i+1;
        if ( !f.attributes.id ){
          f.attributes.id = id;
        }
      } else {
        id = f.attributes[ params.idField ];
      }
      if ( params.objectIds.indexOf( id ) > -1 ){
        features.push( f );
      }
    });
    json.features = features;
    if ( callback ) callback( json );
  },

  // filter the data based on any given query params
  send: function(json, params, callback){
    Query.filter( json, params, callback );
  }

};
<|endoftext|>


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

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

var assert = require('assert-plus');
var restify = require('restify');
var util = require('util');

// ---- globals

var p = console.warn;
var fmt = util.format;
var RestError = restify.RestError;

// ---- exported functions

/**
 * Extend the default Restify 'text/plain' formatter to include the
 * `err.restCode` string in returned error messages.
 */
function formatErrOrText(req, res, body) {
    if (body instanceof Error) {
        res.statusCode = body.statusCode || 500;
        if (body.restCode && body.restCode !== 'CnapiError') {
            body = fmt('(%s) %s', body.restCode, body.message);
        } else {
            body = body.message;
        }
        body += ' (' + req.getId() + ')';

        // Update `res._body` for the audit logger.
        res._body = body;
    } else if (typeof (body) === 'object') {
        body = JSON.stringify(body);
    } else {
        body = body.toString();
    }

    res.setHeader('Content-Length', Buffer.byteLength(body));
    return (body);
}

// ---- CNAPI-specific error class hierarchy

/**
 * Base class for all of our CNAPI errors. This shouldn't be exported,
 * because all usages should be of one of the subclasses.
 *
 * This is a light wrapper around RestError to add some common `cause.body`
 * attributes for logging.
 */
function _CnapiBaseError(opts) {
    assert.object(opts, 'opts');
    RestError.call(this, opts);
    if (opts.cause && opts.cause.body) {
        this.body.errors = opts.cause.body.errors;
    }
}
util.inherits(_CnapiBaseError, RestError);

/**
 * The generic catch-all error to throw if there isn't a specific error class.
 *
 * Usage:
 *      new CnapiError(message);
 *      new CnapiError(cause, message);
 */
function CnapiError(cause, message) {
    if (message === undefined) {
        message = cause;
        cause = undefined;
    }
    assert.string(message, 'message');
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: (cause && cause.statusCode) || this.constructor.statusCode,
        message: message,
        cause: cause
    });
}
util.inherits(CnapiError, _CnapiBaseError);
CnapiError.prototype.name = 'CnapiError';
CnapiError.restCode = 'CnapiError';
CnapiError.statusCode = 500;
CnapiError.description =
    'Encountered an internal error while fulfilling request.';

/**
 * TODO(trentm): call this just "TimeoutError"?
 */
function CommandTimeoutError(cause) {
    assert.object(cause, 'cause');
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message: 'timed-out waiting for request response',
        cause: cause
    });
}
util.inherits(CommandTimeoutError, _CnapiBaseError);
CommandTimeoutError.prototype.name = 'CommandTimeoutError';
CommandTimeoutError.restCode = 'CommandTimeout';
CommandTimeoutError.statusCode = 500;
CommandTimeoutError.description = 'Timed-out waiting for request response.';

function NotImplementedError(feature) {
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message: feature + ' is not implemented'
    });
}
util.inherits(NotImplementedError, _CnapiBaseError);
NotImplementedError.prototype.name = 'NotImplementedError';
NotImplementedError.restCode = 'NotImplemented';
NotImplementedError.statusCode = 400;
NotImplementedError.description =
    'Attempt to use a feature that is not yet implemented';

function NoAllocatableServersError() {
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message: 'No allocatable servers found'
    });
}
util.inherits(NoAllocatableServersError, _CnapiBaseError);
NoAllocatableServersError.prototype.name = 'NoAllocatableServersError';
NoAllocatableServersError.restCode = 'NoAllocatableServersError';
NoAllocatableServersError.statusCode = 409;
NoAllocatableServersError.description = 'No allocatable servers found';

function VolumeServerNoResourcesError() {
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message: 'No space volume-from server'
    });
}
util.inherits(VolumeServerNoResourcesError, _CnapiBaseError);
VolumeServerNoResourcesError.prototype.name = 'VolumeServerNoResourcesError';
VolumeServerNoResourcesError.restCode = 'VolumeServerNoResourcesError';
VolumeServerNoResourcesError.statusCode = 409;
VolumeServerNoResourcesError.description = 'No allocatable servers found';

// ---- exports

module.exports = {
    formatErrOrText: formatErrOrText,

    InternalError: restify.InternalError,
    ResourceNotFoundError: restify.ResourceNotFoundError,
    InvalidHeaderError: restify.InvalidHeaderError,
    ServiceUnavailableError: restify.ServiceUnavailableError,
    ForbiddenError: restify.ForbiddenError,
    BadRequestError: restify.BadRequestError,

    CnapiError: CnapiError,
    NoAllocatableServersError: NoAllocatableServersError,
    CommandTimeoutError: CommandTimeoutError,
    NotImplementedError: NotImplementedError
};
<commit_msg>DOCKER-293: Introduce VolumeServerNoResourcesError<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

var assert = require('assert-plus');
var restify = require('restify');
var util = require('util');

// ---- globals

var p = console.warn;
var fmt = util.format;
var RestError = restify.RestError;

// ---- exported functions

/**
 * Extend the default Restify 'text/plain' formatter to include the
 * `err.restCode` string in returned error messages.
 */
function formatErrOrText(req, res, body) {
    if (body instanceof Error) {
        res.statusCode = body.statusCode || 500;
        if (body.restCode && body.restCode !== 'CnapiError') {
            body = fmt('(%s) %s', body.restCode, body.message);
        } else {
            body = body.message;
        }
        body += ' (' + req.getId() + ')';

        // Update `res._body` for the audit logger.
        res._body = body;
    } else if (typeof (body) === 'object') {
        body = JSON.stringify(body);
    } else {
        body = body.toString();
    }

    res.setHeader('Content-Length', Buffer.byteLength(body));
    return (body);
}

// ---- CNAPI-specific error class hierarchy

/**
 * Base class for all of our CNAPI errors. This shouldn't be exported,
 * because all usages should be of one of the subclasses.
 *
 * This is a light wrapper around RestError to add some common `cause.body`
 * attributes for logging.
 */
function _CnapiBaseError(opts) {
    assert.object(opts, 'opts');
    RestError.call(this, opts);
    if (opts.cause && opts.cause.body) {
        this.body.errors = opts.cause.body.errors;
    }
}
util.inherits(_CnapiBaseError, RestError);

/**
 * The generic catch-all error to throw if there isn't a specific error class.
 *
 * Usage:
 *      new CnapiError(message);
 *      new CnapiError(cause, message);
 */
function CnapiError(cause, message) {
    if (message === undefined) {
        message = cause;
        cause = undefined;
    }
    assert.string(message, 'message');
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: (cause && cause.statusCode) || this.constructor.statusCode,
        message: message,
        cause: cause
    });
}
util.inherits(CnapiError, _CnapiBaseError);
CnapiError.prototype.name = 'CnapiError';
CnapiError.restCode = 'CnapiError';
CnapiError.statusCode = 500;
CnapiError.description =
    'Encountered an internal error while fulfilling request.';

/**
 * TODO(trentm): call this just "TimeoutError"?
 */
function CommandTimeoutError(cause) {
    assert.object(cause, 'cause');
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message: 'timed-out waiting for request response',
        cause: cause
    });
}
util.inherits(CommandTimeoutError, _CnapiBaseError);
CommandTimeoutError.prototype.name = 'CommandTimeoutError';
CommandTimeoutError.restCode = 'CommandTimeout';
CommandTimeoutError.statusCode = 500;
CommandTimeoutError.description = 'Timed-out waiting for request response.';

function NotImplementedError(feature) {
_CnapiBaseError.call(this, {
    restCode: this.constructor.restCode,
    statusCode: this.constructor.statusCode,
    message: feature + ' is not implemented'
});
}
util.inherits(NotImplementedError, _CnapiBaseError);
NotImplementedError.prototype.name = 'NotImplementedError';
NotImplementedError.restCode = 'NotImplemented';
NotImplementedError.statusCode = 400;
NotImplementedError.description =
'Attempt to use a feature that is not yet implemented';

function NoAllocatableServersError() {
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
            message: 'No compute resources available'
        });
}
util.inherits(NoAllocatableServersError, _CnapiBaseError);
NoAllocatableServersError.prototype.name = 'NoAllocatableServersError';
NoAllocatableServersError.restCode = 'NoAllocatableServersError';
NoAllocatableServersError.statusCode = 409;
NoAllocatableServersError.description = 'No compute resources available';

function VolumeServerNoResourcesError() {
    _CnapiBaseError.call(this, {
        restCode: this.constructor.restCode,
        statusCode: this.constructor.statusCode,
        message:
            'No compute resources available on ' +
            'the host containing the mounted volume'
    });
}
util.inherits(VolumeServerNoResourcesError, _CnapiBaseError);
VolumeServerNoResourcesError.prototype.name = 'VolumeServerNoResourcesError';
VolumeServerNoResourcesError.restCode = 'VolumeServerNoResourcesError';
VolumeServerNoResourcesError.statusCode = 409;
VolumeServerNoResourcesError.description =
    'No compute resources available on the host containing the mounted volume';

// ---- exports

module.exports = {
    formatErrOrText: formatErrOrText,

    InternalError: restify.InternalError,
    ResourceNotFoundError: restify.ResourceNotFoundError,
    InvalidHeaderError: restify.InvalidHeaderError,
    ServiceUnavailableError: restify.ServiceUnavailableError,
    ForbiddenError: restify.ForbiddenError,
    BadRequestError: restify.BadRequestError,

    CnapiError: CnapiError,
    NoAllocatableServersError: NoAllocatableServersError,
    VolumeServerNoResourcesError: VolumeServerNoResourcesError,
    CommandTimeoutError: CommandTimeoutError,
    NotImplementedError: NotImplementedError
};
<|endoftext|>


<commit_before>/*
  Event handlers for TTAPI events
*/
//eventEmitter for roomChanged
exports.roomChangedEvent = function(boombot, data){
  //log room entrance to console if config is set to true
  if (boombot.config.consolelog) {
    console.log('[ Entrance ] : ' + data.room.name);
  }
  // Reset the users list object
  boombot.theUsersList = { };
  //add users to the users list object
  var users = data.users;
  for (var i=0; i<users.length; i++) {
    var DJ = require('../models/dj');
    var user = new DJ(users[i].name, users[i].userid);
    boombot.theUsersList[user.userid] = user;
    if (boombot.config.consolelog) {
      console.log('[ EVENT ] : added ' + user.name + ' to theUsersList');
    }
  }
}
//eventEmitter for registered
exports.registeredEvent = function(boombot, data) {
  //log registration to console if config is set to true
  if (boombot.config.consolelog) {
    console.log('[ Registered ] : ' + data.user[0].name);
  }
  // check if user is in the blacklist
  if (Object.keys(boombot.blackList).length > 0) {
    for (banned in boombot.blackList) {
      if (boombot.blacklist[banned] && (data.user[0].userid == boombot.blackList[banned].user.userid)) {
        boombot.bot.bootUser(data.user[0].userid, 'You were blacklisted. Please don\'t come back.');
        return;
      }
    }
  }
  //add user to the users list object
  var DJ = require('../models/dj');
  var user = new DJ(data.user[0].name, data.user[0].userid);
  boombot.theUsersList[user.userid] = user;
  if (boombot.config.consolelog) {
    console.log('[ EVENT ] : added ' + user.name + ' to theUsersList');
  }
  //chat announcer
  if (boombot.shutUp == false) {
    if (data.user[0].userid == boombot.config.botinfo.userid) { //boombot announces himself
      boombot.bot.speak(boombot.config.responses.botwelcome)
    } else if (data.user[0].userid == boombot.config.admin.userid) { //if the master arrives announce him specifically
      boombot.bot.speak(boombot.config.responses.adminwelcome);
    } else {
      //check to see if the user is a mod, if not PM them
      boombot.bot.roomInfo(true, function(data2) {
        var modArray = data2.room.metadata.moderator_id;
        if (modArray.contains(data.user[0].userid)) { //user is a room mod
          boombot.bot.speak(boombot.config.responses.modwelcome.replace('XXX', data.user[0].name));
        } else {
          boombot.bot.pm(boombot.config.responses.welcomepm, data.user[0].userid, function(data) { }); //PM the user
          boombot.bot.speak(boombot.config.responses.welcome.replace('XXX', data.user[0].name)); //welcome the rest
        }
      });
    }
  }
}
//eventEmitter for registered
exports.deregisteredEvent = function(boombot, data) {
  //remove the person from the user list
  var user = data.user[0];
  delete boombot.theUsersList[user.userid];
  if (boombot.djQueue.contains(data.user[0].userid)) {
    boombot.RemoveFromQueue(data.user[0].userid, data.user[0].name);
  }
}
//eventEmitter for update_votes
exports.update_votesEvent = function(boombot, data) {
  //check for down tag in vote
  if (data.room.metadata.votelog[0].toString().match(/down/i)) {
    try {
      var uncut = data.room.metadata.votelog[0].toString();
      var chopped = uncut.substring(0, uncut.indexOf(','));
      var jerk = boombot.theUsersList[chopped].name
      boombot.bot.speak(jerk + ' thinks your song sucks..');
    } catch (err) {
      //initial downvotes go by without a user ID to trap. Also if you have never upvoted your downvotes go by with no ID.
      boombot.bot.speak("Ouch. Someone thinks you're lame.....")
    }
    if (boombot.config.consolelog) {
      console.log("[ LAME ]");
    }
  }
}
//eventEmitter for newsong
exports.newsongEvent = function(boombot, data) {
  //on song start we will reset the snagCounter
  boombot.snagCounter = 0;
  //auto bop
  if (boombot.autoNod) {
    setTimeout(function(){
      boombot.bot.bop();
    }, 10 * 1000);
  }
  /*
    if the queue is on and the array has more than 0:
    remove any dj that is not the first in array,
    after 30 seconds remove them from the array - announce next if there
  */
  boombot.theUsersList[data.room.metadata.current_dj].IncPlays();
  if (boombot.queue) {
    //  get the array of current DJs
    var currDjs = data.room.metadata.djs;
    //  find the next DJ allowed up
    boombot.runQueue(currDjs);
  }
}
//eventEmitter for snagged
exports.snaggedEvent = function(boombot, data) {
  //increment the snag counter when a song is snagged
  boombot.snagCounter++;
}
//eventEmitter for endsong
exports.endsongEvent = function(boombot, data) {
  //if stats true report the song information
  if (boombot.config.stats && boombot.shutUp == false) {
    boombot.bot.speak(data.room.metadata.current_song.metadata.song + " by " + data.room.metadata.current_song.metadata.artist + " got :+1: " + data.room.metadata.upvotes + " :-1: " +  data.room.metadata.downvotes + " <3 " + boombot.snagCounter);
  }
  if (boombot.queue) {
    var djToRem = data.room.metadata.current_dj;
    if (boombot.theUsersList[djToRem].plays >= boombot.queueLength) {
      boombot.bot.remDj(djToRem);
    }
  }
}
//eventEmitter for update_user
exports.update_userEvent = function(boombot, data) {

}
//eventEmitter for booted_user
exports.booted_userEvent = function(boombot, data) {
  if (boombot.shutUp == false) {
    //talk smack to booted users
    boombot.bot.speak('So glad they are gone.....');
  }
}
//eventEmitter for add_dj
exports.add_djEvent = function(boombot, data) {
  if (boombot.shutUp == false) {
    //announce the new DJ
    if (data.user[0].userid == boombot.config.botinfo.userid) {
      boombot.bot.speak(boombot.config.responses.botdjmode);
    } else if (data.user[0].userid == boombot.config.admin.userid) {
      boombot.bot.speak(boombot.config.responses.masterdjmode.replace('XXX', data.user[0].name));
    } else {
      boombot.bot.speak(boombot.config.responses.djmode.replace('XXX', data.user[0].name));
    }
  }
  //if more than 1 real DJ are on decks the bot hops down unless DJMode is true
  boombot.bot.roomInfo(true, function(data) {
    var currDJs = data.room.metadata.djs;
    var countDJs = currDJs.length;
    var isDJ = false;
    //have to loop through the array apparently no contains method in js
    for (i = 0; i < countDJs; i++) {
      if (currDJs[i] == boombot.config.botinfo.userid) {
        isDJ = true;
      }
    }
    if ((isDJ) && (boombot.DJMode == false) && (countDJs > 2)) {
      boombot.bot.speak("Looks like the rooms a rockin, I'll step down.");
      boombot.bot.remDj();
    }
  });
  if (boombot.queue) {
    //  check the users ID and compare to position 0 of q array
    if (data.user[0].userid != boombot.djQueue[0] && boombot.djQueue.length > 0) {
      //  yank the user if they are not position 0
      boombot.yank = true;
      boombot.bot.remDj(data.user[0].userid);
      boombot.bot.speak('Not your turn @' + data.user[0].name + " type q to see the order, or q+ to add yourself.");
    } else {
      boombot.djQueue.splice(0,1);
      boombot.nextUp = {};
      boombot.theUsersList[data.user[0].userid].ClearPlays();
    }
  }
}
//eventEmitter for rem_dj
exports.rem_djEvent = function(boombot, data) {
  //thank the DJ for playing tunes
  if (data.user[0].userid != boombot.config.botinfo.userid && boombot.shutUp == false) {
    boombot.bot.speak('Everyone give it up for '+data.user[0].name+'!');
  }
  //if the DJs drop to just 1 we will save youuuuuu
  boombot.bot.roomInfo(true, function(data) {
      var currDJs = data.room.metadata.djs;
      var countDJs = currDJs.length;
      if (countDJs <= 1) {
        boombot.bot.speak("Forget the whales! SAVE THE BEATS!");
        boombot.bot.addDj();
      }
  });
  if (boombot.queue) {
    if (boombot.djQueue.length > 0) {
      if (boombot.yank) {
        boombot.yank = false;
      } else {
        boombot.bot.roomInfo(true, function(data2) {
          var currDjs = data2.room.metadata.djs;
          boombot.runQueue(currDjs);
        });
      }
    }
  }
}
// single handler for speech and pm
exports.handleCommand = function(boombot, data, private) {
  // we need 3 main things
  // username, userid, and text
  // pm does not send name. userid on pm is named different
  var uname
    , uid
    , text;
  if (private) {
    uname = ''
    uid   = data.senderid
  } else {
    uname = data.name
    uid   = data.userid
  }
  text = data.text
  //Log speak in console if config is set to true
  if (boombot.config.consolelog && !(private)) {
      console.log('[ Chat: ' + uname +' ] : ' + text);
  } else if (boombot.config.consolelog && private) {
    console.log('[ PM: ' + uid +' ] : ' + text);
  }
  //if the chat was a command, run the command
  // TODO
  // make a way to have optional triggers
  bot.roomInfo(true, function(data2) {
    var modArray = data2.room.metadata.moderator_id;
    /*
      MASTER COMMANDS
    */
    if ((uid == boombot.config.admin.userid
        || (modArray.contains(uid) && boombot.config.moderatorControl))
        && text.toLowerCase().indexOf(boombot.config.botinfo.botname) != -1) {
      var master_controls = require('../lib/core/master_controls').script;
      master_controls(boombot, text, uname, uid, private);
    } else {
      /*
        ROOM MODERATOR COMMANDS
      */
      if (modArray.contains(uid)) {
        for (i = 0; i < boombot.modCommands.length; i++) {
          if (boombot.modCommands[i].trigger == text) {
            boombot.modCommands[i].script(boombot, text, uname, uid, private);
          }
        }
      }
      if (text.toLowerCase() == 'q') { //had to put this here for now due to the way i parse triggers.
        if (boombot.config.queue) {
          if (boombot.queue) {
            var x = boombot.djQueue.length;
            var pos;
            var userName;
            if (x === 0) {
              boombot.respond(uid, 'No ones waiting.', private);
            } else {
              var queueOrder = "";
              for (i = 0; i < x; i++) {
                pos = i + 1;
                queueOrder += pos + ': @' + boombot.theUsersList[boombot.djQueue[i]].name + ' ';
              }
              boombot.respond(uid, queueOrder, private);
            }
          } else {
            boombot.respond(uid, 'free for all.... hop up!', private);
          }
        }
      } else {
        /*
          PEASANT COMMANDS
        */
        for (i =0; i < boombot.commands.length; i++) {
          // parse trigger. If begins with a / make it a matching command
          // if it doesnt start with a / we need to check for it anywhere in the text
          if ((boombot.commands[i].trigger[0] == "/" && boombot.commands[i].trigger.toLowerCase() == text.toLowerCase())
            || (boombot.commands[i].trigger[0] != "/" && text.toLowerCase().indexOf(boombot.commands[i].trigger.toLowerCase()) != -1 && uid != boombot.config.botinfo.userid)) {
            try {
              boombot.commands[i].script(boombot, text, uname, uid, private);
            } catch (err) {
              boombot.respond(uid, 'Your script is bad! Check the log for details.', private);
              console.log('[ *ERROR* ] Script error: ' + err);
            }
          }
        }
      }
    }
  });
}<commit_msg>fixed blacklist error in event handler<commit_after>/*
  Event handlers for TTAPI events
*/
//eventEmitter for roomChanged
exports.roomChangedEvent = function(boombot, data){
  //log room entrance to console if config is set to true
  if (boombot.config.consolelog) {
    console.log('[ Entrance ] : ' + data.room.name);
  }
  // Reset the users list object
  boombot.theUsersList = { };
  //add users to the users list object
  var users = data.users;
  for (var i=0; i<users.length; i++) {
    var DJ = require('../models/dj');
    var user = new DJ(users[i].name, users[i].userid);
    boombot.theUsersList[user.userid] = user;
    if (boombot.config.consolelog) {
      console.log('[ EVENT ] : added ' + user.name + ' to theUsersList');
    }
  }
}
//eventEmitter for registered
exports.registeredEvent = function(boombot, data) {
  //log registration to console if config is set to true
  if (boombot.config.consolelog) {
    console.log('[ Registered ] : ' + data.user[0].name);
  }
  // check if user is in the blacklist
  if (Object.keys(boombot.blackList).length > 0) {
    for (banned in boombot.blackList) {
      if (boombot.blackList[banned] && (data.user[0].userid == boombot.blackList[banned].user.userid)) {
        boombot.bot.bootUser(data.user[0].userid, 'You were blacklisted. Please don\'t come back.');
        return;
      }
    }
  }
  //add user to the users list object
  var DJ = require('../models/dj');
  var user = new DJ(data.user[0].name, data.user[0].userid);
  boombot.theUsersList[user.userid] = user;
  if (boombot.config.consolelog) {
    console.log('[ EVENT ] : added ' + user.name + ' to theUsersList');
  }
  //chat announcer
  if (boombot.shutUp == false) {
    if (data.user[0].userid == boombot.config.botinfo.userid) { //boombot announces himself
      boombot.bot.speak(boombot.config.responses.botwelcome)
    } else if (data.user[0].userid == boombot.config.admin.userid) { //if the master arrives announce him specifically
      boombot.bot.speak(boombot.config.responses.adminwelcome);
    } else {
      //check to see if the user is a mod, if not PM them
      boombot.bot.roomInfo(true, function(data2) {
        var modArray = data2.room.metadata.moderator_id;
        if (modArray.contains(data.user[0].userid)) { //user is a room mod
          boombot.bot.speak(boombot.config.responses.modwelcome.replace('XXX', data.user[0].name));
        } else {
          boombot.bot.pm(boombot.config.responses.welcomepm, data.user[0].userid, function(data) { }); //PM the user
          boombot.bot.speak(boombot.config.responses.welcome.replace('XXX', data.user[0].name)); //welcome the rest
        }
      });
    }
  }
}
//eventEmitter for registered
exports.deregisteredEvent = function(boombot, data) {
  //remove the person from the user list
  var user = data.user[0];
  delete boombot.theUsersList[user.userid];
  if (boombot.djQueue.contains(data.user[0].userid)) {
    boombot.RemoveFromQueue(data.user[0].userid, data.user[0].name);
  }
}
//eventEmitter for update_votes
exports.update_votesEvent = function(boombot, data) {
  //check for down tag in vote
  if (data.room.metadata.votelog[0].toString().match(/down/i)) {
    try {
      var uncut = data.room.metadata.votelog[0].toString();
      var chopped = uncut.substring(0, uncut.indexOf(','));
      var jerk = boombot.theUsersList[chopped].name
      boombot.bot.speak(jerk + ' thinks your song sucks..');
    } catch (err) {
      //initial downvotes go by without a user ID to trap. Also if you have never upvoted your downvotes go by with no ID.
      boombot.bot.speak("Ouch. Someone thinks you're lame.....")
    }
    if (boombot.config.consolelog) {
      console.log("[ LAME ]");
    }
  }
}
//eventEmitter for newsong
exports.newsongEvent = function(boombot, data) {
  //on song start we will reset the snagCounter
  boombot.snagCounter = 0;
  //auto bop
  if (boombot.autoNod) {
    setTimeout(function(){
      boombot.bot.bop();
    }, 10 * 1000);
  }
  /*
    if the queue is on and the array has more than 0:
    remove any dj that is not the first in array,
    after 30 seconds remove them from the array - announce next if there
  */
  boombot.theUsersList[data.room.metadata.current_dj].IncPlays();
  if (boombot.queue) {
    //  get the array of current DJs
    var currDjs = data.room.metadata.djs;
    //  find the next DJ allowed up
    boombot.runQueue(currDjs);
  }
}
//eventEmitter for snagged
exports.snaggedEvent = function(boombot, data) {
  //increment the snag counter when a song is snagged
  boombot.snagCounter++;
}
//eventEmitter for endsong
exports.endsongEvent = function(boombot, data) {
  //if stats true report the song information
  if (boombot.config.stats && boombot.shutUp == false) {
    boombot.bot.speak(data.room.metadata.current_song.metadata.song + " by " + data.room.metadata.current_song.metadata.artist + " got :+1: " + data.room.metadata.upvotes + " :-1: " +  data.room.metadata.downvotes + " <3 " + boombot.snagCounter);
  }
  if (boombot.queue) {
    var djToRem = data.room.metadata.current_dj;
    if (boombot.theUsersList[djToRem].plays >= boombot.queueLength) {
      boombot.bot.remDj(djToRem);
    }
  }
}
//eventEmitter for update_user
exports.update_userEvent = function(boombot, data) {

}
//eventEmitter for booted_user
exports.booted_userEvent = function(boombot, data) {
  if (boombot.shutUp == false) {
    //talk smack to booted users
    boombot.bot.speak('So glad they are gone.....');
  }
}
//eventEmitter for add_dj
exports.add_djEvent = function(boombot, data) {
  if (boombot.shutUp == false) {
    //announce the new DJ
    if (data.user[0].userid == boombot.config.botinfo.userid) {
      boombot.bot.speak(boombot.config.responses.botdjmode);
    } else if (data.user[0].userid == boombot.config.admin.userid) {
      boombot.bot.speak(boombot.config.responses.masterdjmode.replace('XXX', data.user[0].name));
    } else {
      boombot.bot.speak(boombot.config.responses.djmode.replace('XXX', data.user[0].name));
    }
  }
  //if more than 1 real DJ are on decks the bot hops down unless DJMode is true
  boombot.bot.roomInfo(true, function(data) {
    var currDJs = data.room.metadata.djs;
    var countDJs = currDJs.length;
    var isDJ = false;
    //have to loop through the array apparently no contains method in js
    for (i = 0; i < countDJs; i++) {
      if (currDJs[i] == boombot.config.botinfo.userid) {
        isDJ = true;
      }
    }
    if ((isDJ) && (boombot.DJMode == false) && (countDJs > 2)) {
      boombot.bot.speak("Looks like the rooms a rockin, I'll step down.");
      boombot.bot.remDj();
    }
  });
  if (boombot.queue) {
    //  check the users ID and compare to position 0 of q array
    if (data.user[0].userid != boombot.djQueue[0] && boombot.djQueue.length > 0) {
      //  yank the user if they are not position 0
      boombot.yank = true;
      boombot.bot.remDj(data.user[0].userid);
      boombot.bot.speak('Not your turn @' + data.user[0].name + " type q to see the order, or q+ to add yourself.");
    } else {
      boombot.djQueue.splice(0,1);
      boombot.nextUp = {};
      boombot.theUsersList[data.user[0].userid].ClearPlays();
    }
  }
}
//eventEmitter for rem_dj
exports.rem_djEvent = function(boombot, data) {
  //thank the DJ for playing tunes
  if (data.user[0].userid != boombot.config.botinfo.userid && boombot.shutUp == false) {
    boombot.bot.speak('Everyone give it up for '+data.user[0].name+'!');
  }
  //if the DJs drop to just 1 we will save youuuuuu
  boombot.bot.roomInfo(true, function(data) {
      var currDJs = data.room.metadata.djs;
      var countDJs = currDJs.length;
      if (countDJs <= 1) {
        boombot.bot.speak("Forget the whales! SAVE THE BEATS!");
        boombot.bot.addDj();
      }
  });
  if (boombot.queue) {
    if (boombot.djQueue.length > 0) {
      if (boombot.yank) {
        boombot.yank = false;
      } else {
        boombot.bot.roomInfo(true, function(data2) {
          var currDjs = data2.room.metadata.djs;
          boombot.runQueue(currDjs);
        });
      }
    }
  }
}
// single handler for speech and pm
exports.handleCommand = function(boombot, data, private) {
  // we need 3 main things
  // username, userid, and text
  // pm does not send name. userid on pm is named different
  var uname
    , uid
    , text;
  if (private) {
    uname = ''
    uid   = data.senderid
  } else {
    uname = data.name
    uid   = data.userid
  }
  text = data.text
  //Log speak in console if config is set to true
  if (boombot.config.consolelog && !(private)) {
      console.log('[ Chat: ' + uname +' ] : ' + text);
  } else if (boombot.config.consolelog && private) {
    console.log('[ PM: ' + uid +' ] : ' + text);
  }
  //if the chat was a command, run the command
  // TODO
  // make a way to have optional triggers
  bot.roomInfo(true, function(data2) {
    var modArray = data2.room.metadata.moderator_id;
    /*
      MASTER COMMANDS
    */
    if ((uid == boombot.config.admin.userid
        || (modArray.contains(uid) && boombot.config.moderatorControl))
        && text.toLowerCase().indexOf(boombot.config.botinfo.botname) != -1) {
      var master_controls = require('../lib/core/master_controls').script;
      master_controls(boombot, text, uname, uid, private);
    } else {
      /*
        ROOM MODERATOR COMMANDS
      */
      if (modArray.contains(uid)) {
        for (i = 0; i < boombot.modCommands.length; i++) {
          if (boombot.modCommands[i].trigger == text) {
            boombot.modCommands[i].script(boombot, text, uname, uid, private);
          }
        }
      }
      if (text.toLowerCase() == 'q') { //had to put this here for now due to the way i parse triggers.
        if (boombot.config.queue) {
          if (boombot.queue) {
            var x = boombot.djQueue.length;
            var pos;
            var userName;
            if (x === 0) {
              boombot.respond(uid, 'No ones waiting.', private);
            } else {
              var queueOrder = "";
              for (i = 0; i < x; i++) {
                pos = i + 1;
                queueOrder += pos + ': @' + boombot.theUsersList[boombot.djQueue[i]].name + ' ';
              }
              boombot.respond(uid, queueOrder, private);
            }
          } else {
            boombot.respond(uid, 'free for all.... hop up!', private);
          }
        }
      } else {
        /*
          PEASANT COMMANDS
        */
        for (i =0; i < boombot.commands.length; i++) {
          // parse trigger. If begins with a / make it a matching command
          // if it doesnt start with a / we need to check for it anywhere in the text
          if ((boombot.commands[i].trigger[0] == "/" && boombot.commands[i].trigger.toLowerCase() == text.toLowerCase())
            || (boombot.commands[i].trigger[0] != "/" && text.toLowerCase().indexOf(boombot.commands[i].trigger.toLowerCase()) != -1 && uid != boombot.config.botinfo.userid)) {
            try {
              boombot.commands[i].script(boombot, text, uname, uid, private);
            } catch (err) {
              boombot.respond(uid, 'Your script is bad! Check the log for details.', private);
              console.log('[ *ERROR* ] Script error: ' + err);
            }
          }
        }
      }
    }
  });
}<|endoftext|>


<commit_before>const most = require('most');
const {replay} = require('./ReplaySource');
const Stream = most.Stream;

Stream.prototype.replay = function() {
  return replay(this);
};
<commit_msg>Fixed missing maxBufferSize argument<commit_after>const most = require('most');
const {replay} = require('./ReplaySource');
const Stream = most.Stream;

Stream.prototype.replay = function(maxBufferSize) {
  return replay(this, maxBufferSize);
};
<|endoftext|>


<commit_before>'use strict';
var exec = require('child_process').exec;

var callback_parse = callbackParse(err, data, stderr, callback){
	console.log(arguments)
	return callback(data, err, stderr)
};

function sysExec(command, callback){
	command = 'unset XDG_SESSION_ID XDG_RUNTIME_DIR; cgm movepid all virt $$; ' + command;
	callback = callback || function(){};

	return exec(command, callback_parse(callback));
};

var lxc = {
	create: function(name, template, config, callback){
		return sysExec('lxc-create -n '+name+' -t '+template, callback);
	},

	clone: function(name, base_name, callback){
		return sysExec('lxc-clone -o '+base_name+ ' -n '+name +' -B overlayfs -s', callback);
	},

	destroy: function(name, callback){
		return sysExec('lxc-destroy -n '+ name, function(data){
			callback(!data.match(/Destroyed container/));
		});
	},

	start: function(name, callback){
		var cmd = 'lxc-start --name '+name+' --daemon';
		return sysExec(cmd, callback);
	},

	startEphemeral: function(name, base_name, callback){
		var command = 'lxc-start-ephemeral -o '+base_name+ ' -n '+name +' --union-type overlayfs -d';
		callback = callback || function(){};

		return sysExec(command, function(data){
			if(data.match("doesn't exist.")){
				return callback({status: 500, error: "doesn't exist."});
			}
			if(data.match("already exists.")){
				return callback({status: 500, error: "already exists"});
			}
			if(data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)){
				return callback({status: 200, state:'RUNNING', ip: data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
			}

			callback({'?': '?', data: data, name: name, base_name: base_name});
		});
	},

	stop: function(name, callback){
		return sysExec('lxc-stop -n '+ name, callback);
	},

	freeze: function(name, callback){
		return sysExec('lxc-freeze -n '+name, callback);
	},

	unfreeze: function(name, callback){
		return sysExec('lxc-unfreeze -n '+name, callback);
	},

	info: function(name, callback){
		return sysExec('lxc-info -n '+name, function(data){
			if(data.match("doesn't exist")){
				return callback({state: 'NULL'});
			}

			var info = {};
			data = data.replace(/\suse/ig, '').replace(/\sbytes/ig, '').split("\n").slice(0,-1);
			for(var i in data){
				var temp = data[i].split(/\:\s+/);
				info[temp[0].toLowerCase().trim()] = temp[1].trim();
			}
			callback(info);
		});
	},

	list: function(callback){
		sysExec('lxc-ls --fancy', function(data){
			var output = data.split("\n");
			var keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1);
			var info = [];

			keys = keys.map(function(v){return v.toLowerCase()});
			output = output.slice(0).splice(1).slice(0,-1);

			for(var i in output){

				var aIn = output[i].split(/\s+/).slice(0,-1);
				var mapOut = {};
				aIn.map(function(value,idx){
					mapOut[keys[idx]] = value;
				});
				info.push(mapOut);

			}
			callback(info);
		});
	}
};

module.exports = lxc;
<commit_msg>testing<commit_after>'use strict';
var exec = require('child_process').exec;

var callback_parse = function(err, data, stderr, callback){
	console.log(arguments)
	return callback(data, err, stderr)
};

function sysExec(command, callback){
	command = 'unset XDG_SESSION_ID XDG_RUNTIME_DIR; cgm movepid all virt $$; ' + command;
	callback = callback || function(){};

	return exec(command, callback_parse(callback));
};

var lxc = {
	create: function(name, template, config, callback){
		return sysExec('lxc-create -n '+name+' -t '+template, callback);
	},

	clone: function(name, base_name, callback){
		return sysExec('lxc-clone -o '+base_name+ ' -n '+name +' -B overlayfs -s', callback);
	},

	destroy: function(name, callback){
		return sysExec('lxc-destroy -n '+ name, function(data){
			callback(!data.match(/Destroyed container/));
		});
	},

	start: function(name, callback){
		var cmd = 'lxc-start --name '+name+' --daemon';
		return sysExec(cmd, callback);
	},

	startEphemeral: function(name, base_name, callback){
		var command = 'lxc-start-ephemeral -o '+base_name+ ' -n '+name +' --union-type overlayfs -d';
		callback = callback || function(){};

		return sysExec(command, function(data){
			if(data.match("doesn't exist.")){
				return callback({status: 500, error: "doesn't exist."});
			}
			if(data.match("already exists.")){
				return callback({status: 500, error: "already exists"});
			}
			if(data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)){
				return callback({status: 200, state:'RUNNING', ip: data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
			}

			callback({'?': '?', data: data, name: name, base_name: base_name});
		});
	},

	stop: function(name, callback){
		return sysExec('lxc-stop -n '+ name, callback);
	},

	freeze: function(name, callback){
		return sysExec('lxc-freeze -n '+name, callback);
	},

	unfreeze: function(name, callback){
		return sysExec('lxc-unfreeze -n '+name, callback);
	},

	info: function(name, callback){
		return sysExec('lxc-info -n '+name, function(data){
			if(data.match("doesn't exist")){
				return callback({state: 'NULL'});
			}

			var info = {};
			data = data.replace(/\suse/ig, '').replace(/\sbytes/ig, '').split("\n").slice(0,-1);
			for(var i in data){
				var temp = data[i].split(/\:\s+/);
				info[temp[0].toLowerCase().trim()] = temp[1].trim();
			}
			callback(info);
		});
	},

	list: function(callback){
		sysExec('lxc-ls --fancy', function(data){
			var output = data.split("\n");
			var keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1);
			var info = [];

			keys = keys.map(function(v){return v.toLowerCase()});
			output = output.slice(0).splice(1).slice(0,-1);

			for(var i in output){

				var aIn = output[i].split(/\s+/).slice(0,-1);
				var mapOut = {};
				aIn.map(function(value,idx){
					mapOut[keys[idx]] = value;
				});
				info.push(mapOut);

			}
			callback(info);
		});
	}
};

module.exports = lxc;
<|endoftext|>