<commit_before>(function () {

    var root = this,
        FBP = (function () {
        var _c = {},
            _g = {};
        return {
            component: function (config, taskConfig) {
                if (arguments.length === 1) {
                    // getter
                    return _c[config];
                } else {
                    // setter i.e. constructor
                    // if 1st argument is an array, we construct several instances
                    var name = null,
                        _inN = 0,
                        task = null,
                        state = null;
                    if ('string' === typeof config) {
                        name = config;
                    } else {
                        name = config.name;
                        state = config.state || {};
                    }
                    if (_c[name]) {
                        throw 'component has already defined';
                    }
                    _inN = taskConfig.length - 1;
                    task = taskConfig[_inN];
                    if (_inN !== task.length - 1) {
                        throw 'in port numbers do not match';
                    }
                    taskConfig.splice(_inN, 1);
                    _c[name] = {
                        name: name,
                        addInput: function (value, inPort) {
                            this.inN = this.inN + 1;
                            this.inputs[inPort] = value;
                            if (this.inN >= this._inN) {
                                FBP.graph(this.graph).invokeComponent(this);
                            }
                        },
                        inputs: {},
                        inN: 0,
                        _inN: _inN,
                        args: taskConfig,
                        task: task,
                        state: state
                    };
                }
            },
            graph: function (name) {
                // graph getter
                return _g[name];
            },
            setup: function (name, constructor) {
                // graph constructor
                var graphName = name,
                    components = [],
                    inPorts = [],
                    inN = 0,
                    outN = 0,
                    dests = {},
                    F = {
                        init: function (name, port) {
                            var component = FBP.component(name);
                            component.graph = graphName;
                            components.push(name);
                            inPorts[name + '.' + port] = {
                                name: name,
                                port: port
                            };
                            inN = inN + 1;
                        },
                        connect: function (fromName, fromPort, toName, toPort) {
                            var toComponent = FBP.component(toName);
                            if (!toComponent.graph || toComponent.graph !== graphName) {
                                toComponent.graph = graphName;
                                components.push(toName);
                            }
                            dests[fromName + '.' + fromPort] = {
                                name: toName,
                                port: toPort
                            };
                        },
                        end: function (name, port) {
                            dests[name + '.' + port] = 'end';
                            outN = outN + 1;
                        }
                    };
                constructor(F);
                F.name = graphName;
                F.components = components;
                F.inPorts = inPorts;
                F.inN = inN;
                F.outN = outN;
                F.outputs = {};
                F.dests = dests;
                F.go = function (inputs, callback) {
                    this.callback = callback;
                    this.tic = Date.now();
                    var input, component, inPort;
                    for (input in inputs) { if (inputs.hasOwnProperty(input)) {
                        component = FBP.component(this.inPorts[input].name);
                        inPort = this.inPorts[input].port;
                        component.addInput(inputs[input], inPort);
                    }}
                };
                F.sendOutput = function (output, outPort) {
                    var interval = Date.now() - this.tic;
                    this.outputs[outPort] = output;
                    this.callback.apply(this, [ null, {
                        outputs: this.outputs,
                        interval: interval
                    }]);
                };
                F.invokeComponent = function (component) {
                    var that = this,
                        input = [],
                        i = 0;
                    for (i; i < component.args.length; i = i + 1) {
                        input[i] = component.inputs[component.args[i]];
                    }
                    input[i] = function (outPort, value) {
                        var destName = component.name + '.' + outPort;
                            dest = that.dests[destName];
                        if (dest === 'end') {
                            that.sendOutput(value, destName);
                        } else {
                            FBP.component(dest.name).addInput(value, dest.port);
                        }
                    };
                    component.task.bind(component.state).apply(component, input);
                };
                _g[arguments[0]] = F;
            }
        }
    }());

    if ('undefined' !== typeof exports) {
        if ('undefined' !== typeof module && module.exports) {
            exports = module.exports = FBP;
        }
        exports.FBP = FBP;
    } else {
        root.FBP = FBP;
    }

}());
<commit_msg>improve component quality<commit_after>(function () {

    var root = this,
        objIterate = function (obj, iterate) {
            for (var O in obj) {
                if (obj.hasOwnProperty(O)) {
                    iterate(O);
                }
            }
        },
        objLength = function (obj) {
            var n = 0;
            objIterate(obj, function () {
                n = n + 1;
            });
            return n;
        },
        FBP = (function () {
        var _c = {},
            _g = {};
        return {
            component: function (config, taskConfig) {
                if (arguments.length === 1) {
                    // getter
                    return _c[config];
                } else {
                    // setter i.e. constructor
                    // if 1st argument is an array, we construct several instances
                    var name = null,
                        _inN = 0,
                        task = null,
                        state = null;
                    if ('string' === typeof config) {
                        name = config;
                    } else {
                        name = config.name;
                        state = config.state || {};
                    }
                    if (_c[name]) {
                        throw 'component has already defined';
                    }
                    task = taskConfig[taskConfig.length - 1];
                    // task.length refers to number of task function inputs
                    if (taskConfig.length !== task.length) {
                        throw 'in port numbers do not match';
                    }
                    taskConfig.splice(taskConfig.length - 1, 1);
                    _c[name] = {
                        name: name,
                        addInput: function (value, inPort) {
                            this.inputs[inPort] = value;
                            if (objLength(this.inputs) === this.args.length) {
                                FBP.graph(this.graph).invokeComponent(this);
                            }
                        },
                        inputs: {}, // pool for waiting inputs from in ports
                        args: taskConfig, // an array of in ports names
                        task: task, // the task function
                        state: state // internal state of the component
                    };
                }
            },
            graph: function (name) {
                // graph getter
                return _g[name];
            },
            setup: function (name, constructor) {
                // graph constructor
                var graphName = name,
                    components = [],
                    inPorts = [],
                    inN = 0,
                    outN = 0,
                    dests = {},
                    F = {
                        init: function (name, port) {
                            var component = FBP.component(name);
                            component.graph = graphName;
                            components.push(name);
                            inPorts[name + '.' + port] = {
                                name: name,
                                port: port
                            };
                            inN = inN + 1;
                        },
                        connect: function (fromName, fromPort, toName, toPort) {
                            var toComponent = FBP.component(toName);
                            if (!toComponent.graph || toComponent.graph !== graphName) {
                                toComponent.graph = graphName;
                                components.push(toName);
                            }
                            dests[fromName + '.' + fromPort] = {
                                name: toName,
                                port: toPort
                            };
                        },
                        end: function (name, port) {
                            dests[name + '.' + port] = 'end';
                            outN = outN + 1;
                        }
                    };
                constructor(F);
                F.name = graphName;
                F.components = components;
                F.inPorts = inPorts;
                F.inN = inN;
                F.outN = outN;
                F.outputs = {};
                F.dests = dests;
                F.go = function (inputs, callback) {
                    this.callback = callback;
                    this.tic = Date.now();
                    var component, inPort;
                    objIterate(inputs, function (input) {
                        component = FBP.component(this.inPorts[input].name);
                        inPort = this.inPorts[input].port;
                        component.addInput(inputs[input], inPort);
                    }.bind(this));
                };
                F.sendOutput = function (output, outPort) {
                    var interval = Date.now() - this.tic;
                    this.outputs[outPort] = output;
                    this.callback.apply(this, [ null, {
                        outputs: this.outputs,
                        interval: interval
                    }]);
                };
                F.invokeComponent = function (component) {
                    var that = this,
                        input = [],
                        i = 0;
                    for (i; i < component.args.length; i = i + 1) {
                        input[i] = component.inputs[component.args[i]];
                    }
                    input[i] = function (outPort, value) {
                        var destName = component.name + '.' + outPort;
                            dest = that.dests[destName];
                        if (dest === 'end') {
                            that.sendOutput(value, destName);
                        } else {
                            FBP.component(dest.name).addInput(value, dest.port);
                        }
                    };
                    component.task.bind(component.state).apply(component, input);
                };
                _g[arguments[0]] = F;
            }
        }
    }());

    if ('undefined' !== typeof exports) {
        if ('undefined' !== typeof module && module.exports) {
            exports = module.exports = FBP;
        }
        exports.FBP = FBP;
    } else {
        root.FBP = FBP;
    }

}());
<|endoftext|>


<commit_before>/*
 * fis
 * http://web.baidu.com/
 */

'use strict';

//kernel
var fis = module.exports = require('fis-kernel');

//cli
fis.cli = {
    //runtime config
    rc : {},
    //commander object
    commander : null,
    //package.json
    info : fis.util.readJSON(fis.util(__dirname, 'package.json')),
    //get rc file
    getRCFile : function(){
        var list = ['LOCALAPPDATA', 'APPDATA', 'USERPROFILE', 'HOME'],
            name = '.fisrc', conf;
        for(var i = 0, len = list.length; i < len; i++){
            var dir = process.env[list[i]];
            if(dir){
                conf = fis.util(dir, name);
                break;
            }
        }
        conf = conf || fis.path.getTempPath(name);
        if(!fis.util.exists(conf)){
            fis.util.write(conf, '{}');
        }
        return conf;
    },
    //output help info
    help : function(){
        var content = [
                '',
                '  usage: fis <command>',
                '',
                '  commands:',
                ''
            ],
            prefix = 'fis-command-',
            prefixLen = prefix.length;
        fis.util.map(fis.cli.info.dependencies, function(name, version){
            if(name.indexOf(prefix) === 0){
                name = name.substring(prefixLen);
                var cmd = fis.require('command', name);
                name = fis.util.pad(cmd.name || name, 12);
                content.push('    ' + name + (cmd.desc || ''));
            }
        });
        content = content.concat([
            '',
            '  options:',
            '',
            '    -h, --help     output usage information',
            '    -v, --version  output the version number',
            ''
        ]);
        console.log(content.join('\n'));
    },
    //output version info
    version : function(){
        var content = [
            '',
            '   v' + fis.cli.info.version,
            '',
            '  ┏┛┻━━━┛┻┓',
            '  ┃｜｜｜｜｜｜｜┃',
            '  ┃　　　━　　　┃',
            '  ┃　┳┛　┗┳　┃ ',
            '  ┃　　　　　　　┃',
            '  ┃　　　┻　　　┃',
            '  ┃　　　　　　　┃',
            '  ┗━┓　　　┏━┛',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┗━━━┓',
            '  　　┃            　┣┓',
            '  　　┃            　┃',
            '  　　┗┓┓┏━┳┓┏┛',
            '  　　　┃┫┫　┃┫┫',
            '  　　　┗┻┛　┗┻┛'
        ].join('\n');
        console.log(content);
    },
    //run cli tools
    run : function(argv){
        var first = argv[2];
        if(argv.length < 3 || first === '-h' ||  first === '--help'){
            fis.cli.help();
        } else if(first === '-v' || first === '--version'){
            fis.cli.version();
        } else if(first[0] === '-'){
            fis.cli.help();
        } else {
            //read runtime config
            var rc = fis.cli.rc = fis.util.readJSON(fis.cli.getRCFile());
            //command alias
            if(rc.alias && rc.alias[first]){
                var alias = rc.alias[first].split(/\s+/);
                Array.prototype.splice.apply(argv, [2, 1].concat(alias));
            }
            var commander = fis.cli.commander = require('commander');
            commander
                .version(fis.cli.info.version)
                .usage('<command>');
            var cmd = fis.require('command', argv[2]);
            commander
                .command(cmd.name || first)
                .usage(cmd.usage)
                .description(cmd.desc);
            cmd.register(commander, fis);
            commander.parse(argv);
        }
    }
};<commit_msg>完成fis命令行系统<commit_after>/*
 * fis
 * http://web.baidu.com/
 */

