<commit_before>var Game;

(function() {

/*
 * Game
 * ====
 *
 * The main Game constructor
 */

Game = function(options, plugins, categories) {
    if(!options) {
        var options = {};
        console.warn(warnings.noOptionsConstructor);
    }
    if(!plugins) {
        var plugins = [];
        console.warn(warnings.noPluginsConstructor);
    }
    if(!categories) {
        var categories = [];
        console.warn(warnings.noCategoriesConstructor);
    }

    EventEmitter(this);

    this.options    = options;

    this.Assets     = null;
    this.Camera     = null;
    this.Colliders  = null;
    this.Draw       = null;
    this.Sound      = null;
    this.World      = null;
    this.Plugins    = new Plugins(this, plugins);
    this.Categories = new Categories(this, categories);

    this.initTime   = null;
    this.loadTime   = null;
    this.startTime  = null;
    this.pauseTime  = null;
    this.stopTime   = null;

    this.playing    = false;
    this.timer      = null;
    this.frames     = 0;

    return this;
}

/* Setup Engine */
Game.prototype.init = function() {
    this.emit("beforeinit", [this]);
    // Throw an Error if a plugin is missing.
    // If Game[plugin] is null, that plugin is missing
    if(!this.Assets || !this.Camera || !this.Colliders || !this.Draw || !this.Sound || !this.World) {
        console.warn(warnings.missingPluginInit);
    }

    this.initTime = this.Utils.time();
    this.Plugins.Init(this);

    // Attach Draw.domElement to Game
    if(this.Draw && this.Draw.domElement) {
        this.domElement = this.Draw.domElement;
    }
    else {
        console.warn(warnings.noDomElement);
    }

    this.emit("init", [this]);
    return this;
}

/* Setup world */
Game.prototype.load = function() {
    if(!this.initTime) {
        this.init();
    }

    this.emit("beforeload", [this]);

    this.loadTime = this.Utils.time();
    this.Plugins.Load(this);

    this.emit("load", [this]);
    return this;
}

/* Start game loop */
Game.prototype.start = function() {
    if(!this.playing) {
        this.startTime = this.Utils.time();
        if(!this.loadTime) {
            this.load();
        }

        this.emit("beforestart", [this]);

        this.timer = this.requestAnimationFrame(this.Loop);
        this.Loop();

        this.emit("start", [this]);
    }

    return this;
}

Game.prototype.pause = function() {
    if(this.playing) {
        this.emit("beforepause", [this]);
        this.pauseTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("pause", [this]);
    }
}

Game.prototype.stop = function() {
    if(this.playing) {
        this.emit("beforestop", [this]);
        this.stopTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("beforestopreset");
        this.reset();
        this.emit("stop", [this]);
    }

    return this;
}

Game.prototype.Loop = function() {
    this.emit("beforeframe", [this]);
    this.frames++;

    this.emit("beforeupdate", [this]);
    // this.World.Update(this);
    // this.Camera.Update(this);

    this.emit("beforedraw", [this]);
    // this.World.Draw(this);

    this.emit("frame", [this]);
    return this;
}

Game.prototype.Utils = {
    capitalize: function(str) {
        return str.substr(0,1).toUpperCase() + str.substr(1).toLowerCase();
    },
    merge: function(first, second, blacklist) {
        if(!blacklist) var blacklist = [];

        for(key in second) {
            if(blacklist.indexOf(key) === -1) {
                first[key] = second[key];
            }
        }

        return first;
    },
    toRadians: function(deg) {
        return (deg * Math.PI) / 180;
    },
    toDegrees: function(rad) {
        return (rad * 180) / Math.PI;
    },
    time: (function() {
        if(performance && performance.now) {
            return function() { return performance.now(); }
        } else if(performance && performance.webkitNow) {
            return function() { return performance.webkitNow(); }
        } else {
            return function() { return Date.now(); }
        }
    })()
}

Game.prototype.plugin = function(plugin) {
    this.Plugins.add(plugin);

    this.emit("plugin", [this, plugin]);
    return this;
}

Game.prototype.category = function(category) {
    this.Categories.add(category);

    this.emit("category", [this, category]);
    return this;
}

// Add Polyfill HERE!
Game.prototype.requestAnimationFrame = function() {
    this.timer = requestAnimationFrame(this.Loop);
    return this;
}

//Add Polyfill HERE!
Game.prototype.cancelAnimationFrame = function() {
    cancelAnimationFrame(this.timer);
    return game;
}

/*
 * Plugins
 * =======
 *
 * The Plugins constructor
 * Provides the plugin system for Game
 */

var Plugins = function(game, plugins) {
    //Save Game for later
    this.game = game;

    this.plugins = {};

    //Add already provided plugins
    if(plugins instanceof Array) {
        for(var i = 0, len = Game.plugins.length; i < len; i++) {
            var plugin = new Game.plugins[i]();
            var index = plugins.indexOf(plugin.name);
            if(index !== -1) {
                this.add(plugin);
            }
        }
    }

    return this;
}

Plugins.prototype.add = function(plugin, override) {
    var type   = plugin.type = this.game.Utils.capitalize(plugin.type);
    var name   = plugin.name;
    var Plugin = this.get(name);

    if(!/^(add|remove|get|use|loop)$/.test(name)) {
        //This type is not yet registered
        if(!this.plugins[type]) {
            this.plugins[type] = [];
        }

        //A plugin with this name already exists, but may be overridden
        if(Plugin && override) {
            this.remove(name);
            this.add(plugin);
        }
        else if(!Plugin) {
            //Push to plugin pool
            this.plugins[type].push(plugin);
            //Use the new plugin. If one already exists, it will not be overridden.
            this.use(name);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }

    return this;
}

Plugins.prototype.remove = function(name) {
    var Plugin = this.get(name);

    if(Plugin) {
        var type = Plugin.type;

        //Remove from plugin pool
        this.loop(function(plugin, index, array) {
            if(plugin.name === name) {
                array.splice(index, 1);
            }
        });
        //Remove from Game
        if(Plugin === this.game[type]) {
            this.game[type] = null;

            //Replace by last added plugin of the same type (if any)
            var plugins = this.plugins[type];
            if(plugins && plugins.length) {
                this.game[type] = plugins[ plugins.length-1 ];
            }
        }
    }

    return this;
}

Plugins.prototype.get = function(name, warn) {
    var Plugin = null;

    //Loop through all the plugins and get the right one out
    this.loop(function(plugin, index, array) {
        if(plugin.name === name) {
            Plugin = plugin;
            return true;
        }
    });

    //No plugin with this name exists
    if(!Plugin && warn) {
        console.warn(warnings.pluginDoesNotExist, name);
        console.trace();
    }

    return Plugin;
}

Plugins.prototype.use = function(name, override) {
    var plugin = this.get(name);

    //Plugin exists
    if(plugin) {
        var type = plugin.type;

        //Only proceed when no plugin of this type is in use, or the plugin in use may be overridden
        if(!this.game[type] || override) {
            this.game[type] = plugin;
            if(this.game.initTime && plugin.Init) {
                plugin.Init(this.game);
            }
        }
        else if(this.game[type]) {
            console.warn(warnings.useAlreadySet, name);
        }
    }
    else {
        console.warn(warnings.useNonExistentPlugin, name);
    }

    return this;
}

Plugins.prototype.loop = function(cb) {
    //Loop through types
    outer:
    for(type in this.plugins) {
        var plugins = this.plugins[type];

        //Loop through plugins (per type)
        for(var i = 0; i < plugins.length; i++) {
            var br = cb(plugins[i], i, plugins);
            // Break loop if `cb` returns `true` (or another truthy value)
            if(br) { break outer; }
        }
    }

    return this;
}

Plugins.prototype.Init = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Init) {
            plugin.Init(game);
        }
    });

    return this;
}

Plugins.prototype.Load = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Load) {
            plugin.Load(game);
        }
    });

    return this;
}

/*
 * Categories
 * ==========
 *
 * The main Categories constructor
 * Provides the categories system for Game
 */

var Categories = function(game, categories) {
    //Save Game for later
    this.game = game;

    //Add already provided catgories
    if(categories instanceof Array) {
        for(var i = 0, len = categories.length; i < len; i++) {
            this.add(categories[i]);
        }
    }

    return this;
}

Categories.prototype.add = function(category) {
    var name = category.name = this.game.Utils.capitalize(category.name);

    if(!/^(add|remove|get|loop)$/.test(name)) {
        this[name] = category;
        if(this.game.initTime && category.Init) {
            category.Init(this.game);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }
}

Categories.prototype.remove = function(name) {
    var name = this.game.Utils.capitalize(name);

    this[name] = undefined;

    return this;
}

Categories.prototype.get = function(name) {
    var name = this.game.Utils.capitalize(name);

    return this[name] || null;
}

Categories.prototype.loop = function(cb) {
    for(name in this) {
        if(!/^(add|remove|get|loop)$/.test(name)) {
            cb(this[name], name);
        }
    }
}

/*
 * EventEmitter
 *
 * EventEmitter allows for easy event registering and emitting. The API is a copy of the Node.js EventEmitter class.
 */

var EventEmitter = function(obj) {
    if(!obj) obj = this;

    obj.__events = {};
    obj.__allEvents = [];

    obj.addListener = obj.on = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            this.__events[event].push(listener);
        }
        else {
            this.__allEvents.push(event); // event is now the callback
        }

        return this;
    }

    obj.once = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            var func = function() {
                listener.call(null, arguments);
                obj.removeListener(event, func);
            }
            this.__events[event].push(func);
        }
        else {
            var func = function() {
                event.call(null, arguments);
                obj.removeListener(func);
            }
            this.__allEvents.push(func);
        }

        return this;
    }

    obj.emit = function(event, args) {
        if(!args) args = [];
        if(this.__events[event]) {
            var listeners = this.__events[event];
            for(var i = 0, len = listeners.length; i < len; i++) {
                listeners[i].apply(null, args);
            }
        }
        var args = [event].concat(args);
        for(var i = 0, len = this.__allEvents.length; i < len; i++) {
            this.__allEvents[i].apply(null, args);
        }

        return this;
    }

    obj.removeListener = function(event, listener) {
        if(!listener) {
            var listener = event;
            for(event in this.__events) {
                this.removeListener(event, listener);
            }
        }
        else {
            var listeners = this.__events[event];
            if(listeners.indexOf(listener) !== -1) {
                listeners.splice(listeners.indexOf(listener), 1);
            }
            if(this.__allEvents.indexOf(listener) !== -1) {
                this.__allEvents.splice(this.__allEvents.indexOf(listener), 1);
            }
        }

        return this;
    }

    obj.removeAllListeners = function(event) {
        this.__events[event] = [];

        return this;
    }

    obj.listeners = function(event) {
        return this.__events[event] || [];
    }

    return obj;
}

Game.prototype.EventEmitter = EventEmitter;

Game.plugins = [];

/*
 * VARS
 * ====
 *
 * Some variables used  by Game.
 */

    var warnings = {
        "noOptionsConstructor": "WARN: No options passed to the Game constructor. Default options will be used.",
        "noPluginsConstructor": "WARN: No plugins passed to the Game constructor. Make sure to add plugins with 'Game.plugin(plugin);'.",
        "noCategoriesConstructor": "WARN: No categories passed to the Game constructor. Make sure to add categories with 'Game.category(category);'.",
        "pluginDoesNotExist": "WARN: A plugin with the name '%s' does not exist.",
        "useNonExistentPlugin": "WARN: You are trying to use() a non-existent plugin, named '%s'.",
        "useAlreadySet": "WARN: You are trying to use() a plugin, named '%s', but a plugin of this type is already in use. Please use Plugins.use(name, true) to override any plugins already in use.",
        "invalidName": "WARN: The name '%s' is invalid.",
        "noPluginPassed": "WARN: No plugin passed to Plugin.add().",
        "noCategoryPassed": "WARN: No category passed to Categories.add().",
        "missingPluginInit": "A vital plugin is missing after Game.init().",
        "noDomElement": "Game.Draw.domElement is empty."
    }

    var container = Game.prototype.container = document.createElement("div");
    container.setAttribute("id", "2D-loaders");
    container.setAttribute("style", "width:0;height:0;visibility:hidden;overflow:hidden");
    document.addEventListener("load", function() {
        document.body.appendChild(container);
    });

})();<commit_msg>Fixed small bug in core<commit_after>var Game;

