var fs = require('fs');
var path = require('path');
var _ = require('underscore')._;
var utils = require('./util.js');
var chalk = require('chalk');

var defaults = {
    root: '/api',
    debug: false,
    rootModule: 'index'
};

var debugMode = false;

function __log(args) {
    if (debugMode) {
        console.log.apply(null, arguments);
    }
}

/**
 * Processes a list of files and produces the api routing for them
 * @param files The list of files to process
 * @param settings express-autoapi settings
 * @param state The process state
 */
function processFileList(files, base, settings, state) {

    for (var i = 0; i < files.length; i++) {

        var modulePath = path.join(base, files[i]);

        var stats = fs.statSync(modulePath);

        if (stats.isFile()) {

            // Try to load the module
            var module = require(modulePath);
            var relative = path.relative(settings.source, modulePath);

            __log('Relative path: %s', relative);

            var pathWithoutExtension = relative.substr(0, relative.lastIndexOf('.'));
            var routeName = pathWithoutExtension.replace(/\\/g, '/').replace(/\./g, '_');

            var isRoot = new RegExp(settings.rootModule + '/?$', 'g').test(routeName);
            var routePath = routeName;

            // Special case for an index file - put these in the root of the api
            if (isRoot) {

                if(routePath.lastIndexOf('/') > -1)
                    routePath = routePath.substr(0, routePath.lastIndexOf('/'));
                else
                    routePath = undefined;
            }

            __log('%s (%s)', routeName, routePath);

            var apiPath = utils.combineApiPath(settings.root, routePath);

            state.endpoints[routeName] = {
                baseUrl: apiPath,
                filename: modulePath,
                routeName: routeName
            };

            __log(state.endpoints[routeName]);

            settings.app.use(apiPath, module);
        }
        else if (stats.isDirectory()) {
            var dirFiles = fs.readdirSync(modulePath);
            processFileList(dirFiles, modulePath, settings, state);
        }
    }
}

module.exports = {

    setup: function(settings) {

        settings = _.extend({}, defaults, settings || {});
        debugMode = settings.debug;

        if (!settings.app)
            throw "Express app not specified";

        var loggedSettings = _.extend({}, settings);
        delete loggedSettings.app;
    	__log("Settings: ", loggedSettings);

        if (!settings.source || typeof settings.source != 'string')
            throw "No Api source directory found";

        if (!fs.existsSync(settings.source))
            return;

        var state = {
            endpoints: {},
            settings: settings
        };

        var files = fs.readdirSync(settings.source);

        processFileList(files, settings.source, settings, state);

        return state;
    }
};


'use strict';

// package module for different environments
function packageModule(global, name, api) {
  if (global.define && global.define.amd) {
    define([], api);
  } else if (typeof exports !== "undefined") {
    module.exports = api;
  } else {
    global[name] = api;
  }
}

function sizeOf(str) {
  // This isn't super correct but will do for our purposes
  return str.length;
}

// QStorage constructor
function QStorage(limit, storage){
  this._limit = limit;
  this._storage = storage;
  this._usage = this._getUsage();
}

// Get current usage
QStorage.prototype._getUsage = function(){
  var usage = 0;
  for(var i=0, len=this._storage.length; i<len; i++) {
    var key = this._storage.key(i);
    usage += sizeOf(key) + sizeOf(this._storage.getItem(key));
  }
  return usage;
};

//
// STORAGE API
// Spec here: http://dev.w3.org/html5/webstorage/#storage-0
//

// Get the key of index idx
QStorage.prototype.key = function(idx){
  return this._storage.key(idx);
};

// Get item for key
QStorage.prototype.getItem = function(key){
  return this._storage.getItem(key);
};

// Set value of key to val
QStorage.prototype.setItem = function(key, val){
  var diff = 0;
  var oldVal = this.getItem(key);
  if(oldVal){
    diff -= (sizeOf(key) + sizeOf(oldVal));
  }
  diff += (sizeOf(key) + sizeOf(val));
  if(this._usage + diff > this._limit){
    throw new Error("Failed to execute 'setItem' on 'Storage': Setting the value of 'test' exceeded the quota.");
  }
  this._usage += diff;
  this._storage.setItem(key, val);
};

// Remove item from storage
QStorage.prototype.removeItem = function(key){
  var oldVal = this.getItem(key);
  if(oldVal){
    this._usage -= (sizeOf(key) + sizeOf(oldVal));
  }
  this._storage.removeItem(key);
};

// Clear storage
QStorage.prototype.clear = function(){
  this._usage = 0;
  this._storage.clear();
};

//
// API
//
var API = {
  createQuota: function(limit, storage){
    return new QStorage(limit, storage);
  }
};

// Module packaging
packageModule(this, 'QuotaStorage', API);


// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/** @typedef {{eventListeners:!Array<!WebInspector.EventListener>, internalHandlers:?WebInspector.RemoteArray}} */
WebInspector.FrameworkEventListenersObject;

/** @typedef {{type: string, useCapture: boolean, passive: boolean, handler: function()}} */
WebInspector.EventListenerObjectInInspectedPage;

/**
 * @param {!WebInspector.RemoteObject} object
 * @return {!Promise<!WebInspector.FrameworkEventListenersObject>}
 */