'use strict';

//kernel
var fis = module.exports = require('fis-kernel');

//cli
fis.cli = {
    //runtime config
    rc : {},
    //commander object
    commander : null,
    //package.json
    info : fis.util.readJSON(fis.util(__dirname, 'package.json')),
    //get rc file
    getRCFile : function(){
        var list = ['LOCALAPPDATA', 'APPDATA', 'USERPROFILE', 'HOME'],
            name = '.fisrc', conf;
        for(var i = 0, len = list.length; i < len; i++){
            var dir = process.env[list[i]];
            if(dir){
                conf = fis.util(dir, name);
                break;
            }
        }
        conf = conf || fis.path.getTempPath(name);
        if(!fis.util.exists(conf)){
            fis.util.write(conf, '{}');
        }
        return conf;
    },
    //output help info
    help : function(){
        var content = [
                '',
                '  usage: fis <command>',
                '',
                '  commands:',
                ''
            ],
            prefix = 'fis-command-',
            prefixLen = prefix.length;
        fis.util.map(fis.cli.info.dependencies, function(name, version){
            if(name.indexOf(prefix) === 0){
                name = name.substring(prefixLen);
                var cmd = fis.require('command', name);
                name = fis.util.pad(cmd.name || name, 12);
                content.push('    ' + name + (cmd.desc || ''));
            }
        });
        content = content.concat([
            '',
            '  options:',
            '',
            '    -h, --help     output usage information',
            '    -v, --version  output the version number',
            ''
        ]);
        console.log(content.join('\n'));
    },
    //output version info
    version : function(){
        var content = [
            '',
            '   v' + fis.cli.info.version,
            '',
            '  ┏┛┻━━━┛┻┓',
            '  ┃｜｜｜｜｜｜｜┃',
            '  ┃　　　━　　　┃',
            '  ┃　┳┛　┗┳　┃ ',
            '  ┃　　　　　　　┃',
            '  ┃　　　┻　　　┃',
            '  ┃　　　　　　　┃',
            '  ┗━┓　　　┏━┛',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┃',
            '  　　┃　　　┗━━━┓',
            '  　　┃            　┣┓',
            '  　　┃            　┃',
            '  　　┗┓┓┏━┳┓┏┛',
            '  　　　┃┫┫　┃┫┫',
            '  　　　┗┻┛　┗┻┛'
        ].join('\n');
        console.log(content);
    },
    //run cli tools
    run : function(argv){
        var first = argv[2];
        if(argv.length < 3 || first === '-h' ||  first === '--help'){
            fis.cli.help();
        } else if(first === '-v' || first === '--version'){
            fis.cli.version();
        } else if(first[0] === '-'){
            fis.cli.help();
        } else {
            //read runtime config
            var rc = fis.cli.rc = fis.util.readJSON(fis.cli.getRCFile());
            //command alias
            if(rc.alias && rc.alias[first]){
                var alias = rc.alias[first].split(/\s+/);
                Array.prototype.splice.apply(argv, [2, 1].concat(alias));
            }
            var commander = fis.cli.commander = require('commander');
            var cmd = fis.require('command', argv[2]);
            cmd.register(
                commander
                    .command(cmd.name || first)
                    .usage(cmd.usage)
                    .description(cmd.desc),
                fis
            );
            commander.parse(argv);
        }
    }
};<|endoftext|>