(function() {

/*
 * Game
 * ====
 *
 * The main Game constructor
 */

Game = function(options, plugins, categories) {
    if(!options) {
        var options = {};
        console.warn(warnings.noOptionsConstructor);
    }
    if(!plugins) {
        var plugins = [];
        console.warn(warnings.noPluginsConstructor);
    }
    if(!categories) {
        var categories = [];
        console.warn(warnings.noCategoriesConstructor);
    }

    EventEmitter(this);

    this.options    = options;

    this.Assets     = null;
    this.Camera     = null;
    this.Colliders  = null;
    this.Draw       = null;
    this.Sound      = null;
    this.World      = null;
    this.Plugins    = new Plugins(this, plugins);
    this.Categories = new Categories(this, categories);

    this.initTime   = null;
    this.loadTime   = null;
    this.startTime  = null;
    this.pauseTime  = null;
    this.stopTime   = null;

    this.playing    = false;
    this.timer      = null;
    this.frames     = 0;

    return this;
}

/* Setup Engine */
Game.prototype.init = function() {
    this.emit("beforeinit", [this]);
    // Throw an Error if a plugin is missing.
    // If Game[plugin] is null, that plugin is missing
    if(!this.Assets || !this.Camera || !this.Colliders || !this.Draw || !this.Sound || !this.World) {
        console.warn(warnings.missingPluginInit);
    }

    this.initTime = this.Utils.time();
    this.Plugins.Init(this);

    // Attach Draw.domElement to Game
    if(this.Draw && this.Draw.domElement) {
        this.domElement = this.Draw.domElement;
    }
    else {
        console.warn(warnings.noDomElement);
    }

    this.emit("init", [this]);
    return this;
}

/* Setup world */
Game.prototype.load = function() {
    if(!this.initTime) {
        this.init();
    }

    this.emit("beforeload", [this]);

    this.loadTime = this.Utils.time();
    this.Plugins.Load(this);

    this.emit("load", [this]);
    return this;
}

/* Start game loop */
Game.prototype.start = function() {
    if(!this.playing) {
        this.startTime = this.Utils.time();
        if(!this.loadTime) {
            this.load();
        }

        this.emit("beforestart", [this]);

        this.timer = this.requestAnimationFrame(this.Loop);
        this.Loop();

        this.emit("start", [this]);
    }

    return this;
}

Game.prototype.pause = function() {
    if(this.playing) {
        this.emit("beforepause", [this]);
        this.pauseTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("pause", [this]);
    }
}

Game.prototype.stop = function() {
    if(this.playing) {
        this.emit("beforestop", [this]);
        this.stopTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("beforestopreset");
        this.reset();
        this.emit("stop", [this]);
    }

    return this;
}

Game.prototype.Loop = function() {
    this.emit("beforeframe", [this]);
    this.frames++;

    this.emit("beforeupdate", [this]);
    // this.World.Update(this);
    // this.Camera.Update(this);

    this.emit("beforedraw", [this]);
    // this.World.Draw(this);

    this.emit("frame", [this]);
    return this;
}

Game.prototype.Utils = {
    capitalize: function(str) {
        return str.substr(0,1).toUpperCase() + str.substr(1).toLowerCase();
    },
    merge: function(first, second, blacklist) {
        if(!blacklist) var blacklist = [];

        for(key in second) {
            if(blacklist.indexOf(key) === -1) {
                first[key] = second[key];
            }
        }

        return first;
    },
    toRadians: function(deg) {
        return (deg * Math.PI) / 180;
    },
    toDegrees: function(rad) {
        return (rad * 180) / Math.PI;
    },
    time: (function() {
        if(performance && performance.now) {
            return function() { return performance.now(); }
        } else if(performance && performance.webkitNow) {
            return function() { return performance.webkitNow(); }
        } else {
            return function() { return Date.now(); }
        }
    })()
}

Game.prototype.plugin = function(plugin) {
    this.Plugins.add(plugin);

    this.emit("plugin", [this, plugin]);
    return this;
}

Game.prototype.category = function(category) {
    this.Categories.add(category);

    this.emit("category", [this, category]);
    return this;
}

// Add Polyfill HERE!
Game.prototype.requestAnimationFrame = function() {
    this.timer = requestAnimationFrame(this.Loop);
    return this;
}

//Add Polyfill HERE!
Game.prototype.cancelAnimationFrame = function() {
    cancelAnimationFrame(this.timer);
    return this;
}

/*
 * Plugins
 * =======
 *
 * The Plugins constructor
 * Provides the plugin system for Game
 */

var Plugins = function(game, plugins) {
    //Save Game for later
    this.game = game;

    this.plugins = {};

    //Add already provided plugins
    if(plugins instanceof Array) {
        for(var i = 0, len = Game.plugins.length; i < len; i++) {
            var plugin = new Game.plugins[i]();
            var index = plugins.indexOf(plugin.name);
            if(index !== -1) {
                this.add(plugin);
            }
        }
    }

    return this;
}

Plugins.prototype.add = function(plugin, override) {
    var type   = plugin.type = this.game.Utils.capitalize(plugin.type);
    var name   = plugin.name;
    var Plugin = this.get(name);

    if(!/^(add|remove|get|use|loop)$/.test(name)) {
        //This type is not yet registered
        if(!this.plugins[type]) {
            this.plugins[type] = [];
        }

        //A plugin with this name already exists, but may be overridden
        if(Plugin && override) {
            this.remove(name);
            this.add(plugin);
        }
        else if(!Plugin) {
            //Push to plugin pool
            this.plugins[type].push(plugin);
            //Use the new plugin. If one already exists, it will not be overridden.
            this.use(name);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }

    return this;
}

Plugins.prototype.remove = function(name) {
    var Plugin = this.get(name);

    if(Plugin) {
        var type = Plugin.type;

        //Remove from plugin pool
        this.loop(function(plugin, index, array) {
            if(plugin.name === name) {
                array.splice(index, 1);
            }
        });
        //Remove from Game
        if(Plugin === this.game[type]) {
            this.game[type] = null;

            //Replace by last added plugin of the same type (if any)
            var plugins = this.plugins[type];
            if(plugins && plugins.length) {
                this.game[type] = plugins[ plugins.length-1 ];
            }
        }
    }

    return this;
}

Plugins.prototype.get = function(name, warn) {
    var Plugin = null;

    //Loop through all the plugins and get the right one out
    this.loop(function(plugin, index, array) {
        if(plugin.name === name) {
            Plugin = plugin;
            return true;
        }
    });

    //No plugin with this name exists
    if(!Plugin && warn) {
        console.warn(warnings.pluginDoesNotExist, name);
        console.trace();
    }

    return Plugin;
}

Plugins.prototype.use = function(name, override) {
    var plugin = this.get(name);

    //Plugin exists
    if(plugin) {
        var type = plugin.type;

        //Only proceed when no plugin of this type is in use, or the plugin in use may be overridden
        if(!this.game[type] || override) {
            this.game[type] = plugin;
            if(this.game.initTime && plugin.Init) {
                plugin.Init(this.game);
            }
        }
        else if(this.game[type]) {
            console.warn(warnings.useAlreadySet, name);
        }
    }
    else {
        console.warn(warnings.useNonExistentPlugin, name);
    }

    return this;
}

Plugins.prototype.loop = function(cb) {
    //Loop through types
    outer:
    for(type in this.plugins) {
        var plugins = this.plugins[type];

        //Loop through plugins (per type)
        for(var i = 0; i < plugins.length; i++) {
            var br = cb(plugins[i], i, plugins);
            // Break loop if `cb` returns `true` (or another truthy value)
            if(br) { break outer; }
        }
    }

    return this;
}

Plugins.prototype.Init = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Init) {
            plugin.Init(game);
        }
    });

    return this;
}

Plugins.prototype.Load = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Load) {
            plugin.Load(game);
        }
    });

    return this;
}

/*
 * Categories
 * ==========
 *
 * The main Categories constructor
 * Provides the categories system for Game
 */

var Categories = function(game, categories) {
    //Save Game for later
    this.game = game;

    //Add already provided catgories
    if(categories instanceof Array) {
        for(var i = 0, len = categories.length; i < len; i++) {
            this.add(categories[i]);
        }
    }

    return this;
}

Categories.prototype.add = function(category) {
    var name = category.name = this.game.Utils.capitalize(category.name);

    if(!/^(add|remove|get|loop)$/.test(name)) {
        this[name] = category;
        if(this.game.initTime && category.Init) {
            category.Init(this.game);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }
}

Categories.prototype.remove = function(name) {
    var name = this.game.Utils.capitalize(name);

    this[name] = undefined;

    return this;
}

Categories.prototype.get = function(name) {
    var name = this.game.Utils.capitalize(name);

    return this[name] || null;
}

Categories.prototype.loop = function(cb) {
    for(name in this) {
        if(!/^(add|remove|get|loop)$/.test(name)) {
            cb(this[name], name);
        }
    }
}

/*
 * EventEmitter
 *
 * EventEmitter allows for easy event registering and emitting. The API is a copy of the Node.js EventEmitter class.
 */

var EventEmitter = function(obj) {
    if(!obj) obj = this;

    obj.__events = {};
    obj.__allEvents = [];

    obj.addListener = obj.on = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            this.__events[event].push(listener);
        }
        else {
            this.__allEvents.push(event); // event is now the callback
        }

        return this;
    }

    obj.once = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            var func = function() {
                listener.call(null, arguments);
                obj.removeListener(event, func);
            }
            this.__events[event].push(func);
        }
        else {
            var func = function() {
                event.call(null, arguments);
                obj.removeListener(func);
            }
            this.__allEvents.push(func);
        }

        return this;
    }

    obj.emit = function(event, args) {
        if(!args) args = [];
        if(this.__events[event]) {
            var listeners = this.__events[event];
            for(var i = 0, len = listeners.length; i < len; i++) {
                listeners[i].apply(null, args);
            }
        }
        var args = [event].concat(args);
        for(var i = 0, len = this.__allEvents.length; i < len; i++) {
            this.__allEvents[i].apply(null, args);
        }

        return this;
    }

    obj.removeListener = function(event, listener) {
        if(!listener) {
            var listener = event;
            for(event in this.__events) {
                this.removeListener(event, listener);
            }
        }
        else {
            var listeners = this.__events[event];
            if(listeners.indexOf(listener) !== -1) {
                listeners.splice(listeners.indexOf(listener), 1);
            }
            if(this.__allEvents.indexOf(listener) !== -1) {
                this.__allEvents.splice(this.__allEvents.indexOf(listener), 1);
            }
        }

        return this;
    }

    obj.removeAllListeners = function(event) {
        this.__events[event] = [];

        return this;
    }

    obj.listeners = function(event) {
        return this.__events[event] || [];
    }

    return obj;
}

Game.prototype.EventEmitter = EventEmitter;

Game.plugins = [];