WebInspector.EventListener.frameworkEventListeners = function(object)
{
    if (!object.target().isPage()) {
        // TODO(kozyatinskiy): figure out how this should work for |window|.
        return Promise.resolve(/** @type {!WebInspector.FrameworkEventListenersObject} */ ({eventListeners: [], internalHandlers: null}));
    }

    var listenersResult = /** @type {!WebInspector.FrameworkEventListenersObject} */({eventListeners: []});
    return object.callFunctionPromise(frameworkEventListeners, undefined)
                 .then(assertCallFunctionResult)
                 .then(getOwnProperties)
                 .then(createEventListeners)
                 .then(returnResult)
                 .catchException(listenersResult);

    /**
     * @param {!WebInspector.RemoteObject} object
     * @return {!Promise<!{properties: ?Array.<!WebInspector.RemoteObjectProperty>, internalProperties: ?Array.<!WebInspector.RemoteObjectProperty>}>}
     */
    function getOwnProperties(object)
    {
        return object.getOwnPropertiesPromise();
    }

    /**
     * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, internalProperties: ?Array<!WebInspector.RemoteObjectProperty>}} result
     * @return {!Promise<undefined>}
     */
    function createEventListeners(result)
    {
        if (!result.properties)
            throw new Error("Object properties is empty");
        var promises = [];
        for (var property of result.properties) {
            if (property.name === "eventListeners" && property.value)
                promises.push(convertToEventListeners(property.value).then(storeEventListeners));
            if (property.name === "internalHandlers" && property.value)
                promises.push(convertToInternalHandlers(property.value).then(storeInternalHandlers));
            if (property.name === "errorString" && property.value)
                printErrorString(property.value);
        }
        return /** @type {!Promise<undefined>} */(Promise.all(promises));
    }

    /**
     * @param {!WebInspector.RemoteObject} pageEventListenersObject
     * @return {!Promise<!Array<!WebInspector.EventListener>>}
     */
    function convertToEventListeners(pageEventListenersObject)
    {
        return WebInspector.RemoteArray.objectAsArray(pageEventListenersObject).map(toEventListener).then(filterOutEmptyObjects);

        /**
         * @param {!WebInspector.RemoteObject} listenerObject
         * @return {!Promise<?WebInspector.EventListener>}
         */
        function toEventListener(listenerObject)
        {
            /** @type {string} */
            var type;
            /** @type {boolean} */
            var useCapture;
            /** @type {boolean} */
            var passive;
            /** @type {?WebInspector.RemoteObject} */
            var handler = null;
            /** @type {?WebInspector.RemoteObject} */
            var originalHandler = null;
            /** @type {?WebInspector.DebuggerModel.Location} */
            var location = null;
            /** @type {?WebInspector.RemoteObject} */
            var removeFunctionObject = null;

            var promises = [];
            promises.push(listenerObject.callFunctionJSONPromise(truncatePageEventListener, undefined).then(storeTruncatedListener));

            /**
             * @suppressReceiverCheck
             * @this {WebInspector.EventListenerObjectInInspectedPage}
             * @return {!{type:string, useCapture:boolean, passive:boolean}}
             */
            function truncatePageEventListener()
            {
                return {type: this.type, useCapture: this.useCapture, passive: this.passive};
            }

            /**
             * @param {!{type:string, useCapture: boolean, passive: boolean}} truncatedListener
             */
            function storeTruncatedListener(truncatedListener)
            {
                type = truncatedListener.type;
                useCapture = truncatedListener.useCapture;
                passive = truncatedListener.passive;
            }

            promises.push(listenerObject.callFunctionPromise(handlerFunction).then(assertCallFunctionResult).then(storeOriginalHandler).then(toTargetFunction).then(storeFunctionWithDetails));

            /**
             * @suppressReceiverCheck
             * @return {function()}
             * @this {WebInspector.EventListenerObjectInInspectedPage}
             */
            function handlerFunction()
            {
                return this.handler;
            }

            /**
             * @param {!WebInspector.RemoteObject} functionObject
             * @return {!WebInspector.RemoteObject}
             */
            function storeOriginalHandler(functionObject)
            {
                originalHandler = functionObject;
                return originalHandler;
            }

            /**
             * @param {!WebInspector.RemoteObject} functionObject
             * @return {!Promise<undefined>}
             */
            function storeFunctionWithDetails(functionObject)
            {
                handler = functionObject;
                return /** @type {!Promise<undefined>} */(functionObject.functionDetailsPromise().then(storeFunctionDetails));
            }

            /**
             * @param {?WebInspector.DebuggerModel.FunctionDetails} functionDetails
             */
            function storeFunctionDetails(functionDetails)
            {
                location = functionDetails ? functionDetails.location : null;
            }

            promises.push(listenerObject.callFunctionPromise(getRemoveFunction).then(assertCallFunctionResult).then(storeRemoveFunction));

            /**
             * @suppressReceiverCheck
             * @return {function()}
             * @this {WebInspector.EventListenerObjectInInspectedPage}
             */
            function getRemoveFunction()
            {
                return this.remove;
            }

            /**
             * @param {!WebInspector.RemoteObject} functionObject
             */
            function storeRemoveFunction(functionObject)
            {
                if (functionObject.type !== "function")
                    return;
                removeFunctionObject = functionObject;
            }

            return Promise.all(promises).then(createEventListener).catchException(/** @type {?WebInspector.EventListener} */(null));

            /**
             * @return {!WebInspector.EventListener}
             */
            function createEventListener()
            {
                if (!location)
                    throw new Error("Empty event listener's location");
                return new WebInspector.EventListener(handler._target, type, useCapture, passive, handler, originalHandler, location, removeFunctionObject, "frameworkUser");
            }
        }
    }

    /**
     * @param {!WebInspector.RemoteObject} pageInternalHandlersObject
     * @return {!Promise<!WebInspector.RemoteArray>}
     */
    function convertToInternalHandlers(pageInternalHandlersObject)
    {
        return WebInspector.RemoteArray.objectAsArray(pageInternalHandlersObject).map(toTargetFunction)
                                       .then(WebInspector.RemoteArray.createFromRemoteObjects);
    }

    /**
     * @param {!WebInspector.RemoteObject} functionObject
     * @return {!Promise<!WebInspector.RemoteObject>}
     */
    function toTargetFunction(functionObject)
    {
        return WebInspector.RemoteFunction.objectAsFunction(functionObject).targetFunction();
    }

    /**
     * @param {!Array<!WebInspector.EventListener>} eventListeners
     */
    function storeEventListeners(eventListeners)
    {
        listenersResult.eventListeners = eventListeners;
    }

    /**
     * @param {!WebInspector.RemoteArray} internalHandlers
     */
    function storeInternalHandlers(internalHandlers)
    {
        listenersResult.internalHandlers = internalHandlers;
    }

    /**
     * @param {!WebInspector.RemoteObject} errorString
     */
    function printErrorString(errorString)
    {
        WebInspector.console.error(errorString.value);
    }

    /**
     * @return {!WebInspector.FrameworkEventListenersObject}
     */
    function returnResult()
    {
        return listenersResult;
    }

    /**
     * @param {!WebInspector.CallFunctionResult} result
     * @return {!WebInspector.RemoteObject}
     */
    function assertCallFunctionResult(result)
    {
        if (result.wasThrown || !result.object)
            throw new Error("Exception in callFunction or empty result");
        return result.object;
    }

    /**
     * @param {!Array<?T>} objects
     * @return {!Array<!T>}
     * @template T
     */
    function filterOutEmptyObjects(objects)
    {
        return objects.filter(filterOutEmpty);

        /**
         * @param {?T} object
         * @return {boolean}
         * @template T
         */
        function filterOutEmpty(object)
        {
            return !!object;
        }
    }

    /*
    frameworkEventListeners fetcher functions should produce following output:
        {
          // framework event listeners
          "eventListeners": [
            {
              "handler": function(),
              "useCapture": true,
              "passive": false,
              "type": "change",
              "remove": function(type, handler, useCapture, passive)
            },
            ...
          ],
          // internal framework event handlers
          "internalHandlers": [
            function(),
            function(),
            ...
          ]
        }
    */
    /**
     * @suppressReceiverCheck
     * @return {!{eventListeners:!Array<!WebInspector.EventListenerObjectInInspectedPage>, internalHandlers:?Array<function()>}}
     * @this {Object}
     */
    function frameworkEventListeners()
    {
        var errorLines = [];
        var eventListeners = [];
        var internalHandlers = [];
        var fetchers = [jQueryFetcher];
        try {
            if (self.devtoolsFrameworkEventListeners && isArrayLike(self.devtoolsFrameworkEventListeners))
                fetchers = fetchers.concat(self.devtoolsFrameworkEventListeners);
        } catch (e) {
            errorLines.push("devtoolsFrameworkEventListeners call produced error: " + toString(e));
        }

        for (var i = 0; i < fetchers.length; ++i) {
            try {
                var fetcherResult = fetchers[i](this);
                if (fetcherResult.eventListeners && isArrayLike(fetcherResult.eventListeners)) {
                    eventListeners = eventListeners.concat(fetcherResult.eventListeners.map(checkEventListener).filter(nonEmptyObject));
                }
                if (fetcherResult.internalHandlers && isArrayLike(fetcherResult.internalHandlers))
                    internalHandlers = internalHandlers.concat(fetcherResult.internalHandlers.map(checkInternalHandler).filter(nonEmptyObject));
            } catch (e) {
                errorLines.push("fetcher call produced error: " + toString(e));
            }
        }
        var result = {eventListeners: eventListeners};
        if (internalHandlers.length)
            result.internalHandlers = internalHandlers;
        if (errorLines.length) {
            var errorString = "Framework Event Listeners API Errors:\n\t" + errorLines.join("\n\t");
            errorString = errorString.substr(0, errorString.length - 1);
            result.errorString = errorString;
        }
        return result;

        /**
         * @param {?Object} obj
         * @return {boolean}
         */
        function isArrayLike(obj)
        {
            if (!obj || typeof obj !== "object")
                return false;
            try {
                if (typeof obj.splice === "function") {
                    var len = obj.length;
                    return typeof len === "number" && (len >>> 0 === len && (len > 0 || 1 / len > 0));
                }
            } catch (e) {
            }
            return false;
        }

        /**
         * @param {*} eventListener
         * @return {?WebInspector.EventListenerObjectInInspectedPage}
         */
        function checkEventListener(eventListener)
        {
            try {
                var errorString = "";
                if (!eventListener)
                    errorString += "empty event listener, ";
                var type = eventListener.type;
                if (!type || (typeof type !== "string"))
                    errorString += "event listener's type isn't string or empty, ";
                var useCapture = eventListener.useCapture;
                if (typeof useCapture !== "boolean")
                    errorString += "event listener's useCapture isn't boolean or undefined, ";
                var passive = eventListener.passive;
                if (typeof passive !== "boolean")
                    errorString += "event listener's passive isn't boolean or undefined, ";
                var handler = eventListener.handler;
                if (!handler || (typeof handler !== "function"))
                    errorString += "event listener's handler isn't a function or empty, ";
                var remove = eventListener.remove;
                if (remove && (typeof remove !== "function"))
                    errorString += "event listener's remove isn't a function, ";
                if (!errorString){
                    return {type: type, useCapture: useCapture, passive: passive, handler: handler, remove: remove};
                } else {
                    errorLines.push(errorString.substr(0, errorString.length - 2));
                    return null;
                }
            } catch (e) {
                errorLines.push(toString(e));
                return null;
            }
        }

        /**
         * @param {*} handler
         * @return {function()|null}
         */
        function checkInternalHandler(handler)
        {
            if (handler && (typeof handler === "function"))
                return handler;
            errorLines.push("internal handler isn't a function or empty");
            return null;
        }

        /**
         * @param {*} obj
         * @return {string}
         * @suppress {uselessCode}
         */
        function toString(obj)
        {
            try {
                return "" + obj;
            } catch (e) {
                return "<error>";
            }
        }

        /**
         * @param {*} obj
         * @return {boolean}
         */
        function nonEmptyObject(obj)
        {
            return !!obj;
        }

        function jQueryFetcher(node)
        {
            if (!node || !(node instanceof Node))
                return {eventListeners: []};
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return {eventListeners: []};
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            var data = jQuery._data || jQuery.data;

            var eventListeners = [];
            var internalHandlers = [];

            if (typeof data === "function") {
                var events = data(node, "events");
                for (var type in events) {
                    for (var key in events[type]) {
                        var frameworkListener = events[type][key];
                        if (typeof frameworkListener === "object" || typeof frameworkListener === "function") {
                            var listener = {
                                handler: frameworkListener.handler || frameworkListener,
                                useCapture: true,
                                passive: false,
                                type: type
                            };
                            listener.remove = jQueryRemove.bind(node, frameworkListener.selector);
                            eventListeners.push(listener);
                        }
                    }
                }
                var nodeData = data(node);
                if (nodeData && typeof nodeData.handle === "function")
                    internalHandlers.push(nodeData.handle);
            }
            var entry = jQueryFunction(node)[0];
            if (entry) {
                var entryEvents = entry["$events"];
                for (var type in entryEvents) {
                    var events = entryEvents[type];
                    for (var key in events) {
                        if (typeof events[key] === "function") {
                            var listener = {
                                handler: events[key],
                                useCapture: true,
                                passive: false,
                                type: type
                            };
                            // We don't support removing for old version < 1.4 of jQuery because it doesn't provide API for getting "selector".
                            eventListeners.push(listener);
                        }
                    }
                }
                if (entry && entry["$handle"])
                    internalHandlers.push(entry["$handle"]);
            }
            return {eventListeners: eventListeners, internalHandlers: internalHandlers};
        }

        /**
         * @param {string} selector
         * @param {string} type
         * @param {function()} handler
         * @this {?Object}
         */
        function jQueryRemove(selector, type, handler)
        {
            if (!this || !(this instanceof Node))
                return;
            var node = /** @type {!Node} */(this);
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return;
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            jQueryFunction(node).off(type, selector, handler);
        }
    }
}


"use strict";

const proxyMap = new WeakMap();

const target = Object.setPrototypeOf(() => {}, null);

delete target.name;
delete target.length;

Object.freeze(target);

/**
 * A proxy for an object that has a Set for this property key will pass through all properties with a name that can be found in that Set.
 * Used internally to define the properties of Apis that should be passed through (i. e. "then" and "catch").
 * @memberof module:proxify
 * @private
 * @ignore
 * @type symbol
 */
const passthrough = Symbol("passthrough");

/**
 * Returns a proxy for the given {@link Api} or {@link ClientApi}. Accessing a property `A` of it will return `proxify(api.route(A))`. Calling the proxy with an argument `B` will return `api.close(B)`.
 * When the properties `then` and `catch` of the proxy are accessed they will not be translated into `route` calls but passed through to `api` directly instead.
 * @module proxify
 * @param {Api|ClientApi} api The Api to proxify.
 * @return {Proxy} A proxified version of the given Api.
 */
function proxify(api) {
	if(!api || typeof api !== "object")
		throw new TypeError("Only objects can be proxified.");

	if(typeof api.route !== "function" || typeof api.close !== "function")
		throw new TypeError("Only objects that offer an owe Api interface can be proxified.");

	const passthroughSet = api[passthrough];

	const proxy = new Proxy(target, {
		get(target, property) {
			if(typeof property === "symbol" || passthroughSet && passthroughSet.has(property) && property in api)
				return typeof api[property] === "function" ? api[property].bind(api) : api[property];

			return proxify(api.route(property));
		},

		apply(target, context, args) {
			return api.close(args[0]);
		},

		deleteProperty() {
			return false;
		}
	});

	proxyMap.set(proxy, api);

	return proxy;
}

/**
 * Reverts the proxify function.
 * @memberof module:proxify
 * @param {Proxy} proxy A proxy that was returned by {@link proxify}.
 * @return {Api|ClientApi} The Api that was used to construct `proxy`.
 */
function revert(proxy) {
	return proxyMap.get(proxy);
}

module.exports = Object.assign(proxify, { revert, passthrough });


/* Bus - A generic event bus
 *
 * Use var myObj = new require("ebus")(); to inherit the functions
 * Use myObj.on("event", callback) to attach event handlers
 * Use emit("event", data, callback) to trigger the event handlers
 *
 *   Each listener is called with two parameters, data and a function.
 *
 *   Listeners are expected to call the function with no parameters
 *   if they are successful, and with an error object to stop the
 *   event from propagating to downstream listeners.
 *
 *   Finally, the callback passed to emit itself will be called, either
 *   with no arguments, if all handlers were successful, or with
 *   the error object returned by the listener which failed.
 */

/* global performance */
/* eslint-env node */

/*
	Debug levels
	0 - None
	1 - Definite problem, e.g. calling next twice
	2 - Likely problem, e.g. thrown error
	3 - Possible problem, e.g. error in callback
	4 - Trace execution path through ebus
	5 - Log performance

	Each level includes all the messages from lower levels.
*/
require("setimmediate"); // polyfills the global setImmediate