<commit_before>define(function(require, module, exports) {
    main.consumes = [
        "Plugin", "build", "settings", "commands", "fs", "save",
        "menus", "tabManager", "ui", "dialog.error"
    ];
    main.provides = ["build.gui"];
    return main;

    function main(options, imports, register) {
        var Plugin      = imports.Plugin;
        var settings    = imports.settings;
        var commands    = imports.commands;
        var menus       = imports.menus;
        var save        = imports.save;
        var build       = imports.build;
        var fs          = imports.fs;
        var ui          = imports.ui;
        var tabs        = imports.tabManager;
        var showError   = imports["dialog.error"].show;
        var uCaseFirst  = require("c9/string").uCaseFirst;

        /***** Initialization *****/

        var plugin  = new Plugin("Ajax.org", main.consumes);
        // var emit    = plugin.getEmitter();

        var process, currentBuilder;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Commands
            commands.addCommand({
                name    : "build",
                group   : "Run & Debug",
                hint    : "builds the current file (focussed document)",
                bindKey : { mac: "Command-B", win: "Ctrl-B" },
                isAvailable : function(){
                    return getFocusTab() ? true : false;
                },
                exec : function(){
                    buildFocusTab();
                }
            }, plugin);

            commands.addCommand({
                name    : "stopbuild",
                group   : "Run & Debug",
                hint    : "stop a running build",
                bindKey : { mac: "Ctrl-Shift-C", win: "Ctrl-Shift-C" },
                isAvailable : function(){
                    return process && process.running;
                },
                exec    : function(){
                    process && process.stop();
                }
            }, plugin);

            // Settings
            settings.on("read", function(){
                settings.setDefaults("project/build", [
                    ["saveall", "true"],
                    ["builder", "auto"]
                ]);
                settings.setDefaults("user/build", [
                    ["autobuild", "true"]
                ]);

                var name = settings.get("project/build/@builder");
                setCurrentBuilder(name, function(){});
            });

            // Menus
            var c = 10000;
            menus.addItemByPath("Run/~", new ui.divider(), c += 100, plugin);

            var mnuBuildSystem = new ui.menu({
                "onprop.visible": function(e){
                    if (e.value) {
                        build.listBuilders(function(err, names){
                            var nodes = mnuBuildSystem.childNodes;
                            for (var i = nodes.length - 3; i >= 2; i--) {
                                mnuBuildSystem.removeChild(nodes[i]);
                            }

                            var builder = settings.get("project/build/@builder");
                            if (builder == "auto")
                                nodes[0].select();

                            var c = 300;
                            names.forEach(function(name){
                                menus.addItemToMenu(mnuBuildSystem, new ui.item({
                                    type     : "radio",
                                    caption  : uCaseFirst(name),
                                    value    : name,
                                    selected : builder == name
                                }), c++, plugin);
                            });
                        });
                    }
                },
                "onitemclick": function(e){
                    if (e.value == "new-build-system") {
                        tabs.open({
                            path   : settings.get("project/build/@path")
                              + "/New Build System",
                            active : true,
                            value  : '// Create a custom Cloud9 build system - similar to the Sublime build system\n'
                              + '// For more information see http://docs.c9.io:8080/#!/api/run-method-run\n'
                              + '{\n'
                              + '    "caption" : "",\n'
                              + '    "cmd" : ["ls", "$file", "$args"],\n'
                              + '    "info" : "Building $project_path/$file",\n'
                              + '    "selector": "source.ext"\n'
                              + '}',
                            document : {
                                meta : {
                                    newfile: true
                                },
                                ace : {
                                    customSyntax : "javascript"
                                }
                            }
                        }, function(){});
                        return;
                    }

                    setCurrentBuilder(e.value, function(){});
                    settings.set("project/build/@builder", e.value);
                }
            });

            menus.addItemByPath("Run/Build System/", mnuBuildSystem,
                c += 100, plugin);
            menus.addItemByPath("Run/Build", new ui.item({
                command : "build"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Cancel Build", new ui.item({
                command : "stopbuild"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Show Build Result", new ui.item({
                onclick: function(){
                    commands.exec("showoutput", null, { id: "build" });
                }
            }), c += 100, plugin);
            menus.addItemByPath("Run/Automatically Build Supported Files", new ui.item({
                type    : "check",
                checked : "[{settings.model}::user/build/@autobuild]"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Save All on Build", new ui.item({
                type    : "check",
                checked : "[{settings.model}::project/build/@saveall]"
            }), c += 100, plugin);

            c = 0;
            menus.addItemByPath("Run/Build System/Automatic", new ui.item({
                type  : "radio",
                value : "auto"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Build System/~", new ui.divider(), c += 100, plugin);
            menus.addItemByPath("Run/Build System/~", new ui.divider(), c += 1000, plugin);
            menus.addItemByPath("Run/Build System/New Build System", new ui.item({
                value : "new-build-system"
            }), c += 100, plugin);

            // Hook into FS and build file when writeFile is triggered
            save.on("afterSave", function(e){
                if (!settings.getBool("user/build/@autobuild"))
                    return;

                var ext = fs.getExtension(e.path);
                if (!ext)
                    return;

                // @todo consider making this a hash map
                if (currentBuilder == "auto") {
                    if (Object.keys(build.builders).every(function(name){
                        return build.builders[name].selector != "source." + ext;
                    })) return;
                }
                else if (currentBuilder.selector != "source." + ext)
                    return;

                buildFocusTab(true, e.path);
            });
        };

        /***** Methods *****/

        function setCurrentBuilder(name, callback){
            currentBuilder = name;
            if (currentBuilder != "auto") {
                build.getBuilder(currentBuilder, true, function(err, builder){
                    if (err)
                        currentBuilder = "auto";
                    else
                        currentBuilder = builder;
                    callback(err, builder);
                });
            }
        }

        function getFocusTab(){
            var tab = tabs.focussedTab;
            if (!tab) return false;
            if (tab.path) return tab;
            if (tab.editor.type != "output") return false;

            var splits = tab.pane.aml
                .parentNode.parentNode.getElementsByTagName("tab");
            if (splits.length > 1) {
                var idx = splits[0].cloud9pane == tab.pane ? 1 : 0;
                tab = splits[idx].cloud9pane.getTab();
                return tab;
            }
            return false;
        }

        function buildFocusTab(onlyBuild, path){
            if (!path) {
                var tab = getFocusTab();
                if (!tab) return;
                path = tab.path;
            }

            if (!onlyBuild)
                commands.exec("showoutput", null, { id: "build" });

            if (settings.get("project/build/@saveall"))
                save.saveAll(done);
            else
                done();

            function done(){
                process = build.build(currentBuilder,
                    { path: path }, "build", function(err, pid){
                        if (err && err.code != "EBUILDERNOTFOUND")
                            return showError(err);
                    });
            }
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
        });

        /***** Register and define API *****/

        /**
         * UI for the {@link build} plugin. This plugin is responsible for the Run
         * menu in the main menu bar, as well as the settings and the
         * preferences UI for the run plugin.
         * @singleton
         */
        /**
         * @command build Builds the currently focussed tab.
         */
        /**
         * @command stopbuild Stops the running build.
         */
        plugin.freezePublicAPI({

        });

        register(null, {
            "build.gui": plugin
        });
    }
});
<commit_msg>Added alternative bindings<commit_after>define(function(require, module, exports) {
    main.consumes = [
        "Plugin", "build", "settings", "commands", "fs", "save",
        "menus", "tabManager", "ui", "dialog.error"
    ];
    main.provides = ["build.gui"];
    return main;

    function main(options, imports, register) {
        var Plugin      = imports.Plugin;
        var settings    = imports.settings;
        var commands    = imports.commands;
        var menus       = imports.menus;
        var save        = imports.save;
        var build       = imports.build;
        var fs          = imports.fs;
        var ui          = imports.ui;
        var tabs        = imports.tabManager;
        var showError   = imports["dialog.error"].show;
        var uCaseFirst  = require("c9/string").uCaseFirst;

        /***** Initialization *****/

        var plugin  = new Plugin("Ajax.org", main.consumes);
        // var emit    = plugin.getEmitter();

        var process, currentBuilder;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Commands
            commands.addCommand({
                name    : "build",
                group   : "Run & Debug",
                hint    : "builds the current file (focussed document)",
                bindKey : { mac: "Command-B", win: "Ctrl-B" },
                isAvailable : function(){
                    return getFocusTab() ? true : false;
                },
                exec : function(){
                    buildFocusTab();
                }
            }, plugin);

            commands.addCommand({
                name    : "stopbuild",
                group   : "Run & Debug",
                hint    : "stop a running build",
                bindKey : { mac: "Ctrl-Shift-C", win: "Ctrl-Shift-C" },
                isAvailable : function(){
                    return process && process.running;
                },
                exec    : function(){
                    process && process.stop();
                }
            }, plugin);

            // Settings
            settings.on("read", function(){
                settings.setDefaults("project/build", [
                    ["saveall", "true"],
                    ["builder", "auto"]
                ]);
                settings.setDefaults("user/build", [
                    ["autobuild", "true"]
                ]);

                var name = settings.get("project/build/@builder");
                setCurrentBuilder(name, function(){});
            });

            // Menus
            var c = 10000;
            menus.addItemByPath("Run/~", new ui.divider(), c += 100, plugin);

            var mnuBuildSystem = new ui.menu({
                "onprop.visible": function(e){
                    if (e.value) {
                        build.listBuilders(function(err, names){
                            var nodes = mnuBuildSystem.childNodes;
                            for (var i = nodes.length - 3; i >= 2; i--) {
                                mnuBuildSystem.removeChild(nodes[i]);
                            }

                            var builder = settings.get("project/build/@builder");
                            if (builder == "auto")
                                nodes[0].select();

                            var c = 300;
                            names.forEach(function(name){
                                menus.addItemToMenu(mnuBuildSystem, new ui.item({
                                    type     : "radio",
                                    caption  : uCaseFirst(name),
                                    value    : name,
                                    selected : builder == name
                                }), c++, plugin);
                            });
                        });
                    }
                },
                "onitemclick": function(e){
                    if (e.value == "new-build-system") {
                        tabs.open({
                            path   : settings.get("project/build/@path")
                              + "/New Build System",
                            active : true,
                            value  : '// Create a custom Cloud9 build system - similar to the Sublime build system\n'
                              + '// For more information see http://docs.c9.io:8080/#!/api/run-method-run\n'
                              + '{\n'
                              + '    "caption" : "",\n'
                              + '    "cmd" : ["ls", "$file", "$args"],\n'
                              + '    "info" : "Building $project_path/$file",\n'
                              + '    "selector": "source.ext"\n'
                              + '}',
                            document : {
                                meta : {
                                    newfile: true
                                },
                                ace : {
                                    customSyntax : "javascript"
                                }
                            }
                        }, function(){});
                        return;
                    }

                    setCurrentBuilder(e.value, function(){});
                    settings.set("project/build/@builder", e.value);
                }
            });

            menus.addItemByPath("Run/Build System/", mnuBuildSystem,
                c += 100, plugin);
            menus.addItemByPath("Run/Build", new ui.item({
                command : "build"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Cancel Build", new ui.item({
                command : "stopbuild"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Show Build Result", new ui.item({
                onclick: function(){
                    commands.exec("showoutput", null, { id: "build" });
                }
            }), c += 100, plugin);
            menus.addItemByPath("Run/Automatically Build Supported Files", new ui.item({
                type    : "check",
                checked : "user/build/@autobuild"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Save All on Build", new ui.item({
                type    : "check",
                checked : "project/build/@saveall"
            }), c += 100, plugin);

            c = 0;
            menus.addItemByPath("Run/Build System/Automatic", new ui.item({
                type  : "radio",
                value : "auto"
            }), c += 100, plugin);
            menus.addItemByPath("Run/Build System/~", new ui.divider(), c += 100, plugin);
            menus.addItemByPath("Run/Build System/~", new ui.divider(), c += 1000, plugin);
            menus.addItemByPath("Run/Build System/New Build System", new ui.item({
                value : "new-build-system"
            }), c += 100, plugin);

            // Hook into FS and build file when writeFile is triggered
            save.on("afterSave", function(e){
                if (!settings.getBool("user/build/@autobuild"))
                    return;

                var ext = fs.getExtension(e.path);
                if (!ext)
                    return;

                // @todo consider making this a hash map
                if (currentBuilder == "auto") {
                    if (Object.keys(build.builders).every(function(name){
                        return build.builders[name].selector != "source." + ext;
                    })) return;
                }
                else if (currentBuilder.selector != "source." + ext)
                    return;

                buildFocusTab(true, e.path);
            });
        };

        /***** Methods *****/

        function setCurrentBuilder(name, callback){
            currentBuilder = name;
            if (currentBuilder != "auto") {
                build.getBuilder(currentBuilder, true, function(err, builder){
                    if (err)
                        currentBuilder = "auto";
                    else
                        currentBuilder = builder;
                    callback(err, builder);
                });
            }
        }

        function getFocusTab(){
            var tab = tabs.focussedTab;
            if (!tab) return false;
            if (tab.path) return tab;
            if (tab.editor.type != "output") return false;

            var splits = tab.pane.aml
                .parentNode.parentNode.getElementsByTagName("tab");
            if (splits.length > 1) {
                var idx = splits[0].cloud9pane == tab.pane ? 1 : 0;
                tab = splits[idx].cloud9pane.getTab();
                return tab;
            }
            return false;
        }

        function buildFocusTab(onlyBuild, path){
            if (!path) {
                var tab = getFocusTab();
                if (!tab) return;
                path = tab.path;
            }

            if (!onlyBuild)
                commands.exec("showoutput", null, { id: "build" });

            if (settings.get("project/build/@saveall"))
                save.saveAll(done);
            else
                done();

            function done(){
                process = build.build(currentBuilder,
                    { path: path }, "build", function(err, pid){
                        if (err && err.code != "EBUILDERNOTFOUND")
                            return showError(err);
                    });
            }
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
        });

        /***** Register and define API *****/

        /**
         * UI for the {@link build} plugin. This plugin is responsible for the Run
         * menu in the main menu bar, as well as the settings and the
         * preferences UI for the run plugin.
         * @singleton
         */
        /**
         * @command build Builds the currently focussed tab.
         */
        /**
         * @command stopbuild Stops the running build.
         */
        plugin.freezePublicAPI({

        });

        register(null, {
            "build.gui": plugin
        });
    }
});
<|endoftext|>


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

goog.require('processingjs.lint');

/**
 * @type {!Object}
 */