/*
 * VARS
 * ====
 *
 * Some variables used  by Game.
 */

    var warnings = {
        "noOptionsConstructor": "WARN: No options passed to the Game constructor. Default options will be used.",
        "noPluginsConstructor": "WARN: No plugins passed to the Game constructor. Make sure to add plugins with 'Game.plugin(plugin);'.",
        "noCategoriesConstructor": "WARN: No categories passed to the Game constructor. Make sure to add categories with 'Game.category(category);'.",
        "pluginDoesNotExist": "WARN: A plugin with the name '%s' does not exist.",
        "useNonExistentPlugin": "WARN: You are trying to use() a non-existent plugin, named '%s'.",
        "useAlreadySet": "WARN: You are trying to use() a plugin, named '%s', but a plugin of this type is already in use. Please use Plugins.use(name, true) to override any plugins already in use.",
        "invalidName": "WARN: The name '%s' is invalid.",
        "noPluginPassed": "WARN: No plugin passed to Plugin.add().",
        "noCategoryPassed": "WARN: No category passed to Categories.add().",
        "missingPluginInit": "A vital plugin is missing after Game.init().",
        "noDomElement": "Game.Draw.domElement is empty."
    }

    var container = Game.prototype.container = document.createElement("div");
    container.setAttribute("id", "2D-loaders");
    container.setAttribute("style", "width:0;height:0;visibility:hidden;overflow:hidden");
    document.addEventListener("load", function() {
        document.body.appendChild(container);
    });

})();<|endoftext|>


<commit_before>window.onload = init;

function init() {
  var root = new THREERoot({
    createCameraControls: true,
    antialias: (window.devicePixelRatio === 1),
    fov: 80
  });

  root.renderer.setClearColor(0x000000);
  root.renderer.setPixelRatio(window.devicePixelRatio || 1);
  root.camera.position.set(0, 0, 150);

  var light = new THREE.DirectionalLight();
  light.position.set(0, 0, 1);
  root.scene.add(light);

  var width = 100;
  var height = 60;

  var slide = new Slide(width, height);
  slide.setImage(new THREE.ImageLoader().load('image.jpg'));
  root.scene.add(slide);

  var slide2 = new Slide(width, height);
  slide2.setImage(new THREE.ImageLoader().load('image2.jpg'));
  root.scene.add(slide2);

  var tl = new TimelineMax({repeat:-1, repeatDelay:1.0});

  tl.add(slide.transitionOut(), 0);
  tl.add(slide2.transitionIn(), 0);

  //TweenMax.to(slide2, 2, {time:3.0, ease:Power0.easeInOut, repeat:-1});
}

////////////////////
// CLASSES
////////////////////

function Slide(width, height) {
  var plane = new THREE.PlaneGeometry(width, height, width, height);

  THREE.BAS.Utils.separateFaces(plane);

  var geometry = new SlideGeometry(plane);

  geometry.bufferUVs();

  console.log(geometry);

  var aAnimation = geometry.createAttribute('aAnimation', 2);
  var aStartPosition = geometry.createAttribute('aStartPosition', 3);
  var aControl0 = geometry.createAttribute('aControl0', 3);
  var aControl1 = geometry.createAttribute('aControl1', 3);
  var aEndPosition = geometry.createAttribute('aEndPosition', 3);

  var i, i2, i3, i4, v;

  var minDuration = 1.0;
  var maxDuration = 2.0;

  var delta = new THREE.Vector3();
  var control0 = new THREE.Vector3();
  var control1 = new THREE.Vector3();

  for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < geometry.faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
    var face = plane.faces[i];
    var centroid = THREE.BAS.Utils.computeCentroid(plane, face);

    // animation
    var duration = THREE.Math.randFloat(minDuration, maxDuration);
    var delayX = THREE.Math.mapLinear(centroid.x, -width * 0.5, width * 0.5, 0.5, 0.0);
    //var delayY = THREE.Math.mapLinear(centroid.y, -height * 0.5, height * 0.5, 0.5, 0.0);

    for (v = 0; v < 6; v += 2) {
      aAnimation.array[i2 + v]     = delayX + (Math.random() * 0.15);
      aAnimation.array[i2 + v + 1] = duration;
    }

    // positions

    var signX = Math.sign(centroid.x);
    var signY = Math.sign(centroid.y);

    control0.x = THREE.Math.randFloat(24, 32);
    control0.y = -signY * THREE.Math.randFloat(64, 96);
    //control0.z = signY * THREE.Math.randFloat(64, 96);
    control0.z = THREE.Math.randFloatSpread(32);

    control1.x = THREE.Math.randFloat(32, 48);
    control1.y = signY * THREE.Math.randFloat(64, 96);
    //control1.z = -signY * THREE.Math.randFloat(64, 96);
    control1.z = THREE.Math.randFloatSpread(32);

    delta.x = 0;
    delta.y = -signY * THREE.Math.randFloat(32, 48);
    delta.z = 0;

    for (v = 0; v < 9; v += 3) {
      aStartPosition.array[i3 + v]     = centroid.x;
      aStartPosition.array[i3 + v + 1] = centroid.y;
      aStartPosition.array[i3 + v + 2] = centroid.z;

      aControl0.array[i3 + v]     = centroid.x + control0.x;
      aControl0.array[i3 + v + 1] = centroid.y + control0.y;
      aControl0.array[i3 + v + 2] = centroid.z + control0.z;

      aControl1.array[i3 + v]     = centroid.x + control1.x;
      aControl1.array[i3 + v + 1] = centroid.y + control1.y;
      aControl1.array[i3 + v + 2] = centroid.z + control1.z;

      aEndPosition.array[i3 + v]     = centroid.x + delta.x;
      aEndPosition.array[i3 + v + 1] = centroid.y + delta.y;
      aEndPosition.array[i3 + v + 2] = centroid.z + delta.z;
    }
  }

  var material = new THREE.BAS.PhongAnimationMaterial(
    {
      shading: THREE.FlatShading,
      side: THREE.DoubleSide,
      uniforms: {
        uTime: {type: 'f', value: 0},
        uDir: {type: 'f', value: 1.0}
      },
      shaderFunctions: [
        THREE.BAS.ShaderChunk['cubic_bezier'],
        THREE.BAS.ShaderChunk['ease_out_cubic'],
        THREE.BAS.ShaderChunk['quaternion_rotation']
      ],
      shaderParameters: [
        'uniform float uTime;',
        'uniform float uDir;',
        'attribute vec2 aAnimation;',
        'attribute vec3 aStartPosition;',
        'attribute vec3 aControl0;',
        'attribute vec3 aControl1;',
        'attribute vec3 aEndPosition;',
      ],
      shaderVertexInit: [
        'float tDelay = aAnimation.x;',
        'float tDuration = aAnimation.y;',
        'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
        'float tProgress = ease(tTime, 0.0, 1.0, tDuration);'
        //'float tProgress = tTime / tDuration;'
      ],
      shaderTransformPosition: [
        'transformed *= 1.0 - tProgress;',
        'transformed += cubicBezier(aStartPosition, aControl0 * uDir, aControl1 * uDir, aEndPosition, tProgress);',
      ]
    },
    {
      map: new THREE.Texture()
    }
  );

  THREE.Mesh.call(this, geometry, material);

  this.frustumCulled = false;
}
Slide.prototype = Object.create(THREE.Mesh.prototype);
Slide.prototype.constructor = Slide;
Object.defineProperty(Slide.prototype, 'time', {
  get: function () {
    return this.material.uniforms['uTime'].value;
  },
  set: function (v) {
    this.material.uniforms['uTime'].value = v;
  }
});

Slide.prototype.setImage = function(image) {
  this.material.uniforms.map.value.image = image;
  this.material.uniforms.map.value.needsUpdate = true;
};

Slide.prototype.transitionIn = function() {
  this.material.uniforms.uDir.value = -1.0;
  return TweenMax.fromTo(this, 2, {time:3.0}, {time:0.0, ease:Power0.easeInOut});
};
Slide.prototype.transitionOut = function() {
  this.material.uniforms.uDir.value = 1.0;
  return TweenMax.fromTo(this, 2, {time:0.0}, {time:3.0, ease:Power0.easeInOut});
};

function SlideGeometry(model) {
  THREE.BAS.ModelBufferGeometry.call(this, model);
}
SlideGeometry.prototype = Object.create(THREE.BAS.ModelBufferGeometry.prototype);
SlideGeometry.prototype.constructor = SlideGeometry;
SlideGeometry.prototype.bufferPositions = function () {
  var positionBuffer = this.createAttribute('position', 3).array;

  for (var i = 0; i < this.faceCount; i++) {
    var face = this.modelGeometry.faces[i];
    var centroid = THREE.BAS.Utils.computeCentroid(this.modelGeometry, face);

    var a = this.modelGeometry.vertices[face.a];
    var b = this.modelGeometry.vertices[face.b];
    var c = this.modelGeometry.vertices[face.c];

    positionBuffer[face.a * 3]     = a.x - centroid.x;
    positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
    positionBuffer[face.a * 3 + 2] = a.z - centroid.z;

    positionBuffer[face.b * 3]     = b.x - centroid.x;
    positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
    positionBuffer[face.b * 3 + 2] = b.z - centroid.z;

    positionBuffer[face.c * 3]     = c.x - centroid.x;
    positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
    positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
  }
};

function THREERoot(params) {
  params = utils.extend({
    fov: 60,
    zNear: 10,
    zFar: 100000,

    createCameraControls: true
  }, params);

  this.renderer = new THREE.WebGLRenderer({
    antialias: params.antialias
  });
  this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
  document.getElementById('three-container').appendChild(this.renderer.domElement);

  this.camera = new THREE.PerspectiveCamera(
    params.fov,
    window.innerWidth / window.innerHeight,
    params.zNear,
    params.zfar
  );

  this.scene = new THREE.Scene();

  if (params.createCameraControls) {
    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
  }

  this.resize = this.resize.bind(this);
  this.tick = this.tick.bind(this);

  this.resize();
  this.tick();

  window.addEventListener('resize', this.resize, false);
}
THREERoot.prototype = {
  tick: function () {
    this.update();
    this.render();
    requestAnimationFrame(this.tick);
  },
  update: function () {
    this.controls && this.controls.update();
  },
  render: function () {
    this.renderer.render(this.scene, this.camera);
  },
  resize: function () {
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();

    this.renderer.setSize(window.innerWidth, window.innerHeight);
  }
};

////////////////////
// UTILS
////////////////////

var utils = {
  extend: function (dst, src) {
    for (var key in src) {
      dst[key] = src[key];
    }

    return dst;
  },
  randSign: function () {
    return Math.random() > 0.5 ? 1 : -1;
  },
  ease: function (ease, t, b, c, d) {
    return b + ease.getRatio(t / d) * c;
  },
  fibSpherePoint: (function () {
    var vec = {x: 0, y: 0, z: 0};
    var G = Math.PI * (3 - Math.sqrt(5));

    return function (i, n, radius) {
      var step = 2.0 / n;
      var r, phi;

      vec.y = i * step - 1 + (step * 0.5);
      r = Math.sqrt(1 - vec.y * vec.y);
      phi = i * G;
      vec.x = Math.cos(phi) * r;
      vec.z = Math.sin(phi) * r;

      radius = radius || 1;

      vec.x *= radius;
      vec.y *= radius;
      vec.z *= radius;

      return vec;
    }
  })(),
  spherePoint: (function () {
    return function (u, v) {
      u === undefined && (u = Math.random());
      v === undefined && (v = Math.random());

      var theta = 2 * Math.PI * u;
      var phi = Math.acos(2 * v - 1);

      var vec = {};
      vec.x = (Math.sin(phi) * Math.cos(theta));
      vec.y = (Math.sin(phi) * Math.sin(theta));
      vec.z = (Math.cos(phi));

      return vec;
    }
  })()
};

<commit_msg>gallery<commit_after>window.onload = init;