function Ebus(p) {
	"use strict";

	this.debug = false;
	this.yields = false;
	this.handlers = {};

	if (p) {
		this.priorities = p;
	} else {
		this.priorities = {};
	}
}

Ebus.prototype.on = function (event, p1, p2) {
	"use strict";

	var i, line = "", stack, handle,
		len, callback, priority;

	if (typeof p1 === "function") {
		callback = p1;
		priority = p2;
	} else {
		callback = p2;
		priority = p1;
	}

	if (this.debug) {
		stack = new Error().stack;
		line = event + ":" + priority + " " + callback.name;
		if (stack) {
			line = line + "@" + stack.split("\n")[2].
				replace(/^.*\//, "").
				replace(/\:[^:]*$/, "");
		}
	}

	if (typeof priority === "string") {
		priority = this.priorities[priority];
	}

	if (typeof priority !== "number") {
		priority = 0;
//		throw new Error("EBUS_INVALID_PRIORITY");
	}

	if (typeof callback !== "function") {
		throw new Error("EBUS_INVALID_LISTENER");
	}

	if (!this.handlers[event]) {
		this.handlers[event] = [];
	}

	len = this.handlers[event].length;

	handle = {
        fn: callback,
		async: callback.length >= 2,
        priority: priority,
		line: line
    };

	if (!len || priority <= this.handlers[event][len - 1].priority) {
		this.handlers[event].push(handle);
	} else {
		for(i = len - 1; i >= 0; i--) {
			if(this.handlers[event][i].priority >= priority) { break; }
		}
		this.handlers[event].splice(i + 1, 0, handle);
	}

};

Ebus.prototype.off = function(event, cb) {
	"use strict";

	var i, l;

	if (this.handlers[event]) {
		for (i = 0, l = this.handlers[event].length; i < l; i++) {
			if (this.handlers[event][i].fn === cb) {
				this.handlers[event].splice(i, 1);

				break;
			}
		}
	}
};

Ebus.prototype.emit = function(event, data, cb) {
	"use strict";

	var listeners = this.handlers[event] || [],
		status = {},
		i = 0,
		runningCount = 0,
		calledBack = false,
		li,
		prio,

		debug = this.debug,
		timer,

		RUNNING = 1,
		SUCCESS = 2,
		ERROR = 3;

	if (!listeners) {
		if (cb) { cb(null, data); }
		return;
	}

	function success () {
		if(timer) { clearTimeout(timer); }
		calledBack = true;

		if(cb) {
			setImmediate(function () { cb(null, data); });
		}

		return;
	}

	function error(err) {
		if(timer) { clearTimeout(timer); }
		calledBack = true;

		if (cb) {
			setImmediate(function () { cb(err, data); });
		}
		return;
	}

	function dumpStatus() {
		for(var j in status) {
			console.log(listeners[j].line + " -- " + ["Running", "Success", "Error"][status[j] - 1]);
		}
	}

	function getNext(prevIx) {
		var start;

		if(typeof prevIx !== "undefined") { // Skip when invoking first listener
			status[prevIx] = RUNNING;
			runningCount++;

			if(debug) {
				start = process && process.hrtime ? process.hrtime() : performance ? performance.now() : Date.now();
			}
		}

		return function (err) {
			if(typeof prevIx !== "undefined") { // Skip when invoking first listener
				if(debug > 4) {
					console.log(listeners[prevIx].line + " called next after " + (
						process && process.hrtime ? process.hrtime(start)[1] / 1000000 : (performance ? performance.now() : Date.now()) - start
					));
				}

				if(calledBack) {
					if(debug > 0) { console.log("Next() after emit called back" + listeners[prevIx].line); }
					return;
				}

				if(status[prevIx] !== RUNNING) {
					if(debug > 0) { console.log("Multiple next() from " + listeners[prevIx].line); }
					throw Error("EBUS_MULTIPLE_NEXT");
				}

				if (err) {
					status[prevIx] = ERROR;
					if(debug > 2) { console.log("Received error from " + listeners[prevIx].line + ":\n", err); }
					error(err);
					return;
				}

				status[prevIx] = SUCCESS;

				if(runningCount > 0) { runningCount--; }
				if(prevIx === i) {
					if(debug > 4) { console.log("Sync callback from " + listeners[i].line + "; if possible, remove callback for better perf."); }
					return;
				}
				if(runningCount > 0) { return; }
			}

			prio = listeners[i] && listeners[i].priority;

			while(true) {
				if (i >= listeners.length) {
					if (runningCount === 0) {
						success(data);
					}
					return;
				}

				li = listeners[i];

				if(li.priority !== prio) {
					if(runningCount > 0) {
						// if an async listener has been fired, wait for it to be done.
						break;
					} else {
						// otherwise, bump the prio and keep looping
						prio = li.priority;
					}
				}

				if (debug > 3) { console.log("Calling " + li.line); }

				if(li.async) {
					li.fn.call(null, data, getNext(i));
				} else {
					li.fn.call(null, data);
				}

				i++;
			}
		};
	}

	if (debug > 0) {
		timer = setTimeout(function () {
			console.log("Emit timed out. Status:");
			dumpStatus();
		}, 5000);
	}

	getNext()();
};

Ebus.prototype.setDebug = function(level) {
	"use strict";
	if(level === false) {
		level = 0;
	} else if(level === true) {
		level = 5;
	}
	this.debug = level;
};

Ebus.prototype.setYields = function(flag) {
	"use strict";
	console.log("Yields is not yet supported");
	this.yields = flag;
};

Ebus.prototype.dump = function (event) {
	"use strict";
	console.log(this.handlers[event].map(function (handler) {
		return handler.line;
	}).join("\n"));
};

module.exports = Ebus;


"use strict"

module.exports = ApiClient

var glob = require('glob')
var _ = require('underscore')

// setup global underscore template settings
_.templateSettings = {
  escape : /\{\{(.+?)\}\}/g
}

var models = {}
var searchPaths = [
  'sports/*.js',
  'users/*.js',
  'messages/*.js',
  'boss/*.js',
  'venues/*.js',
  'registration/*.js',
  'officials/*.js',
  'teamcenter/*.js'
]

function hasher(ngin) {
  return ngin && ngin.auth && (ngin.auth.access_token || ngin.auth.auth_key || '')
}

// Find all the individual models
searchPaths.forEach(function(path) {
  var files = glob.sync(path, {cwd:__dirname})
  files.forEach(function(modelPath) {
    var modelName = modelPath.substring(modelPath.indexOf('/')+1).replace('.js','')
    modelName = modelName.charAt(0).toUpperCase() + modelName.substring(1)
    var Model = require('./'+modelPath)
    models[modelName] = _.memoize(Model, hasher)
  })
})

/**
 * Common entry point for all API models
 *
 * @param {Object} config
 * @api public
 */

function ApiClient(config) {
  var self = this
  this.config = _.extend({}, config, {client:this})
  config.headers = _.extend({}, config.headers, { Accept: 'application/json' })

  this.auth = config.auth

  models.sync = require('./sync')
  models.Model = require('./modelbase')
  models.NginModel = require('./nginModel')

  // add each model to the ApiClient
  Object.keys(models).forEach(function(modelName) {
    Object.defineProperty(self, modelName, {
      get: function() { return models[modelName](self) },
      enumerable:true,
      configurable:true
    })
  })
  _.extend(this, models)
}

_.extend(ApiClient.prototype, {

  setAuth: function(auth) {
    this.auth = auth
  }

})


"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var isArray_notArray_1 = require("basic-data-handling/isArray_notArray");
var error_if_not_primitive_or_array_1 = require("error-if-not-primitive-or-array");
var getIndexOfPrimitive_1 = require("./getIndexOfPrimitive");
var getFirstIndexOfArray_1 = require("./getFirstIndexOfArray");
// returns -1 if value being searched for isn't found.
// value cannot be object.
function getFirstIndexOf(value, array) {
    error_if_not_primitive_or_array_1.errorIfNotPrimitiveOrArray(value);
    if (isArray_notArray_1.isArray(value)) {
        return getFirstIndexOfArray_1.getFirstIndexOfArray(value, array);
    }
    else { // if primitive...
        return getIndexOfPrimitive_1.getIndexOfPrimitive(value, array);
    }
}
exports.getFirstIndexOf = getFirstIndexOf;


( function ( ) {

'use strict' ;

var definition = function ( exports , undefined ) {

/* js/src/isinstance.js */

var isinstance = function ( type, obj ) {

	return obj !== null &&
	       obj !== undefined &&
	       obj.constructor.prototype === type.prototype;

};

exports.isinstance = isinstance;

/* js/src/isnull.js */

var isnull = function ( obj ) {

	return obj === null;

};

exports.isnull = isnull;

/* js/src/isundefined.js */

var isundefined = function ( obj ) {

	return obj === undefined;

};

exports.isundefined = isundefined;

/* js/src/number */
/* js/src/number/isfinite.js */

var isfinite = function ( value ) {

	return isnumber( value ) &&
	       ! ispositiveinfinity( value ) &&
	       ! isnegativeinfinity( value ) &&
	       ! isnan( value );

};

exports.isfinite = isfinite;

/* js/src/number/isint.js */

var isint = function ( value ) {

	return isfinite( value ) && (value % 1 === 0);

};

exports.isint = isint;

/* js/src/number/isint32.js */

var isint32 = function ( value ) {

	return isfinite( value ) && value === (value | 0);

};

exports.isint32 = isint32;

/* js/src/number/isnan.js */

var isnan = function ( value ) {
	return isnumber( value ) && isNaN( value );
};

exports.isnan = isnan;

/* js/src/number/isnegativeinfinity.js */

var isnegativeinfinity = function ( value ) {
	return value === -Infinity;
};

exports.isnegativeinfinity = isnegativeinfinity;

/* js/src/number/isnumber.js */

var isnumber = function ( value ) {

	return isinstance( Number, value );

};

exports.isnumber = isnumber;

/* js/src/number/ispositiveinfinity.js */

var ispositiveinfinity = function ( value ) {
	return value === Infinity;
};

exports.ispositiveinfinity = ispositiveinfinity;

/* js/src/object */
/* js/src/object/isarray.js */

var isarray = function ( value ) {

	return isinstance( Array, value );

};

exports.isarray = isarray;

/* js/src/object/isboolean.js */

var isboolean = function ( value ) {

	return isinstance( Boolean, value );

};

exports.isboolean = isboolean;

/* js/src/object/isdate.js */

var isdate = function ( value ) {

	return isinstance( Date, value );

};

exports.isdate = isdate;

/* js/src/object/isfunction.js */

var isfunction = function ( value ) {

	return isinstance( Function, value );

};

exports.isfunction = isfunction;

/* js/src/object/isobject.js */

var isobject = function ( value ) {

	return isinstance( Object, value );

};

exports.isobject = isobject;

/* js/src/object/isregexp.js */

var isregexp = function ( value ) {

	return isinstance( RegExp, value );

};

exports.isregexp = isregexp;

/* js/src/object/isstring.js */

var isstring = function ( value ) {

	return isinstance( String, value );

};

exports.isstring = isstring;

return exports ;
} ;
if ( typeof exports === "object" ) {
	definition( exports ) ;
}
else if ( typeof define === "function" && define.amd ) {
	define( "@aureooms/js-type" , [ ] , function ( ) { return definition( { } ) ; } ) ;
}
else if ( typeof window === "object" && typeof window.document === "object" ) {
	definition( window["type"] = { } ) ;
}
else console.error( "unable to detect type of module to define for @aureooms/js-type") ;
} )( ) ;


const XRegExp = require('xregexp')
const BASIC = '(?<CAPTURE>X((((,\\s+X)+,)?)?\\s+or\\s+X)?)'

function re (particle, options = { }) {
  let [ hasCapture, inter, hasConnector, last ] = BASIC.split('X')

  if (options.connector) {
    hasConnector = hasConnector.replace('or', options.connector)
  }

  particle = (options.use_article) ? `an?\\s+(${particle})` : `(${particle})`

  hasCapture = (options.capture_name)
    ? hasCapture.replace('CAPTURE', options.capture_name)
    : hasCapture.replace('?<CAPTURE>', '')

  return [ hasCapture, inter, hasConnector, last ].join(particle)
} // re

const stringBreaker = /^[^"]*"([^"]*)"/
function breakStringList (list) {
  const pieces = []

  for (let m = list.match(stringBreaker); m !== null; m = list.match(stringBreaker)) {
    const [ consumed, matched ] = m
    pieces.push(matched)
    list = list.substring(consumed.length)
  }

  return pieces
} // breakStringList

function breakRoleList (matcher, list) {
  const pieces = []

  const roleBreaker = XRegExp(`^an?\\s+(${matcher.roleMatcher})(,\\s+)?`)
  for (let m = list.match(roleBreaker); m !== null; m = list.match(roleBreaker)) {
    const [ consumed, matched ] = m
    pieces.push(matched)
    list = list.substring(consumed.length)
  }

  const altFinder = XRegExp(`^\\s*(and|or)\\s+an?\\s+(${matcher.roleMatcher})`)
  const altMatch = list.match(altFinder)
  if (altMatch) {
    pieces.push(altMatch[2])
  } // if ...

  return pieces
}

module.exports = {
  BASIC,
  re,
  breakStringList,
  breakRoleList
}


"use strict"
var Url = require('url')
var _ = require('underscore')

module.exports = function(ngin) {
  var SportsModel = ngin.SportsModel
  var Super = SportsModel.prototype
  var config = ngin.config

  /**
   * Scopes the url to the season
   *
   * @param {Object} options
   * @returns {String}
   * @api public
   */

  function scopeUrl(options, inst) {
    options = _.extend({}, inst, options)
    if (!options.season_id)
      throw new Error('season_id required to make division instance api calls')

    return ngin.Season.urlRoot() + '/' + options.season_id + Division.urlRoot()
  }

  /**
   * Division Class
   *
   * @param {Object} attr
   * @param {Object} options
   * @api public
   */

  var Division = SportsModel.extend({

    fetch: function(options, callback) {
      var url = scopeUrl(options, this) + '/' + this.id
      return Super.fetch.call(this, url, options, callback)
    },

    save: function(options, callback) {
      var url = scopeUrl(options, this) + (this.id ? '/' + this.id : '')
      return Super.save.call(this, url, options, callback)
    },

    destroy: function(options, callback) {
      var url = scopeUrl(options, this) + '/' + this.id
      return Super.destroy.call(this, url, options, callback)
    },

    standings: function(options, callback) {
      if (typeof options == 'function') {
        callback = options
        options = {}
      }

      options = _.extend({division_id: this.id}, options)
      return ngin.Standings.create(options).fetch(options, callback)
    },

    teams: function(options, callback) {
      if (typeof options == 'function') {
        callback = options, options = {}
      }
      options.query = options.query || {}
      options.query.division_id = this.id
      return ngin.TeamInstance.list(options, callback)
    },

    addTeam: function(teamID, callback) {
      var url = ngin.Season.urlRoot() + '/' + this.season_id + Division.urlRoot() + '/' + this.id + '/add_team/' + teamID
      return Division.sync('update', null, { url:url }, this.callbackWithParse(callback))
    },

    removeTeam: function(teamID, callback) {
      var url = ngin.Season.urlRoot() + '/' + this.season_id + Division.urlRoot() + '/' + this.id + '/remove_team/' + teamID
      return Division.sync('delete', null, { url:url }, callback)
    }

  }, {

    urlRoot: function(seasonID) {
      return '/divisions'
    },

    list: function(options, callback) {
      var url = scopeUrl(options, this)
      return SportsModel.list.call(this, url, options, callback)
    }

  })

  return Division

}


/*
  Analyse ast, create scopes
*/

var walker = require('./walker').astWalker();
var utils = require('./utils');
var hasOwnProperty = Object.prototype.hasOwnProperty;

var fnWalker = function(token, scope){
  var type = token.type;
  var name = token.id && token.id.name;
  var args = token.params;

  var newScope = new Scope('function', scope);
  newScope.sourceToken = token;
  token.scope = newScope;

  if (name)
  {
    if (type === 'FunctionDeclaration')
      scope.put(name, {
        type: type,
        token: token,
        loc: token.loc.start
      });
    else
      newScope.put(name, {
        type: type,
        token: token,
        loc: token.loc.start
      });
  }

  // arrow function does not have own 'arguments' reference
  if (type !== 'ArrowFunctionExpression')
    newScope.put('arguments', {
      type: 'arguments',
      token: null,
      args: args
    });

  for (var i = 0; i < args.length; i++)
    newScope.put(args[i].name, {
      type: 'arg',
      token: null,
      loc: args[i].loc.start,
      args: args,
      index: i
    });

  this.scopes.push(newScope);
};

//
// main function
//

function process(ast, scope){
  ast.scope = scope;
  ast.names = [];
  ast.scopes = [];

  var varWalker = function(token, scope){
    scope.declarations.push({
      type: 'var',
      name: token.id.name,
      parent: this.top(1),
      loc: token.loc.start
    });

    scope.put(token.id.name, {
      type: 'var',
      token: token.init,
      loc: token.loc.start
    });
  };

  return walker.walk(ast, {
    VariableDeclarator: varWalker,
    FunctionDeclaration: fnWalker,
    FunctionExpression: fnWalker,
    ArrowFunctionExpression: fnWalker,
    ExpressionStatement: function(token){
      if (token.directive && token.directive.toLowerCase() === 'use strict')
        scope.strict = true;
    },

    CatchClause: function(token, scope){
      var newScope = new Scope('catch', scope);

      scope.put(token.param.name, {
        type: 'catch',
        token: null
      });
      token.body.scope = newScope;

      this.scopes.push(scope);
    },

    Identifier: function(token, scope){
      var parent = this.top(1);

      // let insane begin!
      // todo implement more efficient solution in a future version
      var isLabel = parent.type === 'LabeledStatement' || parent.type === 'ContinueStatement' || parent.type === 'BreakStatement';
      var isFunctionName = parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression';
      var isProperty = parent.type === 'Property';
      var isMemberExpression = parent.type === 'MemberExpression';
      var isAssignmentExpression = parent.type === 'AssignmentExpression';
      var isVariableDeclarator = parent.type === 'VariableDeclarator';

      if (isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator)
      {
        var isObjectKey = isProperty && parent.key === token && parent.computed;
        var isObjectValue = isProperty && parent.value === token;
        var isMemberExpressionProperty = isMemberExpression && parent.property === token && parent.computed;
        var isMemberExpressionObject = isMemberExpression&& parent.object === token;
        var isVariableInit = isVariableDeclarator && parent.init === token;
        var isLeftOfAssignment = isAssignmentExpression && parent.left === token && parent.operator !== '=';
        var isRightOfAssignment = isAssignmentExpression && parent.right === token;
        // is it for..in variable? (mark its name as used)
        var isVarInForIn = false;
        if (isVariableDeclarator)
        {
          var declarationParent = this.top(3);
          isVarInForIn = declarationParent && declarationParent.type === 'ForInStatement';
        }

        if (isFunctionName || isLabel ||
          !isObjectKey && !isObjectValue &&
          !isMemberExpressionProperty && !isMemberExpressionObject &&
          !isLeftOfAssignment && !isRightOfAssignment &&
          !isVariableInit && !isVarInForIn)
          return;
      }

      this.names.push({
        scope: scope,
        token: token
      });
    }
  }, {
    names: ast.names,
    scopes: ast.scopes
  });
}

//
// Scope class
//

function Scope(type, parentScope, thisObject){
  this.type = type || 'unknown';
  this.thisObject = thisObject || utils.createIdentifier('undefined');
  this.subscopes = [];
  this.names = {};
  this.declarations = [];

  if (parentScope)
  {
    this.parent = parentScope;
    this.root = parentScope.root;
    this.strict = parentScope.strict;
    parentScope.subscopes.push(this);
  }
  else
  {
    this.root = this;
  }

  this.put('this', {
    type: 'readonly',
    token: this.thisObject
  });
}

Scope.prototype = {
  root: null,
  parent: null,
  subscopes: null,
  thisObject: null,
  names: null,
  strict: false,

  getOwnNames: function(){
    return Object.keys(this.names);
  },
  scopeByName: function(name){
    var cursor = this;

    while (cursor)
    {
      if (hasOwnProperty.call(cursor.names, name))
        return cursor;

      cursor = cursor.parent;
    }

    return null;
  },
  has: function(name){
    return this.scopeByName(name) != null;
  },
  hasOwn: function(name){
    return hasOwnProperty.call(this.names, name);
  },
  get: function(name){
    var ownerScope = this.scopeByName(name);
    if (ownerScope)
      return ownerScope.names[name];
  },
  getOwn: function(name){
    return this.names[name] || null;
  },
  token: function(name){
    var ref = this.get(name);
    return ref && ref.token;
  },
  put: function(name, info){
    this.names[name] = info;
  },
  set: function(name, token){
    var scope = this.scopeByName(name);
    if (scope)
    {
      var ref = scope.names[name];
      ref.token = token;
    }
  },

  resolve: function(token){
    var path = [];
    var cursor = token;

    if (cursor.obj && cursor.ref_)
      return cursor.ref_;

    cycle:
    while (cursor && !cursor.obj)
    {
      switch (cursor.type)
      {
        case 'ThisExpression':
          // FIXME: it seems a hack, remove cursor.scope - thisObject always must be of current scope
          cursor = (cursor.scope || this).thisObject;
          break cycle;
        case 'Identifier':
          var nameScope = cursor.scope || this.scopeByName(cursor.name);

          if (!nameScope)
            return;

          if (nameScope === this)
          {
            cursor = this.names[cursor.name];
            if (cursor)
              cursor = cursor.token;
          }
          else
            cursor = nameScope.resolve(cursor);

          break cycle;

        case 'MemberExpression':
          var property = cursor.property;

          if (cursor.property.computed)
            property = this.resolve(cursor.property);

          if (!property)
            return;

          if (property.type === 'Literal')
            path.unshift(property.value);
          else
            path.unshift(property.name);

          cursor = cursor.object;

          break;

        case 'Literal':
        case 'FunctionDeclaration':
        case 'FunctionExpression':
        case 'ArrowFunctionExpression':
        case 'ObjectExpression':
        case 'ArrayExpression':
          break cycle;

        case 'CallExpression':
          cursor = cursor.ref_;
          break;

        default:
          return;
      }
    }

    if (cursor && path.length)
    {
      if (cursor.ref_)
        cursor = cursor.ref_;

      if (!cursor.obj)
        return;

      for (var i = 0, key; key = path[i]; i++)
        if (cursor.obj && key in cursor.obj && cursor.obj[key])
        {
          cursor = cursor.obj[key];
          if (cursor.ref_)
            cursor = cursor.ref_;
        }
        else
          return;
    }

    return cursor;
  },

  deepResolve: function(token){
    var prev;
    do
    {
      prev = token;
      token = this.resolve(token);
    }
    while (token && token !== prev);

    return token;
  },
  simpleExpression: function(token){
    switch (token.type)
    {
      case 'BinaryExpression':
        if (token.operator === '+')
        {
          var left = this.simpleExpression(token.left);
          var right = this.simpleExpression(token.right);

          if (left.type === 'Literal' && right.type === 'Literal')
            return utils.createLiteral(left.value + right.value);
        }
        break;

      case 'ArrayExpression':
        return { type: 'ArrayExpression', elements: token.elements.map(this.simpleExpression, this) };

      default:
        return this.deepResolve(token);
    }
  },

  isLocal: function(name){
    return hasOwnProperty.call(this.names, name);
  },
  isGlobal: function(name){
    var scope = this.scopeByName(name);
    return scope ? scope.root === scope : true;
  }
};

//
// export
//

module.exports = {
  Scope: Scope,
  process: process
};


/*!
 * Module dependencies
 */
var util = require('util')
  , Resource = require('./')
  , updateMixin = require('../mixins/update')
  ;

/*!
 * Expose `Customer()`.
 */
exports = module.exports = Customer;

/**
 * Initialize a new `Customer` with the given `parent` and `definition`.
 *
 * @param {Function} parent The parent this resource is attached to.
 * @param {Object} definition The resource definition.
 * @api private
 */
function Customer(parent, definition) {
  var key;
  for (key in updateMixin) {
    this[key] = updateMixin[key];
  }
  Customer.super_.apply(this, arguments);
}
util.inherits(Customer, Resource);

Customer.create = require('../mixins/create');
Customer.search = require('../mixins/search');


"use strict";
const util_1 = require("util");
const lodash_1 = require("lodash");
const DEFAULTS = {
    default: '',
    colorize: false,
    hidden: null,
    depth: null,
    exp: /{{([\s\S]+?)}}/g,
    strip: /[{}]+/g,
    split: '|',
    transform: undefined,
    transforms: {
        capitalize: lodash_1.capitalize,
        lowercase: lodash_1.lowerCase,
        uppercase: lodash_1.upperCase,
        camelcase: lodash_1.camelCase,
        titlecase: (str) => lodash_1.startCase(str.toLowerCase())
    }
};
// This does a shallow copy of objects.
// This is needed for objects such as Errors
// Otherwise some properties may not be available.
function copy(obj) {
    return Object.getOwnPropertyNames(obj || {}).reduce((a, c) => {
        a[c] = obj[c];
        return a;
    }, {});
}
function formatr() {
    let _options = Object.assign({}, DEFAULTS);
    function _formatter(options, message, ...args) {
        options = options || _options;
        // OBJECT PASSED USE INSPECT //
        if (typeof message !== 'string')
            return util_1.inspect(message, options.hidden, options.depth, options.colorize);
        // STRING HAS FORMAT TOKENS //
        if (/(%s|%d|%j|%%)/g.test(message)) {
            args = args.map(v => {
                if (typeof v === 'object')
                    return util_1.inspect(v, options.hidden, options.depth, options.colorize);
                return v;
            });
            return util_1.format(message, ...args);
        }
        // USE TEMPLATE FORMATTING //
        // Nothing to format.
        if (!options.exp.test(message) || typeof args[0] !== 'object')
            return message;
        const config = args.reduce((a, c) => {
            return Object.assign({}, a, copy(c));
        }, {});
        return message.replace(options.exp, (key) => {
            // Remove templating expressions.
            key = key.replace(options.strip, '');
            // split the key in to transform parts.
            const trans = key.trim().split(options.split);
            // First is the key.
            key = trans.shift();
            // Get the value from object
            let val = lodash_1.get(config, key);
            // If the value is an object run through inspect.
            if (typeof val === 'object')
                val = util_1.inspect(val, options.hidden, options.depth, options.colorize);
            if (typeof val === 'undefined')
                val = options.default;
            // Check for value transforms.
            trans.forEach(k => {
                if (options.transforms[k])
                    val = options.transforms[k](val, key, config);
            });
            if (options.transform)
                return options.transform(val, key, config);
            return val;
        });
    }
    function setOption(key, val) {
        // If object extend options.
        if (typeof key === 'object')
            _options = Object.assign({}, DEFAULTS, key);
        else
            lodash_1.set(_options, key, val);
        return _options;
    }
    /**
     * Format a message using string formatting, custom formatting or inspect for objects.
     *
     * @param message a string or object to be formatted.
     * @param args arguments used for formatting above message.
     */
    function fmt(message, ...args) {
        return _formatter(null, message, ...args);
    }
    /**
     * Formats a message using the specified options.
     *
     * @param options pass options for this instance of formatting.
     */
    function formatWith(options) {
        options = Object.assign({}, DEFAULTS, options);
        return (message, ...args) => {
            return _formatter(options, message, ...args);
        };
    }
    return {
        setOption,
        format: fmt,
        formatWith
    };
}
const instance = formatr();
module.exports = instance;
//# sourceMappingURL=index.js.map


/**
 * Created by alykoshin on 10.12.15.
 */

var noop = function () {};
var methods = [
  'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
  'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
  'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
  'timeStamp', 'trace', 'warn'
];

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  * Prevents errors on console methods when no console present.
//  * Exposes a global 'debug' function that preserves line numbering and formatting.
var _debug = function (obj) {
  var that = {};

  that.obj = obj;

  var method;
  var con;
  if ( typeof window !== 'undefined') {
    window.console = window.console || {};
    con = window.console;
  } else {
    con = console || {};
  }

  if (!con['debug']) { con.debug = con.log; } // IE does not support debug.

  var length = methods.length;
  while (length--) {
    method = methods[length];

    // Only stub undefined methods.
    if ( ! con[method] ) { // .hasOwnProperty(method) ) { // !con[method] ) {
      con[method] = noop; // Disable for con
      that[method]    = noop; // and for this object too
    } else {
      if (Function.prototype.bind) {
        that[method] = Function.prototype.bind.call(con[method], con, '%s'); // '%s' does not works for group
      } else {
        that[method] = Function.prototype.apply.call(con[method], con, 'xyz',arguments);
      }
    }
  }
  //if(that.obj) {
  //  con.log('>>>>>>>>>>>>', that.obj.debugId, that.obj);
  // }
  //  if (!con.debug) { // IE does not support con.debug
  //    that.debug = Function.prototype.bind.call(con.log,   con, pref + ' **** debug:   %s');;
  //  } else {
  //    that.debug = Function.prototype.bind.call(con.debug, con, pref + ' **** debug: %s');
  //  }

  /** Rewrite specific methods **/
  if (Function.prototype.bind) {
    // con.log('_debug(): if (Function.prototype.bind) ');
    var pref = '[' + ( (that.obj && that.obj.debugId) ? that.obj.debugId : 'null') +']';

    that.error = Function.prototype.bind.call(con.error, con, pref + ' * error: %s');
    that.warn  = Function.prototype.bind.call(con.warn , con, pref + ' ** warn:  %s');
    that.info  = Function.prototype.bind.call(con.info,  con, pref + ' *** info:  %s');
    if (!con.debug) { // IE does not support con.debug
      that.debug = Function.prototype.bind.call(con.log,   con);//pref + ' **** debug:   %s');;
    } else {
      that.debug = Function.prototype.bind.call(con.debug, con);//pref + ' **** debug: %s');
    }
    that.log   = Function.prototype.bind.call(con.log,   con, pref + ' ***** log:   %s');
    //    that.group = Function.prototype.bind.call(con.group, con, '%s');
    that.group = Function.prototype.bind.call(con.log, con, pref + ' GROUP:   %s');
    //    that.groupCollapsed = Function.prototype.bind.call(con.groupCollapsed, con, '%s');
    that.groupCollapsed = Function.prototype.bind.call(con.log, con, pref + ' GROUP: %s');
    //    if (!that.assert) { that.assert = Function.prototype.bind.call(con.error, con, '* assert: %s'); }
    //  } else {
    //    that.error = function() { Function.prototype.apply.call(con.error, con, arguments); };
    //    that.warn  = function() { Function.prototype.apply.call(con.warn , con, arguments); };
    //    that.info  = function() { Function.prototype.apply.call(con.info,  con, arguments); };
    //    that.debug = function() { Function.prototype.apply.call(con.debug, con, arguments); };
    //    that.log   = function() { Function.prototype.apply.call(con.log,   con, arguments); };
  }

  return that;
};
function _no_debug() {
  var that = {};

  var length = methods.length;
  while (length--) {
    var method = methods[length];
    that[method] = noop;
  }
  return that;
}
//var debug = _no_debug();
var debugObj = _debug();
//var debug = console;

var assert     = function(condition, message) {
  if (!condition) {
    throw message ? 'Assertion failed: \'' + message +'\'': 'Assertion failed.';
  }
};
//var assert = debug.assert;

//assert(false, 'test-message');

//window.console = null;

////////////////////////////////////////////////////////////////////////////////

if (typeof module !== 'undefined') {
  var exports = debugObj;
  //exports.debug = debugObj;
  exports.assert = assert;

  module.exports = exports;
}

if (typeof window !== 'undefined') {
  window.debug = debugObj;
  window.assert  = assert;
}


'use strict';

const fs = require('fs');
const Bzip2 = require('compressjs').Bzip2;
const AdmZip = require('adm-zip');
const archiver = require('archiver');
const rimraf = require('rimraf');
const path = require('path');
const tar = require('tar-fs');

module.exports = {
    /**
     * Zips up a directory.
     *
     * @param sourceDir {string} the directory to be zipped
     * @param destFile {string} the output file
     * @param opts {{}}
     * @returns {Promise.<string>} path to the archive
     */
    zip: function(sourceDir, destFile, opts) {
        opts = opts || { archive_path: '/' };
        return new Promise(function (resolve, reject) {
            try {
                var archive = archiver.create('zip', {
                    zlib: {
                        level: 9
                    }
                });
                var output = fs.createWriteStream(destFile);
                output.on('finish', function () {
                    resolve(destFile);
                });
                archive.pipe(output);
                archive.directory(sourceDir, opts.archive_path);
                archive.finalize();
            } catch(err) {
                reject(err);
            }
        });
    },

    /**
     * Extracts a zip to a directory.
     * This will fail if the destination already exists.
     *
     * @param sourceFile {string}
     * @param destDir {string}
     * @returns {Promise.<string>} path to the destination
     */
    unzip: function(sourceFile, destDir) {
        return new Promise(function(resolve, reject) {
            var zip = new AdmZip(sourceFile);
            try {
                zip.extractAllTo(destDir);
                resolve(destDir);
            } catch(err) {
                reject(err);
            }
        });
    },

    /**
     * Create a Bzip2 compressed tar of a directory.
     *
     * @param sourceDir {string} the directory to be compressed
     * @param destFile {string} the output file
     * @param opts {{}}
     * @returns {Promise.<string>} path to the archive
     */
    tar: function(sourceDir, destFile, opts) {
        opts = opts || { archive_path: '/' };
        return new Promise(function(resolve, reject) {
            // pack
            var tempFile = destFile + '.tmp.tar';
            try {
                var archive = archiver.create('tar');
                var output = fs.createWriteStream(tempFile);
                output.on('finish', function () {
                    resolve(tempFile);
                });
                archive.pipe(output);
                archive.directory(sourceDir, opts.archive_path);
                archive.finalize();
            } catch (err) {
                reject(err);
            }
        })
        .then(function(tempFile) {
            // compress
            try {
                var data = new Buffer(fs.readFileSync(tempFile), 'utf8');
                var compressed = new Buffer(Bzip2.compressFile(data));
                fs.writeFileSync(destFile, compressed);
                return destFile;
            } catch(err) {
                throw err;
            } finally {
                rimraf.sync(tempFile);
            }
        });
    },

    /**
     * Extracts a tar to a directory.
     *
     * @param sourceFile {string}
     * @param destDir {string}
     * @returns {Promise.<string>} path to the destination
     */
    untar: function(sourceFile, destDir) {
        return new Promise(function(resolve, reject) {
            // expand
            var tempFile = sourceFile + '.tmp.tar';
            try {
                var data = new Buffer(fs.readFileSync(sourceFile));
                var expanded = Bzip2.decompressFile(data);
                fs.writeFileSync(tempFile, new Buffer(expanded));
                resolve(tempFile);
            } catch(err) {
                reject(err);
            }
        }).then(function(tempFile) {
            // un-pack
            return new Promise(function(resolve, reject) {
                try {
                    var rs = fs.createReadStream(tempFile);
                    rs.pipe(tar.extract(destDir).on('finish', function() {
                        rimraf.sync(tempFile);
                        resolve(destDir);
                    }));
                } catch (err) {
                    rimraf.sync(tempFile);
                    reject(err);
                }
            });
        });
    },

    /**
     * Reads a path within a tar archive.
     *
     * @param sourceFile {string} the path to the tar file
     * @param path {string} the path inside the tar file to read
     * @returns {Promise.<ReadStream>} the contents of the path in the tar file
     */
    readtar: function(sourceFile, path) {
        return new Promise(function(resolve, reject) {
            reject('not implemented');
        });
    }
};


var _isNumber = require('./isNumber');
var _isObject = require('./isObject');
var REGEX_ENUM = require('./internal/enum/regexEnum');

/**
 * 校验参数 `val` 是否为负数
 *
 * 该接口存在两种模式, 即严格模式、非严格模式;
 *
 * 默认采用 `非严格模式`
 *
 * 若参数 `val` 为 number 类型, 并且是负数 则返回 true, 否则返回 false
 * 若参数 `val` 为 string 类型, 并且通过验证为负数字符串, 则返回 true, 否则返回 false
 * 若参数 `val` 不属于以上两种类型, 则直接返回 false
 *
 * 若参数 `val` 的值为空字符串（''、'   '）, 则直接返回 false
 *
 * 若是参数 `options` 指定了严格模式, 即 options.isStrict = true, 则对于 string 类型直接返回 false
 *
 * e.g.
 *
 * 待校验参数 '-3'
 *  > 若是严格模式, 则该参数值校验后, 返回 false
 *  > 若是非严格模式, 则该参数值校验后, 返回 true
 *
 * @param   {*}       val              待校验的参数
 * @param   {Object}  options          可选参数
 * @param   {Boolean} options.isStrict 是否严格模式
 * @return  {Boolean} 返回校验结果
 * @version 0.0.7
 * @since   0.0.4
 */
function _isNegativeNumber(val, options) {
  var opts = _isObject(options) ? options : {};

  if (opts.isStrict === true) {
    return _isNumber(val) && REGEX_ENUM.NEGATIVE_NUMBER_REX.test(val);
  }

  return REGEX_ENUM.NEGATIVE_NUMBER_REX.test(val);
}

module.exports = _isNegativeNumber;


const { mkdir } = require('fs');
let makePromise = require('makepromise'); if (makePromise && makePromise.__esModule) makePromise = makePromise.default;
const { dirname } = require('path');

/**
 * Makes sure that a file can be created by creating all directories to which it belongs, e.g., `ensurePath('~/path/to/wrote.data')` will attempt to create `~/path/to` directory recursively.
 * @param {string} path Path to the file
 * @throws {Error} When the first folder in the path is non-executable
 */
               async function ensurePath(path) {
  const dir = dirname(path)
  try {
    await make(dir)
    return path
  } catch (err) {
    if (/EEXIST/.test(err.message) && err.message.indexOf(dir) != -1) {
      return path
    }
    throw err
  }
}

/**
 * Recursive promise-based mkdir.
 * @param {string} dir Path to the directory to be created
 */
async function make(dir) {
  try {
    await makePromise(mkdir, dir)
  } catch (err) {
    if (err.code == 'ENOENT') {
      const parentDir = dirname(dir)
      await make(parentDir)
      await make(dir)
    } else if (err.code != 'EEXIST') { // created in parallel
      throw err
    }
  }
}

module.exports = ensurePath


'use strict';

var path = require('path')
  , fs = require('fs');

/**
 * Expose small fabrication helper.
 *
 * Possible options:
 *
 *  - source:    {String}   Absolute path to be used to resolve file paths.
 *  - recursive: {Boolean}  Should file paths be recursively discovered.
 *  - name:      {String}   Force a name for a given constructor.
 *
 * @param {Mixed} stack String, array or object that contains constructible entities
 * @param {Object} options Optional options.
 * @returns {Array} collection of constructors.
 * @api public
 */
function fabricator(stack, options) {
  options = options || {};

  //
  // Empty strings, arrays or objects should not be processed, return early.
  //
  if (empty(stack)) return [];

  switch (is(stack)) {
    case 'string':
      stack = read(stack, options);
    break;

    case 'object':
      stack = Object.keys(stack).reduce(iterator(read, stack, options), []);
    break;

    case 'array':
      stack = stack.reduce(iterator(read, null, options), []);
    break;

    default:
      if ('function' !== typeof stack) {
        throw new Error('Unsupported type, cannot fabricate an: '+ is(stack));
      }

      stack = [init(stack, undefined, options)];
  }

  return (stack || []).filter(Boolean);
}

/**
 * Read directory and initialize JavaScript files.
 *
 * @param {String} filepath Full directory path.
 * @param {Object} options Additional configuration.
 * @return {Array} collection of constructor
 * @api private
 */
function read(filepath, options) {
  if ('string' !== is(filepath)) return fabricator(filepath, options);
  if (options.source) filepath = path.resolve(options.source, filepath);

  //
  // Check if the provided string is a JS file or when recursion is not allowed.
  //
  if (js(filepath) || options.recursive === false) return [
    init(filepath, path.basename(filepath, '.js'), options)
  ];

  //
  // Read the directory, only process files.
  //
  if (!fs.existsSync(filepath)) return false;
  return fs.readdirSync(filepath).map(function locate(file) {
    file = path.resolve(filepath, file);

    var stat = fs.statSync(file);

    if (stat.isDirectory() && fs.existsSync(path.join(file, 'index.js'))) {
      //
      // Use the directory name instead of `index` for name as it probably has
      // more meaning then just `index` as a name.
      //
      return init(path.join(file, 'index.js'), path.basename(file, '.js'), options);
    }

    //
    // Only allow JS files, init determines if it is a constructible instance.
    //
    if (!stat.isFile() || !js(file)) return;

    return init(file, path.basename(file, '.js'), options);
  });
}

/**
 * Return iterator for array or object.
 *
 * @param {Function} traverse Recursive iterator, called on directories.
 * @param {Object} obj Original object, if set values are fetched by entity.
 * @param {Object} options Configuration.
 * @return {Function} iterator
 * @api private
 */
function iterator(traverse, obj, options) {
  return function reduce(stack, entity) {
    var base = obj ? obj[entity] : entity
      , name = options.name || entity;

    //
    // Fabricated objects should provide each constructor with the name
    // of its property on the original object.
    //
    if (obj) options.name = entity;

    //
    // Run the functions, traverse will handle init.
    //
    if (js(base)) {
      return stack.concat(init(
        base,
        'string' === is(name) ? name : '',
        options
      ));
    }

    //
    // When we've been supplied with an array as base assume we want to keep it
    // as array and do not want it to be merged.
    //
    if (Array.isArray(base)) {
      options.name = name; // Force the name of the entry for all items in array.
      stack.push(traverse(base, options));

      return stack;
    }

    return stack.concat(traverse(base, options));
  };
}

/**
 * Make sure only valid JavaScript files are used as source. Ignore other files,
 * like .log files. Also allow constructors.
 *
 * @param {String|Function} file Path or constructor function.
 * @returns {Boolean} allow entity to be used or not.
 * @api private
 */
function js(file) {
  var type = is(file);

  return 'function' === type
  || 'string' === type && path.extname(file) === '.js';
}

/**
 * A better alternative to `typeof` checks by trying to figure out the root
 * class of things. This eliminates the needs for Array.is checks when the type
 * is an object etc.
 *
 * @param {Mixed} obj Unknown thing we need to know.
 * @returns {String}
 * @api private
 */
function is(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

/**
 * Simple check to see if the provided stack is empty or falsy.
 *
 * @param {Mixed} value Entity to check
 * @return {Boolean} result of check
 * @api private
 */
function empty(value) {
  if (!value) return true;
  switch (is(value)) {
    case "object": return !Object.keys(value).length;
    case "array": return !value.length;
    default: return !value;
  }
}

/**
 * It's not required to supply resolve with instances, we can just
 * automatically require them if they are using the:
 *
 *   module.exports = function Constructor() {};
 *
 * @param {String} constructor
 * @param {String} name Optional identifier for the constructor.
 * @returns {Object} initialized object
 * @api private
 */
function init(constructor, name, options) {
  constructor = ('string' === is(constructor)) ? require(constructor) : constructor;

  //
  // We really want to have a function/class here. Make sure that we can
  // construct it using `new constructor`
  //
  if (!constructor.prototype) return;

  name = constructor.prototype.name || name || constructor.name;
  if (options.name) name = options.name;

  //
  // Sets the name on the prototype to a string.
  //
  if ('name' in constructor.prototype) {
    constructor.prototype.name = name.toString();
  }

  return constructor;
}

//
// Expose the module.
//
module.exports = fabricator;


prettyPrint();

// line number anchors
(function() {
	var hash = document.location.hash.substring(1),
		code = hash && document.getElementsByClassName('prettyprint source linenums'),
		lines, i;
	if (code && code[0]) {
		lines = code[0].getElementsByTagName('li');
		for (i=lines.length; i--; ) {
			lines[i].id = 'line' + i;
			if (lines[i].id===hash) {
				lines[i].className += ' selected';
			}
		}
	}
})();

// menu updates
(function() {
	function updateNav() {
		var url = location.href,
			links = document.querySelectorAll('nav li a'),
			i;
		for (i=links.length; i--; ) {
			if (links[i].href===url) {
				links[i].className = 'current';
			}
			else if (links[i].href===url.replace(/#.*/g,'')) {
				links[i].className = 'parent';
			}
			else {
				links[i].className = '';
			}
		}
		//links = document.querySelectorAll('.navinner');
		//for (i=links.length; i--; ) {
		//	links[i].style.display = (links[i].previousSibling.querySelector('.current') || links[i].querySelector('.current')) ? 'block' : 'none';
		//}
	}

	updateNav();

	addEventListener('popstate', updateNav);
	addEventListener('hashchange', updateNav);

	// menu link is a toggle, sidebar links are close-only
	function click(e) {
		var op = 'remove';
		if (this.className==='menuLink') {
			op = document.body.classList.contains('menu-open') ? 'remove' : 'add';
			e.preventDefault();
		}
		document.body.classList[op]('menu-open');
	}
	[].forEach.call(document.querySelectorAll('nav a, .menuLink'), function(v) {
		v.addEventListener('click', click);
	});
})();


/*
 * Copyright 2012 Karl Düüna <karl.dyyna@gmail.com> All rights reserved.
 */
'use strict';

var streams = ['stdin','stdout','stderr'];
var pipeStream = require('./pipeStream');

module.exports = ShellStream;

/**
 * Main function for creating a shellstream
 *
 * @param {Array} args -> arguments to apply to PipeStream
 *
 * @returns {ShellStream}
 */
function ShellStream(args){
    if(this instanceof ShellStream === false){
        return new ShellStream(args);
    }

    this._command = args;
    this._events = [];
    var self = this;
    // Create holders for events to be added
    streams.forEach(function(stream){
        self[stream] = {on:this.on, _events:[]};
    });
}
/**
 * Mock the event adding procedure
 *
 * @param {String} event -> name of the event
 * @param {Function} func -> function to call
 * @returns {undefined}
 */
ShellStream.prototype.on = function(event, func){
    this._events.push({'e':event, 'f':func});
};

/**
 * Function for creating a PipeStream from the ShellStream object
 *
 * @returns {PipeStream}
 */
ShellStream.prototype.run = function(){
    var self = this;
    // Create PipeStream
    var newSpawn = pipeStream.createPipeStream.apply({}, self._command);

    // Add cached events
    self._events.forEach(function(ev){
        newSpawn.on(ev.e, ev.f);
    });

    streams.forEach(function(stream){
        self[stream]._events.forEach(function(ev){
            newSpawn[stream].on(ev.e, ev.f);
        });
    });
    return newSpawn;
};


/**
 * Utilities from conslidate.js
 *
 */

'use strict';

/**
 * Module dependencies.
 */

var fs = require('fs');
var path = require('path');

/**
 * Requires cache.
 */

exports.requires = {};

/**
 * File/string caches
 */

var cacheStore = {};
var readCache = {};

/**
 * Clear the cache.
 *
 * @api public
 */

exports.clearCache = function () {
  cacheStore = {};
};

/**
 * Conditionally cache `compiled` template based
 * on the `options` filename and `.cache` boolean.
 *
 * @param {Object} options
 * @param {Function} compiled
 * @return {Function}
 * @api private
 */

exports.cache = function cache(options, compiled) {
  // cachable
  if (compiled && options.filename && options.cache) {
    delete readCache[options.filename];
    cacheStore[options.filename] = compiled;
    return compiled;
  }

  // check cache
  if (options.filename && options.cache) {
    return cacheStore[options.filename];
  }
  return compiled;
};

/**
 * Read `path` with `options` with
 * callback `(err, str)`. When `options.cache`
 * is true the template string will be cached.
 *
 * @param {String} options
 * @param {Function} callback
 * @api private
 */

function read(path, options, callback) {
  var str = readCache[path];
  var cached = options.cache && str && ('string' === typeof str);

  // cached (only if cached is a string and not a compiled template function)
  if (cached) {
    return callback(null, str);
  }

  // read
  fs.readFile(path, 'utf8', function (err, str) {
    if (err) {
      return callback(err);
    }
    // remove extraneous utf8 BOM marker
    str = str.replace(/^\uFEFF/, '');
    if (options.cache) {readCache[path] = str;}
    callback(null, str);
  });
}

/**
 * Read `path` with `options` with
 * callback `(err, str)`. When `options.cache`
 * is true the partial string will be cached.
 *
 * @param {String} options
 * @param {Function} callback
 * @api private
 */

exports.readPartials = function(filepath, options, callback) {
  if (!options.partials) {
    return callback();
  }
  var partials = options.partials;
  var keys = Object.keys(partials);

  function next(index) {
    if (index === keys.length) {
      return callback(null);
    }
    var key = keys[index];
    var file = path.join(path.dirname(filepath), partials[key] + path.extname(filepath));
    read(file, options, function (err, str) {
      if (err) {
        return callback(err);
      }
      options.partials[key] = str;
      next(++index);
    });
  }
  next(0);
};

/**
 * fromStringRenderer
 */

exports.fromStringRenderer = function (name) {
  return function (path, options, callback) {
    options.filename = path;
    exports.readPartials(path, options, function (err) {
      if (err) {
        return callback(err);
      }
      if (exports.cache(options)) {
        exports[name].render('', options, callback);
      } else {
        read(path, options, function (err, str) {
          if (err) {
            return callback(err);
          }
          exports[name].render(str, options, callback);
        });
      }
    });
  };
};


/**
 * gulp-jbb-profile - Javascript Binary Bundles - Profile Compiler
 * Copyright (C) 2015 Ioannis Charalampidis <ioannis.charalampidis@cern.ch>
 *
 * 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.
 *
 * @author Ioannis Charalampidis / https://github.com/wavesoft
 */

var crypto = require('crypto');

/**
 * A representation of an object in the profile
 */
var ProfileObject = function(name, specs) {
	this.name = name;
	this.id = 0;
	this.properties = specs.properties || [];
	this.extends = specs.extends || null;
	this.depends = specs.depends || null;
	this.factory = specs.factory || "new";
	this.init = specs.init || "default";
	this.frequent = false;
	this.keepUsedProperties = false;
	this.initProperties = true;
	this.initConstructorArgs = [];
	this.propCustomAssign = {};
	this.propAssign = "";
	this.propCustomGet = {};
	this.propGet = "";
	this.postInit = specs.postInit || "";
	this.embed = specs.embed || [];
	if (this.postInit) this.postInit += "\n";

	// Calculate a safe name
	this.safeName = name.replace(/[,\.\- \_]/g, '_');

	// Change init to 'constructor' if init is array
	if (this.init instanceof Array) {
		this.initConstructorArgs = this.init;
		this.init = "constructor";
		this.factory = "create"
	} else if (this.init instanceof {}.constructor) {
		this.propCustomAssign = this.init;
		this.init = "default";

		// Extract default
		if (this.propCustomAssign['default']) {
			this.propAssign = this.propCustomAssign['default'];
			delete this.propCustomAssign['default'];
		}

	} else if (this.init !== "default") {
		// Custom user init function
		if (this.factory === "new")
			this.factory = "create";
	}

	// Check if we have custom property getters
	if (specs.getter) {
		if (typeof specs == 'object') {
			this.propCustomGet = specs.getter;

			// Extract default
			if (this.propCustomGet['default']) {
				this.propGet = this.propCustomGet['default'];
				delete this.propCustomGet['default'];
			}

		} else {
			this.propGet = specs.getter;
		}
	}

	// Initialize boolean fields
	if (specs.frequent !== undefined) {
		this.frequent = (["yes","true","1"].indexOf(specs.frequent.toString().toLowerCase()) >= 0);
	}
	if (specs.initProperties !== undefined) {
		this.initProperties = (["yes","true","1"].indexOf(specs.initProperties.toString().toLowerCase()) >= 0);
	}
	if (specs.keepUsedProperties !== undefined) {
		this.keepUsedProperties = (["yes","true","1"].indexOf(specs.keepUsedProperties.toString().toLowerCase()) >= 0);
	}

}

ProfileObject.prototype = {

	/**
	 * Extend our properties based on specified object
	 */
	'applyExtend': function( o ) {
		// Don't extend 'depends', extend only 'extends'
		if (this.extends) {
			this.embed = o.embed.concat(this.embed);
			this.properties = o.properties.concat(this.properties);
			this.postInit = o.postInit + this.postInit;

			// Replace init & Factory if different
			if (this.init === "default") this.init = o.init;
			if (this.factory === "new") this.factory = o.factory;

			// Replace default property assigned if not defined
			if (!this.propAssign) this.propAssign = o.propAssign;

			// Implement undefined extended property assigners
			for (var k in o.propCustomAssign) {
				if (!this.propCustomAssign[k]) {
					this.propCustomAssign[k] = o.propCustomAssign[k];
				}
			}
		}
	},

	/**
	 * Generate the piece of code that fabricates (but not initializes)
	 * the object
	 */
	'generateFactory': function() {
		if (this.factory === 'new') {
			return 'new '+this.name+'()';
		} else if (this.factory === 'create') {
			return 'Object.create('+this.name+'.prototype)';
		} else {
			// Use custom user factory
			console.warn("Using custom factory for "+this.name);
			return this.factory + '('+this.name+')';
		}
	},

	/**
	 * Generate the property getter
	 */
	'generatePropertyGetter': function( instVar, prefix ) {
		var code = "[", getCode = "", prop="", defaultGet = "$inst.$prop";
		if (this.defaultGet) defaultGet = defaultGet;
		for (var i=0, l=this.properties.length; i<l; ++i) {
			prop = this.properties[i];
			if (i > 0) code += ",";
			if (this.propCustomGet[prop]) {
				getCode = this.propCustomGet[prop]
					.replace(/\$inst/g, instVar)
					.replace(/\$prop/g, prop);
			} else {
				getCode = defaultGet
					.replace(/\$inst/g, instVar)
					.replace(/\$prop/g, prop);
			}

			// Check if we should embed this property
			if (this.embed.indexOf(prop) === -1) {
				code += "\n" + prefix + getCode;
			} else {
				code += "\n" + prefix + "new BinaryEncoder.FileResource( " + getCode + " )";
			}

		}
		code += "]";
		return code;
	},

	/**
	 * Generate the name of the property initialization function.
	 * This is used to de-duplicate init functions for the same properties
	 */
	'getPropertyInitializerName': function() {
		var props = this.properties.slice().sort();
		return 'init' + crypto.createHash('md5').update(props.join(",")).digest("hex");
	},

	/**
	 * Generate the piece of code that initializes an instance of the object
	 */
	'generateInitializer': function( instVar, valVar, pageszVar, offsetVar, prefix, indent ) {
		var code = "", usedProps = {}, defaultAssign = "$inst.$prop = $value",
			replaceVariableMacro = (function(s,v) {
				var i = this.properties.indexOf(v);
				if (i >= 0) {
					usedProps[v] = true;
				} else {
					throw "Macro "+s+" refers to a property not part of property table!";
				}
			}).bind(this);

		//
		// [default] - Default empty constructor
		//
		if (this.init == "default") {

		//
		// [constructor] - Call constructor
		//
		} else if (this.init == 'constructor') {
			code += prefix + this.name+".call("+instVar;
			for (var i=0, l=this.initConstructorArgs.length; i<l; i++) {
				var arg = this.initConstructorArgs[i],
					partIdx = arg.search(/[\.\[]/),
					part = "", found = false;

				// Try to translate constructor arguments to components of the value
				// array when possivle
				if (partIdx == -1) partIdx = arg.length;
				part = arg.substr(0,partIdx);
				for (var j=0, jl=this.properties.length; j<jl; ++j) {
					if (this.properties[j] == part) {
						arg = valVar + "["+offsetVar+'+'+pageszVar+'*'+j+"]" + arg.substr(partIdx);
						usedProps[part] = true;
						found = true;
						break;
					}
				}

				// Warn user if not found
				if (!found) {
					console.warn("Could not find property '"+arg+"' in "+this.name+". Assuming literal");
				}

				// Update constructor call
				code += ",\n"+prefix+indent+arg;
			}
			code += ");\n";

		//
		// [other] - Custom user function
		//
		} else {
			console.warn("Using custom init function for "+this.name);
			code += prefix + this.init + "(" + instVar +", " + valVar + ");\n";

		}

		// Replace variable macros in the property assigners & track handled properties
		for (var k in this.propCustomAssign) {
			this.propCustomAssign[k] = this.propCustomAssign[k]
				.replace(/\$\$(\w+)/g, replaceVariableMacro);
		}

		// Get default assign function
		if (this.propAssign) defaultAssign = this.propAssign;
		defaultAssign = defaultAssign
			.replace(/\$\$(\w+)/g, replaceVariableMacro);

		// Call property initializer (might be shared with other instances)
		if (this.initProperties) {
			for (var i=0, l=this.properties.length; i<l; ++i) {
				var prop = this.properties[i];
				// Skip properties used in the constructor
				if (usedProps[prop] && !this.keepUsedProperties) continue;
				if (this.propCustomAssign[prop]) {
					code += prefix + this.propCustomAssign[prop]
						.replace(/\$inst/g, instVar)
						.replace(/\$prop/g, prop)
						.replace(/\$values/g, valVar)
						.replace(/\$value/g, valVar+"["+offsetVar+'+'+pageszVar+'*'+i+"]") + ";\n";
				} else {
					code += prefix + defaultAssign
						.replace(/\$inst/g, instVar)
						.replace(/\$prop/g, prop)
						.replace(/\$values/g, valVar)
						.replace(/\$value/g, valVar+"["+offsetVar+'+'+pageszVar+'*'+i+"]") + ";\n";
				}
			}
		}

		// Call post-init
		if (this.postInit) {
			code += "\n" + prefix + "// Custom init function\n";
			code += prefix + this.postInit.replace(/\n/g, "\n"+prefix)
					.replace(/\$inst/g, instVar)
					.replace(/\$values/g, valVar)
					.replace(/\$\$(\w+)/g, replaceVariableMacro);
		}

		return code;
	},

};

module.exports = ProfileObject;


/**
 * gulp-jbb-profile - Javascript Binary Bundles - Profile Compiler
 * Copyright (C) 2015 Ioannis Charalampidis <ioannis.charalampidis@cern.ch>
 *
 * 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.
 *
 * @author Ioannis Charalampidis / https://github.com/wavesoft
 */

var through2 		= require('through2');
var gutil 			= require('gulp-util');
var fs   			= require('fs');
var path 			= require('path');
var toArray  		= require('stream-to-array');
var Readable 		= require('stream').Readable;
var PluginError 	= gutil.PluginError;
var ProfileCompiler	= require('./lib/ProfileCompiler.js');

const PLUGIN_NAME 	= 'gulp-jbb-profile';

/**
 * Read entire buffer and compile
 */
function bufferMode( contents, options, callback ) {
	ProfileCompiler( contents.toString('utf-8'), options, function(err, encBuf, decBuf){
		if (err) {
			callback(err);
			return;
		}

		// Callback buffers
		callback(null, new Buffer(encBuf,'utf8'),
					   new Buffer(decBuf,'utf8') );
	});
}

/**
 * Read entire stream and process
 */
function streamMode( contents, options, callback ) {
	toArray(contents, function(err, chunks) {
		if (err) {
			callback(err);
			return;
		}
		bufferMode( Buffer.concat(chunks), options, function(err, encBuf, decBuf) {
			if (err) {
				callback(err);
				return;
			}

			var encStream = new Readable();
			encStream.push(encBuf);
			encStream.push(null);

			var decStream = new Readable();
			decStream.push(decBuf);
			decStream.push(null);

			// Callback streams
			callback(null, encStream, decStream);
		});
	});
}

/**
 * Interface to Gulp
 */
module.exports = function( options ) {

	// Combine user defined options with default options
	var config = { };
	for (var attrname in options) { config[attrname] = options[attrname]; }

	// Create a through2 object stream. This is our plugin export
	var stream = through2.obj(compile);

	// Expose the config so we can test it
	stream.config = config;

	function compile(originalFile, enc, done) {
		var self = this;

	    // Call when finished with compression
	    var finished = function( err, encContents, decContents ) {

	    	// Emmit errors
			if (err) {
				var error = new PluginError(PLUGIN_NAME, err, { showStack: true });
				self.emit('error', error);
				done();
				return;
			}

			// Get base name
			var dir = path.dirname( originalFile.path );
			var name = path.basename( originalFile.path );
			var parts = name.split("."); parts.pop();
			var baseName = self.config.name || parts.join(".");

			// The encode file
			var f = originalFile.clone();
			f.contents = encContents;
			f.path = path.join( dir, baseName + '-encode.js' );
			self.push(f);

			// The decode file
			var f = originalFile.clone();
			f.contents = decContents;
			f.path = path.join( dir, baseName + '-decode.js' );
			self.push(f);

	    	// We are done
			done();
			return;
	    }

        // Nothing to do on empty files
        if (originalFile.isNull()) {
            return done(null, originalFile);
        }

        // Handle stream
        if (originalFile.isStream()) {
        	streamMode( originalFile.contents, this.config, finished );
        } else if (originalFile.isBuffer()) {
        	bufferMode( originalFile.contents, this.config, finished );
        }

	}

	return stream;
}


/**
* journal.js
*
* The journal module implements the logging logic of agency.js
* Three methods are available by passing a parameter to the agency constructor:
*  'q' quiet, produces no log
*  'v' verbose, log is displayed on the console (recommended during development)
*  'l' log, writes the creation and execution events in a file (recommended for production)
*
* Copyright 2016 Fernando Pires
*
* Released under the MIT License.
*
* --------------------------------------------------------
*
* author:  Fernando Pires
* version: 1.0.0
*/

function journal() {
  'use strict';

  var fs = require('fs');

  // private properties
  var eventList = {
    'creationEvents' : {},
    'executionEvents' : {}
  };
  var logMode;

  // sets the log method: 'q', 'v' or 'l'
  // exposed by the agency constructor
  function setLogMode(mode) {
    logMode = mode;
  }

  // records the agent's validation and creation events in a temporary structure if log method is 'l' or
  // outputs the same events to the console if method is 'v'
  function logCreationEvent(id, type, message, time) {

    if (logMode === 'l') {
      if (!eventList.creationEvents[id]) {
        eventList.creationEvents[id] =  [];
      }
      eventList.creationEvents[id].push({'type': type, 'event': message, "timestamp": time});
    } else if (logMode === 'v') {
      console.log(type + ': Agent ' + id +  ' ' + message + ' on ' + time);
    }

  }

  // records the agent's execution events in a temporary structure if log method is 'l' or
  // outputs the same events to the console if method is 'v'
  function logExecutionEvent(id, type, message, time) {

    if (logMode === 'l') {
      if (!eventList.executionEvents[id]) {
        eventList.executionEvents[id] =  [];
      }
      eventList.executionEvents[id].push({'type': type, 'event': message, "timestamp": time});
    } else if (logMode === 'v') {
      console.log(type + ': Agent ' + id +  ' ' + message + ' on ' + time);
    }

  }

  // outputs the contents of the temporary creation and execution structure to a specific file
  // defined by the user; if file is not defined outputs to a default file; otherwise outputs error to the console
  function report(logFile) {
    var defaultLogFile = (new Date()).toJSON() + '.log';
    var data = JSON.stringify(eventList, null, 3);

    if (logFile) {
      fs.writeFile(logFile, data, function(err) {
        if(err) {
          console.log('\nCould not write log to file "' + logFile + '"\n' + err);
          fs.writeFile(defaultLogFile, data, function(err) {
            if(err) {
              console.log('Could not write log file: ' + err);
            } else {
              console.log('Log was written on default file "' + defaultLogFile + '"');
            }
          });
        }
      });
    } else {
      fs.writeFile(defaultLogFile, data, function(err) {
        if(err) {
          console.log('Could not write log file: ' + err);
        }
      });
    }
  }

  //public interface
  return {
    setLogMode: setLogMode,
    logCreationEvent: logCreationEvent,
    logExecutionEvent: logExecutionEvent,
    report: report
  };
}

module.exports = journal;


"use strict"
var Url = require('url')
var _ = require('underscore')

module.exports = function(ngin) {
  var SportsModel = ngin.SportsModel
  var Super = SportsModel.prototype
  var config = ngin.config

  /**
   * Scopes the url to the team and member
   *
   * @param {Object} options
   * @returns {String}
   * @api public
   */

  function scopeUrl(options, inst) {
    options = _.extend({}, inst, options)
    if (!options.teamcenter_team_id)
      throw new Error('teamcenter_team_id required to make TeamCenterContact instance api calls')
    if (!options.teamcenter_member_id)
      throw new Error('teamcenter_member_id require to make TeamCenterContact instance api calls')

    return ngin.TeamCenterTeam.urlRoot() + '/' + options.teamcenter_team_id + ngin.TeamCenterMember.urlRoot() + '/' + options.teamcenter_member_id + TeamCenterContact.urlRoot()
  }

  /**
   * TeamCenterContact Class
   *
   * @param {Object} attr
   * @param {Object} options
   * @api public
   */

  var TeamCenterContact = SportsModel.extend({

    fetch: function(options, callback) {
      var url = scopeUrl(options, this) + '/' + this.id
      return Super.fetch.call(this, url, options, callback)
    },

    save: function(options, callback) {
      var url = scopeUrl(options, this) + (this.id ? '/' + this.id : '')
      return Super.save.call(this, url, options, callback)
    },

    destroy: function(options, callback) {
      var url = scopeUrl(options, this) + '/' + this.id
      return Super.destroy.call(this, url, options, callback)
    }

  }, {

    urlRoot: function() {
      return '/contacts'
    },

    list: function(options, callback) {
      var url = scopeUrl(options, this)
      return SportsModel.list.call(this, url, options, callback)
    }

  })

  return TeamCenterContact

}