var ide = (/** @type {function(): !Object} */ (function() {
  var ide = {
    /** @type {?Processing} */
    processing: null,
    /** @type {?CodeMirror} */
    codemirror: null,
    /** @type {?Element} */
    helpDiv: null,
    /** @type {?Element} */
    canvasDiv: null,
    /** @type {?Element} */
    canvas: null,
    /** @type {?HTMLCanvasElement} */
    processingCanvas: null,
    /** @type {?HTMLTextAreaElement} */
    textarea: null,
    /** @type {!Object<string, !Element>} */
    referenceDict: {},
    /** @type {number} */
    prevHeight: 0,
    /** @type {number} */
    prevWidth: 0,
    // The last saved sketch state.
    /** @type {string} */
    saved: "",
    // The cache for TTS blobs.
    /** @type {!Object<string, !Blob>} */
    ttsCache: new Object(),
  };

  /**
   * @return{!Object<string, string>}
   */
  function parseFragment() {
    var params = {};
    var parts = window.location.hash.substring(1).split('&');
    for (var i = 0; i < parts.length; i++) {
      var part = parts[i];
      if (part == '') continue;
      var pieces = part.split('=');
      if (pieces.length != 2) {
        window.console.error('Invalid fragment parameter: ' + part);
        continue;
      }
      params[pieces[0]] = decodeURIComponent(pieces[1]);
    }
    return params;
  }

  /**
   * Update the fragment hash with a new key-value pair.
   * If value is null, removes that part from the fragment hash.
   * @param {string} key
   * @param {?string} value
   */
  function updateFragment(key, value) {
    var params = parseFragment();
    if (value == null) {
      delete params[key];
    } else {
      params[key] = value;
    }
    var hash = "";
    for (key in params) {
      if (hash.length > 0) {
        hash = hash + '&';
      }
      hash = hash + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
    }
    window.location.hash = hash;
  }

  function startSketch() {
    var /** string */ processingCode = ide.codemirror.getValue();
    // window.console.log(processingCode);
    try {
      // Try compilation and report an error if any.
      Processing.compile(processingCode);
    } catch(/** @type{!Error} */e) {
      window.console.error(e);
      ide.canvasDiv.innerHTML = 'Error: ' + e;
    }
    // Isolate the running Processing sketch in an iframe.
    var iframe = /** @type {!HTMLIFrameElement} */(document.createElement("iframe"));
    // Find out the links to processing.js library from the current
    // page.
    /** @type {string} */
    var processing_js;
    try {
      processing_js = /** @type {string} */ ($("script[src*='processing.']")[0].src);
    } catch(e) {
      processing_js = '/static/processing.min.js';
    }
    /** @type{string} */
    var style_css;
    try {
      style_css = $("link[href*='style']")[0].href.replace('style.css', 'inner.css');
    } catch(e) {
      style_css = '/static/inner.css';
    }
    // Create the iframe HTML.
    var iframeHtml = '<!DOCTYPE html>\n' +
      '<link rel="stylesheet" type="text/css" href="'+ style_css + '">'+
      '' +
      ''+
      '<canvas id="pjs"></canvas>';

    // Delete all existing children. This will drop the previous
    // iframe.
    $(ide.canvasDiv).empty();
    ide.canvasDiv.appendChild(iframe);
    var contentWindow = /** @type {!Window} */(iframe.contentWindow);
    contentWindow.document.open();
    contentWindow.document.write(iframeHtml);
    contentWindow.document.close();
    // Share the TTS cache.
    contentWindow['ttsCache'] = ide.ttsCache;
    window.setTimeout(function() {
      // Assume there is only one instance running in the iframe.
      /** @type {!Processing} */
      var inst;
      try {
        /** @suppress {missingProperties} */
        inst = /** @type {!Processing} */(contentWindow.Processing['instances'][0]);
      } catch(/** @type {!Error} */e) {
        window.console.log('Could not find Processing in ');
      }
      ide.processing = inst;
      iframe.style.height = '' + (inst.height) + 'px';
      iframe.style.width = '' + (inst.width) + 'px';
      ide.prevWidth = inst.width;
      ide.prevHeight = inst.height;
    }, 200);
    if (ide.prevHeight > 0) {
      iframe.style.height = '' + (ide.prevHeight) + 'px';
      iframe.style.width = '' + (ide.prevWidth) + 'px';
    }
    ide.canvasDiv.style.overflow = 'visible';
  }

  function stopSketch() {
    switchSketchState(false);
    ide.canvasDiv.style.overflow = 'hidden';
    //ide.processingCanvas.style.width = '100%';
    //ide.processingCanvas.style.height = '100%';
  }

  /**
   * @param {boolean} on
   */
  function switchSketchState(on) {
    if (!ide.processing) {
      window.console.error('No processing instance');
      return;
    }
    if (on) {
      ide.processing.loop();
    } else {
      ide.processing.noLoop();
    }
  }

  /**
   * @param {string} refkey
   */
  function showHelpSection(refkey) {
    if (refkey.startsWith('#')) refkey = refkey.substr(1);
    /** @type {?Element} */
    var doc = ide.referenceDict[refkey];
    if (doc) {
      // Empty the help div.
      while (ide.helpDiv.lastChild) {
        ide.helpDiv.removeChild(ide.helpDiv.lastChild);
      }
      ide.helpDiv.appendChild(doc);
      updateFragment('help', refkey.substr(4));
    } else {
      var keyword = refkey.substr(4);
      ide.helpDiv.innerHTML =
          ('
No help on ' + keyword + '.' +
     '
Put the cursor on a function name and press [Help] button
');
    }
  }

  function showHelp() {
    var cursor = ide.codemirror.getCursor();
    var line = ide.codemirror.getLine(cursor.line);
    // Find the identifier under cursor.
    var match = /^([a-zA-Z0-9_]*)/.exec(line.substr(cursor.ch));
    match = /([a-zA-Z_][a-zA-Z0-9_]*)([^a-zA-Z_]*)$/.exec(
        line.substr(0, cursor.ch) + match[1]);
    if (!match) {
      // Retry with the complete line.
      match = /([a-zA-Z_][a-zA-Z0-9_]*)/.exec(line);
    }
    if (!match) {
      // Help invoked on empty line?
      window.console.log('no help');
      return;
    }
    var keyword = match[1];
    showHelpSection('ref-' + keyword);
  }

  // Saves the sketch automatically if there were any changes.
  function autosaveSketch() {
    /** @type {string} */
    var source = ide.codemirror.getValue();
    if (ide.saved != source) {
      saveSketch();
      ide.saved = source;
    }
  }

  function saveSketch() {
    var /** string */processingCode = ide.codemirror.getValue();
    var params = parseFragment();
    ide.textarea.value = processingCode;
    var data = $(ide.textarea).serializeArray();
    var id = params['sketch'];
    // Note the saved state.
    if (id) {
      //window.console.log("Saving /sketch/" + id);
      $.post('/sketch/' + id, data, function(data, status, xhr) {
        if (status == 'success') {
          //ide.helpDiv.innerHTML = '
Saved OK
';
          window.console.log("Saved /sketch/" + id);
        } else {
          //ide.helpDiv.innerHTML = '
Saved error: ' + status + '
';
          window.console.error(status);
        }
      });
    } else {
      //window.console.log("Saving new sketch");
      $.post('/sketch', data, function(data, status, xhr) {
        var id = data;
        if (status == 'success') {
          //ide.helpDiv.innerHTML = '
Saved OK
';
          window.console.log("Saved /sketch/" + id);
          updateFragment('sketch', id);
        } else {
          //ide.helpDiv.innerHTML = '
Saved error: ' + status + '
';
          window.console.error(status);
        }
      });
    }
  }

  /**
   * @param {!Event} ev
   * @return {boolean}
   */
  function showDoc(ev) {
    var elt = /** @type {!Element} */ (ev.target);
    var hash = elt.getAttribute('href');
    showHelpSection(hash);
    updateFragment('help', hash.substr(5));
    return false;
  }

  /**
   * @param {!Event} ev
   */
  function helpTop(ev) {
    ev.preventDefault();
    showHelpSection('ref-help');
  }

  /**
   * @param {!Event} ev
   */
  function helpIndex(ev) {
    ev.preventDefault();
    showHelpSection('ref-index');
  }

  function computeReferenceDict() {
    $('div.section').each(function(index, elt) {
      ide.referenceDict[elt.id] = elt;
    });
    $('a').each(function(index, elt) {
      var href = elt.getAttribute('href');
      if (href.startsWith('#ref-')) {
        $(elt).click(showDoc);
      }
    });
    // Add the [Load] buttons to code snippets.
    $('pre').each(function(index, elt) {
      var code = $(elt).find('code');
      if (code.length == 1) {
        var source = /** @type {string} */(code.text());
        var button = document.createElement("button");
        $(button).text('読み込む');
        $(button).click(function(ev) {
          ev.preventDefault();
          ide.codemirror.setValue(source);
          // Avoid autosaving unless there were changes.
          ide.saved = source;
          // Forget the previous sketch id.
          updateFragment('sketch', null);
        });
        $(elt).prepend($('
'));
        $(elt).prepend(button);
      }
    });
  }

  function setup() {
    computeReferenceDict();
    document.getElementById('start_sketch_button')
      .addEventListener('click',  startSketch);
    document.getElementById('stop_sketch_button')
      .addEventListener('click', stopSketch);
    document.getElementById('show_help_button')
      .addEventListener('click', showHelp);
    document.getElementById('help_top_button')
      .addEventListener('click', helpTop);
    document.getElementById('help_index_button')
      .addEventListener('click', helpIndex);
    ide.textarea = /** @type {!HTMLTextAreaElement} */ (
        document.getElementById('editor_textarea'));
    var validator = function(text, options) {
      return processingjs.lint.validator(text, options, toplevelGrammar.parse);
    };
    var codemirror_options = {
      value: ide.textarea.value,
      mode: 'clike',
      lint: validator,
      extraKeys: {
        'F1': showHelp,
      },
    };
    // Parse and act on the fragment address.
    if (window.location.hash) {
      var params = parseFragment();
      //window.console.log(params);
      if (params['sketch']) {
        var id = params['sketch'];
        $.ajax('/sketch/' + id, {
          success:
          /**
           * @param {string} data
           */
          function(data) {
            window.console.log("Loaded /sketch/" + id);
            // Reset the saved state.
            ide.saved = data;
            ide.textarea.value = data;
            ide.codemirror.setValue(data);
          },
          error:
          /**
           * @param {!Object} jqXHR
           * @param {?Object} status
           * @param {?Object} err
           */
          function(jqXHR, status, err) {
            window.console.error(status, err);
          },
        });
      }
      // TODO(salikh): Parse 'help' key from the fragment
      // and show the appropriate help page.
    }
    // Instantiate CodeMirror.
    ide.codemirror = CodeMirror.fromTextArea(ide.textarea, codemirror_options);
    ide.codemirror.setOption("extraKeys", { Tab: showHelp });
    ide.canvasDiv = document.getElementById('canvas_div');
    ide.helpDiv = document.getElementById('help_div');
    ide.processingCanvas = /** @type{HTMLCanvasElement!} */(document.getElementById('processing_canvas'));
    if (params['help']) {
      showHelpSection('ref-' + params['help']);
    }
  }

  window.addEventListener('load', function() {
    // window.console.log("page loaded");
    setup();
  });

  // Autosave every 3 seconds.
  window.setInterval(autosaveSketch, 3000);

  return ide;
}))();
<commit_msg>Try detecting the sketch size by regexp, default to the last size.<commit_after>/**
 * @license
 * Copyright 2018 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.require('processingjs.lint');

/**
 * @type {!Object}
 */
var ide = (/** @type {function(): !Object} */ (function() {
  var ide = {
    /** @type {?Processing} */
    processing: null,
    /** @type {?CodeMirror} */
    codemirror: null,
    /** @type {?Element} */
    helpDiv: null,
    /** @type {?Element} */
    canvasDiv: null,
    /** @type {?Element} */
    canvas: null,
    /** @type {?HTMLCanvasElement} */
    processingCanvas: null,
    /** @type {?HTMLTextAreaElement} */
    textarea: null,
    /** @type {!Object<string, !Element>} */
    referenceDict: {},
    /** @type {number} */
    prevHeight: 0,
    /** @type {number} */
    prevWidth: 0,
    // The last saved sketch state.
    /** @type {string} */
    saved: "",
    // The cache for TTS blobs.
    /** @type {!Object<string, !Blob>} */
    ttsCache: new Object(),
  };

  /**
   * @return{!Object<string, string>}
   */
  function parseFragment() {
    var params = {};
    var parts = window.location.hash.substring(1).split('&');
    for (var i = 0; i < parts.length; i++) {
      var part = parts[i];
      if (part == '') continue;
      var pieces = part.split('=');
      if (pieces.length != 2) {
        window.console.error('Invalid fragment parameter: ' + part);
        continue;
      }
      params[pieces[0]] = decodeURIComponent(pieces[1]);
    }
    return params;
  }

  /**
   * Update the fragment hash with a new key-value pair.
   * If value is null, removes that part from the fragment hash.
   * @param {string} key
   * @param {?string} value
   */
  function updateFragment(key, value) {
    var params = parseFragment();
    if (value == null) {
      delete params[key];
    } else {
      params[key] = value;
    }
    var hash = "";
    for (key in params) {
      if (hash.length > 0) {
        hash = hash + '&';
      }
      hash = hash + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
    }
    window.location.hash = hash;
  }

  function startSketch() {
    var /** string */ processingCode = ide.codemirror.getValue();
    // window.console.log(processingCode);
    try {
      // Try compilation and report an error if any.
      Processing.compile(processingCode);
    } catch(/** @type{!Error} */e) {
      window.console.error(e);
      ide.canvasDiv.innerHTML = 'Error: ' + e;
    }
    // Isolate the running Processing sketch in an iframe.
    var iframe = /** @type {!HTMLIFrameElement} */(document.createElement("iframe"));
    // Find out the links to processing.js library from the current
    // page.
    /** @type {string} */
    var processing_js;
    try {
      processing_js = /** @type {string} */ ($("script[src*='processing.']")[0].src);
    } catch(e) {
      processing_js = '/static/processing.min.js';
    }
    /** @type{string} */
    var style_css;
    try {
      style_css = $("link[href*='style']")[0].href.replace('style.css', 'inner.css');
    } catch(e) {
      style_css = '/static/inner.css';
    }
    // Create the iframe HTML.
    var iframeHtml = '<!DOCTYPE html>\n' +
      '<link rel="stylesheet" type="text/css" href="'+ style_css + '">'+
      '' +
      ''+
      '<canvas id="pjs"></canvas>';

    // Delete all existing children. This will drop the previous
    // iframe.
    $(ide.canvasDiv).empty();
    ide.canvasDiv.appendChild(iframe);
    var contentWindow = /** @type {!Window} */(iframe.contentWindow);
    contentWindow.document.open();
    contentWindow.document.write(iframeHtml);
    contentWindow.document.close();
    // Share the TTS cache.
    contentWindow['ttsCache'] = ide.ttsCache;
    window.setTimeout(function() {
      // Assume there is only one instance running in the iframe.
      /** @type {!Processing} */
      var inst;
      try {
        /** @suppress {missingProperties} */
        inst = /** @type {!Processing} */(contentWindow.Processing['instances'][0]);
      } catch(/** @type {!Error} */e) {
        window.console.log('Could not find Processing in ');
      }
      ide.processing = inst;
      iframe.style.height = '' + (inst.height) + 'px';
      iframe.style.width = '' + (inst.width) + 'px';
      ide.prevWidth = inst.width;
      ide.prevHeight = inst.height;
    }, 1000);
    // Detect the size inside of the sketch.
    var m = processingCode.match(/[\r\n \t]size[ \t]*\([ \t]*([0-9]+)[ \t]*,[ \t]*([0-9]+)[ \t]*\)/);
    if (m) {
      iframe.style.height = '' + m[2] + 'px';
      iframe.style.width = '' + m[1] + 'px';
    } else if (ide.prevHeight > 0) {
      // Otherwise default to the previously detected size.
      iframe.style.height = '' + (ide.prevHeight) + 'px';
      iframe.style.width = '' + (ide.prevWidth) + 'px';
    }
    ide.canvasDiv.style.overflow = 'visible';
  }

  function stopSketch() {
    switchSketchState(false);
    ide.canvasDiv.style.overflow = 'hidden';
    //ide.processingCanvas.style.width = '100%';
    //ide.processingCanvas.style.height = '100%';
  }

  /**
   * @param {boolean} on
   */
  function switchSketchState(on) {
    if (!ide.processing) {
      window.console.error('No processing instance');
      return;
    }
    if (on) {
      ide.processing.loop();
    } else {
      ide.processing.noLoop();
    }
  }

  /**
   * @param {string} refkey
   */
  function showHelpSection(refkey) {
    if (refkey.startsWith('#')) refkey = refkey.substr(1);
    /** @type {?Element} */
    var doc = ide.referenceDict[refkey];
    if (doc) {
      // Empty the help div.
      while (ide.helpDiv.lastChild) {
        ide.helpDiv.removeChild(ide.helpDiv.lastChild);
      }
      ide.helpDiv.appendChild(doc);
      updateFragment('help', refkey.substr(4));
    } else {
      var keyword = refkey.substr(4);
      ide.helpDiv.innerHTML =
          ('
No help on ' + keyword + '.' +
     '
Put the cursor on a function name and press [Help] button
');
    }
  }

  function showHelp() {
    var cursor = ide.codemirror.getCursor();
    var line = ide.codemirror.getLine(cursor.line);
    // Find the identifier under cursor.
    var match = /^([a-zA-Z0-9_]*)/.exec(line.substr(cursor.ch));
    match = /([a-zA-Z_][a-zA-Z0-9_]*)([^a-zA-Z_]*)$/.exec(
        line.substr(0, cursor.ch) + match[1]);
    if (!match) {
      // Retry with the complete line.
      match = /([a-zA-Z_][a-zA-Z0-9_]*)/.exec(line);
    }
    if (!match) {
      // Help invoked on empty line?
      window.console.log('no help');
      return;
    }
    var keyword = match[1];
    showHelpSection('ref-' + keyword);
  }

  // Saves the sketch automatically if there were any changes.
  function autosaveSketch() {
    /** @type {string} */
    var source = ide.codemirror.getValue();
    if (ide.saved != source) {
      saveSketch();
      ide.saved = source;
    }
  }

  function saveSketch() {
    var /** string */processingCode = ide.codemirror.getValue();
    var params = parseFragment();
    ide.textarea.value = processingCode;
    var data = $(ide.textarea).serializeArray();
    var id = params['sketch'];
    // Note the saved state.
    if (id) {
      //window.console.log("Saving /sketch/" + id);
      $.post('/sketch/' + id, data, function(data, status, xhr) {
        if (status == 'success') {
          //ide.helpDiv.innerHTML = '
Saved OK
';
          window.console.log("Saved /sketch/" + id);
        } else {
          //ide.helpDiv.innerHTML = '
Saved error: ' + status + '
';
          window.console.error(status);
        }
      });
    } else {
      //window.console.log("Saving new sketch");
      $.post('/sketch', data, function(data, status, xhr) {
        var id = data;
        if (status == 'success') {
          //ide.helpDiv.innerHTML = '
Saved OK
';
          window.console.log("Saved /sketch/" + id);
          updateFragment('sketch', id);
        } else {
          //ide.helpDiv.innerHTML = '
Saved error: ' + status + '
';
          window.console.error(status);
        }
      });
    }
  }

  /**
   * @param {!Event} ev
   * @return {boolean}
   */
  function showDoc(ev) {
    var elt = /** @type {!Element} */ (ev.target);
    var hash = elt.getAttribute('href');
    showHelpSection(hash);
    updateFragment('help', hash.substr(5));
    return false;
  }

  /**
   * @param {!Event} ev
   */
  function helpTop(ev) {
    ev.preventDefault();
    showHelpSection('ref-help');
  }

  /**
   * @param {!Event} ev
   */
  function helpIndex(ev) {
    ev.preventDefault();
    showHelpSection('ref-index');
  }

  function computeReferenceDict() {
    $('div.section').each(function(index, elt) {
      ide.referenceDict[elt.id] = elt;
    });
    $('a').each(function(index, elt) {
      var href = elt.getAttribute('href');
      if (href.startsWith('#ref-')) {
        $(elt).click(showDoc);
      }
    });
    // Add the [Load] buttons to code snippets.
    $('pre').each(function(index, elt) {
      var code = $(elt).find('code');
      if (code.length == 1) {
        var source = /** @type {string} */(code.text());
        var button = document.createElement("button");
        $(button).text('読み込む');
        $(button).click(function(ev) {
          ev.preventDefault();
          ide.codemirror.setValue(source);
          // Avoid autosaving unless there were changes.
          ide.saved = source;
          // Forget the previous sketch id.
          updateFragment('sketch', null);
        });
        $(elt).prepend($('
'));
        $(elt).prepend(button);
      }
    });
  }

  function setup() {
    computeReferenceDict();
    document.getElementById('start_sketch_button')
      .addEventListener('click',  startSketch);
    document.getElementById('stop_sketch_button')
      .addEventListener('click', stopSketch);
    document.getElementById('show_help_button')
      .addEventListener('click', showHelp);
    document.getElementById('help_top_button')
      .addEventListener('click', helpTop);
    document.getElementById('help_index_button')
      .addEventListener('click', helpIndex);
    ide.textarea = /** @type {!HTMLTextAreaElement} */ (
        document.getElementById('editor_textarea'));
    var validator = function(text, options) {
      return processingjs.lint.validator(text, options, toplevelGrammar.parse);
    };
    var codemirror_options = {
      value: ide.textarea.value,
      mode: 'clike',
      lint: validator,
      extraKeys: {
        'F1': showHelp,
      },
    };
    // Parse and act on the fragment address.
    if (window.location.hash) {
      var params = parseFragment();
      //window.console.log(params);
      if (params['sketch']) {
        var id = params['sketch'];
        $.ajax('/sketch/' + id, {
          success:
          /**
           * @param {string} data
           */
          function(data) {
            window.console.log("Loaded /sketch/" + id);
            // Reset the saved state.
            ide.saved = data;
            ide.textarea.value = data;
            ide.codemirror.setValue(data);
          },
          error:
          /**
           * @param {!Object} jqXHR
           * @param {?Object} status
           * @param {?Object} err
           */
          function(jqXHR, status, err) {
            window.console.error(status, err);
          },
        });
      }
      // TODO(salikh): Parse 'help' key from the fragment
      // and show the appropriate help page.
    }
    // Instantiate CodeMirror.
    ide.codemirror = CodeMirror.fromTextArea(ide.textarea, codemirror_options);
    ide.codemirror.setOption("extraKeys", { Tab: showHelp });
    ide.canvasDiv = document.getElementById('canvas_div');
    ide.helpDiv = document.getElementById('help_div');
    ide.processingCanvas = /** @type{HTMLCanvasElement!} */(document.getElementById('processing_canvas'));
    if (params['help']) {
      showHelpSection('ref-' + params['help']);
    }
  }

  window.addEventListener('load', function() {
    // window.console.log("page loaded");
    setup();
  });

  // Autosave every 3 seconds.
  window.setInterval(autosaveSketch, 3000);

  return ide;
}))();
<|endoftext|>


<commit_before>
var kue = require('kue')
  , redis = require('redis');

/*
 *
 * The jobs plugin initializes Kue.
 *
 */
var Plugin = module.exports = {};

/**
 * @param {Number} config.port Port where redis is running
 * @param {String} config.host Hostname where the redis instance runs
 * @param {Object} config.auth Authentication options for redis
 * @param {String} config.webPath Path under which the admin webapp will be mounted
 */
Plugin.attach = function(config) {

    kue.redis.createClient = function() {
        var client = redis.createClient(config.port, config.host);
        if (config.auth) {
            client.auth(config.auth);
        }
        return client;
    };

    this.jobs = kue.createQueue();

    if (this.express && config.webPath) {
        this.express.after(config.webPath, kue.app);
    }

};
<commit_msg>Handling issues with Kue connection failures.<commit_after>
var kue = require('kue')
  , logger = require('winston')
  , redis = require('redis');

/*
 *
 * The jobs plugin initializes Kue.
 *
 */
var Plugin = module.exports = {};

/**
 * @param {Number} config.port Port where redis is running
 * @param {String} config.host Hostname where the redis instance runs
 * @param {Object} config.auth Authentication options for redis
 * @param {String} config.webPath Path under which the admin webapp will be mounted
 */
Plugin.attach = function(config) {

    kue.redis.createClient = function() {
        var client = redis.createClient(config.port, config.host);
        client.on('error', function(error) {
            logger.error("Error in connection to KUE Redis");
        });
        client.on('connect', function() {
            logger.info("Connection to KUE Redis server open");
        })
        if (config.auth) {
            client.auth(config.auth);
        }
        return client;
    };

    this.jobs = kue.createQueue();

    if (this.express && config.webPath) {
        this.express.after(config.webPath, kue.app);
    }

};
<|endoftext|>


<commit_before>// Miscellaneous helpers
//

// log4js is optional.
function getLogger(label) {
  var log;
  try {
    log = require('log4js')().getLogger(scrub_creds(label || 'audit_couchdb'));
    log.setLevel('info');
  } catch(e) {
    log = { "trace": function() {}
          , "debug": function() {}
          , "info" : console.log
          , "warn" : console.log
          , "error": console.log
          , "fatal": console.log
          }
    log.setLevel = function noop() {};
  }

  // Scrub credentials.
  ; ['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(function(level) {
    var inner = log[level];
    log[level] = function log_scrubbed() {
      var args = Array.prototype.slice.apply(arguments);
      args[0] = scrub_creds(args[0]);
      return inner.apply(this, args);
    }
  })

  return log;
}

function scrub_creds(url) {
  if(typeof url === 'string')
    url = url.replace(/(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
  return url;
}

function join_and_fix_slashes() {
  return Array.prototype.map.apply(arguments, [function trimmed(arg) {
    return arg.replace(/^\/+/, "").replace(/\/+$/, "");
  }]).join('/');
}

module.exports = { "getLogger"  : getLogger
                 , "join"       : join_and_fix_slashes
                 };
<commit_msg>Security and session object helpers<commit_after>// Miscellaneous helpers
//

// log4js is optional.
function getLogger(label) {
  var log;
  try {
    log = require('log4js')().getLogger(scrub_creds(label || 'audit_couchdb'));
    log.setLevel('info');
  } catch(e) {
    log = { "trace": function() {}
          , "debug": function() {}
          , "info" : console.log
          , "warn" : console.log
          , "error": console.log
          , "fatal": console.log
          }
    log.setLevel = function noop() {};
  }

  // Scrub credentials.
  ; ['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(function(level) {
    var inner = log[level];
    log[level] = function log_scrubbed() {
      var args = Array.prototype.slice.apply(arguments);
      args[0] = scrub_creds(args[0]);
      return inner.apply(this, args);
    }
  })

  return log;
}

function scrub_creds(url) {
  if(typeof url === 'string')
    url = url.replace(/(https?:\/\/)[^:]+:[^@]+@(.*)$/, '$1$2'); // Scrub username and password
  return url;
}

function join_and_fix_slashes() {
  return Array.prototype.map.apply(arguments, [function trimmed(arg) {
    return arg.replace(/^\/+/, "").replace(/\/+$/, "");
  }]).join('/');
}

function normalize_security(security) {
  security = JSON.parse(JSON.stringify(security));
  security.admins = security.admins || {};
  security.admins.names = security.admins.names || [];
  security.admins.roles = security.admins.roles || [];
  security.readers = security.readers || {};
  security.readers.names = security.readers.names || [];
  security.readers.roles = security.readers.roles || [];
  return security;
}

function admin_session(name) {
  return { userCtx: { name:(name || null), roles:['_admin'] } }
}

function admin_party_session() {
  return admin_session(null);
}

function normal_session(name, roles) {
  return { userCtx: { name:(name || null), roles:(roles || []) } }
}

function anonymous_session() {
  return normal_session(null, []);
}

session = { anonymous: anonymous_session
          , admin_party: admin_party_session
          , admin      : admin_session
          , normal     : normal_session
          };

module.exports = { "getLogger"  : getLogger
                 , "join"       : join_and_fix_slashes
                 , "normalize_security" : normalize_security
                 , "session"    : session
                 };
<|endoftext|>


<commit_before>var winston = require('winston');

LOG_LEVELS = {
	'g2' : 'debug',
	'gcode' : 'debug',
	'sbp' : 'debug',
	'machine' : 'debug',
	'manual' : 'debug',
	'api' : 'debug'
};

var create_logger = function(name) {
	log_level = LOG_LEVELS[name] || 'info';
	container = winston.loggers;
	l = container.add(name, {
	    console: {
	      level: log_level,
	      colorize: true,
          handleExceptions: false
	    },
  	});
    l.exitOnError = false;
    //return expandErrors(l);
    return l
}

var logger = function(name) {
	if(winston.loggers.has(name)) {
		return winston.loggers.get(name);
	} else {
		return create_logger(name);
	}
}

exports.logger = logger;
<commit_msg>Replace winston with dumber but better-working logger<commit_after>var process = require('process');
try { var colors = require('colors'); } catch(e) {var colors = false}

LEVELS = {
	'debug' : 0,
	'info' : 1,
	'warn' : 2,
	'error' : 3,
}

LOG_LEVELS = {
	'g2' : 'debug',
	'gcode' : 'debug',
	'sbp' : 'debug',
	'machine' : 'debug',
	'manual' : 'debug',
	'api' : 'debug'
};

var logs = {};

var Logger = function(name) {
	this.name = name;
}

Logger.prototype.write = function(level, msg) {
	my_level = LOG_LEVELS[this.name] || 'debug';
	if((LEVELS[level] || 0) >= (LEVELS[my_level] || 0)) {
		if(colors) {
			switch(level) {
				case 'debug':
					console.log((level + ': ').blue + msg)
					break;
				case 'info':
					console.log((level + ': ').green + msg)
					break;
				case 'warn':
					console.log((level + ': ').yellow + msg)
					break;
				case 'error':
					console.log((level + ': ').red + msg)
					break;
			}
		} else {
			console.log(level + ': ' + msg)
		}
	}
}

Logger.prototype.debug = function(msg) {
	this.write('debug', msg)
}

Logger.prototype.info = function(msg) {
	this.write('info', msg)
}

Logger.prototype.warn = function(msg) {
	this.write('warn', msg)
}

Logger.prototype.error = function(msg) {
	this.write('error', msg)
}

var logger = function(name) {
	if(name in logs) {
		return logs[name];
	} else {
		l = new Logger(name);
		logs[name] = l;
		return l;
	}
}

exports.logger = logger;
<|endoftext|>


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

var parseArgs = function(config){
	console.log(config)
	var all = Object.keys(config.defaults);
	// console.log(all)
	for(var i=config.required.length; i--;){
		if(all.indexOf(config.required[i]) !== -1){
			config.required.splice(i, 1);
		}
	}

	if(config.required.length !== 0) return false;

	var out = '';
	for(var i=0; i< config.takes.length; i++){
		if(all.indexOf(config.takes[i]) !== -1){
			out += '--'+config.takes[i]+' '+config.defaults[config.takes[i]]+' ';
		}
	}

	return out;
};

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

	return exec(command, (function(callback){
		return function(err,data,stderr){
			if(callback){
				return callback(data, err, stderr);
			}
		}
	})(callback));
};

var Container = function(config){
	this.name = config.name;
	this.state = config.state || 'STOPPED';
	this.ip = config.ip || (config.ipv4 || '').replace('-', '') || null ;
	this.overlayfs = null
}

Container.prototype.clone = function(callback){
	var overlayfs = this.overlayfs ? ' -B overlayfs -s ' : '';

	return sysExec('lxc-clone -o '+this.orig+ ' -n '+this.name + overlayfs, callback);
};

Container.prototype.start = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name'],
		defaults: extend({}, this)

	});

	var that = this;
	callback = function(callback){
		that.info();
		return callback;
	};
	return sysExec('lxc-start --daemon '+args, callback);
};

Container.prototype.startEphemeral = function(callback){
	var args = parseArgs({
		required: ['orig'],
		takes: ['orig', 'name', 'key', 'union-type', 'keep-data'],
		defaults: extend({}, this)

	});

	var command = 'lxc-start-ephemeral --daemon '+args;
	return sysExec(command, function(data){
		console.log('startEphemeral', arguments);
		if(data.match("doesn't exist.")){
			return callback({status: 500, error: "doesn't exist."});
		}
		if(data.match('already exists.')){
			return callback({status: 500, error: 'already exists'});
		}
		if(data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)){
			return callback({status: 200, state:'RUNNING', ip: data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
		}

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

Container.prototype.destroy = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});

	return sysExec('lxc-destroy '+ args, function(data){
		var info = data.match(/Destroyed container/);
		console.log('destroy info:', info);
		var args = [true].concat(Array.prototype.slice.call(arguments, 1));
		return callback.apply(this, args);
	});
},

Container.prototype.stop = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'reboot', 'nowait', 'timeout', 'kill'],
		defaults: extend({}, this)

	});
		var that = this;
	callback = function(callback){
		that.info();
		return callback;
	};
	return sysExec('lxc-stop '+args, callback);
};