function init() {
  var root = new THREERoot({
    createCameraControls: !true,
    antialias: (window.devicePixelRatio === 1),
    fov: 80
  });

  root.renderer.setClearColor(0x000000);
  root.renderer.setPixelRatio(window.devicePixelRatio || 1);
  root.camera.position.set(0, 0, 120);

  var light = new THREE.DirectionalLight();
  light.position.set(0, 0, 1);
  root.scene.add(light);

  var width = 100;
  var height = 60;

  var slide = new Slide(width, height, 'out');
  slide.setImage(new THREE.ImageLoader().load('image.jpg'));
  root.scene.add(slide);

  var slide2 = new Slide(width, height, 'in');
  slide2.setImage(new THREE.ImageLoader().load('image2.jpg'));
  root.scene.add(slide2);

  var tl = new TimelineMax({repeat:-1, repeatDelay:1.0, yoyo: true});

  tl.add(slide.transition(), 0);
  tl.add(slide2.transition(), 0);

  createTweenScrubber(tl);

  //TweenMax.to(slide2, 2, {time:3.0, ease:Power0.easeInOut, repeat:-1});
}

////////////////////
// CLASSES
////////////////////

function Slide(width, height, animationPhase) {
  var plane = new THREE.PlaneGeometry(width, height, width * 2, height * 2);

  THREE.BAS.Utils.separateFaces(plane);

  var geometry = new SlideGeometry(plane);

  geometry.bufferUVs();

  var aAnimation = geometry.createAttribute('aAnimation', 2);
  var aStartPosition = geometry.createAttribute('aStartPosition', 3);
  var aControl0 = geometry.createAttribute('aControl0', 3);
  var aControl1 = geometry.createAttribute('aControl1', 3);
  var aEndPosition = geometry.createAttribute('aEndPosition', 3);

  var i, i2, i3, i4, v;

  var minDuration = 0.8;
  var maxDuration = 1.0;
  var maxDelay = 1.0;
  var stretch = 0.075;

  this.totalDuration = maxDuration + maxDelay + stretch;

  var startPosition = new THREE.Vector3();
  var control0 = new THREE.Vector3();
  var control1 = new THREE.Vector3();
  var endPosition = new THREE.Vector3();

  var tempPoint = new THREE.Vector3();

  function getControlPoint0(centroid) {
    var signY = Math.sign(centroid.y);

    tempPoint.x = THREE.Math.randFloat(24, 32);
    tempPoint.y = -signY * THREE.Math.randFloat(64, 96);
    tempPoint.z = THREE.Math.randFloatSpread(32);

    return tempPoint;
  }

  function getControlPoint1(centroid) {
    var signY = Math.sign(centroid.y);

    tempPoint.x = THREE.Math.randFloat(32, 48);
    tempPoint.y = signY * THREE.Math.randFloat(64, 96);
    tempPoint.z = THREE.Math.randFloatSpread(32);

    return tempPoint;
  }

  for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < geometry.faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
    var face = plane.faces[i];
    var centroid = THREE.BAS.Utils.computeCentroid(plane, face);

    // animation
    var duration = THREE.Math.randFloat(minDuration, maxDuration);
    var delayX = THREE.Math.mapLinear(centroid.x, -width * 0.5, width * 0.5, maxDelay, 0.0);

    for (v = 0; v < 6; v += 2) {
      aAnimation.array[i2 + v]     = delayX + (Math.random() * stretch * duration);
      aAnimation.array[i2 + v + 1] = duration;
    }

    // positions

    endPosition.copy(centroid);
    startPosition.copy(centroid);

    if (animationPhase === 'in') {
      control0.copy(centroid).sub(getControlPoint0(centroid));
      control1.copy(centroid).sub(getControlPoint1(centroid));
    }
    else { // out
      control0.copy(centroid).add(getControlPoint0(centroid));
      control1.copy(centroid).add(getControlPoint1(centroid));
    }

    for (v = 0; v < 9; v += 3) {
      aStartPosition.array[i3 + v]     = startPosition.x;
      aStartPosition.array[i3 + v + 1] = startPosition.y;
      aStartPosition.array[i3 + v + 2] = startPosition.z;

      aControl0.array[i3 + v]     = control0.x;
      aControl0.array[i3 + v + 1] = control0.y;
      aControl0.array[i3 + v + 2] = control0.z;

      aControl1.array[i3 + v]     = control1.x;
      aControl1.array[i3 + v + 1] = control1.y;
      aControl1.array[i3 + v + 2] = control1.z;

      aEndPosition.array[i3 + v]     = endPosition.x;
      aEndPosition.array[i3 + v + 1] = endPosition.y;
      aEndPosition.array[i3 + v + 2] = endPosition.z;
    }
  }

  var material = new THREE.BAS.PhongAnimationMaterial(
    {
      shading: THREE.FlatShading,
      side: THREE.DoubleSide,
      uniforms: {
        uTime: {type: 'f', value: 0}
      },
      shaderFunctions: [
        THREE.BAS.ShaderChunk['cubic_bezier'],
        //THREE.BAS.ShaderChunk[(animationPhase === 'in' ? 'ease_out_cubic' : 'ease_in_cubic')],
        THREE.BAS.ShaderChunk['ease_in_out_cubic'],
        THREE.BAS.ShaderChunk['quaternion_rotation']
      ],
      shaderParameters: [
        'uniform float uTime;',
        'attribute vec2 aAnimation;',
        'attribute vec3 aStartPosition;',
        'attribute vec3 aControl0;',
        'attribute vec3 aControl1;',
        'attribute vec3 aEndPosition;',
      ],
      shaderVertexInit: [
        'float tDelay = aAnimation.x;',
        'float tDuration = aAnimation.y;',
        'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
        'float tProgress = ease(tTime, 0.0, 1.0, tDuration);'
        //'float tProgress = tTime / tDuration;'
      ],
      shaderTransformPosition: [
        (animationPhase === 'in' ? 'transformed *= tProgress;' : 'transformed *= 1.0 - tProgress;'),
        'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
      ]
    },
    {
      map: new THREE.Texture()
    }
  );

  THREE.Mesh.call(this, geometry, material);

  this.frustumCulled = false;
}
Slide.prototype = Object.create(THREE.Mesh.prototype);
Slide.prototype.constructor = Slide;
Object.defineProperty(Slide.prototype, 'time', {
  get: function () {
    return this.material.uniforms['uTime'].value;
  },
  set: function (v) {
    this.material.uniforms['uTime'].value = v;
  }
});

Slide.prototype.setImage = function(image) {
  this.material.uniforms.map.value.image = image;
  this.material.uniforms.map.value.needsUpdate = true;
};

Slide.prototype.transition = function() {
  return TweenMax.fromTo(this, 2.0, {time:0.0}, {time:this.totalDuration, ease:Power0.easeInOut});
};

function SlideGeometry(model) {
  THREE.BAS.ModelBufferGeometry.call(this, model);
}
SlideGeometry.prototype = Object.create(THREE.BAS.ModelBufferGeometry.prototype);
SlideGeometry.prototype.constructor = SlideGeometry;
SlideGeometry.prototype.bufferPositions = function () {
  var positionBuffer = this.createAttribute('position', 3).array;

  for (var i = 0; i < this.faceCount; i++) {
    var face = this.modelGeometry.faces[i];
    var centroid = THREE.BAS.Utils.computeCentroid(this.modelGeometry, face);

    var a = this.modelGeometry.vertices[face.a];
    var b = this.modelGeometry.vertices[face.b];
    var c = this.modelGeometry.vertices[face.c];

    positionBuffer[face.a * 3]     = a.x - centroid.x;
    positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
    positionBuffer[face.a * 3 + 2] = a.z - centroid.z;

    positionBuffer[face.b * 3]     = b.x - centroid.x;
    positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
    positionBuffer[face.b * 3 + 2] = b.z - centroid.z;

    positionBuffer[face.c * 3]     = c.x - centroid.x;
    positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
    positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
  }
};

function THREERoot(params) {
  params = utils.extend({
    fov: 60,
    zNear: 10,
    zFar: 100000,

    createCameraControls: true
  }, params);

  this.renderer = new THREE.WebGLRenderer({
    antialias: params.antialias
  });
  this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
  document.getElementById('three-container').appendChild(this.renderer.domElement);

  this.camera = new THREE.PerspectiveCamera(
    params.fov,
    window.innerWidth / window.innerHeight,
    params.zNear,
    params.zfar
  );

  this.scene = new THREE.Scene();

  if (params.createCameraControls) {
    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
  }

  this.resize = this.resize.bind(this);
  this.tick = this.tick.bind(this);

  this.resize();
  this.tick();

  window.addEventListener('resize', this.resize, false);
}
THREERoot.prototype = {
  tick: function () {
    this.update();
    this.render();
    requestAnimationFrame(this.tick);
  },
  update: function () {
    this.controls && this.controls.update();
  },
  render: function () {
    this.renderer.render(this.scene, this.camera);
  },
  resize: function () {
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();

    this.renderer.setSize(window.innerWidth, window.innerHeight);
  }
};

////////////////////
// UTILS
////////////////////

var utils = {
  extend: function (dst, src) {
    for (var key in src) {
      dst[key] = src[key];
    }

    return dst;
  },
  randSign: function () {
    return Math.random() > 0.5 ? 1 : -1;
  },
  ease: function (ease, t, b, c, d) {
    return b + ease.getRatio(t / d) * c;
  },
  fibSpherePoint: (function () {
    var vec = {x: 0, y: 0, z: 0};
    var G = Math.PI * (3 - Math.sqrt(5));

    return function (i, n, radius) {
      var step = 2.0 / n;
      var r, phi;

      vec.y = i * step - 1 + (step * 0.5);
      r = Math.sqrt(1 - vec.y * vec.y);
      phi = i * G;
      vec.x = Math.cos(phi) * r;
      vec.z = Math.sin(phi) * r;

      radius = radius || 1;

      vec.x *= radius;
      vec.y *= radius;
      vec.z *= radius;

      return vec;
    }
  })(),
  spherePoint: (function () {
    return function (u, v) {
      u === undefined && (u = Math.random());
      v === undefined && (v = Math.random());

      var theta = 2 * Math.PI * u;
      var phi = Math.acos(2 * v - 1);

      var vec = {};
      vec.x = (Math.sin(phi) * Math.cos(theta));
      vec.y = (Math.sin(phi) * Math.sin(theta));
      vec.z = (Math.cos(phi));

      return vec;
    }
  })()
};

function createTweenScrubber(tween, seekSpeed) {
  seekSpeed = seekSpeed || 0.001;

  function stop() {
    TweenMax.to(tween, 1, {timeScale:0});
  }

  function resume() {
    TweenMax.to(tween, 1, {timeScale:1});
  }

  function seek(dx) {
    var progress = tween.progress();
    var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);

    tween.progress(p);
  }

  var _cx = 0;

  // desktop
  var mouseDown = false;
  document.body.style.cursor = 'pointer';

  window.addEventListener('mousedown', function(e) {
    mouseDown = true;
    document.body.style.cursor = 'ew-resize';
    _cx = e.clientX;
    stop();
  });
  window.addEventListener('mouseup', function(e) {
    mouseDown = false;
    document.body.style.cursor = 'pointer';
    resume();
  });
  window.addEventListener('mousemove', function(e) {
    if (mouseDown === true) {
      var cx = e.clientX;
      var dx = cx - _cx;
      _cx = cx;

      seek(dx);
    }
  });
  // mobile
  window.addEventListener('touchstart', function(e) {
    _cx = e.touches[0].clientX;
    stop();
    e.preventDefault();
  });
  window.addEventListener('touchend', function(e) {
    resume();
    e.preventDefault();
  });
  window.addEventListener('touchmove', function(e) {
    var cx = e.touches[0].clientX;
    var dx = cx - _cx;
    _cx = cx;

    seek(dx);
    e.preventDefault();
  });
}
<|endoftext|>


<commit_before>/**
 * Help Window with static content using 'contentEl' property.
 * @extends Ext.window.Window
 */