Container.prototype.freeze = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});
	return sysExec('lxc-freeze -n '+name, callback);
};

Container.prototype.unfreeze = function(callback){

	return sysExec('lxc-unfreeze --name '+this.name, callback);
};

Container.prototype.info = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'reboot', 'nowait', 'timeout', 'kill'],
		defaults: extend({}, this)

	});
	return sysExec('lxc-stop '+args, callback);
};

Container.prototype.freeze = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});
	return sysExec('lxc-freeze -n '+name, callback);
};

Container.prototype.unfreeze = function(callback){

	return sysExec('lxc-unfreeze --name '+this.name, callback);
};

Container.prototype.info = function(callback){
	var that = this;
	callback = callback || function(){}

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

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

		that.UpdateFromInfo(info);

		var args = [info].concat(Array.prototype.slice.call(arguments, 1));
		return callback.apply(this, args);
	});
};

Container.prototype.UpdateFromInfo = function(data){
	for(var key in Object.keys(data)){
		this[key] = data[key];
	}

	return this;
}

var lxcORM = function(){
	this.containers = {};
	this.isReady = false;
	this.whenReady = [];
	var that = this;

	this.list(function(data){
		for(var idx = data.length; idx--;){
			that.containers[data[idx].name] = new Container(data[idx]);
			if(idx===0){
				// console.log('call ready!')
				that.callReady();
			}
		}
	});

};