Ext.define('CF.view.help.Window', {
    extend: 'Ext.window.Window',
    alias : 'widget.cf_helpwindow',
    initComponent: function() {
        Ext.apply(this, {
            bodyCls: "cf-helpwindow",
            closeAction: "hide",
            layout: 'fit',
            maxWidth: 600,
            title: "Help"
        });
        this.callParent(arguments);
    }
});
<commit_msg>Help page<commit_after>/**
 * Help Window with static content using 'contentEl' property.
 * @extends Ext.window.Window
 */

var helpIframe = '<iframe id="test_iframe" src="http://www.verce-project.eu/projects/docu1/wiki/HPC_use-case?parent=User_documentation" width="1000px" height="600px"></iframe>';
var helpTitle = 'Help';

Ext.define('CF.view.help.Window', {
    extend: 'Ext.window.Window',
    alias : 'widget.cf_helpwindow',
    initComponent: function() {
        Ext.apply(this, {
            bodyCls: "cf-helpwindow",
            closeAction: "hide",
            layout: 'fit',
            maxWidth: 1200,
            html: helpIframe,
            title: helpTitle
        });
        this.callParent(arguments);
    }
});
<|endoftext|>


<commit_before>define([
    "ace",
    "src/languages"
], function(ace, languages) {
    var hr = codebox.require("hr/hr");
    var keyboard = codebox.require("utils/keyboard");

    // Import ace
    var aceRange =  ace.require("ace/range");
    var aceModes = ace.require("ace/ext/modelist");
    var aceLangs = ace.require("ace/ext/language_tools");
    var aceWhitespace = ace.require("ace/ext/whitespace");

    var Tab = codebox.tabs.Panel.extend({
        className: "component-editor",

        initialize: function() {
            var that = this;
            Tab.__super__.initialize.apply(this, arguments);

            // Messages
            this.msgPosition = this.statusbar.add({
                content: ""
            });

            // Create the ace editor
            this.$editor = $("<div>", {
                'class': "editor-content"
            });
            this.$editor.appendTo(this.$el);
            this.editor = ace.edit(this.$editor.get(0));
            this.editor.setTheme({
                'isDark': true,
                'cssClass': "ace-codebox",
                'cssText': ""
            });

            // Bind editor
            this.editor.session.on('change', function(e) {
                that.setTabState("modified", true);
            });

            this.editor.session.selection.on('changeCursor', function(){
                var cursor = that.editor.getSession().getSelection().getCursor();
                that.msgPosition.set("content", "Line "+(cursor.row+1)+", Column "+(cursor.column+1));
                that.trigger("cursor:change", {
                    row: cursor.row,
                    column: cursor.column
                });
            });

            // Allow commands shortcuts in the editor
            var $input = this.editor.textInput.getElement();
            var handleKeyEvent = function(e) {
                if (!e.altKey && !e.ctrlKey && !e.metaKey) return;
                keyboard.enableKeyEvent(e);
            };
            $input.addEventListener('keypress', handleKeyEvent, false);
            $input.addEventListener('keydown', handleKeyEvent, false);
            $input.addEventListener('keyup', handleKeyEvent, false);

            // Update editor layout
            this.listenTo(this.tab, "tab:layout", function() {
                this.editor.resize();
                this.editor.renderer.updateFull();
            });

            // Focus editor
            this.listenTo(this.tab, "tab:state", function(state) {
                if (state) this.focus();
            });

            // Clear editor when tab close
            this.listenTo(this.tab, "tab:close", function() {
                // Destroy the editor
                this.editor.destroy();

                // Destroy events and instance
                this.off();
                this.stopListening();
            });

            // File update
            this.listenTo(this.model, "change", this.updateFile);
            this.updateFile();

            // Read file
            this.read();
        },

        render: function() {
            this.editor.resize();
            this.editor.renderer.updateFull();

            return this.ready();
        },

        // Focus the editor
        focus: function() {
            this.editor.resize();
            this.editor.renderer.updateFull();
            this.editor.focus();
        },

        // Update file
        updateFile: function() {
            this.editor.getSession().setMode("ace/mode/"+languages.getModeByExtension(this.model.getExtension()));
        },

        // Set editor content
        setContent: function(content) {
            return this.editor.setValue(content);
        },

        // Get editor content
        getContent: function(content) {
            return this.editor.getValue();
        },

        // Read the file
        read: function() {
            var that = this;

            return this.model.read()
            .then(function(content) {
                that.setContent(content);
                that.moveCursor(0, 0);
                that.setTabState("modified", false);
                that.focus();
            });
        },

        // Write the file
        write: function() {
            var that = this;

            return this.model.write(this.getContent())
            .then(function() {
                that.setTabState("modified", false);
            });
        },

        // Move cursor
        moveCursor: function(x, y) {
            this.editor.gotoLine(x, y);
        }
    });

    return Tab;
});<commit_msg>Improve api for editor<commit_after>define([
    "ace",
    "src/languages"
], function(ace, languages) {
    var hr = codebox.require("hr/hr");
    var keyboard = codebox.require("utils/keyboard");

    // Import ace
    var aceRange =  ace.require("ace/range");
    var aceModes = ace.require("ace/ext/modelist");
    var aceLangs = ace.require("ace/ext/language_tools");
    var aceWhitespace = ace.require("ace/ext/whitespace");

    var Tab = codebox.tabs.Panel.extend({
        className: "component-editor",

        initialize: function() {
            var that = this;
            Tab.__super__.initialize.apply(this, arguments);

            // Status bar messages
            this.msgPosition = this.statusbar.add({});
            this.listenTo(this, "cursor:change", this.onCursorChange);

            this.msgMode = this.statusbar.add({ position: "right" });
            this.listenTo(this, "mode:change", this.onModeChange);

            // Init the ace editor
            this.initEditor();

            // Init the tab
            this.initTab();

            // Init the file
            this.initFile();

            this.onCursorChange();
            this.onModeChange();
        },

        render: function() {
            this.editor.resize();
            this.editor.renderer.updateFull();

            return this.ready();
        },

        // Focus the editor
        focus: function() {
            this.editor.resize();
            this.editor.renderer.updateFull();
            this.editor.focus();
        },

        // Init editor
        initEditor: function() {
            var that = this;

            this.$editor = $("<div>", {
                'class': "editor-content"
            });
            this.$editor.appendTo(this.$el);
            this.editor = ace.edit(this.$editor.get(0));

            this.editor.setTheme({
                'isDark': true,
                'cssClass': "ace-codebox",
                'cssText': ""
            });

            this.editor.session.on('change', function(e) {
                that.setTabState("modified", true);
                that.trigger("content:change");
            });

            this.editor.session.selection.on('changeCursor', function() {
                that.trigger("cursor:change", that.getCursor());
            });

            this.editor.session.on('modeCursor', function() {
                that.trigger("mode:change", that.getMode());
            });

            // Allow commands shortcuts in the editor
            var $input = this.editor.textInput.getElement();
            var handleKeyEvent = function(e) {
                if (!e.altKey && !e.ctrlKey && !e.metaKey) return;
                keyboard.enableKeyEvent(e);
            };
            $input.addEventListener('keypress', handleKeyEvent, false);
            $input.addEventListener('keydown', handleKeyEvent, false);
            $input.addEventListener('keyup', handleKeyEvent, false);
        },

        // Init the tab
        initTab: function() {
            this.listenTo(this.tab, "tab:layout", function() {
                this.editor.resize();
                this.editor.renderer.updateFull();
            });

            this.listenTo(this.tab, "tab:state", function(state) {
                if (state) this.focus();
            });

            this.listenTo(this.tab, "tab:close", function() {
                // Destroy the editor
                this.editor.destroy();

                // Destroy events and instance
                this.off();
                this.stopListening();
            });
        },

        // Init the file
        initFile: function() {
            this.listenTo(this.model, "change", this.onFileChange);
            this.onFileChange();

            // Read file
            this.read();
        },

        ///// Content management

        // Set editor content
        setContent: function(content) {
            return this.editor.setValue(content);
        },

        // Get editor content
        getContent: function(content) {
            return this.editor.getValue();
        },

        ///// File management

        // Read the file
        read: function() {
            var that = this;

            return this.model.read()
            .then(function(content) {
                that.setContent(content);
                that.moveCursor(0, 0);
                that.setTabState("modified", false);
                that.focus();
            });
        },

        // Write the file
        write: function() {
            var that = this;

            return this.model.write(this.getContent())
            .then(function() {
                that.setTabState("modified", false);
            });
        },

        ///// Cursor management

        // Move cursor
        moveCursor: function(x, y) {
            this.editor.gotoLine(x, y);
        },

        // Return cursor position
        getCursor: function() {
            var cursor = this.editor.getSession().getSelection().getCursor();
            return {
                row: cursor.row,
                column: cursor.column
            };
        },

        ///// Settings management

        // Define the mode
        setMode: function(mode) {
            this.editor.session.setMode("ace/mode/"+mode);
        },

        // Return the mode
        getMode: function() {
            return this.editor.session.getMode().$id.replace("ace/mode/", "");
        },

        ///// Events

        // Update file
        onFileChange: function() {
            this.setMode(languages.getModeByExtension(this.model.getExtension()));
        },

        // Cursor move
        onCursorChange: function() {
            var cursor = this.getCursor();
            this.msgPosition.set("content", "Line "+(cursor.row+1)+", Column "+(cursor.column+1));
        },

        // Mode change
        onModeChange: function() {
            var mode = this.getMode();
            this.msgMode.set("content", mode);
        }
    });

    return Tab;
});<|endoftext|>


<commit_before>"use strict";