lxcORM.prototype.callReady = function(){
	for(var idx=0; idx<this.whenReady.length; idx--){
		this.whenReady[idx].apply(this);
	}
	this.isReady = true;
};

lxcORM.prototype.ready = function(callback){
	if(this.isReady){
		return callback.apply(this);
	}
	else{
		this.whenReady.push(callback);
	}
};

lxcORM.prototype.create = function(args, callback){

	var args = parseArgs({
		required: ['name', 'template'],
		takes: ['name', 'template', ' ', 'd', 'r', 'a'],
		defaults: extend({template:'download', ' ': ' ', d: 'ubuntu', r: 'trusty', a: 'amd64'}, args)

	})

	return sysExec('lxc-create '+args, callback);
};

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

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

		for(var i in output){
			if(output[i].match(/^-/)) continue; // compatibility with 1.x and 2.x output

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

		}
		var args = [info].concat(Array.prototype.slice.call(arguments, 1));
		callback.apply(this, args);
	});
};

module.exports = new lxcORM();
<commit_msg>stuff<commit_after>'use strict';
var exec = require('child_process').exec;
var extend = require('node.extend');

var parseArgs = function(config){
	console.log(config)
	var all = Object.keys(config.defaults);
	// console.log(all)
	for(var i=config.required.length; i--;){
		if(all.indexOf(config.required[i]) !== -1){
			config.required.splice(i, 1);
		}
	}

	if(config.required.length !== 0) return false;

	var out = '';
	for(var i=0; i< config.takes.length; i++){
		if(all.indexOf(config.takes[i]) !== -1){
			out += '--'+config.takes[i]+' '+config.defaults[config.takes[i]]+' ';
		}
	}

	return out;
};

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

	return exec(command, (function(callback){
		return function(err,data,stderr){
			if(callback){
				return callback(data, err, stderr);
			}
		}
	})(callback));
};