module.exports = function() {

	//Occupy the global variable of Chart, and create a simple base class
	var Chart = function(context, config) {
		var me = this;
		var helpers = Chart.helpers;
		me.config = config;

		// Support a jQuery'd canvas element
		if (context.length && context[0].getContext) {
			context = context[0];
		}

		// Support a canvas domnode
		if (context.getContext) {
			context = context.getContext("2d");
		}

		me.ctx = context;
		me.canvas = context.canvas;

		// Figure out what the size of the chart will be.
		// If the canvas has a specified width and height, we use those else
		// we look to see if the canvas node has a CSS width and height.
		// If there is still no height, fill the parent container
		me.width = context.canvas.width || parseInt(helpers.getStyle(context.canvas, 'width'), 10) || helpers.getMaximumWidth(context.canvas);
		me.height = context.canvas.height || parseInt(helpers.getStyle(context.canvas, 'height'), 10) || helpers.getMaximumHeight(context.canvas);

		me.aspectRatio = me.width / me.height;

		if (isNaN(me.aspectRatio) || isFinite(me.aspectRatio) === false) {
			// If the canvas has no size, try and figure out what the aspect ratio will be.
			// Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
			// else use the canvas default ratio of 2
			me.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
		}

		// Store the original style of the element so we can set it back
		me.originalCanvasStyleWidth = context.canvas.style.width;
		me.originalCanvasStyleHeight = context.canvas.style.height;

		// High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
		helpers.retinaScale(me);

		if (config) {
			me.controller = new Chart.Controller(me);
		}

		// Always bind this so that if the responsive state changes we still work
		helpers.addResizeListener(context.canvas.parentNode, function() {
			if (me.controller && me.controller.config.options.responsive) {
				me.controller.resize();
			}
		});

		return me.controller ? me.controller : me;

	};

	//Globally expose the defaults to allow for user updating/changing
	Chart.defaults = {
		global: {
			responsive: true,
			responsiveAnimationDuration: 0,
			maintainAspectRatio: true,
			events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"],
			hover: {
				onHover: null,
				mode: 'single',
				animationDuration: 400
			},
			onClick: null,
			defaultColor: 'rgba(0,0,0,0.1)',
			defaultFontColor: '#666',
			defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
			defaultFontSize: 12,
			defaultFontStyle: 'normal',
			showLines: true,

			// Element defaults defined in element extensions
			elements: {},

			// Legend callback string
			legendCallback: function(chart) {
				var text = [];
				text.push('
');
				for (var i = 0; i < chart.data.datasets.length; i++) {
					text.push('
');
					if (chart.data.datasets[i].label) {
						text.push(chart.data.datasets[i].label);
					}
					text.push('
');
				}
				text.push('
');

				return text.join("");
			}
		}
	};

	return Chart;

};
<commit_msg>Added a reference to Chart within Chart for Issue #2483<commit_after>"use strict";

module.exports = function() {

	//Occupy the global variable of Chart, and create a simple base class
	var Chart = function(context, config) {
		var me = this;
		var helpers = Chart.helpers;
		me.config = config;

		// Support a jQuery'd canvas element
		if (context.length && context[0].getContext) {
			context = context[0];
		}

		// Support a canvas domnode
		if (context.getContext) {
			context = context.getContext("2d");
		}

		me.ctx = context;
		me.canvas = context.canvas;

		// Figure out what the size of the chart will be.
		// If the canvas has a specified width and height, we use those else
		// we look to see if the canvas node has a CSS width and height.
		// If there is still no height, fill the parent container
		me.width = context.canvas.width || parseInt(helpers.getStyle(context.canvas, 'width'), 10) || helpers.getMaximumWidth(context.canvas);
		me.height = context.canvas.height || parseInt(helpers.getStyle(context.canvas, 'height'), 10) || helpers.getMaximumHeight(context.canvas);

		me.aspectRatio = me.width / me.height;

		if (isNaN(me.aspectRatio) || isFinite(me.aspectRatio) === false) {
			// If the canvas has no size, try and figure out what the aspect ratio will be.
			// Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
			// else use the canvas default ratio of 2
			me.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
		}

		// Store the original style of the element so we can set it back
		me.originalCanvasStyleWidth = context.canvas.style.width;
		me.originalCanvasStyleHeight = context.canvas.style.height;

		// High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
		helpers.retinaScale(me);

		if (config) {
			me.controller = new Chart.Controller(me);
		}

		// Always bind this so that if the responsive state changes we still work
		helpers.addResizeListener(context.canvas.parentNode, function() {
			if (me.controller && me.controller.config.options.responsive) {
				me.controller.resize();
			}
		});

		return me.controller ? me.controller : me;

	};

	//Globally expose the defaults to allow for user updating/changing
	Chart.defaults = {
		global: {
			responsive: true,
			responsiveAnimationDuration: 0,
			maintainAspectRatio: true,
			events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"],
			hover: {
				onHover: null,
				mode: 'single',
				animationDuration: 400
			},
			onClick: null,
			defaultColor: 'rgba(0,0,0,0.1)',
			defaultFontColor: '#666',
			defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
			defaultFontSize: 12,
			defaultFontStyle: 'normal',
			showLines: true,

			// Element defaults defined in element extensions
			elements: {},

			// Legend callback string
			legendCallback: function(chart) {
				var text = [];
				text.push('
');
				for (var i = 0; i < chart.data.datasets.length; i++) {
					text.push('
');
					if (chart.data.datasets[i].label) {
						text.push(chart.data.datasets[i].label);
					}
					text.push('
');
				}
				text.push('
');

				return text.join("");
			}
		}
	};

	Chart.Chart = Chart;

	return Chart;

};
<|endoftext|>


<commit_before>var React = require('react');
var Page = require('./components/AutoCompleter');

class App extends React.Component {

  render() {
    return (

AutoCompleter

        <Page/>

    );
  }

}

React.render(<App/>, document.getElementById('app'));
<commit_msg>SHIT GOT REAL, WiP<commit_after>var React = require('react');
var AutoCompleter = require('./components/AutoCompleter');
var EditTable = require('./components/EditTable');

class App extends React.Component {

  render() {
    return (

AutoCompleter

        <AutoCompleter/>
        <EditTable/>

    );
  }

}

React.render(<App/>, document.getElementById('app'));
<|endoftext|>


<commit_before>#!/usr/bin/env seed

Gtk = imports.gi.Gtk;
Gst = imports.gi.Gst;
GObject = imports.gi.GObject;

Gst.init(Seed.argv);
Gtk.init(Seed.argv);

var pipeline = new Gst.Pipeline({name: "test"});
var unique_id = 0;

OscillatorWidget = new GType({
	parent: Gtk.VBox.type,
	name: "OscillatorWidget",
	class_init: function(klass, prototype)
	{
		var flags = (GObject.ParamFlags.CONSTRUCT |
					 GObject.ParamFlags.READABLE |
					 GObject.ParamFlags.WRITABLE);

		var ps = GObject.param_spec_int("frequency",
										"Oscillator Frequency",
										"The frequency of the audiotestsrc.",
										0, 3000, 1000, flags);

		klass.c_install_property(ps);
	},
	init: function(klass)
	{
		// Private

		var hbox = new Gtk.HBox();
		var frequency_slider = new Gtk.VScale();
		var volume_slider = new Gtk.VScale();
		var button = new Gtk.ToggleButton({label: "Enabled"});

		// No actual introspection data for audiotestsrc, so can not
		// instantiate one with a constructor, have to use element_factory,
		// likewise for the others.
		var audiosrc = Gst.ElementFactory.make("audiotestsrc", "source" + unique_id);
		var audiosink = Gst.ElementFactory.make("alsasink", "sink" + unique_id);
		var volume = Gst.ElementFactory.make("volume", "volume" + unique_id);

		unique_id++;

		var toggle_enabled = function(button, that)
		{
			pipeline.set_state(Gst.State.PLAYING);
			volume.volume = button.active ? volume_slider.get_value() : 0;
		};

		var set_frequency = function(range)
		{
			this.frequency = audiosrc.freq = range.get_value();
		};

		var set_volume = function(range)
		{
			if(button.active)
				volume.volume = range.get_value();
		};

		// Implementation

		frequency_slider.adjustment.upper = 3000;
		audiosrc.freq = frequency_slider.adjustment.value = this.frequency;

		volume_slider.adjustment.upper = 10;
		volume_slider.adjustment.value = 1;
		volume.volume = 0;

		pipeline.add(audiosrc);
		pipeline.add(audiosink);
		pipeline.add(volume);
		audiosrc.link(volume);
		volume.link(audiosink);

		button.signal.toggled.connect(toggle_enabled);
		frequency_slider.signal.value_changed.connect(set_frequency);
		volume_slider.signal.value_changed.connect(set_volume);

		hbox.pack_start(frequency_slider, true, true, 10);
		hbox.pack_start(volume_slider, true, true, 10);
		this.pack_start(hbox, true, true, 10);
		this.pack_start(button, false, false, 10);
	}
});

var window = new Gtk.Window();
var button = new Gtk.Button({label: "Add Oscillator"});

window.signal.hide.connect(Gtk.main_quit);
window.resize(600,300);

var hbox = new Gtk.HBox();

function add_oscillator(button)
{
    var os = new OscillatorWidget();
    hbox.pack_start(os, true, true, 10);
    os.show_all();
}
button.signal.clicked.connect(add_oscillator);

window.add(hbox);
hbox.pack_start(button, true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:523.25}), true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:659.26}), true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:783.99}), true, true, 10);
window.show_all();

Gtk.main();

<commit_msg>N-Oscillator: Use float property, not int. Breaking our chord!<commit_after>#!/usr/bin/env seed

Gtk = imports.gi.Gtk;
Gst = imports.gi.Gst;
GObject = imports.gi.GObject;

Gst.init(Seed.argv);
Gtk.init(Seed.argv);

var pipeline = new Gst.Pipeline({name: "test"});
var unique_id = 0;

OscillatorWidget = new GType({
	parent: Gtk.VBox.type,
	name: "OscillatorWidget",
	class_init: function(klass, prototype)
	{
		var flags = (GObject.ParamFlags.CONSTRUCT |
					 GObject.ParamFlags.READABLE |
					 GObject.ParamFlags.WRITABLE);

		var ps = GObject.param_spec_float("frequency",
										  "Oscillator Frequency",
										  "The frequency of the audiotestsrc.",
										  0, 3000, 1000, flags);

		klass.c_install_property(ps);
	},
	init: function(klass)
	{
		// Private

		var hbox = new Gtk.HBox();
		var frequency_slider = new Gtk.VScale();
		var volume_slider = new Gtk.VScale();
		var button = new Gtk.ToggleButton({label: "Enabled"});

		// No actual introspection data for audiotestsrc, so can not
		// instantiate one with a constructor, have to use element_factory,
		// likewise for the others.
		var audiosrc = Gst.ElementFactory.make("audiotestsrc", "source" + unique_id);
		var audiosink = Gst.ElementFactory.make("alsasink", "sink" + unique_id);
		var volume = Gst.ElementFactory.make("volume", "volume" + unique_id);

		unique_id++;

		var toggle_enabled = function(button, that)
		{
			pipeline.set_state(Gst.State.PLAYING);
			volume.volume = button.active ? volume_slider.get_value() : 0;
		};

		var set_frequency = function(range)
		{
			this.frequency = audiosrc.freq = range.get_value();
		};

		var set_volume = function(range)
		{
			if(button.active)
				volume.volume = range.get_value();
		};

		// Implementation

		frequency_slider.adjustment.upper = 3000;
		audiosrc.freq = frequency_slider.adjustment.value = this.frequency;

		volume_slider.adjustment.upper = 10;
		volume_slider.adjustment.value = 0.5;
		volume.volume = 0;

		pipeline.add(audiosrc);
		pipeline.add(audiosink);
		pipeline.add(volume);
		audiosrc.link(volume);
		volume.link(audiosink);

		button.signal.toggled.connect(toggle_enabled);
		frequency_slider.signal.value_changed.connect(set_frequency);
		volume_slider.signal.value_changed.connect(set_volume);

		hbox.pack_start(frequency_slider, true, true, 10);
		hbox.pack_start(volume_slider, true, true, 10);
		this.pack_start(hbox, true, true, 10);
		this.pack_start(button, false, false, 10);
	}
});

var window = new Gtk.Window();
var button = new Gtk.Button({label: "Add Oscillator"});

window.signal.hide.connect(Gtk.main_quit);
window.resize(600,300);

var hbox = new Gtk.HBox();

function add_oscillator(button)
{
    var os = new OscillatorWidget();
    hbox.pack_start(os, true, true, 10);
    os.show_all();
}
button.signal.clicked.connect(add_oscillator);

window.add(hbox);
hbox.pack_start(button, true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:523.25}), true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:659.26}), true, true, 10);
hbox.pack_start(new OscillatorWidget({frequency:783.99}), true, true, 10);
window.show_all();

Gtk.main();

<|endoftext|>


<commit_before>const __ = require('lodash3')
const _ = require('lodash')
const acyclic = require('./acyclic')
const normalize = require('./normalize')
const rank = require('./rank')
const normalizeRanks = require('./util').normalizeRanks
const parentDummyChains = require('./parent-dummy-chains')
const removeEmptyRanks = require('./util').removeEmptyRanks
const nestingGraph = require('./nesting-graph')
const addBorderSegments = require('./add-border-segments')
const coordinateSystem = require('./coordinate-system')
const order = require('./order')
const position = require('./position')
const util = require('./util')
const Graph = require('./graphlib').Graph

module.exports = layout

function layout (g, opts) {
  const time = opts && opts.debugTiming ? util.time : util.notime
  time('layout', function () {
    const layoutGraph = time('  buildLayoutGraph',
                               function () { return buildLayoutGraph(g) })
    time('  runLayout', function () { runLayout(layoutGraph, time) })
    time('  updateInputGraph', function () { updateInputGraph(g, layoutGraph) })
  })
}