var Container = function(config){
	this.name = config.name;
	this.state = config.state || 'STOPPED';
	this.ip = config.ip || (config.ipv4 || '').replace('-', '') || null ;
	this.overlayfs = null
}

Container.prototype.clone = function(callback){
	var overlayfs = this.overlayfs ? ' -B overlayfs -s ' : '';

	return sysExec('lxc-clone -o '+this.orig+ ' -n '+this.name + overlayfs, callback);
};

Container.prototype.start = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name'],
		defaults: extend({}, this)

	});

	var that = this;
	callback = function(callback){
		that.info();
		return callback;
	};
	return sysExec('lxc-start --daemon '+args, callback);
};

Container.prototype.startEphemeral = function(callback){
	var args = parseArgs({
		required: ['orig'],
		takes: ['orig', 'name', 'key', 'union-type', 'keep-data'],
		defaults: extend({}, this)

	});

	var command = 'lxc-start-ephemeral --daemon '+args;
	return sysExec(command, function(data){
		console.log('startEphemeral', arguments);
		if(data.match("doesn't exist.")){
			return callback({status: 500, error: "doesn't exist."});
		}
		if(data.match('already exists.')){
			return callback({status: 500, error: 'already exists'});
		}
		if(data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)){
			return callback({status: 200, state:'RUNNING', ip: data.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
		}

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

Container.prototype.destroy = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});

	return sysExec('lxc-destroy '+ args, function(data){
		var info = data.match(/Destroyed container/);
		console.log('destroy info:', info);
		var args = [true].concat(Array.prototype.slice.call(arguments, 1));
		return callback.apply(this, args);
	});
},

Container.prototype.stop = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'reboot', 'nowait', 'timeout', 'kill'],
		defaults: extend({}, this)

	});
		var that = this;
	callback = function(callback){
		that.info();
		return callback;
	};
	return sysExec('lxc-stop '+args, callback);
};

Container.prototype.freeze = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});
	return sysExec('lxc-freeze -n '+name, callback);
};

Container.prototype.unfreeze = function(callback){

	return sysExec('lxc-unfreeze --name '+this.name, callback);
};

Container.prototype.info = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'reboot', 'nowait', 'timeout', 'kill'],
		defaults: extend({}, this)

	});
	return sysExec('lxc-stop '+args, callback);
};

Container.prototype.freeze = function(callback){
	var args = parseArgs({
		required: ['name'],
		takes: ['name', 'force'],
		defaults: extend({}, this)
	});
	return sysExec('lxc-freeze -n '+name, callback);
};

Container.prototype.unfreeze = function(callback){

	return sysExec('lxc-unfreeze --name '+this.name, callback);
};

Container.prototype.info = function(callback){
	var that = this;
	callback = callback || function(){}

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

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

		that.updateFromInfo(info);

		var args = [info].concat(Array.prototype.slice.call(arguments, 1));
		return callback.apply(that, args);
	});
};

Container.prototype.updateFromInfo = function(data){
	for(var key in Object.keys(data)){
		console.log('update key:', key);
		this[key] = data[key];
	}

	return this;
}

var lxcORM = function(){
	this.containers = {};
	this.isReady = false;
	this.whenReady = [];
	var that = this;

	this.list(function(data){
		for(var idx = data.length; idx--;){
			that.containers[data[idx].name] = new Container(data[idx]);
			if(idx===0){
				// console.log('call ready!')
				that.callReady();
			}
		}
	});

};

lxcORM.prototype.callReady = function(){
	for(var idx=0; idx<this.whenReady.length; idx--){
		this.whenReady[idx].apply(this);
	}
	this.isReady = true;
};

lxcORM.prototype.ready = function(callback){
	if(this.isReady){
		return callback.apply(this);
	}
	else{
		this.whenReady.push(callback);
	}
};

lxcORM.prototype.create = function(args, callback){

	var args = parseArgs({
		required: ['name', 'template'],
		takes: ['name', 'template', ' ', 'd', 'r', 'a'],
		defaults: extend({template:'download', ' ': ' ', d: 'ubuntu', r: 'trusty', a: 'amd64'}, args)

	})

	return sysExec('lxc-create '+args, callback);
};

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

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

		for(var i in output){
			if(output[i].match(/^-/)) continue; // compatibility with 1.x and 2.x output

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

		}
		var args = [info].concat(Array.prototype.slice.call(arguments, 1));
		callback.apply(this, args);
	});
};

module.exports = new lxcORM();
<|endoftext|>


<commit_before>// ;; #path=Mappable #kind=interface
// There are various things that positions can be mapped through.
// We'll denote those as 'mappable'. This is not an actual class in
// the codebase, only an agreed-on interface.

// :: (pos: number, bias: ?number) → MapResult
// #path=Mappable.map
// Map a position through this object. When given, the `bias`
// determines in which direction to move when a chunk of content is
// inserted at or around the mapped position.

export class ReplacedRange {
  constructor(pos, oldSize, newSize) {
    this.pos = pos
    this.oldSize = oldSize
    this.newSize = newSize
  }

  size(old) { return old ? this.oldSize : this.newSize }

  toString() {
    return "[@" + this.pos + " " + this.oldSize + "->" + this.newSize + "]"
  }
}

function mapThrough(ranges, pos, bias = 1, back) {
  let diff = 0
  for (let i = 0; i < ranges.length; i++) {
    let range = ranges[i], start = range.pos - (back ? diff : 0)
    if (start > pos) break
    let oldSize = range.size(!back), newSize = range.size(back), end = start + oldSize
    if (pos <= end) {
      let recover = {index: i, offset: pos - start}
      let side = !oldSize ? bias : pos == start ? -1 : pos == end ? 1 : bias
      return new MapResult(start + diff + (side < 0 ? 0 : newSize), pos != start && pos != end, recover)
    }
    diff += newSize - oldSize
  }
  return new MapResult(pos + diff)
}

function touches(ranges, pos, offset, back) {
  let diff = 0
  for (let i = 0; i < ranges.length; i++) {
    let range = ranges[i], start = range.pos - (back ? diff : 0)
    if (start > pos) break
    let oldSize = range.size(!back), newSize = range.size(back), end = start + oldSize
    if (i == offset.index && pos <= end) return true
    diff += newSize - oldSize
  }
  return false
}

// ;; The return value of mapping a position.
export class MapResult {
  constructor(pos, deleted = false, recover = null) {
    // :: number The mapped version of the position.
    this.pos = pos
    // :: bool Tells you whether the position was deleted, that is,
    // whether the step removed its surroundings from the document.
    this.deleted = deleted
    this.recover = recover
  }
}