function runLayout (g, time) {
  time('    makeSpaceForEdgeLabels', function () { makeSpaceForEdgeLabels(g) })
  time('    removeSelfEdges', function () { removeSelfEdges(g) })
  time('    acyclic', function () { acyclic.run(g) })
  time('    nestingGraph.run', function () { nestingGraph.run(g) })
  time('    rank', function () { rank(util.asNonCompoundGraph(g)) })
  time('    injectEdgeLabelProxies', function () { injectEdgeLabelProxies(g) })
  time('    removeEmptyRanks', function () { removeEmptyRanks(g) })
  time('    nestingGraph.cleanup', function () { nestingGraph.cleanup(g) })
  time('    normalizeRanks', function () { normalizeRanks(g) })
  time('    assignRankMinMax', function () { assignRankMinMax(g) })
  time('    removeEdgeLabelProxies', function () { removeEdgeLabelProxies(g) })
  time('    normalize.run', function () { normalize.run(g) })
  time('    parentDummyChains', function () { parentDummyChains(g) })
  time('    addBorderSegments', function () { addBorderSegments(g) })
  time('    order', function () { order(g) })
  time('    insertSelfEdges', function () { insertSelfEdges(g) })
  time('    adjustCoordinateSystem', function () { coordinateSystem.adjust(g) })
  time('    position', function () { position(g) })
  time('    positionSelfEdges', function () { positionSelfEdges(g) })
  time('    removeBorderNodes', function () { removeBorderNodes(g) })
  time('    normalize.undo', function () { normalize.undo(g) })
  time('    fixupEdgeLabelCoords', function () { fixupEdgeLabelCoords(g) })
  time('    undoCoordinateSystem', function () { coordinateSystem.undo(g) })
  time('    translateGraph', function () { translateGraph(g) })
  time('    assignNodeIntersects', function () { assignNodeIntersects(g) })
  time('    reversePoints', function () { reversePointsForReversedEdges(g) })
  time('    acyclic.undo', function () { acyclic.undo(g) })
}

/*
 * Copies final layout information from the layout graph back to the input
 * graph. This process only copies whitelisted attributes from the layout graph
 * to the input graph, so it serves as a good place to determine what
 * attributes can influence layout.
 */
function updateInputGraph (inputGraph, layoutGraph) {
  _.each(inputGraph.nodes(), function (v) {
    const inputLabel = inputGraph.node(v)
    const layoutLabel = layoutGraph.node(v)

    if (inputLabel) {
      inputLabel.x = layoutLabel.x
      inputLabel.y = layoutLabel.y

      if (layoutGraph.children(v).length) {
        inputLabel.width = layoutLabel.width
        inputLabel.height = layoutLabel.height
      }
    }
  })

  _.each(inputGraph.edges(), function (e) {
    const inputLabel = inputGraph.edge(e)
    const layoutLabel = layoutGraph.edge(e)

    inputLabel.points = layoutLabel.points
    if (_.has(layoutLabel, 'x')) {
      inputLabel.x = layoutLabel.x
      inputLabel.y = layoutLabel.y
    }
  })

  inputGraph.graph().width = layoutGraph.graph().width
  inputGraph.graph().height = layoutGraph.graph().height
}

const graphNumAttrs = ['nodesep', 'edgesep', 'ranksep', 'marginx', 'marginy']
const graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' }
const graphAttrs = ['acyclicer', 'ranker', 'rankdir', 'align']
const nodeNumAttrs = ['width', 'height']
const nodeDefaults = { width: 0, height: 0 }
const edgeNumAttrs = ['minlen', 'weight', 'width', 'height', 'labeloffset']
const edgeDefaults = {
  minlen: 1,
  weight: 1,
  width: 0,
  height: 0,
  labeloffset: 10,
  labelpos: 'r'
}
const edgeAttrs = ['labelpos']

/*
 * Constructs a new graph from the input graph, which can be used for layout.
 * This process copies only whitelisted attributes from the input graph to the
 * layout graph. Thus this function serves as a good place to determine what
 * attributes can influence layout.
 */
function buildLayoutGraph (inputGraph) {
  const g = new Graph({ multigraph: true, compound: true })
  const graph = canonicalize(inputGraph.graph())

  g.setGraph(_.merge({},
    graphDefaults,
    selectNumberAttrs(graph, graphNumAttrs),
    _.pick(graph, graphAttrs)))

  _.each(inputGraph.nodes(), function (v) {
    const node = canonicalize(inputGraph.node(v))
    g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults))
    g.setParent(v, inputGraph.parent(v))
  })

  _.each(inputGraph.edges(), function (e) {
    const edge = canonicalize(inputGraph.edge(e))
    g.setEdge(e, _.merge({},
      edgeDefaults,
      selectNumberAttrs(edge, edgeNumAttrs),
      _.pick(edge, edgeAttrs)))
  })

  return g
}

/*
 * This idea comes from the Gansner paper: to account for edge labels in our
 * layout we split each rank in half by doubling minlen and halving ranksep.
 * Then we can place labels at these mid-points between nodes.
 *
 * We also add some minimal padding to the width to push the label for the edge
 * away from the edge itself a bit.
 */
function makeSpaceForEdgeLabels (g) {
  const graph = g.graph()
  graph.ranksep /= 2
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    edge.minlen *= 2
    if (edge.labelpos.toLowerCase() !== 'c') {
      if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
        edge.width += edge.labeloffset
      } else {
        edge.height += edge.labeloffset
      }
    }
  })
}

/*
 * Creates temporary dummy nodes that capture the rank in which each edge's
 * label is going to, if it has one of non-zero width and height. We do this
 * so that we can safely remove empty ranks while preserving balance for the
 * label's position.
 */
function injectEdgeLabelProxies (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (edge.width && edge.height) {
      const v = g.node(e.v)
      const w = g.node(e.w)
      const label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e }
      util.addDummyNode(g, 'edge-proxy', label, '_ep')
    }
  })
}

function assignRankMinMax (g) {
  let maxRank = 0
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.borderTop) {
      node.minRank = g.node(node.borderTop).rank
      node.maxRank = g.node(node.borderBottom).rank
      maxRank = __.max(maxRank, node.maxRank)
    }
  })
  g.graph().maxRank = maxRank
}

function removeEdgeLabelProxies (g) {
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.dummy === 'edge-proxy') {
      g.edge(node.e).labelRank = node.rank
      g.removeNode(v)
    }
  })
}

function translateGraph (g) {
  let minX = Number.POSITIVE_INFINITY
  let maxX = 0
  let minY = Number.POSITIVE_INFINITY
  let maxY = 0
  const graphLabel = g.graph()
  const marginX = graphLabel.marginx || 0
  const marginY = graphLabel.marginy || 0

  function getExtremes (attrs) {
    const x = attrs.x
    const y = attrs.y
    const w = attrs.width
    const h = attrs.height
    minX = Math.min(minX, x - w / 2)
    maxX = Math.max(maxX, x + w / 2)
    minY = Math.min(minY, y - h / 2)
    maxY = Math.max(maxY, y + h / 2)
  }

  _.each(g.nodes(), function (v) { getExtremes(g.node(v)) })
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (_.has(edge, 'x')) {
      getExtremes(edge)
    }
  })

  minX -= marginX
  minY -= marginY

  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    node.x -= minX
    node.y -= minY
  })

  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    _.each(edge.points, function (p) {
      p.x -= minX
      p.y -= minY
    })
    if (_.has(edge, 'x')) { edge.x -= minX }
    if (_.has(edge, 'y')) { edge.y -= minY }
  })

  graphLabel.width = maxX - minX + marginX
  graphLabel.height = maxY - minY + marginY
}

function assignNodeIntersects (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    const nodeV = g.node(e.v)
    const nodeW = g.node(e.w)
    let p1 = null
    let p2 = null
    if (!edge.points) {
      edge.points = []
      p1 = nodeW
      p2 = nodeV
    } else {
      p1 = edge.points[0]
      p2 = edge.points[edge.points.length - 1]
    }
    edge.points.unshift(util.intersectRect(nodeV, p1))
    edge.points.push(util.intersectRect(nodeW, p2))
  })
}

function fixupEdgeLabelCoords (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (_.has(edge, 'x')) {
      if (edge.labelpos === 'l' || edge.labelpos === 'r') {
        edge.width -= edge.labeloffset
      }
      switch (edge.labelpos) {
        case 'l': edge.x -= edge.width / 2 + edge.labeloffset; break
        case 'r': edge.x += edge.width / 2 + edge.labeloffset; break
      }
    }
  })
}

function reversePointsForReversedEdges (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (edge.reversed) {
      edge.points.reverse()
    }
  })
}

function removeBorderNodes (g) {
  _.each(g.nodes(), function (v) {
    if (g.children(v).length) {
      const node = g.node(v)
      const t = g.node(node.borderTop)
      const b = g.node(node.borderBottom)
      const l = g.node(_.last(node.borderLeft))
      const r = g.node(_.last(node.borderRight))

      node.width = Math.abs(r.x - l.x)
      node.height = Math.abs(b.y - t.y)
      node.x = l.x + node.width / 2
      node.y = t.y + node.height / 2
    }
  })

  _.each(g.nodes(), function (v) {
    if (g.node(v).dummy === 'border') {
      g.removeNode(v)
    }
  })
}

function removeSelfEdges (g) {
  _.each(g.edges(), function (e) {
    if (e.v === e.w) {
      const node = g.node(e.v)
      if (!node.selfEdges) {
        node.selfEdges = []
      }
      node.selfEdges.push({ e: e, label: g.edge(e) })
      g.removeEdge(e)
    }
  })
}

function insertSelfEdges (g) {
  const layers = util.buildLayerMatrix(g)
  _.each(layers, function (layer) {
    let orderShift = 0
    _.each(layer, function (v, i) {
      const node = g.node(v)
      node.order = i + orderShift
      _.each(node.selfEdges, function (selfEdge) {
        util.addDummyNode(g, 'selfedge', {
          width: selfEdge.label.width,
          height: selfEdge.label.height,
          rank: node.rank,
          order: i + (++orderShift),
          e: selfEdge.e,
          label: selfEdge.label
        }, '_se')
      })
      delete node.selfEdges
    })
  })
}

function positionSelfEdges (g) {
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.dummy === 'selfedge') {
      const selfNode = g.node(node.e.v)
      const x = selfNode.x + selfNode.width / 2
      const y = selfNode.y
      const dx = node.x - x
      const dy = selfNode.height / 2
      g.setEdge(node.e, node.label)
      g.removeNode(v)
      node.label.points = [
        { x: x + 2 * dx / 3, y: y - dy },
        { x: x + 5 * dx / 6, y: y - dy },
        { x: x + dx, y: y },
        { x: x + 5 * dx / 6, y: y + dy },
        { x: x + 2 * dx / 3, y: y + dy }
      ]
      node.label.x = node.x
      node.label.y = node.y
    }
  })
}

function selectNumberAttrs (obj, attrs) {
  return _.mapValues(_.pick(obj, attrs), Number)
}

function canonicalize (attrs) {
  const newAttrs = {}
  _.each(attrs, function (v, k) {
    newAttrs[k.toLowerCase()] = v
  })
  return newAttrs
}
<commit_msg>Fix _.max issue<commit_after>const __ = require('lodash3')
const _ = require('lodash')
const acyclic = require('./acyclic')
const normalize = require('./normalize')
const rank = require('./rank')
const normalizeRanks = require('./util').normalizeRanks
const parentDummyChains = require('./parent-dummy-chains')
const removeEmptyRanks = require('./util').removeEmptyRanks
const nestingGraph = require('./nesting-graph')
const addBorderSegments = require('./add-border-segments')
const coordinateSystem = require('./coordinate-system')
const order = require('./order')
const position = require('./position')
const util = require('./util')
const Graph = require('./graphlib').Graph