// ;; A position map, holding information about the way positions in
// the pre-step version of a document correspond to positions in the
// post-step version. This class implements `Mappable`.
export class PosMap {
  constructor(ranges) { this.ranges = ranges }

  recover(offset) {
    let diff = 0
    for (let i = 0; i < offset.index; i++)
      diff += this.ranges[i].oldSize - this.ranges[i].newSize
    return this.ranges[offset.index].pos + diff + offset.offset
  }

  // :: (number, ?number) → MapResult
  // Map the given position through this map. The `bias` parameter can
  // be used to control what happens when the transform inserted
  // content at (or around) this position—if `bias` is negative, the a
  // position before the inserted content will be returned, if it is
  // positive, a position after the insertion is returned.
  map(pos, bias) {
    return mapThrough(this.ranges, pos, bias, false)
  }

  touches(pos, offset) { return touches(this.ranges, pos, offset, false) }

  // :: () → PosMap
  // Create an inverted version of this map. The result can be used to
  // map positions in the post-step document to the pre-step document.
  invert() { return new InvertedPosMap(this.ranges) }

  toString() { return this.ranges.join(" ") }
}

class InvertedPosMap {
  constructor(ranges) { this.ranges = ranges }

  recover(offset) {
    return this.ranges[offset.index].pos + offset.offset
  }

  map(pos, bias) { return mapThrough(this.ranges, pos, bias, true) }

  touches(pos, offset) { return touches(this.ranges, pos, offset, true) }

  invert() { return new PosMap(this.ranges) }

  toString() { return "-" + this.ranges.join(" ") }
}

PosMap.empty = new PosMap([])

// ;; A remapping represents a pipeline of zero or more mappings. It
// is a specialized data structured used to manage mapping through a
// series of steps, typically including inverted and non-inverted
// versions of the same step. (This comes up when ‘rebasing’ steps for
// collaboration or history management.) This class implements
// `Mappable`.
export class Remapping {
  // :: (?[PosMap], ?[PosMap])
  constructor(head = [], tail = [], mirror = Object.create(null)) {
    // :: [PosMap]
    // The maps in the head of the mapping are applied to input
    // positions first, back-to-front. So the map at the end of this
    // array (if any) is the very first one applied.
    this.head = head
    // The maps in the tail are applied last, front-to-back.
    this.tail = tail
    this.mirror = mirror
  }

  // :: (PosMap, ?number) → number
  // Add a map to the mapping's front. If this map is the mirror image
  // (produced by an inverted step) of another map in this mapping,
  // that map's id (as returned by this method or
  // [`addToBack`](#Remapping.addToBack)) should be passed as a second
  // parameter to register the correspondence.
  addToFront(map, corr) {
    this.head.push(map)
    let id = -this.head.length
    if (corr != null) this.mirror[id] = corr
    return id
  }

  // :: (PosMap, ?number) → number
  // Add a map to the mapping's back. If the map is the mirror image
  // of another mapping in this object, the id of that map should be
  // passed to register the correspondence.
  addToBack(map, corr) {
    this.tail.push(map)
    let id = this.tail.length - 1
    if (corr != null) this.mirror[corr] = id
    return id
  }

  get(id) {
    return id < 0 ? this.head[-id - 1] : this.tail[id]
  }

  // :: (number, ?number) → MapResult
  // Map a position through this remapping, optionally passing a bias
  // direction.
  map(pos, bias) {
    let deleted = false, recoverables = null

    for (let i = -this.head.length; i < this.tail.length; i++) {
      let map = this.get(i), rec

      if ((rec = recoverables && recoverables[i]) && map.touches(pos, rec)) {
        pos = map.recover(rec)
        continue
      }

      let result = map.map(pos, bias)
      if (result.recover) {
        let corr = this.mirror[i]
        if (corr != null) {
          if (result.deleted) {
            i = corr
            pos = this.get(corr).recover(result.recover)
            continue
          } else {
            ;(recoverables || (recoverables = Object.create(null)))[corr] = result.recover
          }
        }
      }

      if (result.deleted) deleted = true
      pos = result.pos
    }

    return new MapResult(pos, deleted)
  }
}
<commit_msg>Remove undocumented Remapping constructor arg<commit_after>// ;; #path=Mappable #kind=interface
// There are various things that positions can be mapped through.
// We'll denote those as 'mappable'. This is not an actual class in
// the codebase, only an agreed-on interface.

// :: (pos: number, bias: ?number) → MapResult
// #path=Mappable.map
// Map a position through this object. When given, the `bias`
// determines in which direction to move when a chunk of content is
// inserted at or around the mapped position.

export class ReplacedRange {
  constructor(pos, oldSize, newSize) {
    this.pos = pos
    this.oldSize = oldSize
    this.newSize = newSize
  }

  size(old) { return old ? this.oldSize : this.newSize }

  toString() {
    return "[@" + this.pos + " " + this.oldSize + "->" + this.newSize + "]"
  }
}

function mapThrough(ranges, pos, bias = 1, back) {
  let diff = 0
  for (let i = 0; i < ranges.length; i++) {
    let range = ranges[i], start = range.pos - (back ? diff : 0)
    if (start > pos) break
    let oldSize = range.size(!back), newSize = range.size(back), end = start + oldSize
    if (pos <= end) {
      let recover = {index: i, offset: pos - start}
      let side = !oldSize ? bias : pos == start ? -1 : pos == end ? 1 : bias
      return new MapResult(start + diff + (side < 0 ? 0 : newSize), pos != start && pos != end, recover)
    }
    diff += newSize - oldSize
  }
  return new MapResult(pos + diff)
}

function touches(ranges, pos, offset, back) {
  let diff = 0
  for (let i = 0; i < ranges.length; i++) {
    let range = ranges[i], start = range.pos - (back ? diff : 0)
    if (start > pos) break
    let oldSize = range.size(!back), newSize = range.size(back), end = start + oldSize
    if (i == offset.index && pos <= end) return true
    diff += newSize - oldSize
  }
  return false
}

// ;; The return value of mapping a position.
export class MapResult {
  constructor(pos, deleted = false, recover = null) {
    // :: number The mapped version of the position.
    this.pos = pos
    // :: bool Tells you whether the position was deleted, that is,
    // whether the step removed its surroundings from the document.
    this.deleted = deleted
    this.recover = recover
  }
}

// ;; A position map, holding information about the way positions in
// the pre-step version of a document correspond to positions in the
// post-step version. This class implements `Mappable`.
export class PosMap {
  constructor(ranges) { this.ranges = ranges }

  recover(offset) {
    let diff = 0
    for (let i = 0; i < offset.index; i++)
      diff += this.ranges[i].oldSize - this.ranges[i].newSize
    return this.ranges[offset.index].pos + diff + offset.offset
  }

  // :: (number, ?number) → MapResult
  // Map the given position through this map. The `bias` parameter can
  // be used to control what happens when the transform inserted
  // content at (or around) this position—if `bias` is negative, the a
  // position before the inserted content will be returned, if it is
  // positive, a position after the insertion is returned.
  map(pos, bias) {
    return mapThrough(this.ranges, pos, bias, false)
  }

  touches(pos, offset) { return touches(this.ranges, pos, offset, false) }

  // :: () → PosMap
  // Create an inverted version of this map. The result can be used to
  // map positions in the post-step document to the pre-step document.
  invert() { return new InvertedPosMap(this.ranges) }

  toString() { return this.ranges.join(" ") }
}

class InvertedPosMap {
  constructor(ranges) { this.ranges = ranges }

  recover(offset) {
    return this.ranges[offset.index].pos + offset.offset
  }

  map(pos, bias) { return mapThrough(this.ranges, pos, bias, true) }

  touches(pos, offset) { return touches(this.ranges, pos, offset, true) }

  invert() { return new PosMap(this.ranges) }

  toString() { return "-" + this.ranges.join(" ") }
}

PosMap.empty = new PosMap([])

// ;; A remapping represents a pipeline of zero or more mappings. It
// is a specialized data structured used to manage mapping through a
// series of steps, typically including inverted and non-inverted
// versions of the same step. (This comes up when ‘rebasing’ steps for
// collaboration or history management.) This class implements
// `Mappable`.
export class Remapping {
  // :: (?[PosMap], ?[PosMap])
  constructor(head = [], tail = []) {
    // :: [PosMap]
    // The maps in the head of the mapping are applied to input
    // positions first, back-to-front. So the map at the end of this
    // array (if any) is the very first one applied.
    this.head = head
    // The maps in the tail are applied last, front-to-back.
    this.tail = tail
    this.mirror = Object.create(null)
  }

  // :: (PosMap, ?number) → number
  // Add a map to the mapping's front. If this map is the mirror image
  // (produced by an inverted step) of another map in this mapping,
  // that map's id (as returned by this method or
  // [`addToBack`](#Remapping.addToBack)) should be passed as a second
  // parameter to register the correspondence.
  addToFront(map, corr) {
    this.head.push(map)
    let id = -this.head.length
    if (corr != null) this.mirror[id] = corr
    return id
  }

  // :: (PosMap, ?number) → number
  // Add a map to the mapping's back. If the map is the mirror image
  // of another mapping in this object, the id of that map should be
  // passed to register the correspondence.
  addToBack(map, corr) {
    this.tail.push(map)
    let id = this.tail.length - 1
    if (corr != null) this.mirror[corr] = id
    return id
  }

  get(id) {
    return id < 0 ? this.head[-id - 1] : this.tail[id]
  }

  // :: (number, ?number) → MapResult
  // Map a position through this remapping, optionally passing a bias
  // direction.
  map(pos, bias) {
    let deleted = false, recoverables = null

    for (let i = -this.head.length; i < this.tail.length; i++) {
      let map = this.get(i), rec

      if ((rec = recoverables && recoverables[i]) && map.touches(pos, rec)) {
        pos = map.recover(rec)
        continue
      }

      let result = map.map(pos, bias)
      if (result.recover) {
        let corr = this.mirror[i]
        if (corr != null) {
          if (result.deleted) {
            i = corr
            pos = this.get(corr).recover(result.recover)
            continue
          } else {
            ;(recoverables || (recoverables = Object.create(null)))[corr] = result.recover
          }
        }
      }

      if (result.deleted) deleted = true
      pos = result.pos
    }

    return new MapResult(pos, deleted)
  }
}
<|endoftext|>