module.exports = layout

function layout (g, opts) {
  const time = opts && opts.debugTiming ? util.time : util.notime
  time('layout', function () {
    const layoutGraph = time('  buildLayoutGraph',
                               function () { return buildLayoutGraph(g) })
    time('  runLayout', function () { runLayout(layoutGraph, time) })
    time('  updateInputGraph', function () { updateInputGraph(g, layoutGraph) })
  })
}

function runLayout (g, time) {
  time('    makeSpaceForEdgeLabels', function () { makeSpaceForEdgeLabels(g) })
  time('    removeSelfEdges', function () { removeSelfEdges(g) })
  time('    acyclic', function () { acyclic.run(g) })
  time('    nestingGraph.run', function () { nestingGraph.run(g) })
  time('    rank', function () { rank(util.asNonCompoundGraph(g)) })
  time('    injectEdgeLabelProxies', function () { injectEdgeLabelProxies(g) })
  time('    removeEmptyRanks', function () { removeEmptyRanks(g) })
  time('    nestingGraph.cleanup', function () { nestingGraph.cleanup(g) })
  time('    normalizeRanks', function () { normalizeRanks(g) })
  time('    assignRankMinMax', function () { assignRankMinMax(g) })
  time('    removeEdgeLabelProxies', function () { removeEdgeLabelProxies(g) })
  time('    normalize.run', function () { normalize.run(g) })
  time('    parentDummyChains', function () { parentDummyChains(g) })
  time('    addBorderSegments', function () { addBorderSegments(g) })
  time('    order', function () { order(g) })
  time('    insertSelfEdges', function () { insertSelfEdges(g) })
  time('    adjustCoordinateSystem', function () { coordinateSystem.adjust(g) })
  time('    position', function () { position(g) })
  time('    positionSelfEdges', function () { positionSelfEdges(g) })
  time('    removeBorderNodes', function () { removeBorderNodes(g) })
  time('    normalize.undo', function () { normalize.undo(g) })
  time('    fixupEdgeLabelCoords', function () { fixupEdgeLabelCoords(g) })
  time('    undoCoordinateSystem', function () { coordinateSystem.undo(g) })
  time('    translateGraph', function () { translateGraph(g) })
  time('    assignNodeIntersects', function () { assignNodeIntersects(g) })
  time('    reversePoints', function () { reversePointsForReversedEdges(g) })
  time('    acyclic.undo', function () { acyclic.undo(g) })
}

/*
 * Copies final layout information from the layout graph back to the input
 * graph. This process only copies whitelisted attributes from the layout graph
 * to the input graph, so it serves as a good place to determine what
 * attributes can influence layout.
 */
function updateInputGraph (inputGraph, layoutGraph) {
  _.each(inputGraph.nodes(), function (v) {
    const inputLabel = inputGraph.node(v)
    const layoutLabel = layoutGraph.node(v)

    if (inputLabel) {
      inputLabel.x = layoutLabel.x
      inputLabel.y = layoutLabel.y

      if (layoutGraph.children(v).length) {
        inputLabel.width = layoutLabel.width
        inputLabel.height = layoutLabel.height
      }
    }
  })

  _.each(inputGraph.edges(), function (e) {
    const inputLabel = inputGraph.edge(e)
    const layoutLabel = layoutGraph.edge(e)

    inputLabel.points = layoutLabel.points
    if (_.has(layoutLabel, 'x')) {
      inputLabel.x = layoutLabel.x
      inputLabel.y = layoutLabel.y
    }
  })

  inputGraph.graph().width = layoutGraph.graph().width
  inputGraph.graph().height = layoutGraph.graph().height
}

const graphNumAttrs = ['nodesep', 'edgesep', 'ranksep', 'marginx', 'marginy']
const graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' }
const graphAttrs = ['acyclicer', 'ranker', 'rankdir', 'align']
const nodeNumAttrs = ['width', 'height']
const nodeDefaults = { width: 0, height: 0 }
const edgeNumAttrs = ['minlen', 'weight', 'width', 'height', 'labeloffset']
const edgeDefaults = {
  minlen: 1,
  weight: 1,
  width: 0,
  height: 0,
  labeloffset: 10,
  labelpos: 'r'
}
const edgeAttrs = ['labelpos']

/*
 * Constructs a new graph from the input graph, which can be used for layout.
 * This process copies only whitelisted attributes from the input graph to the
 * layout graph. Thus this function serves as a good place to determine what
 * attributes can influence layout.
 */
function buildLayoutGraph (inputGraph) {
  const g = new Graph({ multigraph: true, compound: true })
  const graph = canonicalize(inputGraph.graph())

  g.setGraph(_.merge({},
    graphDefaults,
    selectNumberAttrs(graph, graphNumAttrs),
    _.pick(graph, graphAttrs)))

  _.each(inputGraph.nodes(), function (v) {
    const node = canonicalize(inputGraph.node(v))
    g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults))
    g.setParent(v, inputGraph.parent(v))
  })

  _.each(inputGraph.edges(), function (e) {
    const edge = canonicalize(inputGraph.edge(e))
    g.setEdge(e, _.merge({},
      edgeDefaults,
      selectNumberAttrs(edge, edgeNumAttrs),
      _.pick(edge, edgeAttrs)))
  })

  return g
}

/*
 * This idea comes from the Gansner paper: to account for edge labels in our
 * layout we split each rank in half by doubling minlen and halving ranksep.
 * Then we can place labels at these mid-points between nodes.
 *
 * We also add some minimal padding to the width to push the label for the edge
 * away from the edge itself a bit.
 */
function makeSpaceForEdgeLabels (g) {
  const graph = g.graph()
  graph.ranksep /= 2
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    edge.minlen *= 2
    if (edge.labelpos.toLowerCase() !== 'c') {
      if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
        edge.width += edge.labeloffset
      } else {
        edge.height += edge.labeloffset
      }
    }
  })
}

/*
 * Creates temporary dummy nodes that capture the rank in which each edge's
 * label is going to, if it has one of non-zero width and height. We do this
 * so that we can safely remove empty ranks while preserving balance for the
 * label's position.
 */
function injectEdgeLabelProxies (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (edge.width && edge.height) {
      const v = g.node(e.v)
      const w = g.node(e.w)
      const label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e }
      util.addDummyNode(g, 'edge-proxy', label, '_ep')
    }
  })
}

function assignRankMinMax (g) {
  let maxRank = 0
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.borderTop) {
      node.minRank = g.node(node.borderTop).rank
      node.maxRank = g.node(node.borderBottom).rank
      maxRank = _.max([maxRank, node.maxRank])
    }
  })
  g.graph().maxRank = maxRank
}

function removeEdgeLabelProxies (g) {
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.dummy === 'edge-proxy') {
      g.edge(node.e).labelRank = node.rank
      g.removeNode(v)
    }
  })
}

function translateGraph (g) {
  let minX = Number.POSITIVE_INFINITY
  let maxX = 0
  let minY = Number.POSITIVE_INFINITY
  let maxY = 0
  const graphLabel = g.graph()
  const marginX = graphLabel.marginx || 0
  const marginY = graphLabel.marginy || 0

  function getExtremes (attrs) {
    const x = attrs.x
    const y = attrs.y
    const w = attrs.width
    const h = attrs.height
    minX = Math.min(minX, x - w / 2)
    maxX = Math.max(maxX, x + w / 2)
    minY = Math.min(minY, y - h / 2)
    maxY = Math.max(maxY, y + h / 2)
  }

  _.each(g.nodes(), function (v) { getExtremes(g.node(v)) })
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (_.has(edge, 'x')) {
      getExtremes(edge)
    }
  })

  minX -= marginX
  minY -= marginY

  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    node.x -= minX
    node.y -= minY
  })

  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    _.each(edge.points, function (p) {
      p.x -= minX
      p.y -= minY
    })
    if (_.has(edge, 'x')) { edge.x -= minX }
    if (_.has(edge, 'y')) { edge.y -= minY }
  })

  graphLabel.width = maxX - minX + marginX
  graphLabel.height = maxY - minY + marginY
}

function assignNodeIntersects (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    const nodeV = g.node(e.v)
    const nodeW = g.node(e.w)
    let p1 = null
    let p2 = null
    if (!edge.points) {
      edge.points = []
      p1 = nodeW
      p2 = nodeV
    } else {
      p1 = edge.points[0]
      p2 = edge.points[edge.points.length - 1]
    }
    edge.points.unshift(util.intersectRect(nodeV, p1))
    edge.points.push(util.intersectRect(nodeW, p2))
  })
}

function fixupEdgeLabelCoords (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (_.has(edge, 'x')) {
      if (edge.labelpos === 'l' || edge.labelpos === 'r') {
        edge.width -= edge.labeloffset
      }
      switch (edge.labelpos) {
        case 'l': edge.x -= edge.width / 2 + edge.labeloffset; break
        case 'r': edge.x += edge.width / 2 + edge.labeloffset; break
      }
    }
  })
}

function reversePointsForReversedEdges (g) {
  _.each(g.edges(), function (e) {
    const edge = g.edge(e)
    if (edge.reversed) {
      edge.points.reverse()
    }
  })
}

function removeBorderNodes (g) {
  _.each(g.nodes(), function (v) {
    if (g.children(v).length) {
      const node = g.node(v)
      const t = g.node(node.borderTop)
      const b = g.node(node.borderBottom)
      const l = g.node(_.last(node.borderLeft))
      const r = g.node(_.last(node.borderRight))

      node.width = Math.abs(r.x - l.x)
      node.height = Math.abs(b.y - t.y)
      node.x = l.x + node.width / 2
      node.y = t.y + node.height / 2
    }
  })

  _.each(g.nodes(), function (v) {
    if (g.node(v).dummy === 'border') {
      g.removeNode(v)
    }
  })
}

function removeSelfEdges (g) {
  _.each(g.edges(), function (e) {
    if (e.v === e.w) {
      const node = g.node(e.v)
      if (!node.selfEdges) {
        node.selfEdges = []
      }
      node.selfEdges.push({ e: e, label: g.edge(e) })
      g.removeEdge(e)
    }
  })
}

function insertSelfEdges (g) {
  const layers = util.buildLayerMatrix(g)
  _.each(layers, function (layer) {
    let orderShift = 0
    _.each(layer, function (v, i) {
      const node = g.node(v)
      node.order = i + orderShift
      _.each(node.selfEdges, function (selfEdge) {
        util.addDummyNode(g, 'selfedge', {
          width: selfEdge.label.width,
          height: selfEdge.label.height,
          rank: node.rank,
          order: i + (++orderShift),
          e: selfEdge.e,
          label: selfEdge.label
        }, '_se')
      })
      delete node.selfEdges
    })
  })
}

function positionSelfEdges (g) {
  _.each(g.nodes(), function (v) {
    const node = g.node(v)
    if (node.dummy === 'selfedge') {
      const selfNode = g.node(node.e.v)
      const x = selfNode.x + selfNode.width / 2
      const y = selfNode.y
      const dx = node.x - x
      const dy = selfNode.height / 2
      g.setEdge(node.e, node.label)
      g.removeNode(v)
      node.label.points = [
        { x: x + 2 * dx / 3, y: y - dy },
        { x: x + 5 * dx / 6, y: y - dy },
        { x: x + dx, y: y },
        { x: x + 5 * dx / 6, y: y + dy },
        { x: x + 2 * dx / 3, y: y + dy }
      ]
      node.label.x = node.x
      node.label.y = node.y
    }
  })
}

function selectNumberAttrs (obj, attrs) {
  return _.mapValues(_.pick(obj, attrs), Number)
}

function canonicalize (attrs) {
  const newAttrs = {}
  _.each(attrs, function (v, k) {
    newAttrs[k.toLowerCase()] = v
  })
  return newAttrs
}
<|endoftext|>